From b2b0ade6b46bc13fed94a0550ae57521129b63ce Mon Sep 17 00:00:00 2001 From: ashar Date: Tue, 11 Jun 2024 15:07:03 +0700 Subject: [PATCH] feat(SPG-359) REST API CUD Item / Tenant Item --- src/app.module.ts | 4 + .../strings/constants/module.constants.ts | 1 + src/core/strings/constants/table.constants.ts | 1 + src/database/migrations/1718085330130-item.ts | 15 ++ .../data/models/item-category.model.ts | 9 +- .../infrastructure/dto/item-category.dto.ts | 8 +- src/modules/item-related/item/constants.ts | 5 + .../item/data/models/item.model.ts | 99 +++++++++++++ .../item/data/services/item-data.service.ts | 17 +++ .../event/item-change-status.event.ts | 5 + .../entities/event/item-created.event.ts | 5 + .../entities/event/item-deleted.event.ts | 5 + .../entities/event/item-updated.event.ts | 5 + .../item/domain/entities/item.entity.ts | 18 +++ .../domain/usecases/item-data.orchestrator.ts | 130 ++++++++++++++++++ .../usecases/managers/active-item.manager.ts | 45 ++++++ .../managers/batch-active-item.manager.ts | 45 ++++++ .../managers/batch-confirm-item.manager.ts | 45 ++++++ .../managers/batch-delete-item.manager.ts | 45 ++++++ .../managers/batch-inactive-item.manager.ts | 45 ++++++ .../usecases/managers/confirm-item.manager.ts | 45 ++++++ .../usecases/managers/create-item.manager.ts | 51 +++++++ .../usecases/managers/delete-item.manager.ts | 45 ++++++ .../managers/inactive-item.manager.ts | 45 ++++++ .../usecases/managers/update-item.manager.ts | 46 +++++++ src/modules/item-related/item/index.ts | 0 .../item/infrastructure/dto/item.dto.ts | 122 ++++++++++++++++ .../infrastructure/item-data.controller.ts | 78 +++++++++++ src/modules/item-related/item/item.module.ts | 75 ++++++++++ .../infrastructure/dto/vip-code.dto.ts | 2 +- .../tenant-item-data.controller.ts | 106 ++++++++++++++ .../user-related/tenant/tenant.module.ts | 9 +- .../user/data/models/user.model.ts | 10 +- 33 files changed, 1176 insertions(+), 10 deletions(-) create mode 100644 src/database/migrations/1718085330130-item.ts create mode 100644 src/modules/item-related/item/constants.ts create mode 100644 src/modules/item-related/item/data/models/item.model.ts create mode 100644 src/modules/item-related/item/data/services/item-data.service.ts create mode 100644 src/modules/item-related/item/domain/entities/event/item-change-status.event.ts create mode 100644 src/modules/item-related/item/domain/entities/event/item-created.event.ts create mode 100644 src/modules/item-related/item/domain/entities/event/item-deleted.event.ts create mode 100644 src/modules/item-related/item/domain/entities/event/item-updated.event.ts create mode 100644 src/modules/item-related/item/domain/entities/item.entity.ts create mode 100644 src/modules/item-related/item/domain/usecases/item-data.orchestrator.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/batch-confirm-item.manager.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/batch-delete-item.manager.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/batch-inactive-item.manager.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/confirm-item.manager.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/create-item.manager.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/delete-item.manager.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/inactive-item.manager.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/update-item.manager.ts create mode 100644 src/modules/item-related/item/index.ts create mode 100644 src/modules/item-related/item/infrastructure/dto/item.dto.ts create mode 100644 src/modules/item-related/item/infrastructure/item-data.controller.ts create mode 100644 src/modules/item-related/item/item.module.ts create mode 100644 src/modules/user-related/tenant/infrastructure/tenant-item-data.controller.ts diff --git a/src/app.module.ts b/src/app.module.ts index 01776e0..a6f7361 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -26,6 +26,8 @@ import { VipCategoryModule } from './modules/transaction/vip-category/vip-catego import { VipCategoryModel } from './modules/transaction/vip-category/data/models/vip-category.model'; import { VipCodeModule } from './modules/transaction/vip-code/vip-code.module'; import { VipCodeModel } from './modules/transaction/vip-code/data/models/vip-code.model'; +import { ItemModule } from './modules/item-related/item/item.module'; +import { ItemModel } from './modules/item-related/item/data/models/item.model'; @Module({ imports: [ @@ -46,6 +48,7 @@ import { VipCodeModel } from './modules/transaction/vip-code/data/models/vip-cod UserModel, LogModel, ErrorLogModel, + ItemModel, ItemCategoryModel, VipCategoryModel, VipCodeModel, @@ -66,6 +69,7 @@ import { VipCodeModel } from './modules/transaction/vip-code/data/models/vip-cod // Item ItemCategoryModule, + ItemModule, // transaction VipCategoryModule, diff --git a/src/core/strings/constants/module.constants.ts b/src/core/strings/constants/module.constants.ts index 6f9ffac..586241d 100644 --- a/src/core/strings/constants/module.constants.ts +++ b/src/core/strings/constants/module.constants.ts @@ -1,4 +1,5 @@ export enum MODULE_NAME { + ITEM = 'items', ITEM_CATEGORY = 'item-categories', TENANT = 'tenants', USER = 'users', diff --git a/src/core/strings/constants/table.constants.ts b/src/core/strings/constants/table.constants.ts index 87faba8..ccc0ba8 100644 --- a/src/core/strings/constants/table.constants.ts +++ b/src/core/strings/constants/table.constants.ts @@ -1,5 +1,6 @@ export enum TABLE_NAME { ERROR_LOG = 'log_errors', + ITEM = 'items', ITEM_CATEGORY = 'item_categories', LOG = 'logs', TENANT = 'tenants', diff --git a/src/database/migrations/1718085330130-item.ts b/src/database/migrations/1718085330130-item.ts new file mode 100644 index 0000000..2815d54 --- /dev/null +++ b/src/database/migrations/1718085330130-item.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class Item1718085330130 implements MigrationInterface { + name = 'Item1718085330130'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "items" ADD "image" character varying`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "items" DROP COLUMN "image"`); + } +} diff --git a/src/modules/item-related/item-category/data/models/item-category.model.ts b/src/modules/item-related/item-category/data/models/item-category.model.ts index ce838b2..8862b05 100644 --- a/src/modules/item-related/item-category/data/models/item-category.model.ts +++ b/src/modules/item-related/item-category/data/models/item-category.model.ts @@ -1,8 +1,9 @@ import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { ItemCategoryEntity } from '../../domain/entities/item-category.entity'; -import { Column, Entity } from 'typeorm'; +import { Column, Entity, OneToMany } from 'typeorm'; import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; import { ItemType } from '../../constants'; +import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; @Entity(TABLE_NAME.ITEM_CATEGORY) export class ItemCategoryModel @@ -18,4 +19,10 @@ export class ItemCategoryModel default: ItemType.TIKET_MASUK, }) item_type: ItemType; + + @OneToMany(() => ItemModel, (model) => model.item_category, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + items: ItemModel[]; } diff --git a/src/modules/item-related/item-category/infrastructure/dto/item-category.dto.ts b/src/modules/item-related/item-category/infrastructure/dto/item-category.dto.ts index a4c43c7..6c0b369 100644 --- a/src/modules/item-related/item-category/infrastructure/dto/item-category.dto.ts +++ b/src/modules/item-related/item-category/infrastructure/dto/item-category.dto.ts @@ -1,6 +1,6 @@ import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; import { ItemCategoryEntity } from '../../domain/entities/item-category.entity'; -import { IsEnum, IsString, ValidateIf } from 'class-validator'; +import { IsString } from 'class-validator'; import { ItemType } from '../../constants'; import { ApiProperty } from '@nestjs/swagger'; @@ -14,13 +14,9 @@ export class ItemCategoryDto @ApiProperty({ type: 'string', - required: false, + required: true, description: `Select (${JSON.stringify(Object.values(ItemType))})`, example: ItemType.BUNDLING, }) - @ValidateIf((body) => body.order_type) - @IsEnum(ItemType, { - message: `must be a valid enum ${JSON.stringify(Object.values(ItemType))}`, - }) item_type: ItemType; } diff --git a/src/modules/item-related/item/constants.ts b/src/modules/item-related/item/constants.ts new file mode 100644 index 0000000..e4bd791 --- /dev/null +++ b/src/modules/item-related/item/constants.ts @@ -0,0 +1,5 @@ +export enum LimitType { + NO_LIMIT = 'no limit', + TIME_LIMIT = 'time limit', + QTY_LIMIT = 'qty limit', +} diff --git a/src/modules/item-related/item/data/models/item.model.ts b/src/modules/item-related/item/data/models/item.model.ts new file mode 100644 index 0000000..da5cc93 --- /dev/null +++ b/src/modules/item-related/item/data/models/item.model.ts @@ -0,0 +1,99 @@ +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { ItemEntity } from '../../domain/entities/item.entity'; +import { + Column, + Entity, + JoinColumn, + JoinTable, + ManyToMany, + ManyToOne, +} from 'typeorm'; +import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; +import { ItemType } from 'src/modules/item-related/item-category/constants'; +import { LimitType } from '../../constants'; +import { ItemCategoryModel } from 'src/modules/item-related/item-category/data/models/item-category.model'; +import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; + +@Entity(TABLE_NAME.ITEM) +export class ItemModel + extends BaseStatusModel + implements ItemEntity +{ + @Column('varchar', { name: 'name' }) + name: string; + + @Column('varchar', { name: 'image', nullable: true }) + image: string; + + @Column('enum', { + name: 'item_type', + enum: ItemType, + default: ItemType.TIKET_MASUK, + }) + item_type: ItemType; + + @Column('bigint', { name: 'hpp', nullable: true }) + hpp: number; + + @Column('int', { name: 'sales_margin', nullable: true }) + sales_margin: number; + + @Column('bigint', { name: 'base_price', nullable: true }) + base_price: number; + + @Column('boolean', { name: 'use_queue', default: false }) + use_queue: boolean; + + @Column('boolean', { name: 'show_to_booking', default: false }) + show_to_booking: boolean; + + @Column('enum', { + name: 'limit_type', + enum: LimitType, + default: LimitType.NO_LIMIT, + }) + limit_type: LimitType; + + @Column('int', { name: 'limit_value', nullable: true }) + limit_value: number; + + // relation ke item category + @Column('varchar', { name: 'item_category_id', nullable: true }) + item_category_id: number; + @ManyToOne(() => ItemCategoryModel, (model) => model.items, { + onUpdate: 'CASCADE', + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'item_category_id' }) + item_category: ItemCategoryModel; + + // relation ke tenant + // ? karena item bisajadi merupakan item dari tenant + @Column('varchar', { name: 'tenant_id', nullable: true }) + tenant_id: number; + @ManyToOne(() => UserModel, (model) => model.items, { + onUpdate: 'CASCADE', + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'tenant_id' }) + tenant: UserModel; + + // relasi ke diri sendiri + // ?type bundling bisa punya relasi ke item (item adalah diri sendiri) + @ManyToMany(() => ItemModel, (model) => model.bundling_items, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + @JoinTable({ + name: 'item_bundlings', + joinColumn: { + name: 'item_bundling_id', + referencedColumnName: 'id', + }, + inverseJoinColumn: { + name: 'item_id', + referencedColumnName: 'id', + }, + }) + bundling_items: ItemModel[]; +} diff --git a/src/modules/item-related/item/data/services/item-data.service.ts b/src/modules/item-related/item/data/services/item-data.service.ts new file mode 100644 index 0000000..367a883 --- /dev/null +++ b/src/modules/item-related/item/data/services/item-data.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDataService } from 'src/core/modules/data/service/base-data.service'; +import { ItemEntity } from '../../domain/entities/item.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { ItemModel } from '../models/item.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; + +@Injectable() +export class ItemDataService extends BaseDataService { + constructor( + @InjectRepository(ItemModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/item-related/item/domain/entities/event/item-change-status.event.ts b/src/modules/item-related/item/domain/entities/event/item-change-status.event.ts new file mode 100644 index 0000000..dd14fe5 --- /dev/null +++ b/src/modules/item-related/item/domain/entities/event/item-change-status.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class ItemChangeStatusEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/item-related/item/domain/entities/event/item-created.event.ts b/src/modules/item-related/item/domain/entities/event/item-created.event.ts new file mode 100644 index 0000000..3bbd3cb --- /dev/null +++ b/src/modules/item-related/item/domain/entities/event/item-created.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class ItemCreatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/item-related/item/domain/entities/event/item-deleted.event.ts b/src/modules/item-related/item/domain/entities/event/item-deleted.event.ts new file mode 100644 index 0000000..2d7e56b --- /dev/null +++ b/src/modules/item-related/item/domain/entities/event/item-deleted.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class ItemDeletedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/item-related/item/domain/entities/event/item-updated.event.ts b/src/modules/item-related/item/domain/entities/event/item-updated.event.ts new file mode 100644 index 0000000..4e3562e --- /dev/null +++ b/src/modules/item-related/item/domain/entities/event/item-updated.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class ItemUpdatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/item-related/item/domain/entities/item.entity.ts b/src/modules/item-related/item/domain/entities/item.entity.ts new file mode 100644 index 0000000..e98885c --- /dev/null +++ b/src/modules/item-related/item/domain/entities/item.entity.ts @@ -0,0 +1,18 @@ +import { BaseStatusEntity } from 'src/core/modules/domain/entities/base-status.entity'; +import { ItemType } from 'src/modules/item-related/item-category/constants'; +import { LimitType } from '../../constants'; + +export interface ItemEntity extends BaseStatusEntity { + name: string; + item_type: ItemType; + image: string; + + hpp: number; + sales_margin: number; + base_price: number; + limit_type: LimitType; + limit_value: number; + + use_queue: boolean; + show_to_booking: boolean; +} diff --git a/src/modules/item-related/item/domain/usecases/item-data.orchestrator.ts b/src/modules/item-related/item/domain/usecases/item-data.orchestrator.ts new file mode 100644 index 0000000..d7efe8b --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/item-data.orchestrator.ts @@ -0,0 +1,130 @@ +import { Injectable } from '@nestjs/common'; +import { CreateItemManager } from './managers/create-item.manager'; +import { ItemDataService } from '../../data/services/item-data.service'; +import { ItemEntity } from '../entities/item.entity'; +import { DeleteItemManager } from './managers/delete-item.manager'; +import { UpdateItemManager } from './managers/update-item.manager'; +import { BaseDataTransactionOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-data-transaction.orchestrator'; +import { ActiveItemManager } from './managers/active-item.manager'; +import { InactiveItemManager } from './managers/inactive-item.manager'; +import { ConfirmItemManager } from './managers/confirm-item.manager'; +import { STATUS } from 'src/core/strings/constants/base.constants'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchConfirmItemManager } from './managers/batch-confirm-item.manager'; +import { BatchInactiveItemManager } from './managers/batch-inactive-item.manager'; +import { BatchActiveItemManager } from './managers/batch-active-item.manager'; +import { BatchDeleteItemManager } from './managers/batch-delete-item.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class ItemDataOrchestrator extends BaseDataTransactionOrchestrator { + constructor( + private createManager: CreateItemManager, + private updateManager: UpdateItemManager, + private deleteManager: DeleteItemManager, + private activeManager: ActiveItemManager, + private confirmManager: ConfirmItemManager, + private inactiveManager: InactiveItemManager, + private batchDeleteManager: BatchDeleteItemManager, + private batchActiveManager: BatchActiveItemManager, + private batchConfirmManager: BatchConfirmItemManager, + private batchInactiveManager: BatchInactiveItemManager, + private serviceData: ItemDataService, + ) { + super(); + } + + async create(data, tenantId?: string): Promise { + if (tenantId) { + Object.assign(data, { + tenant_id: tenantId, + }); + } + + this.createManager.setData(data); + this.createManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.createManager.execute(); + return this.createManager.getResult(); + } + + async update(dataId, data, tenantId?: string): Promise { + if (tenantId) { + Object.assign(data, { + tenant_id: tenantId, + }); + } + + this.updateManager.setData(dataId, data); + this.updateManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.updateManager.execute(); + return this.updateManager.getResult(); + } + + async delete(dataId, tenantId?: string): Promise { + this.deleteManager.setData(dataId); + this.deleteManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.deleteManager.execute(); + return this.deleteManager.getResult(); + } + + async batchDelete( + dataIds: string[], + tenantId?: string, + ): Promise { + this.batchDeleteManager.setData(dataIds); + this.batchDeleteManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.batchDeleteManager.execute(); + return this.batchDeleteManager.getResult(); + } + + async active(dataId, tenantId?: string): Promise { + this.activeManager.setData(dataId, STATUS.ACTIVE); + this.activeManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.activeManager.execute(); + return this.activeManager.getResult(); + } + + async batchActive( + dataIds: string[], + tenantId?: string, + ): Promise { + this.batchActiveManager.setData(dataIds, STATUS.ACTIVE); + this.batchActiveManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.batchActiveManager.execute(); + return this.batchActiveManager.getResult(); + } + + async confirm(dataId, tenantId?: string): Promise { + this.confirmManager.setData(dataId, STATUS.ACTIVE); + this.confirmManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.confirmManager.execute(); + return this.confirmManager.getResult(); + } + + async batchConfirm( + dataIds: string[], + tenantId?: string, + ): Promise { + this.batchConfirmManager.setData(dataIds, STATUS.ACTIVE); + this.batchConfirmManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.batchConfirmManager.execute(); + return this.batchConfirmManager.getResult(); + } + + async inactive(dataId, tenantId?: string): Promise { + this.inactiveManager.setData(dataId, STATUS.INACTIVE); + this.inactiveManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.inactiveManager.execute(); + return this.inactiveManager.getResult(); + } + + async batchInactive( + dataIds: string[], + tenantId?: string, + ): Promise { + this.batchInactiveManager.setData(dataIds, STATUS.INACTIVE); + this.batchInactiveManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.batchInactiveManager.execute(); + return this.batchInactiveManager.getResult(); + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts new file mode 100644 index 0000000..f3690b1 --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemModel } from '../../../data/models/item.model'; +import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; + +@Injectable() +export class ActiveItemManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data ${this.result.name}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return ItemModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts new file mode 100644 index 0000000..0802058 --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemModel } from '../../../data/models/item.model'; +import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchActiveItemManager extends BaseBatchUpdateStatusManager { + validateData(data: ItemEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return ItemModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/batch-confirm-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/batch-confirm-item.manager.ts new file mode 100644 index 0000000..349c49d --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/batch-confirm-item.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemModel } from '../../../data/models/item.model'; +import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchConfirmItemManager extends BaseBatchUpdateStatusManager { + validateData(data: ItemEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return ItemModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/batch-delete-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/batch-delete-item.manager.ts new file mode 100644 index 0000000..4a5d0f0 --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/batch-delete-item.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchDeleteManager } from 'src/core/modules/domain/usecase/managers/base-batch-delete.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemModel } from '../../../data/models/item.model'; +import { ItemDeletedEvent } from '../../entities/event/item-deleted.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchDeleteItemManager extends BaseBatchDeleteManager { + async beforeProcess(): Promise { + return; + } + + async validateData(data: ItemEntity): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return ItemModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemDeletedEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/batch-inactive-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/batch-inactive-item.manager.ts new file mode 100644 index 0000000..f0065fa --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/batch-inactive-item.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemModel } from '../../../data/models/item.model'; +import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchInactiveItemManager extends BaseBatchUpdateStatusManager { + validateData(data: ItemEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return ItemModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/confirm-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/confirm-item.manager.ts new file mode 100644 index 0000000..72be21e --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/confirm-item.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemModel } from '../../../data/models/item.model'; +import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; + +@Injectable() +export class ConfirmItemManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data ${this.result.name}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return ItemModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/create-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/create-item.manager.ts new file mode 100644 index 0000000..aebe725 --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/create-item.manager.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@nestjs/common'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemEntity } from '../../entities/item.entity'; +import { ItemModel } from '../../../data/models/item.model'; +import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager'; +import { ItemCreatedEvent } from '../../entities/event/item-created.event'; + +@Injectable() +export class CreateItemManager extends BaseCreateManager { + async beforeProcess(): Promise { + Object.assign(this.data, { + item_type: this.data.item_type.toLowerCase(), + }); + + if (this.data.limit_type) { + Object.assign(this.data, { + limit_type: this.data.limit_type.toLowerCase(), + }); + } + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemCreatedEvent, + data: this.data, + }, + ]; + } + + get entityTarget(): any { + return ItemModel; + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/delete-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/delete-item.manager.ts new file mode 100644 index 0000000..939de6c --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/delete-item.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemModel } from '../../../data/models/item.model'; +import { ItemDeletedEvent } from '../../entities/event/item-deleted.event'; + +@Injectable() +export class DeleteItemManager extends BaseDeleteManager { + getResult(): string { + return `Success`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return ItemModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemDeletedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/inactive-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/inactive-item.manager.ts new file mode 100644 index 0000000..9631099 --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/inactive-item.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemModel } from '../../../data/models/item.model'; +import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; + +@Injectable() +export class InactiveItemManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success inactive data ${this.result.name}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return ItemModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/update-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/update-item.manager.ts new file mode 100644 index 0000000..eabe32c --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/update-item.manager.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { ItemModel } from '../../../data/models/item.model'; +import { ItemUpdatedEvent } from '../../entities/event/item-updated.event'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; + +@Injectable() +export class UpdateItemManager extends BaseUpdateManager { + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get entityTarget(): any { + return ItemModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemUpdatedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/item-related/item/index.ts b/src/modules/item-related/item/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/item-related/item/infrastructure/dto/item.dto.ts b/src/modules/item-related/item/infrastructure/dto/item.dto.ts new file mode 100644 index 0000000..c818e68 --- /dev/null +++ b/src/modules/item-related/item/infrastructure/dto/item.dto.ts @@ -0,0 +1,122 @@ +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { ItemEntity } from '../../domain/entities/item.entity'; +import { ItemType } from 'src/modules/item-related/item-category/constants'; +import { LimitType } from '../../constants'; +import { ApiProperty } from '@nestjs/swagger'; +import { + IsArray, + IsBoolean, + IsNumber, + IsObject, + IsString, + ValidateIf, +} from 'class-validator'; +import { ItemCategoryEntity } from 'src/modules/item-related/item-category/domain/entities/item-category.entity'; + +export class ItemDto extends BaseStatusDto implements ItemEntity { + @ApiProperty({ + type: String, + required: true, + example: 'Entrace Ticket', + }) + @IsString() + name: string; + + @ApiProperty({ + type: String, + required: false, + example: '...', + }) + @IsString() + @ValidateIf((body) => body.image) + image: string; + + @ApiProperty({ + type: 'string', + required: true, + description: `Select (${JSON.stringify(Object.values(ItemType))})`, + example: ItemType.BUNDLING, + }) + @IsString() + item_type: ItemType; + + @ApiProperty({ + type: Object, + required: false, + example: { + id: 'uuid', + }, + }) + @IsObject() + @ValidateIf((body) => body.item_category) + item_category: ItemCategoryEntity; + + @ApiProperty({ + type: Number, + required: false, + example: 100000, + }) + @IsNumber() + @ValidateIf((body) => body.item_type.toLowerCase() != ItemType.FREE_GIFT) + hpp: number; + + @ApiProperty({ + type: Number, + required: false, + example: 50, + }) + @IsNumber() + @ValidateIf((body) => body.item_type.toLowerCase() != ItemType.FREE_GIFT) + sales_margin: number; + + @ApiProperty({ + type: Number, + required: false, + example: 100000, + }) + @IsNumber() + @ValidateIf((body) => body.item_type.toLowerCase() != ItemType.FREE_GIFT) + base_price: number; + + @ApiProperty({ + type: 'string', + required: false, + description: `Select (${JSON.stringify(Object.values(LimitType))})`, + example: LimitType.NO_LIMIT, + }) + @IsString() + @ValidateIf((body) => body.item_type.toLowerCase() == ItemType.WAHANA) + limit_type: LimitType; + + @ApiProperty({ + type: Number, + required: false, + example: 60, + }) + @IsNumber() + @ValidateIf((body) => body.item_type.toLowerCase() == ItemType.WAHANA) + limit_value: number; + + @ApiProperty({ type: Boolean, required: false }) + @IsBoolean() + @ValidateIf((body) => body.use_queue) + use_queue: boolean; + + @ApiProperty({ type: Boolean, required: false }) + @IsBoolean() + @ValidateIf((body) => body.show_to_booking) + show_to_booking: boolean; + + @ApiProperty({ + name: 'bundling_items', + type: [Object], + example: [ + { + id: 'uuid', + }, + ], + }) + @IsArray() + @ValidateIf((body) => body.item_type.toLowerCase() == ItemType.BUNDLING) + bundling_items: ItemEntity[]; +} diff --git a/src/modules/item-related/item/infrastructure/item-data.controller.ts b/src/modules/item-related/item/infrastructure/item-data.controller.ts new file mode 100644 index 0000000..3412b27 --- /dev/null +++ b/src/modules/item-related/item/infrastructure/item-data.controller.ts @@ -0,0 +1,78 @@ +import { + Body, + Controller, + Delete, + Param, + Patch, + Post, + Put, +} from '@nestjs/common'; +import { ItemDataOrchestrator } from '../domain/usecases/item-data.orchestrator'; +import { ItemDto } from './dto/item.dto'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { ItemEntity } from '../domain/entities/item.entity'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; +import { Public } from 'src/core/guards'; + +@ApiTags(`${MODULE_NAME.ITEM.split('-').join(' ')} - data`) +@Controller(MODULE_NAME.ITEM) +@Public(false) +@ApiBearerAuth('JWT') +export class ItemDataController { + constructor(private orchestrator: ItemDataOrchestrator) {} + + @Post() + async create(@Body() data: ItemDto): Promise { + return await this.orchestrator.create(data); + } + + @Put('/batch-delete') + async batchDeleted(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchDelete(body.ids); + } + + @Patch(':id/active') + async active(@Param('id') dataId: string): Promise { + return await this.orchestrator.active(dataId); + } + + @Put('/batch-active') + async batchActive(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchActive(body.ids); + } + + @Patch(':id/confirm') + async confirm(@Param('id') dataId: string): Promise { + return await this.orchestrator.confirm(dataId); + } + + @Put('/batch-confirm') + async batchConfirm(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchConfirm(body.ids); + } + + @Patch(':id/inactive') + async inactive(@Param('id') dataId: string): Promise { + return await this.orchestrator.inactive(dataId); + } + + @Put('/batch-inactive') + async batchInactive(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchInactive(body.ids); + } + + @Put(':id') + async update( + @Param('id') dataId: string, + @Body() data: ItemDto, + ): Promise { + return await this.orchestrator.update(dataId, data); + } + + @Delete(':id') + async delete(@Param('id') dataId: string): Promise { + return await this.orchestrator.delete(dataId); + } +} diff --git a/src/modules/item-related/item/item.module.ts b/src/modules/item-related/item/item.module.ts new file mode 100644 index 0000000..ed35180 --- /dev/null +++ b/src/modules/item-related/item/item.module.ts @@ -0,0 +1,75 @@ +import { Global, Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { ItemDataService } from './data/services/item-data.service'; +import { ItemReadService } from './data/services/item-read.service'; +import { ItemReadController } from './infrastructure/item-read.controller'; +import { ItemReadOrchestrator } from './domain/usecases/item-read.orchestrator'; +import { ItemDataController } from './infrastructure/item-data.controller'; +import { ItemDataOrchestrator } from './domain/usecases/item-data.orchestrator'; +import { CreateItemManager } from './domain/usecases/managers/create-item.manager'; +import { CqrsModule } from '@nestjs/cqrs'; +import { IndexItemManager } from './domain/usecases/managers/index-item.manager'; +import { DeleteItemManager } from './domain/usecases/managers/delete-item.manager'; +import { UpdateItemManager } from './domain/usecases/managers/update-item.manager'; +import { ActiveItemManager } from './domain/usecases/managers/active-item.manager'; +import { ConfirmItemManager } from './domain/usecases/managers/confirm-item.manager'; +import { InactiveItemManager } from './domain/usecases/managers/inactive-item.manager'; +import { DetailItemManager } from './domain/usecases/managers/detail-item.manager'; +import { BatchDeleteItemManager } from './domain/usecases/managers/batch-delete-item.manager'; +import { BatchActiveItemManager } from './domain/usecases/managers/batch-active-item.manager'; +import { BatchConfirmItemManager } from './domain/usecases/managers/batch-confirm-item.manager'; +import { BatchInactiveItemManager } from './domain/usecases/managers/batch-inactive-item.manager'; +import { ItemModel } from './data/models/item.model'; + +@Global() +@Module({ + imports: [ + ConfigModule.forRoot(), + TypeOrmModule.forFeature([ItemModel], CONNECTION_NAME.DEFAULT), + CqrsModule, + ], + controllers: [ItemDataController, ItemReadController], + providers: [ + IndexItemManager, + DetailItemManager, + CreateItemManager, + DeleteItemManager, + UpdateItemManager, + ActiveItemManager, + ConfirmItemManager, + InactiveItemManager, + BatchDeleteItemManager, + BatchActiveItemManager, + BatchConfirmItemManager, + BatchInactiveItemManager, + + ItemDataService, + ItemReadService, + + ItemDataOrchestrator, + ItemReadOrchestrator, + ], + exports: [ + IndexItemManager, + DetailItemManager, + CreateItemManager, + DeleteItemManager, + UpdateItemManager, + ActiveItemManager, + ConfirmItemManager, + InactiveItemManager, + BatchDeleteItemManager, + BatchActiveItemManager, + BatchConfirmItemManager, + BatchInactiveItemManager, + + ItemDataService, + ItemReadService, + + ItemDataOrchestrator, + ItemReadOrchestrator, + ], +}) +export class ItemModule {} diff --git a/src/modules/transaction/vip-code/infrastructure/dto/vip-code.dto.ts b/src/modules/transaction/vip-code/infrastructure/dto/vip-code.dto.ts index 3b1f0fe..9903730 100644 --- a/src/modules/transaction/vip-code/infrastructure/dto/vip-code.dto.ts +++ b/src/modules/transaction/vip-code/infrastructure/dto/vip-code.dto.ts @@ -24,7 +24,7 @@ export class VipCodeDto extends BaseDto implements VipCodeEntity { @ApiProperty({ name: 'vip_category', - type: String, + type: Object, required: true, example: { id: 'uuid', diff --git a/src/modules/user-related/tenant/infrastructure/tenant-item-data.controller.ts b/src/modules/user-related/tenant/infrastructure/tenant-item-data.controller.ts new file mode 100644 index 0000000..f9745c6 --- /dev/null +++ b/src/modules/user-related/tenant/infrastructure/tenant-item-data.controller.ts @@ -0,0 +1,106 @@ +import { + Body, + Controller, + Delete, + Param, + Patch, + Post, + Put, +} from '@nestjs/common'; +import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; +import { Public } from 'src/core/guards'; +import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { ItemEntity } from 'src/modules/item-related/item/domain/entities/item.entity'; +import { ItemDataOrchestrator } from 'src/modules/item-related/item/domain/usecases/item-data.orchestrator'; +import { ItemDto } from 'src/modules/item-related/item/infrastructure/dto/item.dto'; + +@ApiTags(`${MODULE_NAME.TENANT.split('-').join(' ')} item - data`) +@Controller(`${MODULE_NAME.TENANT}/:tenant_id/item`) +@Public(false) +@ApiBearerAuth('JWT') +export class TenantItemDataController { + constructor(private orchestrator: ItemDataOrchestrator) {} + + @Post() + async create( + @Param('tenant_id') tenant_id: string, + @Body() data: ItemDto, + ): Promise { + return await this.orchestrator.create(data, tenant_id); + } + + @Put('/batch-delete') + async batchDeleted( + @Param('tenant_id') tenant_id: string, + @Body() body: BatchIdsDto, + ): Promise { + return await this.orchestrator.batchDelete(body.ids); + } + + @Patch(':id/active') + async active( + @Param('tenant_id') tenant_id: string, + @Param('id') dataId: string, + ): Promise { + return await this.orchestrator.active(dataId); + } + + @Put('/batch-active') + async batchActive( + @Param('tenant_id') tenant_id: string, + @Body() body: BatchIdsDto, + ): Promise { + return await this.orchestrator.batchActive(body.ids); + } + + @Patch(':id/confirm') + async confirm( + @Param('tenant_id') tenant_id: string, + @Param('id') dataId: string, + ): Promise { + return await this.orchestrator.confirm(dataId); + } + + @Put('/batch-confirm') + async batchConfirm( + @Param('tenant_id') tenant_id: string, + @Body() body: BatchIdsDto, + ): Promise { + return await this.orchestrator.batchConfirm(body.ids); + } + + @Patch(':id/inactive') + async inactive( + @Param('tenant_id') tenant_id: string, + @Param('id') dataId: string, + ): Promise { + return await this.orchestrator.inactive(dataId); + } + + @Put('/batch-inactive') + async batchInactive( + @Param('tenant_id') tenant_id: string, + @Body() body: BatchIdsDto, + ): Promise { + return await this.orchestrator.batchInactive(body.ids); + } + + @Put(':id') + async update( + @Param('tenant_id') tenant_id: string, + @Param('id') dataId: string, + @Body() data: ItemDto, + ): Promise { + return await this.orchestrator.update(dataId, data); + } + + @Delete(':id') + async delete( + @Param('tenant_id') tenant_id: string, + @Param('id') dataId: string, + ): Promise { + return await this.orchestrator.delete(dataId); + } +} diff --git a/src/modules/user-related/tenant/tenant.module.ts b/src/modules/user-related/tenant/tenant.module.ts index 77f1143..fe10160 100644 --- a/src/modules/user-related/tenant/tenant.module.ts +++ b/src/modules/user-related/tenant/tenant.module.ts @@ -23,6 +23,8 @@ import { UserModel } from '../user/data/models/user.model'; import { UpdatePasswordTenantManager } from './domain/usecases/managers/update-password-tenant.manager'; import { UserDataService } from '../user/data/services/user-data.service'; import { UserReadService } from '../user/data/services/user-read.service'; +import { TenantItemReadController } from './infrastructure/tenant-item-read.controller'; +import { TenantItemDataController } from './infrastructure/tenant-item-data.controller'; @Module({ imports: [ @@ -30,7 +32,12 @@ import { UserReadService } from '../user/data/services/user-read.service'; TypeOrmModule.forFeature([UserModel], CONNECTION_NAME.DEFAULT), CqrsModule, ], - controllers: [TenantDataController, TenantReadController], + controllers: [ + TenantDataController, + TenantReadController, + TenantItemReadController, + TenantItemDataController, + ], providers: [ IndexTenantManager, DetailTenantManager, diff --git a/src/modules/user-related/user/data/models/user.model.ts b/src/modules/user-related/user/data/models/user.model.ts index bbabae6..55eb6a9 100644 --- a/src/modules/user-related/user/data/models/user.model.ts +++ b/src/modules/user-related/user/data/models/user.model.ts @@ -1,9 +1,10 @@ import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { UserEntity } from '../../domain/entities/user.entity'; -import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; +import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm'; import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; import { UserPrivilegeModel } from 'src/modules/user-related/user-privilege/data/models/user-privilege.model'; import { UserRole } from '../../constants'; +import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; @Entity(TABLE_NAME.USER) export class UserModel @@ -40,4 +41,11 @@ export class UserModel @Column('varchar', { name: 'email', nullable: true }) email: string; + + // relasi ke tenant item + @OneToMany(() => ItemModel, (model) => model.tenant, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + items: ItemModel[]; }