Skip to content

Commit

Permalink
Fes 24 add to cart 2 (#32)
Browse files Browse the repository at this point in the history
* add the optional language info to the request data

* logic for interpret the basic taste customization

* interpret portion customization

* validate SKU

* move 2 fucntions of food service to common service for mutual usage

* validate advanced taste customization input object

* adjust response DTO; move exception handle logic to controller

* extract the insert logic

* add flag to insertCart

* complete the logic of adding to cart

---------

Co-authored-by: NHT <[email protected]>
  • Loading branch information
nfesta2023 and hoangtuan910 authored Jan 9, 2024
1 parent 7218533 commit d6667b8
Show file tree
Hide file tree
Showing 9 changed files with 499 additions and 90 deletions.
8 changes: 8 additions & 0 deletions src/entity/sku-menu-item-variant.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from 'typeorm';
import { SKU } from './sku.entity';
import { MenuItemVariant } from './menu-item-variant.entity';
import { MenuItemVariantOpion } from './menu-item-variant-option.entity';

@Entity('SKU_Menu_Item_Variant')
export class SkuMenuItemVariant {
Expand Down Expand Up @@ -43,4 +44,11 @@ export class SkuMenuItemVariant {
referencedColumnName: 'menu_item_variant_id',
})
public attribute: MenuItemVariant;

@ManyToOne(() => MenuItemVariantOpion)
@JoinColumn({
name: 'option',
referencedColumnName: 'menu_item_variant_option_id',
})
public value: MenuItemVariantOpion;
}
40 changes: 38 additions & 2 deletions src/feature/cart/cart.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Controller, Inject } from '@nestjs/common';
import { Controller, HttpException, Inject } from '@nestjs/common';
import { CartService } from './cart.service';
import { FlagsmithService } from 'src/dependency/flagsmith/flagsmith.service';
import { MessagePattern } from '@nestjs/microservices';
Expand All @@ -14,7 +14,43 @@ export class CartController {
@MessagePattern({ cmd: 'add_cart_item' })
async addCartItem(data: AddToCartRequest): Promise<AddToCartResponse> {
if (this.flagService.isFeatureEnabled('fes-24-add-to-cart')) {
return await this.cartService.addCartItem(data);
const {
customer_id,
sku_id,
qty_ordered,
advanced_taste_customization_obj,
basic_taste_customization_obj,
notes,
} = data;
const res = new AddToCartResponse(200, '');
try {
const cart = await this.cartService.addCartItem(
customer_id,
sku_id,
qty_ordered,
advanced_taste_customization_obj,
basic_taste_customization_obj,
notes,
);
//success
res.statusCode = 200;
res.message = 'Add to cart successfully';
res.data = {
customer_id: customer_id,
cart_info: cart,
};
} 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;
}
}
}
268 changes: 220 additions & 48 deletions src/feature/cart/cart.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Inject, Injectable } from '@nestjs/common';
import { HttpException, Inject, Injectable } from '@nestjs/common';
import { InjectEntityManager } from '@nestjs/typeorm';
import { FlagsmithService } from 'src/dependency/flagsmith/flagsmith.service';
import { EntityManager } from 'typeorm';
import { AddToCartResponse } from './dto/add-to-cart-response.dto';
import { AddToCartRequest } from './dto/add-to-cart-request.dto';
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';

