diff --git a/src/modules/cart/controllers/cart.controller.ts b/src/modules/cart/controllers/cart.controller.ts index c9e5d7a..40462b7 100644 --- a/src/modules/cart/controllers/cart.controller.ts +++ b/src/modules/cart/controllers/cart.controller.ts @@ -19,66 +19,65 @@ export class CartController { @Get() @ApiOperation({ summary: 'Get cart for current user and shop' }) @ApiHeader(API_HEADER_SLUG) - async findOne(@UserId() userId: string, @ShopId() restaurantId: string) { - return this.cartService.getOrCreateCart(userId, restaurantId); + async findOne(@UserId() userId: string, @ShopId() shopId: string) { + return this.cartService.getOrCreateCart(userId, shopId); } - @Post('items/:foodId/increment') + @Post('product/:productId/increment') @ApiOperation({ summary: 'Increment item quantity in cart by 1' }) @ApiHeader(API_HEADER_SLUG) - @ApiParam({ name: 'foodId', description: 'Product ID to increment in cart' }) - async incrementItem(@UserId() userId: string, @ShopId() restaurantId: string, @Param('foodId') foodId: string) { - return this.cartService.incrementItem(userId, restaurantId, foodId, 1); + @ApiParam({ name: 'productId', description: 'Product ID to increment in cart' }) + async incrementItem(@UserId() userId: string, @ShopId() shopId: string, @Param('productId') productId: string) { + return this.cartService.incrementItem(userId, shopId, productId, 1); } - @Post('items/:foodId/decrement') + @Post('product/:productId/decrement') @ApiOperation({ summary: 'Decrement item quantity in cart by 1 (removes item if quantity reaches 0)' }) @ApiHeader(API_HEADER_SLUG) - @ApiParam({ name: 'foodId', description: 'Product ID to decrement in cart' }) - async decrementItem(@UserId() userId: string, @ShopId() restaurantId: string, @Param('foodId') foodId: string) { - return this.cartService.decrementItem(userId, restaurantId, foodId); + @ApiParam({ name: 'productId', description: 'Product ID to decrement in cart' }) + async decrementItem(@UserId() userId: string, @ShopId() shopId: string, @Param('productId') productId: string) { + return this.cartService.decrementItem(userId, shopId, productId); } - @Post('items/bulk') + @Post('product/bulk') @ApiOperation({ summary: 'Bulk add items to cart (increments quantity if items exist)' }) @ApiHeader(API_HEADER_SLUG) @ApiBody({ type: BulkAddItemsToCartDto }) bulkAddItems( @UserId() userId: string, - @ShopId() restaurantId: string, + @ShopId() shopId: string, @Body() bulkAddItemsDto: BulkAddItemsToCartDto, ) { - return this.cartService.bulkAddItems(userId, restaurantId, bulkAddItemsDto); + return this.cartService.bulkAddItems(userId, shopId, bulkAddItemsDto); } - @Delete('items/:foodId') + @Delete('product/:productId') @ApiOperation({ summary: 'Remove item from cart' }) @ApiHeader(API_HEADER_SLUG) - @ApiParam({ name: 'foodId', description: 'Product ID in the cart' }) - async removeItem(@UserId() userId: string, @ShopId() restaurantId: string, @Param('foodId') foodId: string) { - return this.cartService.removeItem(userId, restaurantId, foodId); + @ApiParam({ name: 'productId', description: 'Product ID in the cart' }) + async removeItem(@UserId() userId: string, @ShopId() shopId: string, @Param('productId') productId: string) { + return this.cartService.removeItem(userId, shopId, productId); } @Delete() @ApiOperation({ summary: 'Clear entire cart' }) @ApiHeader(API_HEADER_SLUG) - async clearCart(@UserId() userId: string, @ShopId() restaurantId: string) { - return this.cartService.clearCart(userId, restaurantId); + async clearCart(@UserId() userId: string, @ShopId() shopId: string) { + return this.cartService.clearCart(userId, shopId); } - @Post('apply-coupon') + @Post('coupon') @ApiOperation({ summary: 'Apply coupon to cart' }) @ApiHeader(API_HEADER_SLUG) - @ApiBody({ type: ApplyCouponDto }) - async applyCoupon(@UserId() userId: string, @ShopId() restaurantId: string, @Body() applyCouponDto: ApplyCouponDto) { - return this.cartService.applyCoupon(userId, restaurantId, applyCouponDto); + async applyCoupon(@UserId() userId: string, @ShopId() shopId: string, @Body() applyCouponDto: ApplyCouponDto) { + return this.cartService.applyCoupon(userId, shopId, applyCouponDto); } @Delete('coupon') @ApiOperation({ summary: 'Remove coupon from cart' }) @ApiHeader(API_HEADER_SLUG) - async removeCoupon(@UserId() userId: string, @ShopId() restaurantId: string) { - return this.cartService.removeCoupon(userId, restaurantId); + async removeCoupon(@UserId() userId: string, @ShopId() shopId: string) { + return this.cartService.removeCoupon(userId, shopId); } @@ -86,7 +85,7 @@ export class CartController { @ApiOperation({ summary: 'Set all cart params' }) @ApiHeader(API_HEADER_SLUG) @ApiBody({ type: SetAllCartParmsDto }) - setAllCartParams(@UserId() userId: string, @ShopId() restaurantId: string, @Body() dto: SetAllCartParmsDto) { - return this.cartService.setAllCartParams(userId, restaurantId, dto); + setAllCartParams(@UserId() userId: string, @ShopId() shopId: string, @Body() dto: SetAllCartParmsDto) { + return this.cartService.setAllCartParams(userId, shopId, dto); } } diff --git a/src/modules/cart/dto/bulk-add-items.dto.ts b/src/modules/cart/dto/bulk-add-items.dto.ts index 347edbd..14c92eb 100644 --- a/src/modules/cart/dto/bulk-add-items.dto.ts +++ b/src/modules/cart/dto/bulk-add-items.dto.ts @@ -13,7 +13,7 @@ class AddItemToCartDto { @ApiProperty({ description: 'Product ID' }) @IsNotEmpty() @IsString() - foodId!: string; + productId!: string; } export class BulkAddItemsToCartDto { @@ -21,8 +21,8 @@ export class BulkAddItemsToCartDto { description: 'Array of items to add to cart', type: [AddItemToCartDto], example: [ - { foodId: 'product-123', quantity: 2 }, - { foodId: 'product-456', quantity: 1 }, + { productId: 'product-123', quantity: 2 }, + { productId: 'product-456', quantity: 1 }, ], }) @IsNotEmpty() diff --git a/src/modules/cart/dto/set-all-cart-params.dto.ts b/src/modules/cart/dto/set-all-cart-params.dto.ts index d329a51..df8f7de 100644 --- a/src/modules/cart/dto/set-all-cart-params.dto.ts +++ b/src/modules/cart/dto/set-all-cart-params.dto.ts @@ -1,8 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty, IsObject, IsOptional, IsString } from 'class-validator'; -import { SetCarDeliveryDto } from './set-car-delivery.dto'; - - + export class SetAllCartParmsDto { @ApiProperty({ description: 'Cart description or notes', @@ -27,14 +25,4 @@ export class SetAllCartParmsDto { @IsNotEmpty() @IsString() paymentMethodId!: string; - - @ApiProperty({ description: 'Table number for dine-in orders', example: '5', required: false }) - @IsOptional() - @IsString() - tableNumber?: string; - - @ApiProperty() - @IsOptional() - @IsObject() - carAddress?: SetCarDeliveryDto; } diff --git a/src/modules/cart/dto/set-car-delivery.dto.ts b/src/modules/cart/dto/set-car-delivery.dto.ts deleted file mode 100644 index 61c44dc..0000000 --- a/src/modules/cart/dto/set-car-delivery.dto.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsString } from 'class-validator'; - -export class SetCarDeliveryDto { - @ApiProperty({ description: 'Car model', example: 'Toyota Camry' }) - @IsNotEmpty() - @IsString() - carModel!: string; - - @ApiProperty({ description: 'Car color', example: 'White' }) - @IsNotEmpty() - @IsString() - carColor!: string; - - @ApiProperty({ description: 'License plate number', example: '12ABC345' }) - @IsNotEmpty() - @IsString() - plateNumber!: string; -} diff --git a/src/modules/cart/interfaces/cart.interface.ts b/src/modules/cart/interfaces/cart.interface.ts index bcc0510..9d2771f 100644 --- a/src/modules/cart/interfaces/cart.interface.ts +++ b/src/modules/cart/interfaces/cart.interface.ts @@ -11,8 +11,8 @@ export interface CartItem { export interface Cart { userId: string; - restaurantId: string; - restaurantName?: string; + shopId: string; + shopName?: string; items: CartItem[]; coupon?: OrderCouponDetail; diff --git a/src/modules/cart/providers/cart-calculation.service.ts b/src/modules/cart/providers/cart-calculation.service.ts index ab1379b..41865a8 100644 --- a/src/modules/cart/providers/cart-calculation.service.ts +++ b/src/modules/cart/providers/cart-calculation.service.ts @@ -173,7 +173,7 @@ export class CartCalculationService { cart.couponDiscount = couponDiscount; cart.totalDiscount = couponDiscount + itemsDiscount; - cart.tax = await this.calculateTax(cart.restaurantId, Math.max(0, subTotal - cart.totalDiscount)); + cart.tax = await this.calculateTax(cart.shopId, Math.max(0, subTotal - cart.totalDiscount)); cart.deliveryFee = await this.calculateDeliveryFee(cart); // total = subtotal – totalDiscount + tax + deliveryFee diff --git a/src/modules/cart/providers/cart-item.service.ts b/src/modules/cart/providers/cart-item.service.ts index a06cde2..636a59a 100644 --- a/src/modules/cart/providers/cart-item.service.ts +++ b/src/modules/cart/providers/cart-item.service.ts @@ -58,8 +58,8 @@ export class CartItemService { /** * Add or increment item in cart */ - async addOrIncrementItem(cart: Cart, shopId: string, restaurantId: string, quantityToAdd: number): Promise { - const product = await this.validationService.validateAndGetFood(shopId, restaurantId, quantityToAdd); + async addOrIncrementItem(cart: Cart, productId: string, shopId: string, quantityToAdd: number): Promise { + const product = await this.validationService.validateAndGetFood(productId, shopId, quantityToAdd); const index = this.getItemIndex(cart, product.id); diff --git a/src/modules/cart/providers/cart-validation.service.ts b/src/modules/cart/providers/cart-validation.service.ts index 7493fdf..651f0b8 100644 --- a/src/modules/cart/providers/cart-validation.service.ts +++ b/src/modules/cart/providers/cart-validation.service.ts @@ -14,7 +14,6 @@ import { WalletTransactionRepository } from 'src/modules/users/repositories/wall import { ProductService } from 'src/modules/products/providers/product.service'; import { ShopService } from 'src/modules/shops/providers/shops.service'; import { DeliveryService } from 'src/modules/delivery/providers/delivery.service'; -import { PaymentsService } from 'src/modules/payments/services/payments.service'; import { PaymentMethodService } from 'src/modules/payments/services/payment-method.service'; @Injectable() diff --git a/src/modules/cart/providers/cart.service.ts b/src/modules/cart/providers/cart.service.ts index e433cec..abf6881 100644 --- a/src/modules/cart/providers/cart.service.ts +++ b/src/modules/cart/providers/cart.service.ts @@ -5,7 +5,7 @@ import { OrderCouponDetail } from 'src/modules/orders/interface/order.interface' import { Cart } from '../interfaces/cart.interface'; import { BulkAddItemsToCartDto } from '../dto/bulk-add-items.dto'; import { ApplyCouponDto } from '../dto/apply-coupon.dto'; - import { SetAllCartParmsDto } from '../dto/set-all-cart-params.dto'; +import { SetAllCartParmsDto } from '../dto/set-all-cart-params.dto'; import { CouponService } from 'src/modules/coupons/providers/coupon.service'; import { CartRepository } from '../repositories/cart.repository'; import { CartValidationService } from './cart-validation.service'; @@ -32,15 +32,15 @@ export class CartService { /** * Set all cart parameters at once */ - async setAllCartParams(userId: string, restaurantId: string, params: SetAllCartParmsDto): Promise { - const { deliveryMethodId, paymentMethodId, addressId, carAddress, description, tableNumber } = params; + async setAllCartParams(userId: string, shopId: string, params: SetAllCartParmsDto): Promise { + const { deliveryMethodId, paymentMethodId, addressId, description } = params; // get existing cart (or throw) - const cart = await this.findOneOrFail(userId, restaurantId); + const cart = await this.findOneOrFail(userId, shopId); // Validate and get delivery method const deliveryMethod = await this.validationService.getEnabledDeliveryMethodOrFail( - restaurantId, + shopId, deliveryMethodId, ); cart.deliveryMethodId = deliveryMethodId; @@ -65,7 +65,7 @@ export class CartService { // ensure address is within shop service area await this.validationService.assertAddressInsideServiceArea( - restaurantId, + shopId, address.latitude, address.longitude, ); @@ -85,7 +85,7 @@ export class CartService { // Validate and set payment method const paymentMethod = await this.validationService.getEnabledPaymentMethodOrFail( - restaurantId, + shopId, paymentMethodId, ); @@ -93,7 +93,7 @@ export class CartService { await this.calculationService.recalculateCartTotals(cart); if (paymentMethod.method === PaymentMethodEnum.Wallet) { - await this.validationService.assertWalletHasEnoughBalance(userId, restaurantId, cart.total); + await this.validationService.assertWalletHasEnoughBalance(userId, shopId, cart.total); } cart.paymentMethodId = paymentMethodId; @@ -110,21 +110,21 @@ export class CartService { /** * Get or create cart for user and shop */ - async getOrCreateCart(userId: string, restaurantId: string): Promise { - const existingCart = await this.cartRepository.findByUserAndRestaurant(userId, restaurantId); + async getOrCreateCart(userId: string, shopId: string): Promise { + const existingCart = await this.cartRepository.findByUserAndShop(userId, shopId); if (existingCart) { return existingCart; } // Find shop - const shop = await this.shopService.findOrFail(restaurantId); + const shop = await this.shopService.findOrFail(shopId); // Create new cart const now = this.nowIso(); const cart: Cart = { userId, - restaurantId, - restaurantName: shop.name, + shopId: shop.id, + shopName: shop.name, items: [], deliveryFee: 0, subTotal: 0, @@ -145,8 +145,8 @@ export class CartService { /** * Find cart by user and shop */ - async findOneOrFail(userId: string, restaurantId: string): Promise { - const cart = await this.cartRepository.findByUserAndRestaurant(userId, restaurantId); + async findOneOrFail(userId: string, shopId: string): Promise { + const cart = await this.cartRepository.findByUserAndShop(userId, shopId); if (!cart) { throw new NotFoundException(CartMessage.NOT_FOUND); } @@ -156,17 +156,17 @@ export class CartService { /** * Increment item quantity in cart */ - async incrementItem(userId: string, restaurantId: string, foodId: string, quantity: number): Promise { - const cart = await this.getOrCreateCart(userId, restaurantId); - await this.itemService.addOrIncrementItem(cart, foodId, restaurantId, quantity); + async incrementItem(userId: string, shopId: string, foodId: string, quantity: number): Promise { + const cart = await this.getOrCreateCart(userId, shopId); + await this.itemService.addOrIncrementItem(cart, foodId, shopId, quantity); return this.recalculateAndSaveCart(cart); } /** * Decrement item quantity in cart by 1 (removes item if quantity reaches 0) */ - async decrementItem(userId: string, restaurantId: string, foodId: string): Promise { - const cart = await this.findOneOrFail(userId, restaurantId); + async decrementItem(userId: string, shopId: string, foodId: string): Promise { + const cart = await this.findOneOrFail(userId, shopId); await this.itemService.decrementOrRemoveItem(cart, foodId); return this.recalculateAndSaveCart(cart); } @@ -174,11 +174,11 @@ export class CartService { /** * Bulk add items to cart (increments quantity if items exist) */ - async bulkAddItems(userId: string, restaurantId: string, bulkAddItemsDto: BulkAddItemsToCartDto): Promise { - const cart = await this.getOrCreateCart(userId, restaurantId); + async bulkAddItems(userId: string, shopId: string, bulkAddItemsDto: BulkAddItemsToCartDto): Promise { + const cart = await this.getOrCreateCart(userId, shopId); for (const addItemDto of bulkAddItemsDto.items) { - await this.itemService.addOrIncrementItem(cart, addItemDto.foodId, restaurantId, addItemDto.quantity); + await this.itemService.addOrIncrementItem(cart, addItemDto.productId, shopId, addItemDto.quantity); } return this.recalculateAndSaveCart(cart); @@ -187,8 +187,8 @@ export class CartService { /** * Remove item from cart */ - async removeItem(userId: string, restaurantId: string, foodId: string): Promise { - const cart = await this.findOneOrFail(userId, restaurantId); + async removeItem(userId: string, shopId: string, foodId: string): Promise { + const cart = await this.findOneOrFail(userId, shopId); this.itemService.removeItemOrFail(cart, foodId); return this.recalculateAndSaveCart(cart); } @@ -196,15 +196,15 @@ export class CartService { /** * Apply coupon to cart */ - async applyCoupon(userId: string, restaurantId: string, applyCouponDto: ApplyCouponDto): Promise { - const cart = await this.findOneOrFail(userId, restaurantId); + async applyCoupon(userId: string, shopId: string, applyCouponDto: ApplyCouponDto): Promise { + const cart = await this.findOneOrFail(userId, shopId); const orderAmount = cart.subTotal - cart.itemsDiscount; const user = await this.userService.findOneOrFail(userId); // check if coupon is valid and belong to the shop const { valid, coupon, message } = await this.couponService.validateCoupon( applyCouponDto.code, - restaurantId, + shopId, Number(orderAmount), user.phone, ); @@ -241,8 +241,8 @@ export class CartService { /** * Remove coupon from cart */ - async removeCoupon(userId: string, restaurantId: string): Promise { - const cart = await this.findOneOrFail(userId, restaurantId); + async removeCoupon(userId: string, shopId: string): Promise { + const cart = await this.findOneOrFail(userId, shopId); cart.coupon = undefined; return this.recalculateAndSaveCart(cart); @@ -251,14 +251,14 @@ export class CartService { /** * Set address for cart */ - async setAddress(userId: string, restaurantId: string, addressId: string): Promise { - const cart = await this.findOneOrFail(userId, restaurantId); + async setAddress(userId: string, shopId: string, addressId: string): Promise { + const cart = await this.findOneOrFail(userId, shopId); const deliveryMethodId = this.validationService.requireDeliveryMethodId( cart, 'Delivery method must be set before setting address', ); - const deliveryMethod = await this.deliveryService.findOrFail(restaurantId, deliveryMethodId); + const deliveryMethod = await this.deliveryService.findOrFail(shopId, deliveryMethodId); this.validationService.assertDeliveryMethod( deliveryMethod.method, @@ -274,7 +274,7 @@ export class CartService { // ensure address is within shop service area await this.validationService.assertAddressInsideServiceArea( - restaurantId, + shopId, address.latitude, address.longitude, ); @@ -298,17 +298,17 @@ export class CartService { */ async setPaymentMethod( userId: string, - restaurantId: string, + shopId: string, paymentMethodId: string, ): Promise { - const cart = await this.findOneOrFail(userId, restaurantId); + const cart = await this.findOneOrFail(userId, shopId); const paymentMethod = await this.validationService.getEnabledPaymentMethodOrFail( - restaurantId, + shopId, paymentMethodId, ); if (paymentMethod.method === PaymentMethodEnum.Wallet) { - await this.validationService.assertWalletHasEnoughBalance(userId, restaurantId, cart.total); + await this.validationService.assertWalletHasEnoughBalance(userId, shopId, cart.total); } cart.paymentMethodId = paymentMethodId; return this.recalculateAndSaveCart(cart); @@ -319,13 +319,13 @@ export class CartService { */ async setDeliveryMethod( userId: string, - restaurantId: string, + shopId: string, deliveryMethodId: string, ): Promise { - const cart = await this.findOneOrFail(userId, restaurantId); + const cart = await this.findOneOrFail(userId, shopId); const deliveryMethod = await this.validationService.getEnabledDeliveryMethodOrFail( - restaurantId, + shopId, deliveryMethodId, ); @@ -338,8 +338,8 @@ export class CartService { /** * Set description for cart */ - async setDescription(userId: string, restaurantId: string, description: string): Promise { - const cart = await this.findOneOrFail(userId, restaurantId); + async setDescription(userId: string, shopId: string, description: string): Promise { + const cart = await this.findOneOrFail(userId, shopId); cart.description = description; return this.saveTouchedCart(cart); @@ -349,8 +349,8 @@ export class CartService { /** * Clear cart from cache */ - async clearCart(userId: string, restaurantId: string): Promise { - return this.cartRepository.delete(userId, restaurantId); + async clearCart(userId: string, shopId: string): Promise { + return this.cartRepository.delete(userId, shopId); } /** diff --git a/src/modules/cart/repositories/cart.repository.ts b/src/modules/cart/repositories/cart.repository.ts index 6a0e0c7..b5e714a 100644 --- a/src/modules/cart/repositories/cart.repository.ts +++ b/src/modules/cart/repositories/cart.repository.ts @@ -7,19 +7,19 @@ export class CartRepository { private readonly CART_TTL = 3600; // 1 hour in seconds private readonly CART_KEY_PREFIX = 'cart'; - constructor(private readonly cacheService: CacheService) {} + constructor(private readonly cacheService: CacheService) { } /** * Get cart by user and shop */ - async findByUserAndRestaurant(userId: string, restaurantId: string): Promise { - const cacheKey = this.getCacheKey(userId, restaurantId); + async findByUserAndShop(userId: string, shopId: string): Promise { + const cacheKey = this.getCacheKey(userId, shopId); const cachedCart = await this.cacheService.get(cacheKey); if (cachedCart) { try { const parsed: unknown = JSON.parse(cachedCart); - if (this.isCart(parsed) && parsed.userId === userId && parsed.restaurantId === restaurantId) { + if (this.isCart(parsed) && parsed.userId === userId && parsed.shopId === shopId) { return parsed; } } catch { @@ -34,23 +34,23 @@ export class CartRepository { * Save cart to cache */ async save(cart: Cart): Promise { - const cacheKey = this.getCacheKey(cart.userId, cart.restaurantId); + const cacheKey = this.getCacheKey(cart.userId, cart.shopId); await this.cacheService.set(cacheKey, JSON.stringify(cart), this.CART_TTL); } /** * Delete cart from cache */ - async delete(userId: string, restaurantId: string): Promise { - const cacheKey = this.getCacheKey(userId, restaurantId); + async delete(userId: string, shopId: string): Promise { + const cacheKey = this.getCacheKey(userId, shopId); await this.cacheService.del(cacheKey); } /** * Generate cache key for cart */ - private getCacheKey(userId: string, restaurantId: string): string { - return `${this.CART_KEY_PREFIX}:${userId}:${restaurantId}`; + private getCacheKey(userId: string, shopId: string): string { + return `${this.CART_KEY_PREFIX}:${userId}:${shopId}`; } /** @@ -63,7 +63,7 @@ export class CartRepository { const cart = obj as Record; return ( typeof cart.userId === 'string' && - typeof cart.restaurantId === 'string' && + typeof cart.shopId === 'string' && Array.isArray(cart.items) && typeof cart.subTotal === 'number' && typeof cart.itemsDiscount === 'number' &&