diff --git a/plopfile.js b/plopfile.js index 3fc6cf8..c458132 100644 --- a/plopfile.js +++ b/plopfile.js @@ -29,7 +29,7 @@ module.exports = function (plop) { name: 'location', message: 'Location: ', choices: function () { - return ['item related', 'user related', 'season related', 'transaction']; + return ['item related', 'user related', 'season related', 'transaction', 'web information']; }, }, ], diff --git a/src/app.module.ts b/src/app.module.ts index 8a49cd4..42040cb 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -58,6 +58,8 @@ import { MidtransModule } from './modules/configuration/midtrans/midtrans.module import { RefundModule } from './modules/transaction/refund/refund.module'; import { RefundModel } from './modules/transaction/refund/data/models/refund.model'; import { RefundItemModel } from './modules/transaction/refund/data/models/refund-item.model'; +import { GateModule } from './modules/web-information/gate/gate.module'; +import { GateModel } from './modules/web-information/gate/data/models/gate.model'; @Module({ imports: [ @@ -76,6 +78,7 @@ import { RefundItemModel } from './modules/transaction/refund/data/models/refund entities: [ ...UserPrivilegeModels, ErrorLogModel, + GateModel, ItemModel, ItemCategoryModel, ItemRateModel, @@ -135,6 +138,9 @@ import { RefundItemModel } from './modules/transaction/refund/data/models/refund SeasonTypeModule, SeasonPeriodModule, + // web information + GateModule, + // report ReportModule, ReportBookmarkModule, diff --git a/src/core/strings/constants/base.constants.ts b/src/core/strings/constants/base.constants.ts index 127b142..0ce2413 100644 --- a/src/core/strings/constants/base.constants.ts +++ b/src/core/strings/constants/base.constants.ts @@ -48,3 +48,5 @@ export const BLANK_USER = { role: null, user_privilege_id: null, }; + +export const EMPTY_UUID = '00000000-0000-0000-0000-000000000000'; diff --git a/src/core/strings/constants/module.constants.ts b/src/core/strings/constants/module.constants.ts index a53b60e..9cfef7e 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 { + GATE = 'gates', ITEM = 'items', ITEM_CATEGORY = 'item-categories', ITEM_RATE = 'item-rates', diff --git a/src/core/strings/constants/table.constants.ts b/src/core/strings/constants/table.constants.ts index 3d3230d..5a8679e 100644 --- a/src/core/strings/constants/table.constants.ts +++ b/src/core/strings/constants/table.constants.ts @@ -3,6 +3,7 @@ export enum TABLE_NAME { ITEM = 'items', ITEM_CATEGORY = 'item_categories', ITEM_RATE = 'item_rates', + GATE = 'gates', LOG = 'logs', PAYMENT_METHOD = 'payment_methods', PRICE_FORMULA = 'price_formulas', diff --git a/src/database/migrations/1721024987609-gate.ts b/src/database/migrations/1721024987609-gate.ts new file mode 100644 index 0000000..d2d906e --- /dev/null +++ b/src/database/migrations/1721024987609-gate.ts @@ -0,0 +1,29 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class Gate1721024987609 implements MigrationInterface { + name = 'Gate1721024987609'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TYPE "public"."gates_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`, + ); + await queryRunner.query( + `CREATE TYPE "public"."gates_type_enum" AS ENUM('gate masuk', 'gate keluar')`, + ); + await queryRunner.query( + `CREATE TABLE "gates" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "creator_id" character varying(36), "creator_name" character varying(125), "editor_id" character varying(36), "editor_name" character varying(125), "created_at" bigint NOT NULL, "updated_at" bigint NOT NULL, "status" "public"."gates_status_enum" NOT NULL DEFAULT 'draft', "type" "public"."gates_type_enum" NOT NULL DEFAULT 'gate masuk', "code" character varying, "note" text, "item_id" uuid, CONSTRAINT "PK_2dd58a77462dd2c5695ec4a7975" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `ALTER TABLE "gates" ADD CONSTRAINT "FK_29f020cd153bb079722bcbee830" FOREIGN KEY ("item_id") REFERENCES "items"("id") ON DELETE CASCADE ON UPDATE CASCADE`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "gates" DROP CONSTRAINT "FK_29f020cd153bb079722bcbee830"`, + ); + await queryRunner.query(`DROP TABLE "gates"`); + await queryRunner.query(`DROP TYPE "public"."gates_type_enum"`); + await queryRunner.query(`DROP TYPE "public"."gates_status_enum"`); + } +} diff --git a/src/modules/item-related/item/data/models/item.model.ts b/src/modules/item-related/item/data/models/item.model.ts index 0b9bf82..73205e4 100644 --- a/src/modules/item-related/item/data/models/item.model.ts +++ b/src/modules/item-related/item/data/models/item.model.ts @@ -15,6 +15,7 @@ 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'; import { ItemRateModel } from 'src/modules/item-related/item-rate/data/models/item-rate.model'; +import { GateModel } from 'src/modules/web-information/gate/data/models/gate.model'; @Entity(TABLE_NAME.ITEM) export class ItemModel @@ -108,4 +109,11 @@ export class ItemModel onUpdate: 'CASCADE', }) item_rates: ItemRateModel[]; + + // relasi ke gate + @OneToMany(() => GateModel, (model) => model.item, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + gates: GateModel[]; } diff --git a/src/modules/web-information/gate/constants.ts b/src/modules/web-information/gate/constants.ts new file mode 100644 index 0000000..ee23e1b --- /dev/null +++ b/src/modules/web-information/gate/constants.ts @@ -0,0 +1,4 @@ +export enum GateType { + GATE_IN = 'gate masuk', + GATE_OUT = 'gate keluar', +} diff --git a/src/modules/web-information/gate/data/models/gate.model.ts b/src/modules/web-information/gate/data/models/gate.model.ts new file mode 100644 index 0000000..0940d28 --- /dev/null +++ b/src/modules/web-information/gate/data/models/gate.model.ts @@ -0,0 +1,34 @@ +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { GateEntity } from '../../domain/entities/gate.entity'; +import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; +import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; +import { GateType } from '../../constants'; +import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; + +@Entity(TABLE_NAME.GATE) +export class GateModel + extends BaseStatusModel + implements GateEntity +{ + @Column('enum', { + name: 'type', + enum: GateType, + default: GateType.GATE_IN, + }) + type: GateType; + + @Column('varchar', { name: 'code', nullable: true }) + code: string; + + @Column('text', { name: 'note', nullable: true }) + note: string; + + @Column('varchar', { name: 'item_id', nullable: true }) + item_id: string; + @ManyToOne(() => ItemModel, (model) => model.gates, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + @JoinColumn({ name: 'item_id' }) + item: ItemModel; +} diff --git a/src/modules/web-information/gate/data/services/gate-data.service.ts b/src/modules/web-information/gate/data/services/gate-data.service.ts new file mode 100644 index 0000000..0e9c015 --- /dev/null +++ b/src/modules/web-information/gate/data/services/gate-data.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDataService } from 'src/core/modules/data/service/base-data.service'; +import { GateEntity } from '../../domain/entities/gate.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { GateModel } from '../models/gate.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; + +@Injectable() +export class GateDataService extends BaseDataService { + constructor( + @InjectRepository(GateModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/web-information/gate/domain/entities/event/gate-change-status.event.ts b/src/modules/web-information/gate/domain/entities/event/gate-change-status.event.ts new file mode 100644 index 0000000..cba58f9 --- /dev/null +++ b/src/modules/web-information/gate/domain/entities/event/gate-change-status.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class GateChangeStatusEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/gate/domain/entities/event/gate-created.event.ts b/src/modules/web-information/gate/domain/entities/event/gate-created.event.ts new file mode 100644 index 0000000..808ce86 --- /dev/null +++ b/src/modules/web-information/gate/domain/entities/event/gate-created.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class GateCreatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/gate/domain/entities/event/gate-deleted.event.ts b/src/modules/web-information/gate/domain/entities/event/gate-deleted.event.ts new file mode 100644 index 0000000..a81314c --- /dev/null +++ b/src/modules/web-information/gate/domain/entities/event/gate-deleted.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class GateDeletedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/gate/domain/entities/event/gate-updated.event.ts b/src/modules/web-information/gate/domain/entities/event/gate-updated.event.ts new file mode 100644 index 0000000..2ccb9fd --- /dev/null +++ b/src/modules/web-information/gate/domain/entities/event/gate-updated.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class GateUpdatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/web-information/gate/domain/entities/gate.entity.ts b/src/modules/web-information/gate/domain/entities/gate.entity.ts new file mode 100644 index 0000000..5ef2f0a --- /dev/null +++ b/src/modules/web-information/gate/domain/entities/gate.entity.ts @@ -0,0 +1,10 @@ +import { BaseStatusEntity } from 'src/core/modules/domain/entities/base-status.entity'; +import { GateType } from '../../constants'; + +export interface GateEntity extends BaseStatusEntity { + type: GateType; + code: string; + note: string; + + item_id: string; +} diff --git a/src/modules/web-information/gate/domain/usecases/gate-data.orchestrator.ts b/src/modules/web-information/gate/domain/usecases/gate-data.orchestrator.ts new file mode 100644 index 0000000..1c6dd3e --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/gate-data.orchestrator.ts @@ -0,0 +1,106 @@ +import { Injectable } from '@nestjs/common'; +import { CreateGateManager } from './managers/create-gate.manager'; +import { GateDataService } from '../../data/services/gate-data.service'; +import { GateEntity } from '../entities/gate.entity'; +import { DeleteGateManager } from './managers/delete-gate.manager'; +import { UpdateGateManager } from './managers/update-gate.manager'; +import { BaseDataTransactionOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-data-transaction.orchestrator'; +import { ActiveGateManager } from './managers/active-gate.manager'; +import { InactiveGateManager } from './managers/inactive-gate.manager'; +import { ConfirmGateManager } from './managers/confirm-gate.manager'; +import { STATUS } from 'src/core/strings/constants/base.constants'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchConfirmGateManager } from './managers/batch-confirm-gate.manager'; +import { BatchInactiveGateManager } from './managers/batch-inactive-gate.manager'; +import { BatchActiveGateManager } from './managers/batch-active-gate.manager'; +import { BatchDeleteGateManager } from './managers/batch-delete-gate.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class GateDataOrchestrator extends BaseDataTransactionOrchestrator { + constructor( + private createManager: CreateGateManager, + private updateManager: UpdateGateManager, + private deleteManager: DeleteGateManager, + private activeManager: ActiveGateManager, + private confirmManager: ConfirmGateManager, + private inactiveManager: InactiveGateManager, + private batchDeleteManager: BatchDeleteGateManager, + private batchActiveManager: BatchActiveGateManager, + private batchConfirmManager: BatchConfirmGateManager, + private batchInactiveManager: BatchInactiveGateManager, + private serviceData: GateDataService, + ) { + super(); + } + + async create(data): Promise { + this.createManager.setData(data); + this.createManager.setService(this.serviceData, TABLE_NAME.GATE); + await this.createManager.execute(); + return this.createManager.getResult(); + } + + async update(dataId, data): Promise { + this.updateManager.setData(dataId, data); + this.updateManager.setService(this.serviceData, TABLE_NAME.GATE); + await this.updateManager.execute(); + return this.updateManager.getResult(); + } + + async delete(dataId): Promise { + this.deleteManager.setData(dataId); + this.deleteManager.setService(this.serviceData, TABLE_NAME.GATE); + await this.deleteManager.execute(); + return this.deleteManager.getResult(); + } + + async batchDelete(dataIds: string[]): Promise { + this.batchDeleteManager.setData(dataIds); + this.batchDeleteManager.setService(this.serviceData, TABLE_NAME.GATE); + await this.batchDeleteManager.execute(); + return this.batchDeleteManager.getResult(); + } + + async active(dataId): Promise { + this.activeManager.setData(dataId, STATUS.ACTIVE); + this.activeManager.setService(this.serviceData, TABLE_NAME.GATE); + await this.activeManager.execute(); + return this.activeManager.getResult(); + } + + async batchActive(dataIds: string[]): Promise { + this.batchActiveManager.setData(dataIds, STATUS.ACTIVE); + this.batchActiveManager.setService(this.serviceData, TABLE_NAME.GATE); + await this.batchActiveManager.execute(); + return this.batchActiveManager.getResult(); + } + + async confirm(dataId): Promise { + this.confirmManager.setData(dataId, STATUS.ACTIVE); + this.confirmManager.setService(this.serviceData, TABLE_NAME.GATE); + await this.confirmManager.execute(); + return this.confirmManager.getResult(); + } + + async batchConfirm(dataIds: string[]): Promise { + this.batchConfirmManager.setData(dataIds, STATUS.ACTIVE); + this.batchConfirmManager.setService(this.serviceData, TABLE_NAME.GATE); + await this.batchConfirmManager.execute(); + return this.batchConfirmManager.getResult(); + } + + async inactive(dataId): Promise { + this.inactiveManager.setData(dataId, STATUS.INACTIVE); + this.inactiveManager.setService(this.serviceData, TABLE_NAME.GATE); + await this.inactiveManager.execute(); + return this.inactiveManager.getResult(); + } + + async batchInactive(dataIds: string[]): Promise { + this.batchInactiveManager.setData(dataIds, STATUS.INACTIVE); + this.batchInactiveManager.setService(this.serviceData, TABLE_NAME.GATE); + await this.batchInactiveManager.execute(); + return this.batchInactiveManager.getResult(); + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/active-gate.manager.ts b/src/modules/web-information/gate/domain/usecases/managers/active-gate.manager.ts new file mode 100644 index 0000000..05a0cdc --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/active-gate.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 { GateEntity } from '../../entities/gate.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { GateModel } from '../../../data/models/gate.model'; +import { GateChangeStatusEvent } from '../../entities/event/gate-change-status.event'; + +@Injectable() +export class ActiveGateManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data gate ${this.result.code}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return GateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: GateChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/batch-active-gate.manager.ts b/src/modules/web-information/gate/domain/usecases/managers/batch-active-gate.manager.ts new file mode 100644 index 0000000..1517173 --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/batch-active-gate.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { GateEntity } from '../../entities/gate.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { GateModel } from '../../../data/models/gate.model'; +import { GateChangeStatusEvent } from '../../entities/event/gate-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchActiveGateManager extends BaseBatchUpdateStatusManager { + validateData(data: GateEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return GateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: GateChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/batch-confirm-gate.manager.ts b/src/modules/web-information/gate/domain/usecases/managers/batch-confirm-gate.manager.ts new file mode 100644 index 0000000..660e729 --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/batch-confirm-gate.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { GateEntity } from '../../entities/gate.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { GateModel } from '../../../data/models/gate.model'; +import { GateChangeStatusEvent } from '../../entities/event/gate-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchConfirmGateManager extends BaseBatchUpdateStatusManager { + validateData(data: GateEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return GateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: GateChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/batch-delete-gate.manager.ts b/src/modules/web-information/gate/domain/usecases/managers/batch-delete-gate.manager.ts new file mode 100644 index 0000000..975f1fd --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/batch-delete-gate.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchDeleteManager } from 'src/core/modules/domain/usecase/managers/base-batch-delete.manager'; +import { GateEntity } from '../../entities/gate.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { GateModel } from '../../../data/models/gate.model'; +import { GateDeletedEvent } from '../../entities/event/gate-deleted.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchDeleteGateManager extends BaseBatchDeleteManager { + async beforeProcess(): Promise { + return; + } + + async validateData(data: GateEntity): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return GateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: GateDeletedEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/batch-inactive-gate.manager.ts b/src/modules/web-information/gate/domain/usecases/managers/batch-inactive-gate.manager.ts new file mode 100644 index 0000000..6c3c055 --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/batch-inactive-gate.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { GateEntity } from '../../entities/gate.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { GateModel } from '../../../data/models/gate.model'; +import { GateChangeStatusEvent } from '../../entities/event/gate-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchInactiveGateManager extends BaseBatchUpdateStatusManager { + validateData(data: GateEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return GateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: GateChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/confirm-gate.manager.ts b/src/modules/web-information/gate/domain/usecases/managers/confirm-gate.manager.ts new file mode 100644 index 0000000..5a409c5 --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/confirm-gate.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 { GateEntity } from '../../entities/gate.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { GateModel } from '../../../data/models/gate.model'; +import { GateChangeStatusEvent } from '../../entities/event/gate-change-status.event'; + +@Injectable() +export class ConfirmGateManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data gate ${this.result.code}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return GateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: GateChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/create-gate.manager.ts b/src/modules/web-information/gate/domain/usecases/managers/create-gate.manager.ts new file mode 100644 index 0000000..d8ec3f4 --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/create-gate.manager.ts @@ -0,0 +1,48 @@ +import { + HttpStatus, + Injectable, + UnprocessableEntityException, +} from '@nestjs/common'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { GateEntity } from '../../entities/gate.entity'; +import { GateModel } from '../../../data/models/gate.model'; +import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager'; +import { GateCreatedEvent } from '../../entities/event/gate-created.event'; +import { validateItemGate } from './helpers/validate-item-gate.helper'; + +@Injectable() +export class CreateGateManager extends BaseCreateManager { + async beforeProcess(): Promise { + await validateItemGate(this.dataService, this.data); + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: GateCreatedEvent, + data: this.data, + }, + ]; + } + + get entityTarget(): any { + return GateModel; + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/delete-gate.manager.ts b/src/modules/web-information/gate/domain/usecases/managers/delete-gate.manager.ts new file mode 100644 index 0000000..f60323d --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/delete-gate.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager'; +import { GateEntity } from '../../entities/gate.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { GateModel } from '../../../data/models/gate.model'; +import { GateDeletedEvent } from '../../entities/event/gate-deleted.event'; + +@Injectable() +export class DeleteGateManager 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 GateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: GateDeletedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/helpers/validate-item-gate.helper.ts b/src/modules/web-information/gate/domain/usecases/managers/helpers/validate-item-gate.helper.ts new file mode 100644 index 0000000..725d624 --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/helpers/validate-item-gate.helper.ts @@ -0,0 +1,38 @@ +import { HttpStatus, UnprocessableEntityException } from '@nestjs/common'; +import { EMPTY_UUID } from 'src/core/strings/constants/base.constants'; +import { In, Not } from 'typeorm'; + +export async function validateItemGate(dataService, data, id?) { + // validate same code + const existCode = await dataService.getOneByOptions({ + where: { + code: data.code, + id: Not(In([id ?? EMPTY_UUID])), + }, + }); + + if (existCode) { + throw new UnprocessableEntityException({ + statusCode: HttpStatus.UNPROCESSABLE_ENTITY, + message: `Failed! Gate with code ${data.code} already exist`, + error: 'Unprocessable Entity', + }); + } + + // validate type item + const existType = await dataService.getOneByOptions({ + where: { + item_id: data.item.id, + type: data.type, + id: Not(In([id ?? EMPTY_UUID])), + }, + }); + + if (existType) { + throw new UnprocessableEntityException({ + statusCode: HttpStatus.UNPROCESSABLE_ENTITY, + message: `Failed! Gate type ${data.type} with item ${data.item.name} already exist`, + error: 'Unprocessable Entity', + }); + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/inactive-gate.manager.ts b/src/modules/web-information/gate/domain/usecases/managers/inactive-gate.manager.ts new file mode 100644 index 0000000..94c08ab --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/inactive-gate.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 { GateEntity } from '../../entities/gate.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { GateModel } from '../../../data/models/gate.model'; +import { GateChangeStatusEvent } from '../../entities/event/gate-change-status.event'; + +@Injectable() +export class InactiveGateManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success inactive data gate ${this.result.code}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return GateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: GateChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/gate/domain/usecases/managers/update-gate.manager.ts b/src/modules/web-information/gate/domain/usecases/managers/update-gate.manager.ts new file mode 100644 index 0000000..1018675 --- /dev/null +++ b/src/modules/web-information/gate/domain/usecases/managers/update-gate.manager.ts @@ -0,0 +1,48 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager'; +import { GateEntity } from '../../entities/gate.entity'; +import { GateModel } from '../../../data/models/gate.model'; +import { GateUpdatedEvent } from '../../entities/event/gate-updated.event'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { validateItemGate } from './helpers/validate-item-gate.helper'; + +@Injectable() +export class UpdateGateManager extends BaseUpdateManager { + async validateProcess(): Promise { + await validateItemGate(this.dataService, this.data, this.dataId); + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get entityTarget(): any { + return GateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: GateUpdatedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/web-information/gate/gate.module.ts b/src/modules/web-information/gate/gate.module.ts new file mode 100644 index 0000000..92298cb --- /dev/null +++ b/src/modules/web-information/gate/gate.module.ts @@ -0,0 +1,54 @@ +import { 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 { GateDataService } from './data/services/gate-data.service'; +import { GateReadService } from './data/services/gate-read.service'; +import { GateReadController } from './infrastructure/gate-read.controller'; +import { GateReadOrchestrator } from './domain/usecases/gate-read.orchestrator'; +import { GateDataController } from './infrastructure/gate-data.controller'; +import { GateDataOrchestrator } from './domain/usecases/gate-data.orchestrator'; +import { CreateGateManager } from './domain/usecases/managers/create-gate.manager'; +import { CqrsModule } from '@nestjs/cqrs'; +import { IndexGateManager } from './domain/usecases/managers/index-gate.manager'; +import { DeleteGateManager } from './domain/usecases/managers/delete-gate.manager'; +import { UpdateGateManager } from './domain/usecases/managers/update-gate.manager'; +import { ActiveGateManager } from './domain/usecases/managers/active-gate.manager'; +import { ConfirmGateManager } from './domain/usecases/managers/confirm-gate.manager'; +import { InactiveGateManager } from './domain/usecases/managers/inactive-gate.manager'; +import { DetailGateManager } from './domain/usecases/managers/detail-gate.manager'; +import { BatchDeleteGateManager } from './domain/usecases/managers/batch-delete-gate.manager'; +import { BatchActiveGateManager } from './domain/usecases/managers/batch-active-gate.manager'; +import { BatchConfirmGateManager } from './domain/usecases/managers/batch-confirm-gate.manager'; +import { BatchInactiveGateManager } from './domain/usecases/managers/batch-inactive-gate.manager'; +import { GateModel } from './data/models/gate.model'; + +@Module({ + imports: [ + ConfigModule.forRoot(), + TypeOrmModule.forFeature([GateModel], CONNECTION_NAME.DEFAULT), + CqrsModule, + ], + controllers: [GateDataController, GateReadController], + providers: [ + IndexGateManager, + DetailGateManager, + CreateGateManager, + DeleteGateManager, + UpdateGateManager, + ActiveGateManager, + ConfirmGateManager, + InactiveGateManager, + BatchDeleteGateManager, + BatchActiveGateManager, + BatchConfirmGateManager, + BatchInactiveGateManager, + + GateDataService, + GateReadService, + + GateDataOrchestrator, + GateReadOrchestrator, + ], +}) +export class GateModule {} diff --git a/src/modules/web-information/gate/index.ts b/src/modules/web-information/gate/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/web-information/gate/infrastructure/dto/gate.dto.ts b/src/modules/web-information/gate/infrastructure/dto/gate.dto.ts new file mode 100644 index 0000000..4e22c91 --- /dev/null +++ b/src/modules/web-information/gate/infrastructure/dto/gate.dto.ts @@ -0,0 +1,46 @@ +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { GateEntity } from '../../domain/entities/gate.entity'; +import { GateType } from '../../constants'; +import { ApiProperty } from '@nestjs/swagger'; +import { string } from 'mathjs'; +import { IsObject, IsString } from 'class-validator'; +import { Exclude } from 'class-transformer'; +import { ItemEntity } from 'src/modules/item-related/item/domain/entities/item.entity'; + +export class GateDto extends BaseStatusDto implements GateEntity { + @ApiProperty({ + type: string, + required: true, + example: GateType.GATE_IN, + }) + @IsString() + type: GateType; + + @ApiProperty({ + type: string, + required: true, + example: '41245', + }) + code: string; + + @ApiProperty({ + type: string, + required: false, + example: '41245', + }) + note: string; + + @ApiProperty({ + type: Object, + required: true, + example: { + id: 'uuid', + name: 'whana', + }, + }) + @IsObject() + item: ItemEntity; + + @Exclude() + item_id: string; +} diff --git a/src/modules/web-information/gate/infrastructure/gate-data.controller.ts b/src/modules/web-information/gate/infrastructure/gate-data.controller.ts new file mode 100644 index 0000000..96074d9 --- /dev/null +++ b/src/modules/web-information/gate/infrastructure/gate-data.controller.ts @@ -0,0 +1,78 @@ +import { + Body, + Controller, + Delete, + Param, + Patch, + Post, + Put, +} from '@nestjs/common'; +import { GateDataOrchestrator } from '../domain/usecases/gate-data.orchestrator'; +import { GateDto } from './dto/gate.dto'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { GateEntity } from '../domain/entities/gate.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.GATE.split('-').join(' ')} - data`) +@Controller(`v1/${MODULE_NAME.GATE}`) +@Public(false) +@ApiBearerAuth('JWT') +export class GateDataController { + constructor(private orchestrator: GateDataOrchestrator) {} + + @Post() + async create(@Body() data: GateDto): 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: GateDto, + ): Promise { + return await this.orchestrator.update(dataId, data); + } + + @Delete(':id') + async delete(@Param('id') dataId: string): Promise { + return await this.orchestrator.delete(dataId); + } +}