@Injectable()
export class CartService {
Expand All @@ -14,64 +14,236 @@ export class CartService {
@InjectEntityManager() private readonly entityManager: EntityManager,
private readonly commonService: CommonService,
) {}
async addCartItem(inputData: AddToCartRequest): Promise<AddToCartResponse> {
async addCartItem(
customer_id: number,
sku_id: number,
qty_ordered: number,
advanced_taste_customization_obj: OptionSelection[],
basic_taste_customization_obj: BasicTasteSelection[],
notes: string,
lang: string = 'vie',
): Promise<CartItem[]> {
if (this.flagService.isFeatureEnabled('fes-24-add-to-cart')) {
const res = new AddToCartResponse(200, '');

const {
customer_id,
sku_id,
qty_ordered,
const advanced_taste_customization_obj_txt = JSON.stringify(
advanced_taste_customization_obj,
);
const basic_taste_customization_obj_txt = JSON.stringify(
basic_taste_customization_obj,
notes,
} = inputData;
);

//Check if the SKU does exist
const sku = await this.entityManager
.createQueryBuilder(SKU, 'sku')
.leftJoinAndSelect('sku.menu_item', 'menuItem')
.where('sku.sku_id = :sku_id', { sku_id })
.getOne();
if (!sku) {
throw new HttpException('SKU does not exist', 404);
}

// Check if the advanced_taste_customization_obj is all available to this SKU
const advancedTasteCustomizationValidation =
await this.commonService.validateAdvacedTasteCustomizationObjWithMenuItem(
advanced_taste_customization_obj,
sku.menu_item_id,
);
if (!advancedTasteCustomizationValidation.isValid) {
throw new HttpException(
advancedTasteCustomizationValidation.message,
400,
);
}

// Check if the basic_taste_customization_obj is all available to this SKU
const basicTasteCustomizationValidation =
await this.commonService.validateBasicTasteCustomizationObjWithMenuItem(
basic_taste_customization_obj,
sku.menu_item_id,
);
if (!basicTasteCustomizationValidation.isValid) {
throw new HttpException(basicTasteCustomizationValidation.message, 400);
}

//Get the current cart
const cart = await this.entityManager
.createQueryBuilder(CartItem, 'cart')
.where('cart.customer_id = :customer_id', { customer_id })
.getMany();
const currentCart = await this.getCart(customer_id);

//Interpret Advance Taste Customization
const advanced_taste_customization =
await this.commonService.interpretAdvanceTaseCustomization(
advanced_taste_customization_obj,
lang,
);
console.log('advanced_taste_customization', advanced_taste_customization);

//Interpret Basic Taste Customization
const basic_taste_customization =
await this.commonService.interpretBasicTaseCustomization(
basic_taste_customization_obj,
lang,
);

//Interpret Portion Customization
const portion_customization =
await this.commonService.interpretPortionCustomization(sku_id, lang);

//If cart is empty, create a new cart
// if (cart.length === 0) {
// const item = await this.entityManager
// .createQueryBuilder()
// .insert()
// .into(CartItem)
// .values({
// customer_id: customer_id,
// sku_id: sku_id,
// qty_ordered: qty_ordered,
// advanced_taste_customization: '',
// basic_taste_customization: '',
// portion_customization: '',
// advanced_taste_customization_obj: JSON.stringify(
// advanced_taste_customization_obj,
// ),
// basic_taste_customization_obj: JSON.stringify(
// basic_taste_customization_obj,
// ),
// notes: notes,
// restaurant_id: null,
// })
// .execute();
// }

//success
res.statusCode = 200;
// res.message = 'Add to cart successfully';
res.message = cart;
res.data = null;

return res;
if (currentCart.length === 0) {
await this.insertCart(
customer_id,
sku_id,
qty_ordered,
advanced_taste_customization,
basic_taste_customization,
portion_customization,
advanced_taste_customization_obj_txt,
basic_taste_customization_obj_txt,
notes,
sku.menu_item.restaurant_id,
);
return await this.getCart(customer_id);
}

// Check if the sku_id’s restaurant is the same as the current cart’s items
if (sku.menu_item.restaurant_id != currentCart[0].restaurant_id) {
//Only compare to the first item of the cart. Assume that all of the items
//of the cart have the same restaurant_id
throw new HttpException(
`Added item should have the same restaurant_id as the current cart`,
400,
);
}

//Get the item which having the same sku_id
const similarCartItem = currentCart.find((i) => i.sku_id == sku_id);
if (!similarCartItem) {
//There is no item which having the same sku_id in the cart
await this.insertCart(
customer_id,
sku_id,
qty_ordered,
advanced_taste_customization,
basic_taste_customization,
portion_customization,
advanced_taste_customization_obj_txt,
basic_taste_customization_obj_txt,
notes,
sku.menu_item.restaurant_id,
);
return await this.getCart(customer_id);
}

//check if the similar item has the same advanced_taste_customization_obj
//and basic_taste_customization_obj
const isSameCustomization =
advanced_taste_customization_obj_txt ==
similarCartItem.advanced_taste_customization_obj &&
basic_taste_customization_obj_txt ==
similarCartItem.basic_taste_customization_obj;
if (isSameCustomization) {
await this.updateCart(
similarCartItem.item_id,
similarCartItem.customer_id,
similarCartItem.sku_id,
similarCartItem.qty_ordered + qty_ordered,
similarCartItem.advanced_taste_customization,
similarCartItem.basic_taste_customization,
similarCartItem.portion_customization,
similarCartItem.advanced_taste_customization_obj,
similarCartItem.basic_taste_customization_obj,
similarCartItem.notes,
similarCartItem.restaurant_id,
);
return await this.getCart(customer_id);
}

await this.insertCart(
customer_id,
sku_id,
qty_ordered,
advanced_taste_customization,
basic_taste_customization,
portion_customization,
advanced_taste_customization_obj_txt,
basic_taste_customization_obj_txt,
notes,
sku.menu_item.restaurant_id,
);
return await this.getCart(customer_id);
}
}

async getCart(customer_id: number): Promise<CartItem[]> {
if (this.flagService.isFeatureEnabled('fes-24-add-to-cart')) {
return await this.entityManager
.createQueryBuilder(CartItem, 'cart')
.where('cart.customer_id = :customer_id', { customer_id })
.getMany();
}
}

async insertCart(
customer_id: number,
sku_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,
): Promise<void> {
if (this.flagService.isFeatureEnabled('fes-24-add-to-cart')) {
await this.entityManager
.createQueryBuilder()
.insert()
.into(CartItem)
.values({
customer_id: customer_id,
sku_id: sku_id,
qty_ordered: qty_ordered,
advanced_taste_customization: advanced_taste_customization,
basic_taste_customization: basic_taste_customization,
portion_customization: portion_customization,
advanced_taste_customization_obj: advanced_taste_customization_obj,
basic_taste_customization_obj: basic_taste_customization_obj,
notes: notes,
restaurant_id: restaurant_id,
})
.execute();
}
}

async updateCart(
item_id: number,
customer_id: number,
sku_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,
): Promise<void> {
if (this.flagService.isFeatureEnabled('fes-24-add-to-cart')) {
await this.entityManager
.createQueryBuilder()
.update(CartItem)
.set({
customer_id: customer_id,
sku_id: sku_id,
qty_ordered: qty_ordered,
advanced_taste_customization: advanced_taste_customization,
basic_taste_customization: basic_taste_customization,
portion_customization: portion_customization,
advanced_taste_customization_obj: advanced_taste_customization_obj,
basic_taste_customization_obj: basic_taste_customization_obj,
notes: notes,
restaurant_id: restaurant_id,
})
.where('item_id = :item_id', { item_id })
.execute();
}
}
}
6 changes: 5 additions & 1 deletion src/feature/cart/dto/add-to-cart-request.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ export class AddToCartRequest {
sku_id: number;
qty_ordered: number;
advanced_taste_customization_obj: OptionSelection[];
basic_taste_customization_obj: OptionSelection[];
basic_taste_customization_obj: BasicTasteSelection[];
notes: string;
lang?: string;
}

interface OptionSelection {
option_id: string;
value_id: string;
}
interface BasicTasteSelection {
no_adding_id: string;
}
Loading

0 comments on commit d6667b8

Please sign in to comment.