tosanoob commited on
Commit
a6d8fe5
2 Parent(s): 0dd6a66 fddef2e

Merge branch 'main' of https://github.com/PBL6-team-CATS/PBL6-informative-system into feature/frontend_update

Browse files
Files changed (32) hide show
  1. Dockerfile +1 -1
  2. README.md +1 -0
  3. backend/src/app.module.ts +43 -39
  4. backend/src/common/enums/OrderStatus.enum.ts +7 -0
  5. backend/src/common/enums/OrderType.enum.ts +5 -0
  6. backend/src/common/enums/PaymentMethod.enum.ts +5 -0
  7. backend/src/common/enums/role.enum.ts +7 -7
  8. backend/src/entities/branch-menu.entity.ts +5 -2
  9. backend/src/entities/branch.entity.ts +37 -35
  10. backend/src/entities/feed.entity.ts +2 -2
  11. backend/src/entities/menu-item.entity.ts +2 -1
  12. backend/src/entities/order-item.entity.ts +37 -0
  13. backend/src/entities/order.entity.ts +70 -0
  14. backend/src/entities/payment.entity.ts +28 -0
  15. backend/src/entities/user.entity.ts +55 -54
  16. backend/src/migrations/1729963419864-enum-role.ts +0 -22
  17. backend/src/migrations/1730474673934-RefactorAll.ts +56 -0
  18. backend/src/modules/branch-menus/branch-menus.controller.ts +55 -0
  19. backend/src/modules/branch-menus/branch-menus.module.ts +13 -0
  20. backend/src/modules/branch-menus/branch-menus.service.ts +72 -0
  21. backend/src/modules/branch-menus/dto/create-branch-menu.dto.ts +10 -0
  22. backend/src/modules/branch-menus/dto/update-branch-menu.dto.ts +4 -0
  23. backend/src/modules/branch/branch.controller.ts +4 -4
  24. backend/src/modules/branch/branch.module.ts +1 -0
  25. backend/src/modules/branch/branch.service.ts +11 -2
  26. backend/src/modules/branch/dto/create-branch.dto.ts +3 -0
  27. backend/src/modules/menu-item/menu-item.module.ts +1 -0
  28. backend/src/modules/order/dto/create-order.dto.ts +26 -0
  29. backend/src/modules/order/dto/order-items.dto.ts +9 -0
  30. backend/src/modules/order/order.controller.ts +66 -0
  31. backend/src/modules/order/order.module.ts +12 -0
  32. backend/src/modules/order/order.service.ts +137 -0
Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
  # Use an official Node.js runtime as a parent image
2
- FROM node:22-alpine
3
 
4
  # Set the working directory
5
  WORKDIR /app
 
1
  # Use an official Node.js runtime as a parent image
2
+ FROM node:22.4.0
3
 
4
  # Set the working directory
5
  WORKDIR /app
README.md CHANGED
@@ -14,3 +14,4 @@ app_port: 3000
14
 
