Skip to content

Commit

Permalink
Fes 24 add to cart (#31)
Browse files Browse the repository at this point in the history
* setup cart module, controller & service, complete the add-to-cart route

* add entity CartItem; interpret advanced taste customization

---------

Co-authored-by: NHT <[email protected]>
  • Loading branch information
nfesta2023 and hoangtuan910 authored Jan 8, 2024
1 parent af6bae8 commit 7218533
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 6 deletions.
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import configuration from './config/configuration';
import { FlagsmithModule } from './dependency/flagsmith/flagsmith.module';
import { SearchModule } from './feature/search/search.module';
import { CommonModule } from './feature/common/common.module';
import { CartModule } from './feature/cart/cart.module';

@Module({
imports: [
Expand Down Expand Up @@ -41,6 +42,7 @@ import { CommonModule } from './feature/common/common.module';
FlagsmithModule,
SearchModule,
CommonModule,
CartModule,
],
controllers: [AppController],
providers: [AppService],
Expand Down
7 changes: 2 additions & 5 deletions src/dto/sku.dto.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { OptionSelection } from 'src/type';

export class SkuDTO {
sku_id: number;
price: number;
Expand All @@ -11,8 +13,3 @@ export class SkuDTO {
portion_customization: OptionSelection[];
// taste_customization: OptionSelection[];
}

interface OptionSelection {
option_id: string;
value_id: string;
}
50 changes: 50 additions & 0 deletions src/entity/cart-item.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
} from 'typeorm';

@Entity('Cart_Item')
export class CartItem {
@PrimaryGeneratedColumn()
public item_id: number;

@Column({ type: 'int', unique: false, nullable: false })
public customer_id: number;

@Column({ type: 'int', unique: false, nullable: false })
public sku_id: number;

@Column({ type: 'int', unique: false, nullable: true })
public qty_ordered: number;

@Column({ type: 'varchar', length: 255, unique: false, nullable: true })
public advanced_taste_customization: string;

@Column({ type: 'varchar', length: 255, unique: false, nullable: true })
public basic_taste_customization: string;

@Column({ type: 'varchar', length: 255, unique: false, nullable: true })
public portion_customization: string;

@Column({ type: 'text', unique: false, nullable: true })
public advanced_taste_customization_obj: string;

@Column({ type: 'text', unique: false, nullable: true })
public basic_taste_customization_obj: string;

@Column({ type: 'text', unique: false, nullable: true })
public notes: string;

@Column({ type: 'int', unique: false, nullable: true })
public restaurant_id: number;

@CreateDateColumn({
type: 'datetime',
nullable: false,
unique: false,
default: () => 'CURRENT_TIMESTAMP',
})
public created_at: Date;
}
20 changes: 20 additions & 0 deletions src/feature/cart/cart.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Controller, Inject } from '@nestjs/common';
import { CartService } from './cart.service';
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';

@Controller()
export class CartController {
constructor(
@Inject('FLAGSMITH_SERVICE') private readonly flagService: FlagsmithService,
private readonly cartService: CartService,
) {}
@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);
}
}
}
13 changes: 13 additions & 0 deletions src/feature/cart/cart.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { CartController } from './cart.controller';
import { CartService } from './cart.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CartItem } from 'src/entity/cart-item.entity';

