diff --git a/src/feature/cart/cart.controller.ts b/src/feature/cart/cart.controller.ts index c82b238..bdfb1af 100644 --- a/src/feature/cart/cart.controller.ts +++ b/src/feature/cart/cart.controller.ts @@ -4,6 +4,8 @@ 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 { GetCartDetailResponse } from './dto/get-cart-detail-response.dto'; import { CartItem } from 'src/entity/cart-item.entity'; @@ -86,4 +88,41 @@ export class CartController { return res; } } + + @MessagePattern({ cmd: 'update_cart' }) + async updateCart(data: UpdateCartRequest): Promise { + if (this.flagService.isFeatureEnabled('fes-28-update-cart')) { + const { customer_id, updated_items, lang = 'vie' } = data; + const res = new UpdateCartResponse(200, ''); + try { + if (updated_items.length <= 0) { + throw new HttpException('Updated Items cannot be empty', 400); + } + const cartItems: CartItem[] = + await this.cartService.updateCartFromEndPoint( + customer_id, + updated_items, + lang, + ); + 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 0ba8dd8..dd35221 100644 --- a/src/feature/cart/cart.service.ts +++ b/src/feature/cart/cart.service.ts @@ -5,7 +5,11 @@ import { EntityManager } from 'typeorm'; import { CartItem } from 'src/entity/cart-item.entity'; import { CommonService } from '../common/common.service'; import { SKU } from 'src/entity/sku.entity'; -import { BasicTasteSelection, OptionSelection } from 'src/type'; +import { + BasicTasteSelection, + OptionSelection, + UpdatedCartItem, +} from 'src/type'; @Injectable() export class CartService { @@ -229,4 +233,58 @@ export class CartService { .execute(); } } + + async updateCartFromEndPoint( + customer_id: number, + updated_cart_items: UpdatedCartItem[], + lang: string, + ): Promise { + if (this.flagService.isFeatureEnabled('fes-28-update-cart')) { + const mentionedCartItems = await this.getCartByItemId( + updated_cart_items.map((i) => i.item_id), + customer_id, + ); + + if (mentionedCartItems.length < updated_cart_items.length) { + throw new HttpException( + 'There are some of updated items which do not belong to the customer', + 400, + ); + } + + //build new cart + const fullUpdatedItems: CartItem[] = []; + for (const mentionedCartItem of mentionedCartItems) { + const updatedCartItem = updated_cart_items.find( + (i) => i.item_id === mentionedCartItem.item_id, + ); + + if (updatedCartItem.sku_id != mentionedCartItem.sku_id) { + const isAllowedSku = + await this.commonService.checkIfSkuHasSameMenuItem([ + updatedCartItem.sku_id, + mentionedCartItem.sku_id, + ]); + + if (!isAllowedSku) { + throw new HttpException( + `Updated sku_id ${updatedCartItem.sku_id} does not have the same Menu Item as the current mentioning sku_id`, + 400, + ); + } + } + } + + return await this.getCart(customer_id); + } + } + async getCartByItemId(item_ids: number[], customer_id) { + if (this.flagService.isFeatureEnabled('fes-28-update-cart')) { + return await this.entityManager + .createQueryBuilder(CartItem, 'cart') + .where('cart.customer_id = :customer_id', { customer_id }) + .andWhere('cart.item_id IN (:...item_ids)', { item_ids }) + .getMany(); + } + } } diff --git a/src/feature/cart/dto/update-cart-request.dto.ts b/src/feature/cart/dto/update-cart-request.dto.ts new file mode 100644 index 0000000..78de8a1 --- /dev/null +++ b/src/feature/cart/dto/update-cart-request.dto.ts @@ -0,0 +1,23 @@ +export class UpdateCartRequest { + customer_id: number; + updated_items: UpdatedCartItem[]; + lang?: string; +} + +interface UpdatedCartItem { + item_id: number; + sku_id: number; + qty_ordered: number; + advanced_taste_customization_obj: OptionSelection[]; + basic_taste_customization_obj: BasicTasteSelection[]; + notes: string; +} + +interface OptionSelection { + option_id: string; + value_id: string; +} + +interface BasicTasteSelection { + no_adding_id: string; +} diff --git a/src/feature/cart/dto/update-cart-response.dto.ts b/src/feature/cart/dto/update-cart-response.dto.ts new file mode 100644 index 0000000..afef2ce --- /dev/null +++ b/src/feature/cart/dto/update-cart-response.dto.ts @@ -0,0 +1,25 @@ +import { GeneralResponse } from 'src/dto/general-response.dto'; + +export class UpdateCartResponse 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/common/common.service.ts b/src/feature/common/common.service.ts index b24db5e..fdca17e 100644 --- a/src/feature/common/common.service.ts +++ b/src/feature/common/common.service.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { HttpException, Inject, Injectable } from '@nestjs/common'; import { BasicTasteSelection, DeliveryRestaurant, @@ -430,4 +430,26 @@ export class CommonService { return result; } } + + async checkIfSkuHasSameMenuItem(sku_ids: number[]): Promise { + if (this.flagService.isFeatureEnabled('fes-28-update-cart')) { + const skuList = await this.entityManager + .createQueryBuilder(SKU, 'sku') + .where('sku.sku_id IN (:...sku_ids)', { sku_ids }) + .getMany(); + + if (skuList.length != sku_ids.length) { + throw new HttpException( + 'There are some sku_id which does not exist', + 404, + ); + } + const menuItems = skuList.map((i) => i.menu_item_id); + const uniqueMenuItems = [...new Set(menuItems)]; + if (uniqueMenuItems.length != 1) { + return false; + } + return true; + } + } } diff --git a/src/type/index.ts b/src/type/index.ts index 0ad4029..372a56e 100644 --- a/src/type/index.ts +++ b/src/type/index.ts @@ -89,3 +89,12 @@ export interface ValidationResult { message: string; data?: any; } + +export interface UpdatedCartItem { + item_id: number; + sku_id: number; + qty_ordered: number; + advanced_taste_customization_obj: OptionSelection[]; + basic_taste_customization_obj: BasicTasteSelection[]; + notes: string; +}