15
  - [Trello](https://trello.com/w/pbl6hthngthongtin1)
16
  - [Google drive](https://drive.google.com/drive/folders/19qQ5Wn4uat0hSeDX3N5c0X19abYkQLfc?usp=drive_link)
 
 
14
 
15
  - [Trello](https://trello.com/w/pbl6hthngthongtin1)
16
  - [Google drive](https://drive.google.com/drive/folders/19qQ5Wn4uat0hSeDX3N5c0X19abYkQLfc?usp=drive_link)
17
+ - [API docs](https://hackmd.io/NCILuSy3Rxif-KRVQZjNIg#Menu-item)
backend/src/app.module.ts CHANGED
@@ -1,39 +1,43 @@
1
- import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
2
- import { AppController } from './app.controller.js';
3
- import { AppService } from './app.service.js';
4
- import { ConfigModule } from '@nestjs/config';
5
- import { TypeOrmModule } from '@nestjs/typeorm';
6
- import { configuration } from './config/config.js';
7
- import { DatabaseConfigService } from './config/database.js';
8
- import { AppLoggerMiddleware } from './common/middlewares/app-logger.middleware.js';
9
- import { DeviceInfoMiddleware } from './common/middlewares/device-info.middleware.js';
10
- import { UserModule } from './modules/user/user.module.js';
11
- import { BranchModule } from './modules/branch/branch.module.js';
12
- import { AuthenticationModule } from './modules/authentication/authentication.module.js';
13
- import { MenuItemModule } from './modules/menu-item/menu-item.module.js';
14
- import { FeedsModule } from './modules/feeds/feeds.module.js';
15
- @Module({
16
- imports: [
17
- ConfigModule.forRoot({
18
- isGlobal: true,
19
- load: [configuration],
20
- }),
21
- TypeOrmModule.forRootAsync({
22
- imports: [ConfigModule],
23
- useClass: DatabaseConfigService,
24
- }),
25
- UserModule,
26
- BranchModule,
27
- AuthenticationModule,
28
- MenuItemModule,
29
- FeedsModule,
30
- ],
31
- controllers: [AppController],
32
- providers: [AppService],
33
- })
34
- export class AppModule implements NestModule {
35
- configure(consumer: MiddlewareConsumer): void {
36
- consumer.apply(AppLoggerMiddleware).forRoutes('*');
37
- consumer.apply(DeviceInfoMiddleware).forRoutes('*');
38
- }
39
- }
 
 
 
 
 
1
+ import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
2
+ import { AppController } from './app.controller.js';
3
+ import { AppService } from './app.service.js';
4
+ import { ConfigModule } from '@nestjs/config';
5
+ import { TypeOrmModule } from '@nestjs/typeorm';
6
+ import { configuration } from './config/config.js';
7
+ import { DatabaseConfigService } from './config/database.js';
8
+ import { AppLoggerMiddleware } from './common/middlewares/app-logger.middleware.js';
9
+ import { DeviceInfoMiddleware } from './common/middlewares/device-info.middleware.js';
10
+ import { UserModule } from './modules/user/user.module.js';
11
+ import { BranchModule } from './modules/branch/branch.module.js';
12
+ import { AuthenticationModule } from './modules/authentication/authentication.module.js';
13
+ import { MenuItemModule } from './modules/menu-item/menu-item.module.js';
14
+ import { FeedsModule } from './modules/feeds/feeds.module.js';
15
+ import { OrderModule } from './modules/order/order.module.js';
16
+ import { BranchMenusModule } from './modules/branch-menus/branch-menus.module.js';
17
+ @Module({
18
+ imports: [
19
+ ConfigModule.forRoot({
20
+ isGlobal: true,
21
+ load: [configuration],
22
+ }),
23
+ TypeOrmModule.forRootAsync({
24
+ imports: [ConfigModule],
25
+ useClass: DatabaseConfigService,
26
+ }),
27
+ UserModule,
28
+ BranchModule,
29
+ AuthenticationModule,
30
+ MenuItemModule,
31
+ FeedsModule,
32
+ OrderModule,
33
+ BranchMenusModule,
34
+ ],
35
+ controllers: [AppController],
36
+ providers: [AppService],
37
+ })
38
+ export class AppModule implements NestModule {
39
+ configure(consumer: MiddlewareConsumer): void {
40
+ consumer.apply(AppLoggerMiddleware).forRoutes('*');
41
+ consumer.apply(DeviceInfoMiddleware).forRoutes('*');
42
+ }
43
+ }
backend/src/common/enums/OrderStatus.enum.ts ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ export enum OrderStatus {
2
+ PENDING = 'pending', // KH đặt hàng đã thanh toán online, nhân viên chưa xác nhận <online>
3
+ CONFIRMED = 'confirmed', // nhân viên xác nhận và chuyển sang trạng thái <online>
4
+ PREPARING = 'preparing', // nhân viên xác nhận và sang trạng thái preparing này ngay lập tức <online/offline>
5
+ DELIVERING = 'delivering', // dang giao hàng <online>
6
+ DONE = 'done', // <online, offline>
7
+ }
backend/src/common/enums/OrderType.enum.ts ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ export enum OrderType {
2
+ TAKE_AWAY = 'take_away',
3
+ OFFLINE = 'offline',
4
+ ONLINE = 'online',
5
+ }
backend/src/common/enums/PaymentMethod.enum.ts ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ export enum PaymentMethod {
2
+ CASH = 'cash',
3
+ CARD = 'card',
4
+ ONLINE_PAYMENT = 'online_payment',
5
+ }
backend/src/common/enums/role.enum.ts CHANGED
@@ -1,8 +1,8 @@
1
- export enum Role {
2
- CUSTOMER = 'CUSTOMER',
3
- ADMIN = 'ADMIN',
4
- BRANCH_MANAGER = 'BRANCH_MANAGER',
5
- AREA_MANAGER = 'AREA_MANAGER',
6
- STAFF = 'STAFF',
7
- SHIPPER = 'SHIPPER'
8
  }
 
1
+ export enum Role {
2
+ CUSTOMER = 'CUSTOMER',
3
+ ADMIN = 'ADMIN',
4
+ BRANCH_MANAGER = 'BRANCH_MANAGER',
5
+ AREA_MANAGER = 'AREA_MANAGER',
6
+ STAFF = 'STAFF',
7
+ SHIPPER = 'SHIPPER'
8
  }
backend/src/entities/branch-menu.entity.ts CHANGED
@@ -2,6 +2,7 @@ import {
2
  BaseEntity,
3
  Column,
4
  Entity,
 
5
  ManyToOne,
6
  OneToMany,
7
  PrimaryGeneratedColumn,
@@ -21,15 +22,17 @@ export class BranchMenuEntity extends BaseEntity {
21
  @Column()
22
  menu_id: string;
23
 
24
- @Column()
25
  description: string;
26
 
27
- @Column()
28
  is_open: boolean;
29
 
30
  @ManyToOne(() => BranchEntity, (a) => a.menu_items)
 
31
  branch: Relation<BranchEntity>;
32
 
33
  @ManyToOne(() => MenuItemEntity, (a) => a.branch_menus)
 
34
  menu_item: Relation<MenuItemEntity>;
35
  }
 
2
  BaseEntity,
3
  Column,
4
  Entity,
5
+ JoinColumn,
6
  ManyToOne,
7
  OneToMany,
8
  PrimaryGeneratedColumn,
 
22
  @Column()
23
  menu_id: string;
24
 
25
+ @Column({ nullable: true })
26
  description: string;
27
 
28
+ @Column({ default: true })
29
  is_open: boolean;
30
 
31
  @ManyToOne(() => BranchEntity, (a) => a.menu_items)
32
+ @JoinColumn({ name: 'branch_id' })
33
  branch: Relation<BranchEntity>;
34
 
35
  @ManyToOne(() => MenuItemEntity, (a) => a.branch_menus)
36
+ @JoinColumn({ name: 'menu_id' })
37
  menu_item: Relation<MenuItemEntity>;
38
  }
backend/src/entities/branch.entity.ts CHANGED
@@ -1,35 +1,37 @@
1
- import {
2
- BaseEntity,
3
- Column,
4
- Entity,
5
- ManyToOne,
6
- OneToMany,
7
- PrimaryGeneratedColumn,
8
- Relation,
9
- } from 'typeorm';
10
- import { UserEntity } from './user.entity.js';
11
- import { BranchMenuEntity } from './branch-menu.entity.js';
12
-
13
- @Entity('branches')
14
- export class BranchEntity extends BaseEntity {
15
- @PrimaryGeneratedColumn('uuid')
16
- id: string;
17
-
18
- @Column()
19
- name: string;
20
-
21
- @Column()
22
- location: string;
23
-
24
- @Column()
25
- phone_number: string;
26
-
27
- @ManyToOne(() => UserEntity, (user) => user.branches)
28
- owner: Relation<UserEntity>;
29
-
30
- @OneToMany(() => BranchMenuEntity, (a) => a.branch)
31
- menu_items: Relation<BranchMenuEntity>[];
32
-
33
- @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
34
- create_at: Date;
35
- }
 
 
 
1
+ import {
2
+ BaseEntity,
3
+ Column,
4
+ CreateDateColumn,
5
+ Entity,
6
+ ManyToOne,
7
+ OneToMany,
8
+ PrimaryColumn,
9
+ PrimaryGeneratedColumn,
10
+ Relation,
11
+ } from 'typeorm';
12
+ import { UserEntity } from './user.entity.js';
13
+ import { BranchMenuEntity } from './branch-menu.entity.js';
14
+
15
+ @Entity('branches')
16
+ export class BranchEntity extends BaseEntity {
17
+ @PrimaryColumn()
18
+ id: string;
19
+
20
+ @Column()
21
+ name: string;
22
+
23
+ @Column()
24
+ location: string;
25
+
26
+ @Column()
27
+ phone_number: string;
28
+
29
+ @ManyToOne(() => UserEntity, (user) => user.branches)
30
+ owner: Relation<UserEntity>;
31
+
32
+ @OneToMany(() => BranchMenuEntity, (a) => a.branch)
33
+ menu_items: Relation<BranchMenuEntity>[];
34
+
35
+ @CreateDateColumn()
36
+ create_at: Date;
37
+ }
backend/src/entities/feed.entity.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Entity, Column, BaseEntity, PrimaryGeneratedColumn } from 'typeorm';
2
 
3
  @Entity('feeds')
4
  export class FeedEntity extends BaseEntity {
@@ -17,6 +17,6 @@ export class FeedEntity extends BaseEntity {
17
  @Column({ nullable: true })
18
  description: string;
19
 
20
- @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
21
  create_at: Date;
22
  }
 
1
+ import { Entity, Column, BaseEntity, PrimaryGeneratedColumn, CreateDateColumn } from 'typeorm';
2
 
3
  @Entity('feeds')
4
  export class FeedEntity extends BaseEntity {
 
17
  @Column({ nullable: true })
18
  description: string;
19
 
20
+ @CreateDateColumn()
21
  create_at: Date;
22
  }
backend/src/entities/menu-item.entity.ts CHANGED
@@ -1,6 +1,7 @@
1
  import {
2
  BaseEntity,
3
  Column,
 
4
  Entity,
5
  OneToMany,
6
  PrimaryColumn,
@@ -32,6 +33,6 @@ export class MenuItemEntity extends BaseEntity {
32
  @OneToMany(() => BranchMenuEntity, (a) => a.menu_item)
33
  branch_menus: Relation<BranchMenuEntity>[];
34
 
35
- @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
36
  create_at: Date;
37
  }
 
1
  import {
2
  BaseEntity,
3
  Column,
4
+ CreateDateColumn,
5
  Entity,
6
  OneToMany,
7
  PrimaryColumn,
 
33
  @OneToMany(() => BranchMenuEntity, (a) => a.menu_item)
34
  branch_menus: Relation<BranchMenuEntity>[];
35
 
36
+ @CreateDateColumn()
37
  create_at: Date;
38
  }
backend/src/entities/order-item.entity.ts ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ BaseEntity,
3
+ Column,
4
+ Entity,
5
+ JoinColumn,
6
+ ManyToOne,
7
+ PrimaryGeneratedColumn,
8
+ Relation,
9
+ } from 'typeorm';
10
+ import { BranchMenuEntity } from './branch-menu.entity.js';
11
+ import { OrderEntity } from './order.entity.js';
12
+
13
+ @Entity('order_items')
14
+ export class OrderItemEntity extends BaseEntity {
15
+ @PrimaryGeneratedColumn()
16
+ id: number;
17
+
18
+ @Column()
19
+ order_id: number;
20
+
21
+ @ManyToOne(() => OrderEntity, (a) => a.order_items)
22
+ @JoinColumn({ name: 'order_id' })
23
+ order: Relation<OrderEntity>;
24
+
25
+ @Column()
26
+ branch_menu_id: string;
27
+
28
+ @ManyToOne(() => BranchMenuEntity)
29
+ @JoinColumn({ name: 'branch_menu_id' })
30
+ branch_menu: Relation<BranchMenuEntity>;
31
+
32
+ @Column()
33
+ quantity: number;
34
+
35
+ @Column()
36
+ price: number;
37
+ }
backend/src/entities/order.entity.ts ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ BaseEntity,
3
+ Column,
4
+ CreateDateColumn,
5
+ Entity,
6
+ JoinColumn,
7
+ ManyToOne,
8
+ OneToMany,
9
+ OneToOne,
10
+ PrimaryGeneratedColumn,
11
+ Relation,
12
+ } from 'typeorm';
13
+ import { BranchEntity } from './branch.entity.js';
14
+ import { UserEntity } from './user.entity.js';
15
+ import { OrderType } from '../common/enums/OrderType.enum.js';
16
+ import { OrderStatus } from '../common/enums/OrderStatus.enum.js';
17
+ import { OrderItemEntity } from './order-item.entity.js';
18
+ import { PaymentEntity } from './payment.entity.js';
19
+
20
+ @Entity('orders')
21
+ export class OrderEntity extends BaseEntity {
22
+ @PrimaryGeneratedColumn()
23
+ id: number;
24
+
25
+ @Column({ nullable: true })
26
+ customer_id: string;
27
+
28
+ @ManyToOne(() => UserEntity, { nullable: true })
29
+ @JoinColumn({ name: 'customer_id' })
30
+ customer: Relation<UserEntity>;
31
+
32
+ @Column()
33
+ branch_id: string;
34
+
35
+ @ManyToOne(() => BranchEntity)
36
+ @JoinColumn({ name: 'branch_id' })
37
+ branch: Relation<BranchEntity>;
38
+
39
+ @Column({ nullable: true })
40
+ staff_id: string;
41
+
42
+ @ManyToOne(() => UserEntity, { nullable: true })
43
+ @JoinColumn({ name: 'staff_id' })
44
+ staff: Relation<UserEntity>;
45
+
46
+ @Column({ nullable: true })
47
+ table_number: number;
48
+
49
+ @Column()
50
+ total_value: number;
51
+
52
+ @CreateDateColumn()
53
+ create_at: Date;
54
+
55
+ @Column({ type: 'enum', enum: OrderType, default: OrderType.ONLINE })
56
+ order_type: OrderType;
57
+
58
+ @Column({ type: 'enum', enum: OrderStatus, default: OrderStatus.PENDING })
59
+ order_status: OrderStatus;
60
+
61
+ @OneToMany(() => OrderItemEntity, (a) => a.order)
62
+ order_items: Relation<OrderItemEntity>[];
63
+
64
+ @Column({ nullable: true })
65
+ payment_id: number;
66
+
67
+ @OneToOne(() => PaymentEntity, (a) => a.order)
68
+ @JoinColumn({ name: 'payment_id' })
69
+ payment: Relation<PaymentEntity>;
70
+ }
backend/src/entities/payment.entity.ts ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ BaseEntity,
3
+ Column,
4
+ Entity,
5
+ JoinColumn,
6
+ ManyToOne,
7
+ OneToOne,
8
+ PrimaryGeneratedColumn,
9
+ Relation,
10
+ } from 'typeorm';
11
+ import { BranchMenuEntity } from './branch-menu.entity.js';
12
+ import { OrderEntity } from './order.entity.js';
13
+ import { PaymentMethod } from '../common/enums/PaymentMethod.enum.js';
14
+
15
+ @Entity('payments')
16
+ export class PaymentEntity extends BaseEntity {
17
+ @PrimaryGeneratedColumn()
18
+ id: number;
19
+
20
+ @OneToOne(() => OrderEntity, (a) => a.payment)
21
+ order: Relation<OrderEntity>;
22
+
23
+ @Column({ type: 'enum', enum: PaymentMethod, default: PaymentMethod.CASH })
24
+ payment_method: PaymentMethod; // E.g., 'Cash', 'Credit Card', 'Online Payment'
25
+
26
+ @Column()
27
+ value: number;
28
+ }
backend/src/entities/user.entity.ts CHANGED
@@ -1,54 +1,55 @@
1
- import {
2
- Entity,
3
- Column,
4
- BaseEntity,
5
- PrimaryGeneratedColumn,
6
- OneToMany,
7
- ManyToOne,
8
- Relation,
9
- JoinColumn,
10
- } from 'typeorm';
11
- import { BranchEntity } from './branch.entity.js';
12
- import { IsOptional } from 'class-validator';
13
- import { Role } from '../common/enums/role.enum.js';
14
-
15
- @Entity('users')
16
- export class UserEntity extends BaseEntity {
17
- @PrimaryGeneratedColumn('uuid')
18
- id: string;
19
-
20
- @IsOptional()
21
- @Column({ nullable: true })
22
- avatar: string;
23
-
24
- @Column()
25
- full_name: string;
26
-
27
- @Column({ unique: true })
28
- phone_number: string;
29
-
30
- @IsOptional()
31
- @Column({ nullable: true })
32
- address: string;
33
-
34
- @Column({ nullable: true, unique: true })
35
- email: string;
36
-
37
- @Column({ type: 'enum', enum: Role, default: 'CUSTOMER' })
38
- role: Role;
39
-
40
- @Column()
41
- hash_password: string;
42
-
43
- @IsOptional()
44
- @Column({ default: true })
45
- is_valid: boolean;
46
-
47
- @IsOptional()
48
- @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
49
- create_at: Date;
50
-
51
- @IsOptional()
52
- @OneToMany(() => BranchEntity, (branch) => branch.owner)
53
- branches: Relation<BranchEntity>[];
54
- }
 
 
1
+ import {
2
+ Entity,
3
+ Column,
4
+ BaseEntity,
5
+ PrimaryGeneratedColumn,
6
+ OneToMany,
7
+ ManyToOne,
8
+ Relation,
9
+ JoinColumn,
10
+ CreateDateColumn,
11
+ } from 'typeorm';
12
+ import { BranchEntity } from './branch.entity.js';
13
+ import { IsOptional } from 'class-validator';
14
+ import { Role } from '../common/enums/role.enum.js';
15
+
16
+ @Entity('users')
17
+ export class UserEntity extends BaseEntity {
18
+ @PrimaryGeneratedColumn('uuid')
19
+ id: string;
20
+
21
+ @IsOptional()
22
+ @Column({ nullable: true })
23
+ avatar: string;
24
+
25
+ @Column()
26
+ full_name: string;
27
+
28
+ @Column({ unique: true })
29
+ phone_number: string;
30
+
31
+ @IsOptional()
32
+ @Column({ nullable: true })
33
+ address: string;
34
+
35
+ @Column({ nullable: true, unique: true })
36
+ email: string;
37
+
38
+ @Column({ type: 'enum', enum: Role, default: 'CUSTOMER' })
39
+ role: Role;
40
+
41
+ @Column()
42
+ hash_password: string;
43
+
44
+ @IsOptional()
45
+ @Column({ default: true })
46
+ is_valid: boolean;
47
+
48
+ @IsOptional()
49
+ @CreateDateColumn()
50
+ create_at: Date;
51
+
52
+ @IsOptional()
53
+ @OneToMany(() => BranchEntity, (branch) => branch.owner)
54
+ branches: Relation<BranchEntity>[];
55
+ }
backend/src/migrations/1729963419864-enum-role.ts DELETED
@@ -1,22 +0,0 @@
1
- import { MigrationInterface, QueryRunner } from "typeorm";
2
-
3
- export class EnumRole1729963419864 implements MigrationInterface {
4
- name = 'EnumRole1729963419864'
5
-
6
- public async up(queryRunner: QueryRunner): Promise<void> {
7
- await queryRunner.query(`ALTER TABLE "users" DROP CONSTRAINT "FK_a2cecd1a3531c0b041e29ba46e1"`);
8
- await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "role_id" TO "role"`);
9
- await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "role"`);
10
- await queryRunner.query(`CREATE TYPE "public"."users_role_enum" AS ENUM('CUSTOMER', 'ADMIN', 'BRANCH_MANAGER', 'AREA_MANAGER', 'STAFF', 'SHIPPER')`);
11
- await queryRunner.query(`ALTER TABLE "users" ADD "role" "public"."users_role_enum" NOT NULL DEFAULT 'CUSTOMER'`);
12
- }
13
-
14
- public async down(queryRunner: QueryRunner): Promise<void> {
15
- await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "role"`);
16
- await queryRunner.query(`DROP TYPE "public"."users_role_enum"`);
17
- await queryRunner.query(`ALTER TABLE "users" ADD "role" uuid NOT NULL DEFAULT 'f3750930-48ab-4c30-8681-d50e68e2bda7'`);
18
- await queryRunner.query(`ALTER TABLE "users" RENAME COLUMN "role" TO "role_id"`);
19
- await queryRunner.query(`ALTER TABLE "users" ADD CONSTRAINT "FK_a2cecd1a3531c0b041e29ba46e1" FOREIGN KEY ("role_id") REFERENCES "role"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
20
- }
21
-
22
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
backend/src/migrations/1730474673934-RefactorAll.ts ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class RefactorAll1730474673934 implements MigrationInterface {
4
+ name = 'RefactorAll1730474673934'
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(`CREATE TABLE "feeds" ("id" SERIAL NOT NULL, "author_id" character varying, "image_url" character varying, "title" character varying NOT NULL, "description" character varying, "create_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_3dafbf766ecbb1eb2017732153f" PRIMARY KEY ("id"))`);
8
+ await queryRunner.query(`CREATE TYPE "public"."users_role_enum" AS ENUM('CUSTOMER', 'ADMIN', 'BRANCH_MANAGER', 'AREA_MANAGER', 'STAFF', 'SHIPPER')`);
9
+ await queryRunner.query(`CREATE TABLE "users" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "avatar" character varying, "full_name" character varying NOT NULL, "phone_number" character varying NOT NULL, "address" character varying, "email" character varying, "role" "public"."users_role_enum" NOT NULL DEFAULT 'CUSTOMER', "hash_password" character varying NOT NULL, "is_valid" boolean NOT NULL DEFAULT true, "create_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_17d1817f241f10a3dbafb169fd2" UNIQUE ("phone_number"), CONSTRAINT "UQ_97672ac88f789774dd47f7c8be3" UNIQUE ("email"), CONSTRAINT "PK_a3ffb1c0c8416b9fc6f907b7433" PRIMARY KEY ("id"))`);
10
+ await queryRunner.query(`CREATE TABLE "branches" ("id" character varying NOT NULL, "name" character varying NOT NULL, "location" character varying NOT NULL, "phone_number" character varying NOT NULL, "create_at" TIMESTAMP NOT NULL DEFAULT now(), "ownerId" uuid, CONSTRAINT "PK_7f37d3b42defea97f1df0d19535" PRIMARY KEY ("id"))`);
11
+ await queryRunner.query(`CREATE TYPE "public"."menu_items_item_type_enum" AS ENUM('monchinh', 'trangmieng', 'giaikhat', 'khac')`);
12
+ await queryRunner.query(`CREATE TABLE "menu_items" ("id" character varying NOT NULL, "item_name" character varying NOT NULL, "image_url" character varying, "item_type" "public"."menu_items_item_type_enum" NOT NULL DEFAULT 'khac', "description" character varying NOT NULL, "price" integer NOT NULL, "create_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_57e6188f929e5dc6919168620c8" PRIMARY KEY ("id"))`);
13
+ await queryRunner.query(`CREATE TABLE "branch_menu" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "branch_id" character varying NOT NULL, "menu_id" character varying NOT NULL, "description" character varying, "is_open" boolean NOT NULL DEFAULT true, CONSTRAINT "PK_977becffe98bbc626a56031b9e7" PRIMARY KEY ("id"))`);
14
+ await queryRunner.query(`CREATE TYPE "public"."payments_payment_method_enum" AS ENUM('cash', 'card', 'online_payment')`);
15
+ await queryRunner.query(`CREATE TABLE "payments" ("id" SERIAL NOT NULL, "payment_method" "public"."payments_payment_method_enum" NOT NULL DEFAULT 'cash', "value" integer NOT NULL, CONSTRAINT "PK_197ab7af18c93fbb0c9b28b4a59" PRIMARY KEY ("id"))`);
16
+ await queryRunner.query(`CREATE TYPE "public"."orders_order_type_enum" AS ENUM('take_away', 'offline', 'online')`);
17
+ await queryRunner.query(`CREATE TYPE "public"."orders_order_status_enum" AS ENUM('pending', 'confirmed', 'preparing', 'delivering', 'done')`);
18
+ await queryRunner.query(`CREATE TABLE "orders" ("id" SERIAL NOT NULL, "customer_id" uuid, "branch_id" character varying NOT NULL, "staff_id" uuid, "table_number" integer, "total_value" integer NOT NULL, "create_at" TIMESTAMP NOT NULL DEFAULT now(), "order_type" "public"."orders_order_type_enum" NOT NULL DEFAULT 'online', "order_status" "public"."orders_order_status_enum" NOT NULL DEFAULT 'pending', "payment_id" integer, CONSTRAINT "REL_5b3e94bd2aedc184f9ad8c1043" UNIQUE ("payment_id"), CONSTRAINT "PK_710e2d4957aa5878dfe94e4ac2f" PRIMARY KEY ("id"))`);
19
+ await queryRunner.query(`CREATE TABLE "order_items" ("id" SERIAL NOT NULL, "order_id" integer NOT NULL, "branch_menu_id" uuid NOT NULL, "quantity" integer NOT NULL, "price" integer NOT NULL, CONSTRAINT "PK_005269d8574e6fac0493715c308" PRIMARY KEY ("id"))`);
20
+ await queryRunner.query(`ALTER TABLE "branches" ADD CONSTRAINT "FK_8c6ae9f9c654c4fac71bccbb7ed" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
21
+ await queryRunner.query(`ALTER TABLE "branch_menu" ADD CONSTRAINT "FK_96fd74bed807987cf2ee5d8f168" FOREIGN KEY ("branch_id") REFERENCES "branches"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
22
+ await queryRunner.query(`ALTER TABLE "branch_menu" ADD CONSTRAINT "FK_703aa953158d2e80f3fbb0eb9ea" FOREIGN KEY ("menu_id") REFERENCES "menu_items"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
23
+ await queryRunner.query(`ALTER TABLE "orders" ADD CONSTRAINT "FK_772d0ce0473ac2ccfa26060dbe9" FOREIGN KEY ("customer_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
24
+ await queryRunner.query(`ALTER TABLE "orders" ADD CONSTRAINT "FK_17b723da2c12837f4bc21e33398" FOREIGN KEY ("branch_id") REFERENCES "branches"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
25
+ await queryRunner.query(`ALTER TABLE "orders" ADD CONSTRAINT "FK_40337bbb0e0cc7113dc3037fc60" FOREIGN KEY ("staff_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
26
+ await queryRunner.query(`ALTER TABLE "orders" ADD CONSTRAINT "FK_5b3e94bd2aedc184f9ad8c10439" FOREIGN KEY ("payment_id") REFERENCES "payments"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
27
+ await queryRunner.query(`ALTER TABLE "order_items" ADD CONSTRAINT "FK_145532db85752b29c57d2b7b1f1" FOREIGN KEY ("order_id") REFERENCES "orders"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
28
+ await queryRunner.query(`ALTER TABLE "order_items" ADD CONSTRAINT "FK_927879f38b3098216737427d2f0" FOREIGN KEY ("branch_menu_id") REFERENCES "branch_menu"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
29
+ }
30
+
31
+ public async down(queryRunner: QueryRunner): Promise<void> {
32
+ await queryRunner.query(`ALTER TABLE "order_items" DROP CONSTRAINT "FK_927879f38b3098216737427d2f0"`);
33
+ await queryRunner.query(`ALTER TABLE "order_items" DROP CONSTRAINT "FK_145532db85752b29c57d2b7b1f1"`);
34
+ await queryRunner.query(`ALTER TABLE "orders" DROP CONSTRAINT "FK_5b3e94bd2aedc184f9ad8c10439"`);
35
+ await queryRunner.query(`ALTER TABLE "orders" DROP CONSTRAINT "FK_40337bbb0e0cc7113dc3037fc60"`);
36
+ await queryRunner.query(`ALTER TABLE "orders" DROP CONSTRAINT "FK_17b723da2c12837f4bc21e33398"`);
37
+ await queryRunner.query(`ALTER TABLE "orders" DROP CONSTRAINT "FK_772d0ce0473ac2ccfa26060dbe9"`);
38
+ await queryRunner.query(`ALTER TABLE "branch_menu" DROP CONSTRAINT "FK_703aa953158d2e80f3fbb0eb9ea"`);
39
+ await queryRunner.query(`ALTER TABLE "branch_menu" DROP CONSTRAINT "FK_96fd74bed807987cf2ee5d8f168"`);
40
+ await queryRunner.query(`ALTER TABLE "branches" DROP CONSTRAINT "FK_8c6ae9f9c654c4fac71bccbb7ed"`);
41
+ await queryRunner.query(`DROP TABLE "order_items"`);
42
+ await queryRunner.query(`DROP TABLE "orders"`);
43
+ await queryRunner.query(`DROP TYPE "public"."orders_order_status_enum"`);
44
+ await queryRunner.query(`DROP TYPE "public"."orders_order_type_enum"`);
45
+ await queryRunner.query(`DROP TABLE "payments"`);
46
+ await queryRunner.query(`DROP TYPE "public"."payments_payment_method_enum"`);
47
+ await queryRunner.query(`DROP TABLE "branch_menu"`);
48
+ await queryRunner.query(`DROP TABLE "menu_items"`);
49
+ await queryRunner.query(`DROP TYPE "public"."menu_items_item_type_enum"`);
50
+ await queryRunner.query(`DROP TABLE "branches"`);
51
+ await queryRunner.query(`DROP TABLE "users"`);
52
+ await queryRunner.query(`DROP TYPE "public"."users_role_enum"`);
53
+ await queryRunner.query(`DROP TABLE "feeds"`);
54
+ }
55
+
56
+ }
backend/src/modules/branch-menus/branch-menus.controller.ts ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ Controller,
3
+ Get,
4
+ Post,
5
+ Body,
6
+ Patch,
7
+ Param,
8
+ Delete,
9
+ } from '@nestjs/common';
10
+ import { BranchMenusService } from './branch-menus.service.js';
11
+ import { CreateBranchMenuDto } from './dto/create-branch-menu.dto.js';
12
+ import { UpdateBranchMenuDto } from './dto/update-branch-menu.dto.js';
13
+ import { Public } from '../authentication/authentication.decorator.js';
14
+ import { Paginate, PaginateQuery } from 'nestjs-paginate';
15
+
16
+ @Public()
17
+ @Controller('branchs/:branchId/menus')
18
+ export class BranchMenusController {
19
+ constructor(private readonly branchMenusService: BranchMenusService) {}
20
+
21
+ @Post() // thêm menu vào branch
22
+ create(
23
+ @Param('branchId') branchId: string,
24
+ @Body() createBranchMenuDto: CreateBranchMenuDto,
25
+ ) {
26
+ return this.branchMenusService.create(branchId, createBranchMenuDto);
27
+ }
28
+
29
+ @Get() // lấy danh sách menu trong branch
30
+ findAll(
31
+ @Param('branchId') branchId: string,
32
+ @Paginate() query: PaginateQuery,
33
+ ) {
34
+ // console.log('branchId', branchId);
35
+ return this.branchMenusService.findAll(branchId, query);
36
+ }
37
+
38
+ @Get(':id') // lấy một menu trong branch
39
+ findOne(@Param('branchId') branchId: string, @Param('id') id: string) {
40
+ return this.branchMenusService.findOne(branchId, id);
41
+ }
42
+
43
+ @Patch(':id')
44
+ update(
45
+ @Param('id') id: string,
46
+ @Body() updateBranchMenuDto: UpdateBranchMenuDto,
47
+ ) {
48
+ return this.branchMenusService.update(+id, updateBranchMenuDto);
49
+ }
50
+
51
+ @Delete(':id')
52
+ remove(@Param('id') id: string) {
53
+ return this.branchMenusService.remove(+id);
54
+ }
55
+ }
backend/src/modules/branch-menus/branch-menus.module.ts ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Module } from '@nestjs/common';
2
+ import { BranchMenusService } from './branch-menus.service.js';
3
+ import { BranchMenusController } from './branch-menus.controller.js';
4
+ import { BranchModule } from '../branch/branch.module.js';
5
+ import { MenuItemModule } from '../menu-item/menu-item.module.js';
6
+
7
+ @Module({
8
+ imports: [BranchModule, MenuItemModule],
9
+ controllers: [BranchMenusController],
10
+ providers: [BranchMenusService],
11
+ exports: [BranchMenusService],
12
+ })
13
+ export class BranchMenusModule {}
backend/src/modules/branch-menus/branch-menus.service.ts ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Injectable } from '@nestjs/common';
2
+ import { CreateBranchMenuDto } from './dto/create-branch-menu.dto.js';
3
+ import { UpdateBranchMenuDto } from './dto/update-branch-menu.dto.js';
4
+ import { BranchService } from '../branch/branch.service.js';
5
+ import { MenuItemService } from '../menu-item/menu-item.service.js';
6
+ import { BranchMenuEntity } from '../../entities/branch-menu.entity.js';
7
+ import { paginate, PaginateConfig, PaginateQuery } from 'nestjs-paginate';
8
+ import { isUUID } from 'class-validator';
9
+
10
+ @Injectable()
11
+ export class BranchMenusService {
12
+ constructor(
13
+ private readonly branchService: BranchService,
14
+ private readonly menuItemService: MenuItemService,
15
+ ) {}
16
+ async create(branchId: string, createBranchMenuDto: CreateBranchMenuDto) {
17
+ const branch = await this.branchService.getBranchOrError(branchId);
18
+ const menuItem = await this.menuItemService.getMenuItemOrError(
19
+ createBranchMenuDto.menu_id,
20
+ );
21
+ if (createBranchMenuDto.description) {
22
+ return await BranchMenuEntity.create({
23
+ ...createBranchMenuDto,
24
+ branch_id: branchId,
25
+ }).save();
26
+ } else {
27
+ return await BranchMenuEntity.create({
28
+ ...createBranchMenuDto,
29
+ branch_id: branchId,
30
+ description: menuItem.description,
31
+ }).save();
32
+ }
33
+ }
34
+
35
+ async findAll(branchId: string, query: PaginateQuery) {
36
+ const paginateConfig: PaginateConfig<BranchMenuEntity> = {
37
+ sortableColumns: ['id', 'branch_id', 'menu_id', 'description'],
38
+ nullSort: 'last',
39
+ defaultSortBy: [['id', 'DESC']],
40
+ searchableColumns: ['description'],
41
+ filterableColumns: {
42
+ // price: [],
43
+ // item_type: [FilterOperator.EQ],
44
+ },
45
+ };
46
+ return paginate(
47
+ query,
48
+ BranchMenuEntity.createQueryBuilder('bm')
49
+ .leftJoinAndSelect('bm.menu_item', 'menu_item')
50
+ .where('bm.branch_id = :branchId', { branchId: branchId }),
51
+ paginateConfig,
52
+ );
53
+ }
54
+
55
+ async findOne(branchId: string, id: string) {
56
+ if (isUUID(id)) return await BranchMenuEntity.findOneBy({ id });
57
+ else {
58
+ return await BranchMenuEntity.findOne({
59
+ where: { branch_id: branchId, menu_id: id },
60
+ relations: ['menu_item'],
61
+ });
62
+ }
63
+ }
64
+
65
+ update(id: number, updateBranchMenuDto: UpdateBranchMenuDto) {
66
+ return `This action updates a #${id} branchMenu`;
67
+ }
68
+
69
+ remove(id: number) {
70
+ return `This action removes a #${id} branchMenu`;
71
+ }
72
+ }
backend/src/modules/branch-menus/dto/create-branch-menu.dto.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { IsOptional, IsString } from 'class-validator';
2
+
3
+ export class CreateBranchMenuDto {
4
+ @IsString()
5
+ menu_id: string;
6
+
7
+ @IsString()
8
+ @IsOptional()
9
+ description?: string;
10
+ }
backend/src/modules/branch-menus/dto/update-branch-menu.dto.ts ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ import { PartialType } from '@nestjs/mapped-types';
2
+ import { CreateBranchMenuDto } from './create-branch-menu.dto.js';
3
+
4
+ export class UpdateBranchMenuDto extends PartialType(CreateBranchMenuDto) {}
backend/src/modules/branch/branch.controller.ts CHANGED
@@ -10,8 +10,10 @@ import {
10
  import { BranchService } from './branch.service.js';
11
  import { CreateBranchDto } from './dto/create-branch.dto.js';
12
  import { UpdateBranchDto } from './dto/update-branch.dto.js';
 
13
 
14
- @Controller('branch')
 
15
  export class BranchController {
16
  constructor(private readonly branchService: BranchService) {}
17
 
@@ -47,7 +49,5 @@ export class BranchController {
47
  async addMenuItemToBranch(@Param('id') id: string) {}
48
 
49
  @Get(':id/menu-items')
50
- async getMenuItemWithBranchId(@Param('id') id: string) {
51
-
52
- }
53
  }
 
10
  import { BranchService } from './branch.service.js';
11
  import { CreateBranchDto } from './dto/create-branch.dto.js';
12
  import { UpdateBranchDto } from './dto/update-branch.dto.js';
13
+ import { Public } from '../authentication/authentication.decorator.js';
14
 
15
+ @Public()
16
+ @Controller('branchs')
17
  export class BranchController {
18
  constructor(private readonly branchService: BranchService) {}
19
 
 
49
  async addMenuItemToBranch(@Param('id') id: string) {}
50
 
51
  @Get(':id/menu-items')
52
+ async getMenuItemWithBranchId(@Param('id') id: string) {}
 
 
53
  }
backend/src/modules/branch/branch.module.ts CHANGED
@@ -5,5 +5,6 @@ import { BranchController } from './branch.controller.js';
5
  @Module({
6
  controllers: [BranchController],
7
  providers: [BranchService],
 
8
  })
9
  export class BranchModule {}
 
5
  @Module({
6
  controllers: [BranchController],
7
  providers: [BranchService],
8
+ exports: [BranchService],
9
  })
10
  export class BranchModule {}
backend/src/modules/branch/branch.service.ts CHANGED
@@ -1,4 +1,8 @@
1
- import { Injectable, NotFoundException } from '@nestjs/common';
 
 
 
 
2
  import { CreateBranchDto } from './dto/create-branch.dto.js';
3
  import { BranchEntity } from '../../entities/branch.entity.js';
4
  import { Public } from '../authentication/authentication.decorator.js';
@@ -9,6 +13,10 @@ import { plainToClass } from 'class-transformer';
9
  @Injectable()
10
  export class BranchService {
11
  async create(createBranchDto: CreateBranchDto) {
 
 
 
 
12
  return await BranchEntity.create({ ...createBranchDto }).save();
13
  }
14
 
@@ -21,9 +29,10 @@ export class BranchService {
21
  }
22
 
23
  async getBranchOrError(id: string) {
 
24
  const branch = await BranchEntity.findOneBy({ id });
25
  if (!branch) {
26
- throw new NotFoundException('Menu item not found');
27
  }
28
  return branch;
29
  }
 
1
+ import {
2
+ BadRequestException,
3
+ Injectable,
4
+ NotFoundException,
5
+ } from '@nestjs/common';
6
  import { CreateBranchDto } from './dto/create-branch.dto.js';
7
  import { BranchEntity } from '../../entities/branch.entity.js';
8
  import { Public } from '../authentication/authentication.decorator.js';
 
13
  @Injectable()
14
  export class BranchService {
15
  async create(createBranchDto: CreateBranchDto) {
16
+ const branch = await BranchEntity.findOneBy({ id: createBranchDto.id });
17
+ if (branch) {
18
+ throw new BadRequestException('Branch already exists');
19
+ }
20
  return await BranchEntity.create({ ...createBranchDto }).save();
21
  }
22
 
 
29
  }
30
 
31
  async getBranchOrError(id: string) {
32
+ console.log(id);
33
  const branch = await BranchEntity.findOneBy({ id });
34
  if (!branch) {
35
+ throw new NotFoundException('Branch not found');
36
  }
37
  return branch;
38
  }
backend/src/modules/branch/dto/create-branch.dto.ts CHANGED
@@ -1,6 +1,9 @@
1
  import { IsString } from 'class-validator';
2
 
3
  export class CreateBranchDto {
 
 
 
4
  @IsString()
5
  name: string;
6
 
 
1
  import { IsString } from 'class-validator';
2
 
3
  export class CreateBranchDto {
4
+ @IsString()
5
+ id: string;
6
+
7
  @IsString()
8
  name: string;
9
 
backend/src/modules/menu-item/menu-item.module.ts CHANGED
@@ -5,5 +5,6 @@ import { MenuItemController } from './menu-item.controller.js';
5
  @Module({
6
  controllers: [MenuItemController],
7
  providers: [MenuItemService],
 
8
  })
9
  export class MenuItemModule {}
 
5
  @Module({
6
  controllers: [MenuItemController],
7
  providers: [MenuItemService],
8
+ exports: [MenuItemService],
9
  })
10
  export class MenuItemModule {}
backend/src/modules/order/dto/create-order.dto.ts ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ IsArray,
3
+ IsEnum,
4
+ IsNumber,
5
+ IsObject,
6
+ IsOptional,
7
+ IsString,
8
+ ValidateNested,
9
+ } from 'class-validator';
10
+ import { OrderType } from '../../../common/enums/OrderType.enum.js';
11
+ import { OrderItemsDto } from './order-items.dto.js';
12
+ import { Type } from 'class-transformer';
13
+
14
+ export class CreateOrderDto {
15
+ @IsOptional()
16
+ @IsNumber()
17
+ table_number?: number;
18
+
19
+ @IsEnum(OrderType)
20
+ order_type: OrderType;
21
+
22
+ @IsArray()
23
+ @ValidateNested()
24
+ @Type(() => OrderItemsDto)
25
+ order_items: OrderItemsDto[];
26
+ }
backend/src/modules/order/dto/order-items.dto.ts ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import { IsNumber, IsString } from 'class-validator';
2
+
3
+ export class OrderItemsDto {
4
+ @IsString()
5
+ menu_id: string;
6
+
7
+ @IsNumber()
8
+ quantity: number;
9
+ }
backend/src/modules/order/order.controller.ts ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ Controller,
3
+ Get,
4
+ Post,
5
+ Body,
6
+ Patch,
7
+ Param,
8
+ Delete,
9
+ Req,
10
+ } from '@nestjs/common';
11
+ import { OrderService } from './order.service.js';
12
+ import { CreateOrderDto } from './dto/create-order.dto.js';
13
+ import { Role } from '../../common/enums/role.enum.js';
14
+
15
+ @Controller('branchs/:branchId/orders')
16
+ export class OrderController {
17
+ constructor(private readonly orderService: OrderService) {}
18
+
19
+ @Post()
20
+ async create(
21
+ @Param('branchId') branchId: string,
22
+ @Req() req: Request,
23
+ @Body() createOrderDto: CreateOrderDto,
24
+ ) {
25
+ const userId = req['user'].sub;
26
+ const role = req['user'].roles;
27
+ console.log(req['user']);
28
+ if (role == Role.CUSTOMER)
29
+ return this.orderService.createFromCustomer(
30
+ branchId,
31
+ userId,
32
+ createOrderDto,
33
+ );
34
+ else
35
+ return this.orderService.createFromStaff(
36
+ branchId,
37
+ userId,
38
+ createOrderDto,
39
+ );
40
+ }
41
+
42
+ @Get()
43
+ async findAll(@Req() req: Request) {
44
+ const userId = req['user'].sub;
45
+ console.log(req['user']);
46
+ return this.orderService.findAll();
47
+ }
48
+
49
+ @Get(':id')
50
+ async findOne(@Param('id') id: string) {
51
+ return this.orderService.findOne(+id);
52
+ }
53
+
54
+ // @Patch(':id')
55
+ // async update(
56
+ // @Param('id') id: string,
57
+ // @Body() updateOrderDto: UpdateOrderDto,
58
+ // ) {
59
+ // return this.orderService.update(+id, updateOrderDto);
60
+ // }
61
+
62
+ @Delete(':id')
63
+ remove(@Param('id') id: string) {
64
+ return this.orderService.remove(+id);
65
+ }
66
+ }
backend/src/modules/order/order.module.ts ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Module } from '@nestjs/common';
2
+ import { OrderService } from './order.service.js';
3
+ import { OrderController } from './order.controller.js';
4
+ import { BranchModule } from '../branch/branch.module.js';
5
+ import { BranchMenusModule } from '../branch-menus/branch-menus.module.js';
6
+
7
+ @Module({
8
+ imports: [BranchModule, BranchMenusModule],
9
+ controllers: [OrderController],
10
+ providers: [OrderService],
11
+ })
12
+ export class OrderModule {}
backend/src/modules/order/order.service.ts ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { BadRequestException, Injectable } from '@nestjs/common';
2
+ import { CreateOrderDto } from './dto/create-order.dto.js';
3
+ import { UserEntity } from '../../entities/user.entity.js';
4
+ import { OrderEntity } from '../../entities/order.entity.js';
5
+ import { BranchService } from '../branch/branch.service.js';
6
+ import { OrderType } from '../../common/enums/OrderType.enum.js';
7
+ import { isUUID } from 'class-validator';
8
+ import { OrderItemEntity } from '../../entities/order-item.entity.js';
9
+ import { BranchMenuEntity } from '../../entities/branch-menu.entity.js';
10
+ import { OrderStatus } from '../../common/enums/OrderStatus.enum.js';
11
+
12
+ @Injectable()
13
+ export class OrderService {
14
+ constructor(private readonly branchService: BranchService) {}
15
+ async createFromCustomer(
16
+ branchId: string,
17
+ userId: string,
18
+ createOrderDto: CreateOrderDto,
19
+ ) {
20
+ console.log('??');
21
+ if (createOrderDto.order_type != OrderType.ONLINE) {
22
+ throw new BadRequestException('customer cannot create offline order');
23
+ }
24
+
25
+ const user = await UserEntity.findOneBy({ id: userId });
26
+ if (!user) {
27
+ throw new BadRequestException('User not found');
28
+ }
29
+ const branch = await this.branchService.getBranchOrError(branchId);
30
+ if (!branch) {
31
+ throw new BadRequestException('Branch not found');
32
+ }
33
+ const order = OrderEntity.create();
34
+ order.branch = branch;
35
+ order.customer = user;
36
+ order.order_type = createOrderDto.order_type;
37
+ order.order_status = OrderStatus.PENDING;
38
+ order.total_value = 0;
39
+ await order.save();
40
+
41
+ let orderItems: OrderItemEntity[] = [];
42
+ let totalValue = 0;
43
+ for (const item of createOrderDto.order_items) {
44
+ let branchMenu: BranchMenuEntity;
45
+ if (!isUUID(item.menu_id)) {
46
+ branchMenu = await BranchMenuEntity.findOne({
47
+ where: { branch_id: branchId, menu_id: item.menu_id },
48
+ relations: ['menu_item'],
49
+ });
50
+ } else {
51
+ branchMenu = await BranchMenuEntity.findOne({
52
+ where: { branch_id: branchId, id: item.menu_id },
53
+ relations: ['menu_item'],
54
+ });
55
+ }
56
+ if (!branchMenu) {
57
+ throw new BadRequestException('Item not found in branch menu');
58
+ }
59
+ const orderItem = OrderItemEntity.create();
60
+ orderItem.branch_menu = branchMenu;
61
+ orderItem.price = branchMenu.menu_item.price;
62
+ orderItem.quantity = item.quantity;
63
+ orderItem.order_id = order.id;
64
+ totalValue += orderItem.price * orderItem.quantity;
65
+ orderItems.push(orderItem);
66
+ }
67
+ await order.save();
68
+ order.total_value = totalValue;
69
+ await OrderItemEntity.save(orderItems);
70
+ return { ...order, order_items: orderItems };
71
+ }
72
+
73
+ async createFromStaff(
74
+ branchId: string,
75
+ userId: string,
76
+ createOrderDto: CreateOrderDto,
77
+ ) {
78
+ if (createOrderDto.order_type == OrderType.ONLINE) {
79
+ throw new BadRequestException('staff cannot create online order');
80
+ }
81
+ // staff
82
+ const staff = await UserEntity.findOneBy({ id: userId });
83
+ const branch = await this.branchService.getBranchOrError(branchId);
84
+ const order = OrderEntity.create();
85
+
86
+ order.branch = branch;
87
+ order.staff = staff;
88
+ order.order_type = createOrderDto.order_type;
89
+ order.table_number = createOrderDto.table_number;
90
+ order.order_status = OrderStatus.PREPARING;
91
+ order.total_value = 0;
92
+ await order.save();
93
+
94
+ let orderItems: OrderItemEntity[] = [];
95
+ let totalValue = 0;
96
+ for (const item of createOrderDto.order_items) {
97
+ let branchMenu: BranchMenuEntity;
98
+ if (!isUUID(item.menu_id)) {
99
+ branchMenu = await BranchMenuEntity.findOne({
100
+ where: { branch_id: branchId, menu_id: item.menu_id },
101
+ relations: ['menu_item'],
102
+ });
103
+ } else {
104
+ branchMenu = await BranchMenuEntity.findOne({
105
+ where: { branch_id: branchId, id: item.menu_id },
106
+ relations: ['menu_item'],
107
+ });
108
+ }
109
+ if (!branchMenu) {
110
+ throw new BadRequestException('Item not found in branch menu');
111
+ }
112
+ const orderItem = OrderItemEntity.create();
113
+ orderItem.branch_menu = branchMenu;
114
+ orderItem.price = branchMenu.menu_item.price;
115
+ orderItem.quantity = item.quantity;
116
+ orderItem.order_id = order.id;
117
+ totalValue += orderItem.price * orderItem.quantity;
118
+ orderItems.push(orderItem);
119
+ }
120
+ await order.save();
121
+ order.total_value = totalValue;
122
+ await OrderItemEntity.save(orderItems);
123
+ return { ...order, order_items: orderItems };
124
+ }
125
+
126
+ findAll() {
127
+ return `This action returns all order`;
128
+ }
129
+
130
+ findOne(id: number) {
131
+ return `This action returns a #${id} order`;
132
+ }
133
+
134
+ remove(id: number) {
135
+ return `This action removes a #${id} order`;
136
+ }
137
+ }