diff --git a/src/feature/cart/cart.controller.ts b/src/feature/cart/cart.controller.ts index 7cd5810..f43e7f1 100644 --- a/src/feature/cart/cart.controller.ts +++ b/src/feature/cart/cart.controller.ts @@ -4,10 +4,12 @@ import { FlagsmithService } from 'src/dependency/flagsmith/flagsmith.service'; import { MessagePattern } from '@nestjs/microservices'; import { AddToCartRequest } from './dto/add-to-cart-request.dto'; import { AddToCartResponse } from './dto/add-to-cart-response.dto'; -import { UpdateCartRequest } from './dto/update-cart-request.dto'; -import { UpdateCartResponse } from './dto/update-cart-response.dto'; +import { UpdateCartAdvancedRequest } from './dto/update-cart-advanced-request.dto'; +import { UpdateCartAdvancedResponse } from './dto/update-cart-advanced-response.dto'; import { GetCartDetailResponse } from './dto/get-cart-detail-response.dto'; import { CartItem } from 'src/entity/cart-item.entity'; +import { UpdateCartBasicRequest } from './dto/update-cart-basic-request.dto'; +import { UpdateCartBasicResponse } from './dto/update-cart-basic-response.dto'; @Controller() export class CartController { @@ -89,8 +91,10 @@ export class CartController { } } - @MessagePattern({ cmd: 'update_cart' }) - async updateCart(data: UpdateCartRequest): Promise { + @MessagePattern({ cmd: 'update_cart_advanced' }) + async updateCartAdvanced( + data: UpdateCartAdvancedRequest, + ): Promise { if (this.flagService.isFeatureEnabled('fes-28-update-cart')) { const { customer_id, @@ -102,10 +106,10 @@ export class CartController { notes, lang = 'vie', } = data; - const res = new UpdateCartResponse(200, ''); + const res = new UpdateCartAdvancedResponse(200, ''); try { const cartItems: CartItem[] = - await this.cartService.updateCartFromEndPoint( + await this.cartService.updateCartAdvancedFromEndPoint( customer_id, item_id, sku_id, @@ -136,4 +140,39 @@ export class CartController { return res; } } + + @MessagePattern({ cmd: 'update_cart_basic' }) + async updateCartBasic( + data: UpdateCartBasicRequest, + ): Promise { + if (this.flagService.isFeatureEnabled('fes-28-update-cart')) { + const { customer_id, updated_items } = data; + const res = new UpdateCartAdvancedResponse(200, ''); + try { + const cartItems: CartItem[] = + await this.cartService.updateCartBasicFromEndPoint( + customer_id, + updated_items, + ); + res.statusCode = 200; + res.message = 'Update cart successfully'; + res.data = { + customer_id: data.customer_id, + cart_info: cartItems, + }; + } catch (error) { + if (error instanceof HttpException) { + res.statusCode = error.getStatus(); + res.message = error.getResponse(); + res.data = null; + } else { + res.statusCode = 500; + res.message = error.toString(); + res.data = null; + } + } + + return res; + } + } } diff --git a/src/feature/cart/cart.service.ts b/src/feature/cart/cart.service.ts index 56c4cb5..6f2aab0 100644 --- a/src/feature/cart/cart.service.ts +++ b/src/feature/cart/cart.service.ts @@ -8,7 +8,7 @@ import { SKU } from 'src/entity/sku.entity'; import { BasicTasteSelection, OptionSelection, - UpdatedCartItem, + QuantityUpdatedItem, } from 'src/type'; @Injectable() @@ -236,7 +236,7 @@ export class CartService { } } - async updateCartFromEndPoint( + async updateCartAdvancedFromEndPoint( customer_id: number, item_id: number, sku_id: number, @@ -247,6 +247,8 @@ export class CartService { lang: string, ): Promise { if (this.flagService.isFeatureEnabled('fes-28-update-cart')) { + // https://n-festa.atlassian.net/browse/FES-28 + // Get the corresponding cart items in DB const mentionedCartItem = ( await this.getCartByItemId([item_id], customer_id) @@ -508,4 +510,67 @@ export class CartService { ); } } + + async updateCartBasicFromEndPoint( + customer_id: number, + quantity_updated_items: QuantityUpdatedItem[], + ): Promise { + // https://n-festa.atlassian.net/browse/FES-28 + if (this.flagService.isFeatureEnabled('fes-28-update-cart')) { + // quantity_updated_items cannot be empty + if (!quantity_updated_items || quantity_updated_items.length <= 0) { + throw new HttpException('The updated_items cannot be empty', 400); + } + + // Get the corresponding cart items in DB + const mentionedCartItems = await this.getCartByItemId( + quantity_updated_items.map((i) => i.item_id), + customer_id, + ); + // The list of updated items must belong to the customer + if (mentionedCartItems.length != quantity_updated_items.length) { + throw new HttpException( + 'Some of cart items do not belong to the customer or not exist', + 404, + ); + } + + // The quantity must be greater than 0 + const isQuantityValid = quantity_updated_items.find( + (i) => !Boolean(i.qty_ordered > 0), + ); + if (isQuantityValid) { + throw new HttpException( + 'The quantity cannot be negative or different from number', + 400, + ); + } + + // MASS UPDATE + await this.massUpdateCartItemWithQuantity(quantity_updated_items); + + return await this.getCart(customer_id); + } + } + + async massUpdateCartItemWithQuantity( + items: QuantityUpdatedItem[], + ): Promise { + if (this.flagService.isFeatureEnabled('fes-28-update-cart')) { + await this.entityManager.transaction( + async (transactionalEntityManager) => { + for (const item of items) { + await transactionalEntityManager + .createQueryBuilder() + .update(CartItem) + .set({ + qty_ordered: item.qty_ordered, + }) + .where('item_id = :item_id', { item_id: item.item_id }) + .execute(); + } + }, + ); + } + } } diff --git a/src/feature/cart/dto/update-cart-request.dto.ts b/src/feature/cart/dto/update-cart-advanced-request.dto.ts similarity index 89% rename from src/feature/cart/dto/update-cart-request.dto.ts rename to src/feature/cart/dto/update-cart-advanced-request.dto.ts index 80075cc..33a24aa 100644 --- a/src/feature/cart/dto/update-cart-request.dto.ts +++ b/src/feature/cart/dto/update-cart-advanced-request.dto.ts @@ -1,4 +1,4 @@ -export class UpdateCartRequest { +export class UpdateCartAdvancedRequest { customer_id: number; item_id: number; sku_id: number; diff --git a/src/feature/cart/dto/update-cart-advanced-response.dto.ts b/src/feature/cart/dto/update-cart-advanced-response.dto.ts new file mode 100644 index 0000000..aec561b --- /dev/null +++ b/src/feature/cart/dto/update-cart-advanced-response.dto.ts @@ -0,0 +1,25 @@ +import { GeneralResponse } from 'src/dto/general-response.dto'; + +export class UpdateCartAdvancedResponse extends GeneralResponse { + data: CartDetail; +} + +interface CartDetail { + customer_id: number; + cart_info: CartItem[]; +} + +interface CartItem { + item_id: number; + sku_id: number; + customer_id: number; + qty_ordered: number; + advanced_taste_customization: string; + basic_taste_customization: string; + portion_customization: string; + advanced_taste_customization_obj: string; + basic_taste_customization_obj: string; + notes: string; + restaurant_id: number; + created_at: Date; +} diff --git a/src/feature/cart/dto/update-cart-basic-request.dto.ts b/src/feature/cart/dto/update-cart-basic-request.dto.ts new file mode 100644 index 0000000..46302d2 --- /dev/null +++ b/src/feature/cart/dto/update-cart-basic-request.dto.ts @@ -0,0 +1,8 @@ +export class UpdateCartBasicRequest { + customer_id: number; + updated_items: QuantityUpdatedItem[]; +} +interface QuantityUpdatedItem { + item_id: number; + qty_ordered: number; +} diff --git a/src/feature/cart/dto/update-cart-response.dto.ts b/src/feature/cart/dto/update-cart-basic-response.dto.ts similarity index 89% rename from src/feature/cart/dto/update-cart-response.dto.ts rename to src/feature/cart/dto/update-cart-basic-response.dto.ts index afef2ce..a1d6122 100644 --- a/src/feature/cart/dto/update-cart-response.dto.ts +++ b/src/feature/cart/dto/update-cart-basic-response.dto.ts @@ -1,6 +1,6 @@ import { GeneralResponse } from 'src/dto/general-response.dto'; -export class UpdateCartResponse extends GeneralResponse { +export class UpdateCartBasicResponse extends GeneralResponse { data: CartDetail; } diff --git a/src/type/index.ts b/src/type/index.ts index 372a56e..1abfba6 100644 --- a/src/type/index.ts +++ b/src/type/index.ts @@ -98,3 +98,8 @@ export interface UpdatedCartItem { basic_taste_customization_obj: BasicTasteSelection[]; notes: string; } + +export interface QuantityUpdatedItem { + item_id: number; + qty_ordered: number; +}