@Module({
imports: [TypeOrmModule.forFeature([CartItem])],
controllers: [CartController],
providers: [CartService],
exports: [CartService],
})
export class CartModule {}
77 changes: 77 additions & 0 deletions src/feature/cart/cart.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { 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';

@Injectable()
export class CartService {
constructor(
@Inject('FLAGSMITH_SERVICE') private readonly flagService: FlagsmithService,
@InjectEntityManager() private readonly entityManager: EntityManager,
private readonly commonService: CommonService,
) {}
async addCartItem(inputData: AddToCartRequest): Promise<AddToCartResponse> {
if (this.flagService.isFeatureEnabled('fes-24-add-to-cart')) {
const res = new AddToCartResponse(200, '');

const {
customer_id,
sku_id,
qty_ordered,
advanced_taste_customization_obj,
basic_taste_customization_obj,
notes,
} = inputData;

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

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

//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;
}
}
}
13 changes: 13 additions & 0 deletions src/feature/cart/dto/add-to-cart-request.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export class AddToCartRequest {
customer_id: number;
sku_id: number;
qty_ordered: number;
advanced_taste_customization_obj: OptionSelection[];
basic_taste_customization_obj: OptionSelection[];
notes: string;
}

interface OptionSelection {
option_id: string;
value_id: string;
}
31 changes: 31 additions & 0 deletions src/feature/cart/dto/add-to-cart-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { GeneralResponse } from 'src/dto/general-response.dto';

export class AddToCartResponse extends GeneralResponse {
data: AddToCartResponseData;
}

interface AddToCartResponseData {
restaurant_id: number;
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: OptionSelection[];
basic_taste_customization_obj: OptionSelection[];
notes: string;
restaurant_id: number;
created_at: Date;
}

interface OptionSelection {
option_id: string;
value_id: string;
}
92 changes: 91 additions & 1 deletion src/feature/common/common.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Inject, Injectable } from '@nestjs/common';
import { DeliveryRestaurant, Review, TextByLang } from 'src/type';
import {
DeliveryRestaurant,
OptionSelection,
Review,
TextByLang,
} from 'src/type';
import { FlagsmithService } from 'src/dependency/flagsmith/flagsmith.service';
import { RestaurantExt } from 'src/entity/restaurant-ext.entity';
import { InjectEntityManager } from '@nestjs/typeorm';
Expand All @@ -11,6 +16,10 @@ import { SKU } from 'src/entity/sku.entity';
import { PERCENTAGE } from 'src/constant/unit.constant';
import { MenuItem } from 'src/entity/menu-item.entity';
import { FoodDTO } from 'src/dto/food.dto';
import { MenuItemVariant } from 'src/entity/menu-item-variant.entity';
import { TasteExt } from 'src/entity/taste-ext.entity';
import { resourceUsage } from 'process';
import { MenuItemVariantOpion } from 'src/entity/menu-item-variant-option.entity';

@Injectable()
export class CommonService {
Expand Down Expand Up @@ -160,4 +169,85 @@ export class CommonService {
units_sold: menuItem.units_sold,
};
}

async interpretAdvanceTaseCustomization(
obj_list: OptionSelection[],
lang: string = 'vie',
): Promise<string> {
if (this.flagService.isFeatureEnabled('fes-24-add-to-cart')) {
let result = '';

//if object is empty => return ''
if (obj_list.length == 0) {
result = '';
return result;
}

const menuItemVariantIds = obj_list.map((i) => i.option_id);
const menuItemVariants = await this.entityManager
.createQueryBuilder(MenuItemVariant, 'menuItemVariant')
.leftJoinAndSelect('menuItemVariant.taste_ext', 'taseExt')
.where(
'menuItemVariant.menu_item_variant_id IN (:...menuItemVariantIds)',
{ menuItemVariantIds },
)
.andWhere('menuItemVariant.type = :type', { type: 'taste' })
.andWhere('taseExt.ISO_language_code = :lang', { lang })
.getMany();

const menuItemVariantOptionIds = obj_list.map((i) => i.value_id);
const menuItemVariantOptions = await this.entityManager
.createQueryBuilder(MenuItemVariantOpion, 'option')
.leftJoinAndSelect('option.taste_value_ext', 'ext')
.where(
'option.menu_item_variant_option_id IN (:...menuItemVariantOptionIds)',
{ menuItemVariantOptionIds },
)
.andWhere('option.taste_value <> :tasteVal', { tasteVal: 'original' }) //dont generate note for original options
.andWhere('ext.ISO_language_code = :lang', { lang })
.getMany();

const strArr = [];
for (const option of obj_list) {
let str = '';
const menuItemVariant = menuItemVariants.find(
(i) => i.menu_item_variant_id.toString() == option.option_id,
);
//check if the option_id has been filtered out
if (!menuItemVariant) {
continue;
}
const menuItemVariantOption = menuItemVariantOptions.find(
(i) => i.menu_item_variant_option_id.toString() == option.value_id,
);
// check if the value_id has been filtered out
if (!menuItemVariantOption) {
continue;
}
//check if the option_id and value_id is consistent - belong to the same menu_item_variant_id
if (
menuItemVariantOption.menu_item_variant_id !=
menuItemVariant.menu_item_variant_id
) {
console.log(
'menuItemVariantOption ',
menuItemVariantOption.menu_item_variant_option_id,
' does not belong to menuItemVariant ',
menuItemVariant.menu_item_variant_id,
);
continue;
}
str =
menuItemVariantOption.taste_value_ext[0].name +
' ' +
menuItemVariant.taste_ext[0].name;

strArr.push(str);
}
console.log('strArr', strArr);
result = strArr.join(' - ');

return result;
}
}
}
5 changes: 5 additions & 0 deletions src/type/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,8 @@ export interface DayShift {
to: string;
isAvailable?: boolean;
}

export interface OptionSelection {
option_id: string;
value_id: string;
}

0 comments on commit 7218533

Please sign in to comment.