From 148ef1c2efd791cb87728532a854268413f9d386 Mon Sep 17 00:00:00 2001 From: nfesta2023 <142601504+nfesta2023@users.noreply.github.com> Date: Sat, 2 Mar 2024 21:31:28 +0700 Subject: [PATCH] FES-79-update-packaging-db-change (#61) - adjust dto, entity and logic to get data Co-authored-by: NHT --- .prettierrc | 4 +- src/dto/food-detail.dto.ts | 9 +- src/entity/media.entity.ts | 7 ++ src/entity/menu-item.entity.ts | 12 ++- src/entity/menuitem-packaging.entity.ts | 54 ++++++++++ src/entity/packaging-ext.entity.ts | 12 +-- src/entity/packaging.entity.ts | 25 +++-- .../food/dto/get-food-detail-response.dto.ts | 10 +- src/feature/food/food.service.ts | 98 ++++++++++++++----- src/type/index.ts | 8 ++ 10 files changed, 189 insertions(+), 50 deletions(-) create mode 100644 src/entity/menuitem-packaging.entity.ts diff --git a/.prettierrc b/.prettierrc index d6c339a..9409967 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ { "singleQuote": true, "trailingComma": "all", - "printWidth": 200 -} \ No newline at end of file + "printWidth": 80 +} diff --git a/src/dto/food-detail.dto.ts b/src/dto/food-detail.dto.ts index 9e81346..e5acc99 100644 --- a/src/dto/food-detail.dto.ts +++ b/src/dto/food-detail.dto.ts @@ -10,7 +10,7 @@ export class FoodDetailDTO { units_sold: number; review_number: number; promotion: string; - packaging_info: TextByLang[]; + packaging_info: PackagingInfo[]; cutoff_time: string; ingredients: Ingredient[]; description: TextByLang[]; @@ -31,3 +31,10 @@ class BasicCustomization { no_adding_id: string; description: TextByLang[]; } +interface PackagingInfo { + image_url: string; + name: TextByLang[]; + description: TextByLang[]; + price: number; + currency: string; +} diff --git a/src/entity/media.entity.ts b/src/entity/media.entity.ts index a956f37..7095739 100644 --- a/src/entity/media.entity.ts +++ b/src/entity/media.entity.ts @@ -2,10 +2,13 @@ import { Column, CreateDateColumn, Entity, + JoinColumn, + ManyToOne, OneToMany, PrimaryGeneratedColumn, } from 'typeorm'; import { MenuItem } from './menu-item.entity'; +import { Packaging } from './packaging.entity'; @Entity('Media') export class Media { @@ -51,4 +54,8 @@ export class Media { @OneToMany(() => MenuItem, (menuItem) => menuItem.image_obj) public menu_item_obj: MenuItem[]; + + @ManyToOne(() => Packaging, (packaging) => packaging.media_obj) + @JoinColumn({ name: 'packaging_id', referencedColumnName: 'packaging_id' }) + public packaging_obj: Packaging; } diff --git a/src/entity/menu-item.entity.ts b/src/entity/menu-item.entity.ts index bbb1e29..3eaf1e9 100644 --- a/src/entity/menu-item.entity.ts +++ b/src/entity/menu-item.entity.ts @@ -12,7 +12,7 @@ import { MenuItemExt } from './menu-item-ext.entity'; import { SKU } from './sku.entity'; import { Media } from './media.entity'; import { Recipe } from './recipe.entity'; -import { Packaging } from './packaging.entity'; +import { MenuItemPackaging } from './menuitem-packaging.entity'; @Entity('Menu_Item') export class MenuItem { @@ -113,6 +113,12 @@ export class MenuItem { @OneToMany(() => Recipe, (recipe) => recipe.menu_item) public recipe: Promise; - @OneToMany(() => Packaging, (packaging) => packaging.menu_item_obj) - public packaging_obj: Packaging[]; + // @OneToMany(() => Packaging, (packaging) => packaging.menu_item_obj) + // public packaging_obj: Packaging[]; + + @OneToMany( + () => MenuItemPackaging, + (menuItemPackaging) => menuItemPackaging.menu_item_obj, + ) + public menuItemPackaging_obj: MenuItemPackaging[]; } diff --git a/src/entity/menuitem-packaging.entity.ts b/src/entity/menuitem-packaging.entity.ts new file mode 100644 index 0000000..cafba2c --- /dev/null +++ b/src/entity/menuitem-packaging.entity.ts @@ -0,0 +1,54 @@ +import { + Entity, + CreateDateColumn, + PrimaryColumn, + Column, + JoinColumn, + ManyToOne, + OneToOne, +} from 'typeorm'; +import { Packaging } from './packaging.entity'; +import { MenuItem } from './menu-item.entity'; +import { Media } from './media.entity'; + +@Entity('MenuItem_Packaging') +export class MenuItemPackaging { + @PrimaryColumn({ type: 'int', nullable: false }) + public packaging_id: number; + + @PrimaryColumn({ type: 'int', nullable: false }) + public menu_item_id: number; + + @Column({ type: 'int', nullable: false }) + public image: number; + + @CreateDateColumn({ + type: 'datetime', + nullable: false, + unique: false, + default: () => 'CURRENT_TIMESTAMP', + }) + public created_at: Date; + + //RELATIONSHIP + @ManyToOne(() => Packaging) + @JoinColumn({ + name: 'packaging_id', + referencedColumnName: 'packaging_id', + }) + public packaging_obj: Packaging; + + @ManyToOne(() => MenuItem) + @JoinColumn({ + name: 'menu_item_id', + referencedColumnName: 'menu_item_id', + }) + public menu_item_obj: MenuItem; + + @OneToOne(() => Media) + @JoinColumn({ + name: 'image', + referencedColumnName: 'media_id', + }) + image_obj: Media; +} diff --git a/src/entity/packaging-ext.entity.ts b/src/entity/packaging-ext.entity.ts index e9f7def..0a7f552 100644 --- a/src/entity/packaging-ext.entity.ts +++ b/src/entity/packaging-ext.entity.ts @@ -1,11 +1,4 @@ -import { - Entity, - CreateDateColumn, - PrimaryColumn, - Column, - ManyToOne, - JoinColumn, -} from 'typeorm'; +import { Entity, CreateDateColumn, PrimaryColumn, Column, ManyToOne, JoinColumn } from 'typeorm'; import { Packaging } from './packaging.entity'; @Entity('Packaging_Ext') @@ -15,6 +8,9 @@ export class PackagingExt { @PrimaryColumn() public ISO_language_code: string; + @Column({ type: 'varchar', length: 64, nullable: true, unique: false }) + public name: string; + @Column({ type: 'varchar', length: 255, nullable: true, unique: false }) public description: string; diff --git a/src/entity/packaging.entity.ts b/src/entity/packaging.entity.ts index 721ebbe..defb65e 100644 --- a/src/entity/packaging.entity.ts +++ b/src/entity/packaging.entity.ts @@ -9,20 +9,24 @@ import { } from 'typeorm'; import { MenuItem } from './menu-item.entity'; import { PackagingExt } from './packaging-ext.entity'; +import { Media } from './media.entity'; @Entity('Packaging') export class Packaging { @PrimaryGeneratedColumn() public packaging_id: number; + // @Column({ type: 'int', nullable: false, unique: false }) + // public menu_item_id: number; + @Column({ type: 'int', nullable: false, unique: false }) - public menu_item_id: number; + public restaurant_id: number; @Column({ type: 'int', nullable: false, unique: false }) public price: number; - @Column({ type: 'int', nullable: false, unique: false }) - public currency: number; + // @Column({ type: 'int', nullable: false, unique: false }) + // public currency: number; @CreateDateColumn({ type: 'datetime', @@ -34,13 +38,16 @@ export class Packaging { //RELATIONSHIPS - @ManyToOne(() => MenuItem, (menuItem) => menuItem.packaging_obj) - @JoinColumn({ - name: 'menu_item_id', - referencedColumnName: 'menu_item_id', - }) - public menu_item_obj: MenuItem; + // @ManyToOne(() => MenuItem, (menuItem) => menuItem.packaging_obj) + // @JoinColumn({ + // name: 'menu_item_id', + // referencedColumnName: 'menu_item_id', + // }) + // public menu_item_obj: MenuItem; @OneToMany(() => PackagingExt, (packagingExt) => packagingExt.packaging_obj) public packaging_ext_obj: PackagingExt[]; + + @OneToMany(() => Media, (media) => media.packaging_obj) + public media_obj: Media[]; } diff --git a/src/feature/food/dto/get-food-detail-response.dto.ts b/src/feature/food/dto/get-food-detail-response.dto.ts index 8d9d64d..c3f8d54 100644 --- a/src/feature/food/dto/get-food-detail-response.dto.ts +++ b/src/feature/food/dto/get-food-detail-response.dto.ts @@ -14,7 +14,7 @@ interface FoodDetail { units_sold: number; review_number: number; promotion: string; - packaging_info: TextByLang[]; + packaging_info: PackagingInfo[]; cutoff_time: string; ingredients: Ingredient[]; description: TextByLang[]; @@ -64,3 +64,11 @@ interface TextByLang { ISO_language_code: string; text: string; } + +interface PackagingInfo { + image_url: string; + name: TextByLang[]; + description: TextByLang[]; + price: number; + currency: string; +} diff --git a/src/feature/food/food.service.ts b/src/feature/food/food.service.ts index f4c75cd..de5fe66 100644 --- a/src/feature/food/food.service.ts +++ b/src/feature/food/food.service.ts @@ -6,6 +6,7 @@ import { DayShift, Option, OptionValue, + PackagingInfo, PriceRange, RatingStatistic, Review, @@ -32,6 +33,7 @@ import { DayName, Shift } from 'src/enum'; import { FoodDTO } from 'src/dto/food.dto'; import { GetFoodDetailResponse } from './dto/get-food-detail-response.dto'; import { readFileSync } from 'fs'; +import { MenuItemPackaging } from 'src/entity/menuitem-packaging.entity'; @Injectable() export class FoodService { @@ -213,7 +215,10 @@ export class FoodService { units_sold: foods[0].units_sold, review_number: ratingStatistic.total_count, promotion: foods[0].promotion, - packaging_info: await this.generatePackageSentenceByLang(packaging), + packaging_info: await this.generatePackagingInfoForMenuItem( + packaging, + menuItemId, + ), cutoff_time: foods[0].cutoff_time, ingredients: recipe.map((item) => { return { @@ -289,16 +294,6 @@ export class FoodService { // Get data from table Media // - image profile // - other iamge with menu_item_id - // - package image with packaging_id - - //Get list of packaging_id - const packaging_ids = ( - await this.entityManager - .createQueryBuilder(Packaging, 'packaging') - .where('packaging.menu_item_id = :menu_item_id', { menu_item_id }) - .select(['packaging.packaging_id']) - .getMany() - ).map((item) => item.packaging_id); //Select medias const data = await this.entityManager @@ -306,16 +301,26 @@ export class FoodService { .leftJoin('media.menu_item_obj', 'menuItem') .where('menuItem.menu_item_id = :menu_item_id', { menu_item_id }) .orWhere('media.menu_item_id = :menu_item_id', { menu_item_id }) - .orWhere('media.packaging_id IN (:...packaging_ids)', { packaging_ids }) .getMany(); return data; } // end of getAllMediaByMenuItemId - async getPackagingByMenuItemId(menu_item_id: number): Promise { + async getPackagingByMenuItemId( + menu_item_id: number, + ): Promise { + // const data = await this.entityManager + // .createQueryBuilder(Packaging, 'packaging') + // .leftJoinAndSelect('packaging.packaging_ext_obj', 'ext') + // .where('packaging.menu_item_id = :menu_item_id', { menu_item_id }) + // .getMany(); + const data = await this.entityManager - .createQueryBuilder(Packaging, 'packaging') - .leftJoinAndSelect('packaging.packaging_ext_obj', 'ext') - .where('packaging.menu_item_id = :menu_item_id', { menu_item_id }) + .createQueryBuilder(MenuItemPackaging, 'menuItemPackaging') + .leftJoinAndSelect('menuItemPackaging.image_obj', 'itemImage') + .leftJoinAndSelect('menuItemPackaging.packaging_obj', 'packaging') + .leftJoinAndSelect('packaging.packaging_ext_obj', 'packageExt') + .leftJoinAndSelect('packaging.media_obj', 'media') + .where('menuItemPackaging.menu_item_id = :menu_item_id', { menu_item_id }) .getMany(); return data; } // end of getPackagingByMenuItemId @@ -344,19 +349,49 @@ export class FoodService { return data; } // end of getPortionCustomizationByMenuItemId - async generatePackageSentenceByLang(packageInfo: Packaging[]) { - const sentenceByLang: TextByLang[] = []; - for (const item of packageInfo) { - item.packaging_ext_obj.forEach((element) => { - const sentence: TextByLang = { - ISO_language_code: element.ISO_language_code, - text: `${element.description} (+${item.price})`, + async generatePackagingInfoForMenuItem( + menuItemPackagings: MenuItemPackaging[], + menu_item_id: number, + ): Promise { + const currency = await this.getCurrencyOfMenuItem(menu_item_id); + const packagingInfos: PackagingInfo[] = []; + for (const menuItemPackaging of menuItemPackagings) { + //packaging image + let image_url = ''; + if (menuItemPackaging.image_obj) { + image_url = menuItemPackaging.image_obj.url; + } else if (menuItemPackaging.packaging_obj.media_obj.length > 0) { + image_url = menuItemPackaging.packaging_obj.media_obj[0].url; + } else { + image_url = null; + } + //packaging name & description + const name = []; + const description = []; + menuItemPackaging.packaging_obj.packaging_ext_obj.forEach((e) => { + const nameExt: TextByLang = { + ISO_language_code: e.ISO_language_code, + text: e.name, }; - sentenceByLang.push(sentence); + name.push(nameExt); + const descriptionExt: TextByLang = { + ISO_language_code: e.ISO_language_code, + text: e.description, + }; + description.push(descriptionExt); }); + + const packagingInfo: PackagingInfo = { + image_url: image_url, + name: name, + description: description, + price: menuItemPackaging.packaging_obj.price, + currency: currency.symbol, + }; + packagingInfos.push(packagingInfo); } - return sentenceByLang; - } // end of generatePackageSentenceByLang + return packagingInfos; + } // end of generatePackagingInfoForMenuItem async convertPortionCustomization( portionCustomization: MenuItemAttribute[], @@ -771,4 +806,15 @@ export class FoodService { } return foods; } // end of getAvailableFoodByRestaurantFromEndPoint + + async getCurrencyOfMenuItem(menu_item_id: number): Promise { + const menuItem = await this.entityManager + .createQueryBuilder(MenuItem, 'menuItem') + .leftJoinAndSelect('menuItem.restaurant', 'restaurant') + .leftJoinAndSelect('restaurant.unit_obj', 'unit') + .where('menuItem.menu_item_id = :menu_item_id', { menu_item_id }) + .getOne(); + return menuItem.restaurant.unit_obj; + } + //end of getCurrencyOfMenuItem } diff --git a/src/type/index.ts b/src/type/index.ts index 491600d..6eaaec0 100644 --- a/src/type/index.ts +++ b/src/type/index.ts @@ -173,3 +173,11 @@ export interface PriceUnitByMenuItem { menu_item_id: number; price_unit: string; } + +export interface PackagingInfo { + image_url: string; + name: TextByLang[]; + description: TextByLang[]; + price: number; + currency: string; +}