From 30be5402f33595838a7fe5a35ad961e241ac0c83 Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Tue, 10 Feb 2026 12:40:44 +0330 Subject: [PATCH] cart refactor --- .../cart/controllers/cart.controller.ts | 24 +++++------- .../cart/providers/cart-item.service.ts | 39 ++++++++++--------- .../cart/providers/cart-validation.service.ts | 9 +++-- src/modules/cart/providers/cart.service.ts | 12 +++--- .../products/providers/product.service.ts | 8 ++++ 5 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/modules/cart/controllers/cart.controller.ts b/src/modules/cart/controllers/cart.controller.ts index cf12e20..252203a 100644 --- a/src/modules/cart/controllers/cart.controller.ts +++ b/src/modules/cart/controllers/cart.controller.ts @@ -23,26 +23,23 @@ export class CartController { return this.cartService.getOrCreateCart(userId, shopId); } - @Post('product/:productId/increment') + @Post('variant/:variantId/increment') @ApiOperation({ summary: 'Increment item quantity in cart by 1' }) @ApiHeader(API_HEADER_SLUG) - @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); + async incrementItem(@UserId() userId: string, @ShopId() shopId: string, @Param('variantId') variantId: string) { + return this.cartService.incrementItem(userId, shopId, variantId, 1); } - @Post('product/:productId/decrement') + @Post('variant/:variantId/decrement') @ApiOperation({ summary: 'Decrement item quantity in cart by 1 (removes item if quantity reaches 0)' }) @ApiHeader(API_HEADER_SLUG) - @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); + async decrementItem(@UserId() userId: string, @ShopId() shopId: string, @Param('variantId') variantId: string) { + return this.cartService.decrementItem(userId, shopId, variantId); } - @Post('product/bulk') + @Post('variant/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() shopId: string, @@ -51,12 +48,11 @@ export class CartController { return this.cartService.bulkAddItems(userId, shopId, bulkAddItemsDto); } - @Delete('product/:productId') + @Delete('variant/:variantId') @ApiOperation({ summary: 'Remove item from cart' }) @ApiHeader(API_HEADER_SLUG) - @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); + async removeItem(@UserId() userId: string, @ShopId() shopId: string, @Param('variantId') variantId: string) { + return this.cartService.removeItem(userId, shopId, variantId); } @Delete() diff --git a/src/modules/cart/providers/cart-item.service.ts b/src/modules/cart/providers/cart-item.service.ts index 62d2d59..338efd9 100644 --- a/src/modules/cart/providers/cart-item.service.ts +++ b/src/modules/cart/providers/cart-item.service.ts @@ -5,6 +5,7 @@ import { CartValidationService } from './cart-validation.service'; import { CartCalculationService } from './cart-calculation.service'; import { CartMessage } from 'src/common/enums/message.enum'; import { ProductService } from 'src/modules/products/providers/product.service'; +import { Variant } from 'src/modules/products/entities/variant.entity'; @Injectable() export class CartItemService { @@ -17,13 +18,13 @@ export class CartItemService { /** * Create a new cart item from product */ - createCartItem(product: Product, quantity: number): CartItem { - const itemPrice = product.price || 0; - const itemDiscount = product.discount || 0; + createCartItem(variant: Variant, quantity: number): CartItem { + const itemPrice = variant.price || 0; + const itemDiscount = variant.product.discount || 0; return { - variantId: product.id, - productTitle: product.title, + variantId: variant.id, + productTitle: variant.product.title, quantity, price: itemPrice, discount: itemDiscount, @@ -34,13 +35,13 @@ export class CartItemService { /** * Build cart item from product (updating existing item if provided) */ - buildCartItemFromFood(product: Product, quantity: number, previous?: CartItem): CartItem { - const itemPrice = product.price || 0; - const itemDiscount = product.discount || 0; + buildCartItemFromFood(variant: Variant, quantity: number, previous?: CartItem): CartItem { + const itemPrice = variant.price || 0; + const itemDiscount = variant.product.discount || 0; return { ...(previous ?? ({} as CartItem)), - variantId: product.id, - productTitle: product.title, + variantId: variant.id, + productTitle: variant.product.title, quantity, price: itemPrice, discount: itemDiscount, @@ -58,20 +59,20 @@ export class CartItemService { /** * Add or increment item in cart */ - async addOrIncrementItem(cart: Cart, productId: string, shopId: string, quantityToAdd: number): Promise { - const product = await this.validationService.validateAndGetFood(productId, shopId, quantityToAdd); + async addOrIncrementItem(cart: Cart, variantId: string, shopId: string, quantityToAdd: number): Promise { + const variant = await this.validationService.validateAndGetVariant(variantId, shopId, quantityToAdd); - const index = this.getItemIndex(cart, product.id); + const index = this.getItemIndex(cart, variant.id); if (index < 0) { - cart.items.push(this.createCartItem(product, quantityToAdd)); + cart.items.push(this.createCartItem(variant, quantityToAdd)); return; } const existingItem = cart.items[index]; const newQuantity = existingItem.quantity + quantityToAdd; - cart.items[index] = this.buildCartItemFromFood(product, newQuantity, existingItem); + cart.items[index] = this.buildCartItemFromFood(variant, newQuantity, existingItem); } /** @@ -88,8 +89,8 @@ export class CartItemService { /** * Decrement item quantity or remove if quantity reaches 0 */ - async decrementOrRemoveItem(cart: Cart, productId: string): Promise { - const itemIndex = this.getItemIndex(cart, productId); + async decrementOrRemoveItem(cart: Cart, variantId: string): Promise { + const itemIndex = this.getItemIndex(cart, variantId); if (itemIndex < 0) { throw new NotFoundException(CartMessage.ITEM_NOT_FOUND); } @@ -102,8 +103,8 @@ export class CartItemService { return; } - const product = await this.productService.findOrFail(productId); - cart.items[itemIndex] = this.buildCartItemFromFood(product, newQuantity, existingItem); + const variant = await this.productService.findOrFailVariant(variantId); + cart.items[itemIndex] = this.buildCartItemFromFood(variant, newQuantity, existingItem); } } diff --git a/src/modules/cart/providers/cart-validation.service.ts b/src/modules/cart/providers/cart-validation.service.ts index c522ec9..3c06814 100644 --- a/src/modules/cart/providers/cart-validation.service.ts +++ b/src/modules/cart/providers/cart-validation.service.ts @@ -15,6 +15,7 @@ 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 { PaymentMethodService } from 'src/modules/payments/services/payment-method.service'; +import { Variant } from 'src/modules/products/entities/variant.entity'; @Injectable() export class CartValidationService { @@ -30,14 +31,14 @@ export class CartValidationService { /** * Validate product exists and belongs to shop */ - async validateAndGetFood(productId: string, shopId: string, quantity: number): Promise { - const product = await this.productService.findOrFail(productId) + async validateAndGetVariant(variantId: string, shopId: string, quantity: number): Promise { + const variant = await this.productService.findOrFailVariant(variantId) - if (product.shop.id !== shopId) { + if (variant.product.shop.id !== shopId) { throw new BadRequestException(CartMessage.PRODUCT_NOT_BELONGS_TO_SHOP); } - return product; + return variant; } diff --git a/src/modules/cart/providers/cart.service.ts b/src/modules/cart/providers/cart.service.ts index 623da25..3da9f9b 100644 --- a/src/modules/cart/providers/cart.service.ts +++ b/src/modules/cart/providers/cart.service.ts @@ -156,18 +156,18 @@ export class CartService { /** * Increment item quantity in cart */ - async incrementItem(userId: string, shopId: string, foodId: string, quantity: number): Promise { + async incrementItem(userId: string, shopId: string, variantId: string, quantity: number): Promise { const cart = await this.getOrCreateCart(userId, shopId); - await this.itemService.addOrIncrementItem(cart, foodId, shopId, quantity); + await this.itemService.addOrIncrementItem(cart, variantId, shopId, quantity); return this.recalculateAndSaveCart(cart); } /** * Decrement item quantity in cart by 1 (removes item if quantity reaches 0) */ - async decrementItem(userId: string, shopId: string, foodId: string): Promise { + async decrementItem(userId: string, shopId: string, variantId: string): Promise { const cart = await this.findOneOrFail(userId, shopId); - await this.itemService.decrementOrRemoveItem(cart, foodId); + await this.itemService.decrementOrRemoveItem(cart, variantId); return this.recalculateAndSaveCart(cart); } @@ -187,9 +187,9 @@ export class CartService { /** * Remove item from cart */ - async removeItem(userId: string, shopId: string, foodId: string): Promise { + async removeItem(userId: string, shopId: string, variantId: string): Promise { const cart = await this.findOneOrFail(userId, shopId); - this.itemService.removeItemOrFail(cart, foodId); + this.itemService.removeItemOrFail(cart, variantId); return this.recalculateAndSaveCart(cart); } diff --git a/src/modules/products/providers/product.service.ts b/src/modules/products/providers/product.service.ts index 92ff00f..7ad35a8 100644 --- a/src/modules/products/providers/product.service.ts +++ b/src/modules/products/providers/product.service.ts @@ -222,4 +222,12 @@ export class ProductService { return product } + + async findOrFailVariant(variantId: string) { + const variant = await this.em.findOne(Variant, { id: variantId } ,{ populate: ['product','product.shop',] }); + + if (!variant) throw new NotFoundException('Variant not found'); + + return variant + } }