From 72bc4de42d4ab5d57ba8fe088cd2b6893fa53fec Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Wed, 2 Jul 2025 18:43:32 +0700 Subject: [PATCH] feat(SPG-1124): create feature crud data scheduling and data scheduling default --- env/env.development | 4 +- env/env.production | 4 +- src/app.module.ts | 8 ++ .../strings/constants/module.constants.ts | 2 + src/core/strings/constants/table.constants.ts | 2 + .../1751455019718-data-scheduling.ts | 23 ++++ .../data-scheduling/data-scheduling.module.ts | 70 ++++++++++ .../models/data-scheduling-default.model.ts | 13 ++ .../data/models/data-scheduling.model.ts | 22 +++ .../services/data-scheduling-data.service.ts | 17 +++ .../services/data-scheduling-read.service.ts | 17 +++ .../domain/entities/data-scheduling.entity.ts | 13 ++ .../data-scheduling-change-status.event.ts | 5 + .../event/data-scheduling-created.event.ts | 5 + .../event/data-scheduling-deleted.event.ts | 5 + .../event/data-scheduling-updated.event.ts | 5 + .../entities/filter-data-scheduling.entity.ts | 6 + .../data-scheduling-data.orchestrator.ts | 125 +++++++++++++++++ .../data-scheduling-read.orchestrator.ts | 33 +++++ .../active-data-scheduling.manager.ts | 45 ++++++ .../batch-active-data-scheduling.manager.ts | 45 ++++++ .../batch-confirm-data-scheduling.manager.ts | 45 ++++++ .../batch-delete-data-scheduling.manager.ts | 45 ++++++ .../batch-inactive-data-scheduling.manager.ts | 45 ++++++ .../confirm-data-scheduling.manager.ts | 45 ++++++ .../create-data-scheduling.manager.ts | 87 ++++++++++++ .../data-scheduling-default.manager.ts | 66 +++++++++ .../delete-data-scheduling.manager.ts | 45 ++++++ .../detail-data-scheduling.manager.ts | 59 ++++++++ .../inactive-data-scheduling.manager.ts | 45 ++++++ .../managers/index-data-scheduling.manager.ts | 75 ++++++++++ .../update-data-scheduling.manager.ts | 76 ++++++++++ .../data-scheduling-data.controller.ts | 130 ++++++++++++++++++ .../data-scheduling-read.controller.ts | 30 ++++ .../infrastructure/dto/data-scheduling.dto.ts | 92 +++++++++++++ .../dto/filter-data-scheduling.dto.ts | 17 +++ .../guards/setup-scheduling.guard.ts | 26 ++++ .../infrastructure/helpers/index.ts | 7 + 38 files changed, 1402 insertions(+), 2 deletions(-) create mode 100644 src/database/migrations/1751455019718-data-scheduling.ts create mode 100644 src/modules/configuration/data-scheduling/data-scheduling.module.ts create mode 100644 src/modules/configuration/data-scheduling/data/models/data-scheduling-default.model.ts create mode 100644 src/modules/configuration/data-scheduling/data/models/data-scheduling.model.ts create mode 100644 src/modules/configuration/data-scheduling/data/services/data-scheduling-data.service.ts create mode 100644 src/modules/configuration/data-scheduling/data/services/data-scheduling-read.service.ts create mode 100644 src/modules/configuration/data-scheduling/domain/entities/data-scheduling.entity.ts create mode 100644 src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-change-status.event.ts create mode 100644 src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-created.event.ts create mode 100644 src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-deleted.event.ts create mode 100644 src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-updated.event.ts create mode 100644 src/modules/configuration/data-scheduling/domain/entities/filter-data-scheduling.entity.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/data-scheduling-data.orchestrator.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/data-scheduling-read.orchestrator.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/active-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/batch-active-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/batch-confirm-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/batch-delete-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/batch-inactive-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/confirm-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/create-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/data-scheduling-default.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/delete-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/detail-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/inactive-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/index-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/domain/usecases/managers/update-data-scheduling.manager.ts create mode 100644 src/modules/configuration/data-scheduling/infrastructure/data-scheduling-data.controller.ts create mode 100644 src/modules/configuration/data-scheduling/infrastructure/data-scheduling-read.controller.ts create mode 100644 src/modules/configuration/data-scheduling/infrastructure/dto/data-scheduling.dto.ts create mode 100644 src/modules/configuration/data-scheduling/infrastructure/dto/filter-data-scheduling.dto.ts create mode 100644 src/modules/configuration/data-scheduling/infrastructure/guards/setup-scheduling.guard.ts create mode 100644 src/modules/configuration/data-scheduling/infrastructure/helpers/index.ts diff --git a/env/env.development b/env/env.development index 1e241d4..2941384 100644 --- a/env/env.development +++ b/env/env.development @@ -46,4 +46,6 @@ SUPERSET_ADMIN_USERNAME=admin SUPERSET_ADMIN_PASSWORD=admin WHATSAPP_BUSINESS_ACCOUNT_NUMBER_ID=604883366037548 -WHATSAPP_BUSINESS_ACCESS_TOKEN=EAAINOvRRiEEBO9yQsYDnYtjHZB7q1nZCwbBpRcxIGMDWajKZBtmWxNRKvPYkS95KQZBsZBOvSFyjiEg5CcCZBZBtaSZApxyV8fiA3cEyVwf7iVZBQP2YCTPRQZArMFeeXbO0uq5TGygmjsIz3M4YxcUHxPzKO4pKxIyxnzcoUZCqCSo1NqQSLVf3a0JyZAwgDXGL55dV \ No newline at end of file +WHATSAPP_BUSINESS_ACCESS_TOKEN=EAAINOvRRiEEBO9yQsYDnYtjHZB7q1nZCwbBpRcxIGMDWajKZBtmWxNRKvPYkS95KQZBsZBOvSFyjiEg5CcCZBZBtaSZApxyV8fiA3cEyVwf7iVZBQP2YCTPRQZArMFeeXbO0uq5TGygmjsIz3M4YxcUHxPzKO4pKxIyxnzcoUZCqCSo1NqQSLVf3a0JyZAwgDXGL55dV + +SETUP_SCHEDULING_KEY=scheduling_key_example \ No newline at end of file diff --git a/env/env.production b/env/env.production index fce7b16..1d16625 100644 --- a/env/env.production +++ b/env/env.production @@ -43,4 +43,6 @@ SUPERSET_ADMIN_USERNAME=admin SUPERSET_ADMIN_PASSWORD=admin WHATSAPP_BUSINESS_ACCOUNT_NUMBER_ID=604883366037548 -WHATSAPP_BUSINESS_ACCESS_TOKEN=EAAINOvRRiEEBO9yQsYDnYtjHZB7q1nZCwbBpRcxIGMDWajKZBtmWxNRKvPYkS95KQZBsZBOvSFyjiEg5CcCZBZBtaSZApxyV8fiA3cEyVwf7iVZBQP2YCTPRQZArMFeeXbO0uq5TGygmjsIz3M4YxcUHxPzKO4pKxIyxnzcoUZCqCSo1NqQSLVf3a0JyZAwgDXGL55dV \ No newline at end of file +WHATSAPP_BUSINESS_ACCESS_TOKEN=EAAINOvRRiEEBO9yQsYDnYtjHZB7q1nZCwbBpRcxIGMDWajKZBtmWxNRKvPYkS95KQZBsZBOvSFyjiEg5CcCZBZBtaSZApxyV8fiA3cEyVwf7iVZBQP2YCTPRQZArMFeeXbO0uq5TGygmjsIz3M4YxcUHxPzKO4pKxIyxnzcoUZCqCSo1NqQSLVf3a0JyZAwgDXGL55dV + +SETUP_SCHEDULING_KEY=scheduling_key_example \ No newline at end of file diff --git a/src/app.module.ts b/src/app.module.ts index cef2349..631989f 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -107,6 +107,9 @@ import { OtpVerificationModel } from './modules/configuration/otp-verification/d import { OtpVerifierModel } from './modules/configuration/otp-verification/data/models/otp-verifier.model'; import { RescheduleVerificationModel } from './modules/booking-online/order/data/models/reschedule-verification.model'; import { OtpCheckerGuard } from './core/guards/domain/otp-checker.guard'; +import { DataSchedulingModel } from './modules/configuration/data-scheduling/data/models/data-scheduling.model'; +import { DataSchedulingModule } from './modules/configuration/data-scheduling/data-scheduling.module'; +import { DataSchedulingDefaultModel } from './modules/configuration/data-scheduling/data/models/data-scheduling-default.model'; @Module({ imports: [ @@ -176,6 +179,10 @@ import { OtpCheckerGuard } from './core/guards/domain/otp-checker.guard'; OtpVerificationModel, OtpVerifierModel, + + // Data Scheduling + DataSchedulingModel, + DataSchedulingDefaultModel, ], synchronize: false, }), @@ -242,6 +249,7 @@ import { OtpCheckerGuard } from './core/guards/domain/otp-checker.guard'; BookingOnlineAuthModule, BookingOrderModule, OtpVerificationModule, + DataSchedulingModule, ], controllers: [], providers: [ diff --git a/src/core/strings/constants/module.constants.ts b/src/core/strings/constants/module.constants.ts index 8e8896e..f07635c 100644 --- a/src/core/strings/constants/module.constants.ts +++ b/src/core/strings/constants/module.constants.ts @@ -33,4 +33,6 @@ export enum MODULE_NAME { OTP_VERIFICATIONS = 'otp-verification', OTP_VERIFIER = 'otp-verifier', + DATA_SCHEDULING = 'data-scheduling', + DATA_SCHEDULING_DEFAULT = 'data-scheduling-default', } diff --git a/src/core/strings/constants/table.constants.ts b/src/core/strings/constants/table.constants.ts index 2139ba6..470fa71 100644 --- a/src/core/strings/constants/table.constants.ts +++ b/src/core/strings/constants/table.constants.ts @@ -47,4 +47,6 @@ export enum TABLE_NAME { TIME_GROUPS = 'time_groups', OTP_VERIFICATIONS = 'otp_verifications', OTP_VERIFIER = 'otp_verifier', + DATA_SCHEDULING = 'data_scheduling', + DATA_SCHEDULING_DEFAULT = 'data_scheduling_default', } diff --git a/src/database/migrations/1751455019718-data-scheduling.ts b/src/database/migrations/1751455019718-data-scheduling.ts new file mode 100644 index 0000000..76f2bc9 --- /dev/null +++ b/src/database/migrations/1751455019718-data-scheduling.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class DataScheduling1751455019718 implements MigrationInterface { + name = 'DataScheduling1751455019718'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TYPE "public"."data_scheduling_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'partial refund', 'pending', 'proses refund', 'refunded', 'rejected', 'settled', 'waiting')`, + ); + await queryRunner.query( + `CREATE TABLE "data_scheduling" ("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"."data_scheduling_status_enum" NOT NULL DEFAULT 'draft', "name" character varying NOT NULL, "indexing_key" character varying NOT NULL, "schedule_date_from" date NOT NULL, "schedule_date_to" date NOT NULL, CONSTRAINT "PK_118219da41190e9b934072b4cc5" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `CREATE TABLE "data_scheduling_default" ("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, "default_value" integer NOT NULL, CONSTRAINT "PK_c0c3bb2b53c67440a9b534d42b9" PRIMARY KEY ("id"))`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "data_scheduling_default"`); + await queryRunner.query(`DROP TABLE "data_scheduling"`); + await queryRunner.query(`DROP TYPE "public"."data_scheduling_status_enum"`); + } +} diff --git a/src/modules/configuration/data-scheduling/data-scheduling.module.ts b/src/modules/configuration/data-scheduling/data-scheduling.module.ts new file mode 100644 index 0000000..c587598 --- /dev/null +++ b/src/modules/configuration/data-scheduling/data-scheduling.module.ts @@ -0,0 +1,70 @@ +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 { DataSchedulingDataService } from './data/services/data-scheduling-data.service'; +import { DataSchedulingReadService } from './data/services/data-scheduling-read.service'; +import { DataSchedulingReadController } from './infrastructure/data-scheduling-read.controller'; +import { DataSchedulingReadOrchestrator } from './domain/usecases/data-scheduling-read.orchestrator'; +import { + DataSchedulingDataController, + DataSchedulingDefaultController, + DataSchedulingSetupController, +} from './infrastructure/data-scheduling-data.controller'; +import { DataSchedulingDataOrchestrator } from './domain/usecases/data-scheduling-data.orchestrator'; +import { CreateDataSchedulingManager } from './domain/usecases/managers/create-data-scheduling.manager'; +import { CqrsModule } from '@nestjs/cqrs'; +import { IndexDataSchedulingManager } from './domain/usecases/managers/index-data-scheduling.manager'; +import { DeleteDataSchedulingManager } from './domain/usecases/managers/delete-data-scheduling.manager'; +import { UpdateDataSchedulingManager } from './domain/usecases/managers/update-data-scheduling.manager'; +import { ActiveDataSchedulingManager } from './domain/usecases/managers/active-data-scheduling.manager'; +import { ConfirmDataSchedulingManager } from './domain/usecases/managers/confirm-data-scheduling.manager'; +import { InactiveDataSchedulingManager } from './domain/usecases/managers/inactive-data-scheduling.manager'; +import { DetailDataSchedulingManager } from './domain/usecases/managers/detail-data-scheduling.manager'; +import { BatchDeleteDataSchedulingManager } from './domain/usecases/managers/batch-delete-data-scheduling.manager'; +import { BatchActiveDataSchedulingManager } from './domain/usecases/managers/batch-active-data-scheduling.manager'; +import { BatchConfirmDataSchedulingManager } from './domain/usecases/managers/batch-confirm-data-scheduling.manager'; +import { BatchInactiveDataSchedulingManager } from './domain/usecases/managers/batch-inactive-data-scheduling.manager'; +import { DataSchedulingModel } from './data/models/data-scheduling.model'; +import { DataSchedulingDefaultModel } from './data/models/data-scheduling-default.model'; +import { DataSchedulingDefaultManager } from './domain/usecases/managers/data-scheduling-default.manager'; + +@Module({ + imports: [ + ConfigModule.forRoot(), + TypeOrmModule.forFeature( + [DataSchedulingModel, DataSchedulingDefaultModel], + CONNECTION_NAME.DEFAULT, + ), + CqrsModule, + ], + controllers: [ + DataSchedulingDataController, + DataSchedulingReadController, + DataSchedulingDefaultController, + DataSchedulingSetupController, + ], + providers: [ + IndexDataSchedulingManager, + DetailDataSchedulingManager, + CreateDataSchedulingManager, + DeleteDataSchedulingManager, + UpdateDataSchedulingManager, + ActiveDataSchedulingManager, + ConfirmDataSchedulingManager, + InactiveDataSchedulingManager, + BatchDeleteDataSchedulingManager, + BatchActiveDataSchedulingManager, + BatchConfirmDataSchedulingManager, + BatchInactiveDataSchedulingManager, + + DataSchedulingDataService, + DataSchedulingReadService, + + DataSchedulingDataOrchestrator, + DataSchedulingReadOrchestrator, + + DataSchedulingDefaultManager, + ], +}) +export class DataSchedulingModule {} diff --git a/src/modules/configuration/data-scheduling/data/models/data-scheduling-default.model.ts b/src/modules/configuration/data-scheduling/data/models/data-scheduling-default.model.ts new file mode 100644 index 0000000..2ff8728 --- /dev/null +++ b/src/modules/configuration/data-scheduling/data/models/data-scheduling-default.model.ts @@ -0,0 +1,13 @@ +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { DataSchedulingDefaultEntity } from '../../domain/entities/data-scheduling.entity'; +import { Column, Entity } from 'typeorm'; +import { BaseModel } from 'src/core/modules/data/model/base.model'; + +@Entity(TABLE_NAME.DATA_SCHEDULING_DEFAULT) +export class DataSchedulingDefaultModel + extends BaseModel + implements DataSchedulingDefaultEntity +{ + @Column('int', { nullable: false }) + default_value: number; +} diff --git a/src/modules/configuration/data-scheduling/data/models/data-scheduling.model.ts b/src/modules/configuration/data-scheduling/data/models/data-scheduling.model.ts new file mode 100644 index 0000000..a806445 --- /dev/null +++ b/src/modules/configuration/data-scheduling/data/models/data-scheduling.model.ts @@ -0,0 +1,22 @@ +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { DataSchedulingEntity } from '../../domain/entities/data-scheduling.entity'; +import { Column, Entity } from 'typeorm'; +import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; + +@Entity(TABLE_NAME.DATA_SCHEDULING) +export class DataSchedulingModel + extends BaseStatusModel + implements DataSchedulingEntity +{ + @Column('varchar', { name: 'name' }) + name: string; + + @Column('varchar', { name: 'indexing_key' }) + indexing_key: string; + + @Column('date', { name: 'schedule_date_from', nullable: false }) + schedule_date_from: Date; + + @Column('date', { name: 'schedule_date_to', nullable: false }) + schedule_date_to: Date; +} diff --git a/src/modules/configuration/data-scheduling/data/services/data-scheduling-data.service.ts b/src/modules/configuration/data-scheduling/data/services/data-scheduling-data.service.ts new file mode 100644 index 0000000..689dd20 --- /dev/null +++ b/src/modules/configuration/data-scheduling/data/services/data-scheduling-data.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDataService } from 'src/core/modules/data/service/base-data.service'; +import { DataSchedulingEntity } from '../../domain/entities/data-scheduling.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { DataSchedulingModel } from '../models/data-scheduling.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; + +@Injectable() +export class DataSchedulingDataService extends BaseDataService { + constructor( + @InjectRepository(DataSchedulingModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/configuration/data-scheduling/data/services/data-scheduling-read.service.ts b/src/modules/configuration/data-scheduling/data/services/data-scheduling-read.service.ts new file mode 100644 index 0000000..7385da0 --- /dev/null +++ b/src/modules/configuration/data-scheduling/data/services/data-scheduling-read.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { DataSchedulingEntity } from '../../domain/entities/data-scheduling.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { DataSchedulingModel } from '../models/data-scheduling.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; +import { BaseReadService } from 'src/core/modules/data/service/base-read.service'; + +@Injectable() +export class DataSchedulingReadService extends BaseReadService { + constructor( + @InjectRepository(DataSchedulingModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/configuration/data-scheduling/domain/entities/data-scheduling.entity.ts b/src/modules/configuration/data-scheduling/domain/entities/data-scheduling.entity.ts new file mode 100644 index 0000000..49b0e5b --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/entities/data-scheduling.entity.ts @@ -0,0 +1,13 @@ +import { BaseStatusEntity } from 'src/core/modules/domain/entities/base-status.entity'; +import { BaseEntity } from 'src/core/modules/domain/entities/base.entity'; + +export interface DataSchedulingEntity extends BaseStatusEntity { + name: string; + indexing_key: number | string; + schedule_date_from: Date; + schedule_date_to: Date; +} + +export interface DataSchedulingDefaultEntity extends BaseEntity { + default_value: number; +} diff --git a/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-change-status.event.ts b/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-change-status.event.ts new file mode 100644 index 0000000..86c8e9c --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-change-status.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class DataSchedulingChangeStatusEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-created.event.ts b/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-created.event.ts new file mode 100644 index 0000000..0ce8274 --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-created.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class DataSchedulingCreatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-deleted.event.ts b/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-deleted.event.ts new file mode 100644 index 0000000..592233a --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-deleted.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class DataSchedulingDeletedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-updated.event.ts b/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-updated.event.ts new file mode 100644 index 0000000..e888703 --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/entities/event/data-scheduling-updated.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class DataSchedulingUpdatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/configuration/data-scheduling/domain/entities/filter-data-scheduling.entity.ts b/src/modules/configuration/data-scheduling/domain/entities/filter-data-scheduling.entity.ts new file mode 100644 index 0000000..5ea5426 --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/entities/filter-data-scheduling.entity.ts @@ -0,0 +1,6 @@ +import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity'; + +export interface FilterDataSchedulingEntity extends BaseFilterEntity { + schedule_date_from: Date; + schedule_date_to: Date; +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/data-scheduling-data.orchestrator.ts b/src/modules/configuration/data-scheduling/domain/usecases/data-scheduling-data.orchestrator.ts new file mode 100644 index 0000000..086bcef --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/data-scheduling-data.orchestrator.ts @@ -0,0 +1,125 @@ +import { Injectable } from '@nestjs/common'; +import { CreateDataSchedulingManager } from './managers/create-data-scheduling.manager'; +import { DataSchedulingDataService } from '../../data/services/data-scheduling-data.service'; +import { DataSchedulingEntity } from '../entities/data-scheduling.entity'; +import { DeleteDataSchedulingManager } from './managers/delete-data-scheduling.manager'; +import { UpdateDataSchedulingManager } from './managers/update-data-scheduling.manager'; +import { BaseDataTransactionOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-data-transaction.orchestrator'; +import { ActiveDataSchedulingManager } from './managers/active-data-scheduling.manager'; +import { InactiveDataSchedulingManager } from './managers/inactive-data-scheduling.manager'; +import { ConfirmDataSchedulingManager } from './managers/confirm-data-scheduling.manager'; +import { STATUS } from 'src/core/strings/constants/base.constants'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchConfirmDataSchedulingManager } from './managers/batch-confirm-data-scheduling.manager'; +import { BatchInactiveDataSchedulingManager } from './managers/batch-inactive-data-scheduling.manager'; +import { BatchActiveDataSchedulingManager } from './managers/batch-active-data-scheduling.manager'; +import { BatchDeleteDataSchedulingManager } from './managers/batch-delete-data-scheduling.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class DataSchedulingDataOrchestrator extends BaseDataTransactionOrchestrator { + constructor( + private createManager: CreateDataSchedulingManager, + private updateManager: UpdateDataSchedulingManager, + private deleteManager: DeleteDataSchedulingManager, + private activeManager: ActiveDataSchedulingManager, + private confirmManager: ConfirmDataSchedulingManager, + private inactiveManager: InactiveDataSchedulingManager, + private batchDeleteManager: BatchDeleteDataSchedulingManager, + private batchActiveManager: BatchActiveDataSchedulingManager, + private batchConfirmManager: BatchConfirmDataSchedulingManager, + private batchInactiveManager: BatchInactiveDataSchedulingManager, + private serviceData: DataSchedulingDataService, + ) { + super(); + } + + async create(data): Promise { + this.createManager.setData(data); + this.createManager.setService(this.serviceData, TABLE_NAME.DATA_SCHEDULING); + await this.createManager.execute(); + await this.createManager.generateConfig(); + return this.createManager.getResult(); + } + + async update(dataId, data): Promise { + this.updateManager.setData(dataId, data); + this.updateManager.setService(this.serviceData, TABLE_NAME.DATA_SCHEDULING); + await this.updateManager.execute(); + return this.updateManager.getResult(); + } + + async delete(dataId): Promise { + this.deleteManager.setData(dataId); + this.deleteManager.setService(this.serviceData, TABLE_NAME.DATA_SCHEDULING); + await this.deleteManager.execute(); + return this.deleteManager.getResult(); + } + + async batchDelete(dataIds: string[]): Promise { + this.batchDeleteManager.setData(dataIds); + this.batchDeleteManager.setService( + this.serviceData, + TABLE_NAME.DATA_SCHEDULING, + ); + 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.DATA_SCHEDULING); + 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.DATA_SCHEDULING, + ); + 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.DATA_SCHEDULING, + ); + 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.DATA_SCHEDULING, + ); + 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.DATA_SCHEDULING, + ); + 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.DATA_SCHEDULING, + ); + await this.batchInactiveManager.execute(); + return this.batchInactiveManager.getResult(); + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/data-scheduling-read.orchestrator.ts b/src/modules/configuration/data-scheduling/domain/usecases/data-scheduling-read.orchestrator.ts new file mode 100644 index 0000000..b27759c --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/data-scheduling-read.orchestrator.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { IndexDataSchedulingManager } from './managers/index-data-scheduling.manager'; +import { DataSchedulingReadService } from '../../data/services/data-scheduling-read.service'; +import { DataSchedulingEntity } from '../entities/data-scheduling.entity'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; +import { DetailDataSchedulingManager } from './managers/detail-data-scheduling.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class DataSchedulingReadOrchestrator extends BaseReadOrchestrator { + constructor( + private indexManager: IndexDataSchedulingManager, + private detailManager: DetailDataSchedulingManager, + private serviceData: DataSchedulingReadService, + ) { + super(); + } + + async index(params): Promise> { + this.indexManager.setFilterParam(params); + this.indexManager.setService(this.serviceData, TABLE_NAME.DATA_SCHEDULING); + await this.indexManager.execute(); + return this.indexManager.getResult(); + } + + async detail(dataId: string): Promise { + this.detailManager.setData(dataId); + this.detailManager.setService(this.serviceData, TABLE_NAME.DATA_SCHEDULING); + await this.detailManager.execute(); + return this.detailManager.getResult(); + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/active-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/active-data-scheduling.manager.ts new file mode 100644 index 0000000..66fdfee --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/active-data-scheduling.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 { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; +import { DataSchedulingChangeStatusEvent } from '../../entities/event/data-scheduling-change-status.event'; + +@Injectable() +export class ActiveDataSchedulingManager 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 DataSchedulingModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: DataSchedulingChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-active-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-active-data-scheduling.manager.ts new file mode 100644 index 0000000..d1ad181 --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-active-data-scheduling.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; +import { DataSchedulingChangeStatusEvent } from '../../entities/event/data-scheduling-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchActiveDataSchedulingManager extends BaseBatchUpdateStatusManager { + validateData(data: DataSchedulingEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return DataSchedulingModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: DataSchedulingChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-confirm-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-confirm-data-scheduling.manager.ts new file mode 100644 index 0000000..51ba35f --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-confirm-data-scheduling.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; +import { DataSchedulingChangeStatusEvent } from '../../entities/event/data-scheduling-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchConfirmDataSchedulingManager extends BaseBatchUpdateStatusManager { + validateData(data: DataSchedulingEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return DataSchedulingModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: DataSchedulingChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-delete-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-delete-data-scheduling.manager.ts new file mode 100644 index 0000000..30b3cae --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-delete-data-scheduling.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchDeleteManager } from 'src/core/modules/domain/usecase/managers/base-batch-delete.manager'; +import { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; +import { DataSchedulingDeletedEvent } from '../../entities/event/data-scheduling-deleted.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchDeleteDataSchedulingManager extends BaseBatchDeleteManager { + async beforeProcess(): Promise { + return; + } + + async validateData(data: DataSchedulingEntity): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return DataSchedulingModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: DataSchedulingDeletedEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-inactive-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-inactive-data-scheduling.manager.ts new file mode 100644 index 0000000..d74b1fc --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/batch-inactive-data-scheduling.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; +import { DataSchedulingChangeStatusEvent } from '../../entities/event/data-scheduling-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchInactiveDataSchedulingManager extends BaseBatchUpdateStatusManager { + validateData(data: DataSchedulingEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return DataSchedulingModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: DataSchedulingChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/confirm-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/confirm-data-scheduling.manager.ts new file mode 100644 index 0000000..20abaa7 --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/confirm-data-scheduling.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 { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; +import { DataSchedulingChangeStatusEvent } from '../../entities/event/data-scheduling-change-status.event'; + +@Injectable() +export class ConfirmDataSchedulingManager 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 DataSchedulingModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: DataSchedulingChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/create-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/create-data-scheduling.manager.ts new file mode 100644 index 0000000..b9ca2fd --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/create-data-scheduling.manager.ts @@ -0,0 +1,87 @@ +import { Injectable } from '@nestjs/common'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; +import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager'; +import { DataSchedulingCreatedEvent } from '../../entities/event/data-scheduling-created.event'; +import { encryptionTotal } from '../../../infrastructure/helpers'; +import * as moment from 'moment'; + +@Injectable() +export class CreateDataSchedulingManager extends BaseCreateManager { + async beforeProcess(): Promise { + const total = this.data.indexing_key; + + if (total > 100) { + throw new Error('Maksimal nilai total adalah 100.'); + } + + const queryBuilder = this.dataService + .getRepository() + .createQueryBuilder(this.tableName); + + const overlapping = await queryBuilder + .where(`${this.tableName}.schedule_date_from <= :schedule_date_to`, { + schedule_date_to: this.data.schedule_date_to, + }) + .andWhere(`${this.tableName}.schedule_date_to >= :schedule_date_from`, { + schedule_date_from: this.data.schedule_date_from, + }) + .getOne(); + + if (this.data) { + Object.assign(this.data, { + indexing_key: encryptionTotal(total), + }); + } + + console.log(this.data); + // Validation date + if (overlapping) { + throw new Error('Tanggal yang dimasukkan beririsan dengan data lain.'); + } else if (this.data.schedule_date_from && this.data.schedule_date_to) { + const start_time = moment(this.data.schedule_date_from); + const end_time = moment(this.data.schedule_date_to); + + if (end_time.isBefore(start_time)) { + throw new Error('Tanggal akhir harus lebih besar dari tanggal mulai.'); + } + return; + } + + return; + } + + async afterProcess(): Promise { + return; + } + + async generateConfig(): Promise { + // TODO: Implement logic here + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return [{ column: 'name' }]; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: DataSchedulingCreatedEvent, + data: this.data, + }, + ]; + } + + get entityTarget(): any { + return DataSchedulingModel; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/data-scheduling-default.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/data-scheduling-default.manager.ts new file mode 100644 index 0000000..cd31b3e --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/data-scheduling-default.manager.ts @@ -0,0 +1,66 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { UserProvider, UsersSession } from 'src/core/sessions'; +import { BLANK_USER } from 'src/core/strings/constants/base.constants'; +import { EditDataSchedulingDefaultDto } from '../../../infrastructure/dto/data-scheduling.dto'; +import { DataSchedulingDefaultEntity } from '../../entities/data-scheduling.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { DataSchedulingDefaultModel } from '../../../data/models/data-scheduling-default.model'; +import { Repository } from 'typeorm'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { SelectQueryBuilder } from 'typeorm'; + +@Injectable() +export class DataSchedulingDefaultManager { + @Inject() + protected userProvider: UserProvider; + + constructor( + @InjectRepository(DataSchedulingDefaultModel) + private repository: Repository, + ) {} + + private getUser(): UsersSession { + try { + return this.userProvider?.user ?? BLANK_USER; + } catch (error) { + return BLANK_USER; + } + } + + get tableName(): string { + return TABLE_NAME.DATA_SCHEDULING_DEFAULT; + } + + private queryBuilder(): SelectQueryBuilder { + return this.repository.createQueryBuilder(this.tableName); + } + + async update( + body: EditDataSchedulingDefaultDto, + ): Promise { + if (body.default_value > 100) { + throw new Error('Value tidak boleh lebih dari 100.'); + } + + const userData = this.getUser(); + const dateNow = new Date().getTime(); + const existData = await this.queryBuilder().getOne(); + + const payload: DataSchedulingDefaultEntity = { + id: existData?.id, + default_value: body.default_value, + creator_id: userData.id as any, + creator_name: userData.name, + editor_id: userData.id as any, + editor_name: userData.name, + created_at: dateNow, + updated_at: dateNow, + }; + + return this.repository.save(payload); + } + + async getData() { + return this.queryBuilder().getOne(); + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/delete-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/delete-data-scheduling.manager.ts new file mode 100644 index 0000000..05f9b63 --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/delete-data-scheduling.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager'; +import { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; +import { DataSchedulingDeletedEvent } from '../../entities/event/data-scheduling-deleted.event'; + +@Injectable() +export class DeleteDataSchedulingManager 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 DataSchedulingModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: DataSchedulingDeletedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/detail-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/detail-data-scheduling.manager.ts new file mode 100644 index 0000000..c3a74f4 --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/detail-data-scheduling.manager.ts @@ -0,0 +1,59 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { BaseDetailManager } from 'src/core/modules/domain/usecase/managers/base-detail.manager'; +import { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { RelationParam } from 'src/core/modules/domain/entities/base-filter.entity'; +import { decryptionTotal } from '../../../infrastructure/helpers'; + +@Injectable() +export class DetailDataSchedulingManager extends BaseDetailManager { + async prepareData(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get relations(): RelationParam { + return { + joinRelations: [], + selectRelations: [], + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.status`, + `${this.tableName}.name`, + `${this.tableName}.indexing_key`, + `${this.tableName}.schedule_date_from`, + `${this.tableName}.schedule_date_to`, + `${this.tableName}.created_at`, + `${this.tableName}.creator_name`, + `${this.tableName}.updated_at`, + `${this.tableName}.editor_name`, + ]; + } + + get setFindProperties(): any { + return { + id: this.dataId, + }; + } + + getResult(): DataSchedulingEntity { + if (!this.result) throw new NotFoundException('Data not found.'); + + const total = decryptionTotal(this.result.indexing_key as string); + return { + ...this.result, + indexing_key: total, + }; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/inactive-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/inactive-data-scheduling.manager.ts new file mode 100644 index 0000000..0b5c9ed --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/inactive-data-scheduling.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 { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; +import { DataSchedulingChangeStatusEvent } from '../../entities/event/data-scheduling-change-status.event'; + +@Injectable() +export class InactiveDataSchedulingManager 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 DataSchedulingModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: DataSchedulingChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/index-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/index-data-scheduling.manager.ts new file mode 100644 index 0000000..afc20a8 --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/index-data-scheduling.manager.ts @@ -0,0 +1,75 @@ +import { Injectable } from '@nestjs/common'; +import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; +import { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { SelectQueryBuilder } from 'typeorm'; +import { + Param, + RelationParam, +} from 'src/core/modules/domain/entities/base-filter.entity'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { decryptionTotal } from '../../../infrastructure/helpers'; + +@Injectable() +export class IndexDataSchedulingManager extends BaseIndexManager { + async prepareData(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get relations(): RelationParam { + return { + joinRelations: [], + selectRelations: [], + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.status`, + `${this.tableName}.name`, + `${this.tableName}.indexing_key`, + `${this.tableName}.schedule_date_from`, + `${this.tableName}.schedule_date_to`, + `${this.tableName}.created_at`, + `${this.tableName}.creator_name`, + `${this.tableName}.updated_at`, + `${this.tableName}.editor_name`, + ]; + } + + get specificFilter(): Param[] { + return [ + { + cols: `${this.tableName}.name`, + data: this.filterParam.names, + }, + ]; + } + + setQueryFilter( + queryBuilder: SelectQueryBuilder, + ): SelectQueryBuilder { + return queryBuilder; + } + + getResult(): PaginationResponse { + const data = this.result.data; + + return { + ...this.result, + data: data.map((item) => { + const total = decryptionTotal(item.indexing_key as string); + return { ...item, indexing_key: total }; + }), + }; + } +} diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/update-data-scheduling.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/update-data-scheduling.manager.ts new file mode 100644 index 0000000..ff61086 --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/update-data-scheduling.manager.ts @@ -0,0 +1,76 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager'; +import { DataSchedulingEntity } from '../../entities/data-scheduling.entity'; +import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; +import { DataSchedulingUpdatedEvent } from '../../entities/event/data-scheduling-updated.event'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { encryptionTotal } from '../../../infrastructure/helpers'; + +@Injectable() +export class UpdateDataSchedulingManager extends BaseUpdateManager { + async validateProcess(): Promise { + const total = this.data.indexing_key; + + if (total > 100) { + throw new Error('Maksimal nilai total adalah 100.'); + } + + const queryBuilder = this.dataService + .getRepository() + .createQueryBuilder(this.tableName); + + const overlapping = await queryBuilder + .where(`${this.tableName}.schedule_date_from <= :schedule_date_to`, { + schedule_date_to: this.data.schedule_date_to, + }) + .andWhere(`${this.tableName}.schedule_date_to >= :schedule_date_from`, { + schedule_date_from: this.data.schedule_date_from, + }) + .andWhere(`${this.tableName}.id != :id`, { id: this.dataId ?? null }) + .getOne(); + + // Validation date + if (overlapping) { + throw new Error('Tanggal yang dimasukkan tidak boleh sama.'); + } else { + //Encryption total data + Object.assign(this.data, { + indexing_key: encryptionTotal(total), + }); + } + + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return [{ column: 'name' }]; + } + + get entityTarget(): any { + return DataSchedulingModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: DataSchedulingUpdatedEvent, + }, + ]; + } +} diff --git a/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-data.controller.ts b/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-data.controller.ts new file mode 100644 index 0000000..03b04db --- /dev/null +++ b/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-data.controller.ts @@ -0,0 +1,130 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + Patch, + Post, + Put, + UseGuards, +} from '@nestjs/common'; +import { DataSchedulingDataOrchestrator } from '../domain/usecases/data-scheduling-data.orchestrator'; +import { + SetupDataSchedulingDto, + CreateDataSchedulingDto, + EditDataSchedulingDto, + EditDataSchedulingDefaultDto, +} from './dto/data-scheduling.dto'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { + DataSchedulingDefaultEntity, + DataSchedulingEntity, +} from '../domain/entities/data-scheduling.entity'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; +import { ExcludePrivilege, Public } from 'src/core/guards'; +import { SetupSchedulingGuard } from './guards/setup-scheduling.guard'; +import { DataSchedulingDefaultManager } from '../domain/usecases/managers/data-scheduling-default.manager'; +import { get } from 'http'; + +@ApiTags(`${MODULE_NAME.DATA_SCHEDULING.split('-').join(' ')} - data`) +@Controller(`v1/${MODULE_NAME.DATA_SCHEDULING}`) +@Public(false) +@ApiBearerAuth('JWT') +export class DataSchedulingDataController { + constructor(private orchestrator: DataSchedulingDataOrchestrator) {} + + @Post() + async create( + @Body() data: CreateDataSchedulingDto, + ): 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: EditDataSchedulingDto, + ): Promise { + return await this.orchestrator.update(dataId, data); + } + + @Delete(':id') + async delete(@Param('id') dataId: string): Promise { + return await this.orchestrator.delete(dataId); + } +} + +@ApiTags( + `${MODULE_NAME.DATA_SCHEDULING_DEFAULT.split('-').join(' ')} setup - Data`, +) +@Controller(`v1/${MODULE_NAME.DATA_SCHEDULING_DEFAULT}`) +@Public(false) +@ApiBearerAuth('JWT') +export class DataSchedulingDefaultController { + constructor(private manager: DataSchedulingDefaultManager) {} + @Post() + async create( + @Body() data: EditDataSchedulingDefaultDto, + ): Promise { + return await this.manager.update(data); + } + + @Get() + async get(): Promise { + console.log('here'); + return await this.manager.getData(); + } +} + +@ApiTags(`${MODULE_NAME.DATA_SCHEDULING.split('-').join(' ')} setup - Data`) +@Controller(``) +@Public(true) +export class DataSchedulingSetupController { + @Post('v1/data-scheduling-setup') + @ExcludePrivilege() + @UseGuards(SetupSchedulingGuard) + async setup( + @Body() data: SetupDataSchedulingDto, + ): Promise { + console.log('payload scheduling setup', { data }); + return; + } +} diff --git a/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-read.controller.ts b/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-read.controller.ts new file mode 100644 index 0000000..4d1f17f --- /dev/null +++ b/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-read.controller.ts @@ -0,0 +1,30 @@ +import { Controller, Get, Param, Query } from '@nestjs/common'; +import { FilterDataSchedulingDto } from './dto/filter-data-scheduling.dto'; +import { Pagination } from 'src/core/response'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { DataSchedulingEntity } from '../domain/entities/data-scheduling.entity'; +import { DataSchedulingReadOrchestrator } from '../domain/usecases/data-scheduling-read.orchestrator'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { Public } from 'src/core/guards'; + +@ApiTags(`${MODULE_NAME.DATA_SCHEDULING.split('-').join(' ')} - read`) +@Controller(`v1/${MODULE_NAME.DATA_SCHEDULING}`) +@Public(false) +@ApiBearerAuth('JWT') +export class DataSchedulingReadController { + constructor(private orchestrator: DataSchedulingReadOrchestrator) {} + + @Get() + @Pagination() + async index( + @Query() params: FilterDataSchedulingDto, + ): Promise> { + return await this.orchestrator.index(params); + } + + @Get(':id') + async detail(@Param('id') id: string): Promise { + return await this.orchestrator.detail(id); + } +} diff --git a/src/modules/configuration/data-scheduling/infrastructure/dto/data-scheduling.dto.ts b/src/modules/configuration/data-scheduling/infrastructure/dto/data-scheduling.dto.ts new file mode 100644 index 0000000..527ec22 --- /dev/null +++ b/src/modules/configuration/data-scheduling/infrastructure/dto/data-scheduling.dto.ts @@ -0,0 +1,92 @@ +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { + DataSchedulingDefaultEntity, + DataSchedulingEntity, +} from '../../domain/entities/data-scheduling.entity'; +import { IsString, ValidateIf } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { BaseCoreDto } from 'src/core/modules/infrastructure/dto/base-core.dto'; +import { Transform } from 'class-transformer'; +import { BaseDto } from 'src/core/modules/infrastructure/dto/base.dto'; + +export class CreateDataSchedulingDto + extends BaseStatusDto + implements DataSchedulingEntity +{ + @ApiProperty({ name: 'name', required: true, example: 'Morning' }) + @IsString() + name: string; + + @ApiProperty({ type: 'integer', required: true, example: 80 }) + @Transform((body) => { + return typeof body.value == 'string' ? Number(body.value) : body.value; + }) + @ValidateIf((body) => body.indexing_key) + indexing_key: number; + + @ApiProperty({ + type: Date, + required: true, + example: '2024-01-01', + }) + schedule_date_from: Date; + + @ApiProperty({ + type: Date, + required: true, + example: '2024-01-02', + }) + schedule_date_to: Date; +} + +export class EditDataSchedulingDto + extends BaseStatusDto + implements DataSchedulingEntity +{ + @ApiProperty({ name: 'name', example: 'Morning' }) + @IsString() + @ValidateIf((body) => body.name) + name: string; + + @ApiProperty({ type: 'integer', required: true, example: 80 }) + @Transform((body) => { + return typeof body.value == 'string' ? Number(body.value) : body.value; + }) + @ValidateIf((body) => body.indexing_key) + indexing_key: number; + + @ApiProperty({ + type: Date, + required: true, + example: '2025-01-01', + }) + schedule_date_from: Date; + + @ApiProperty({ + type: Date, + required: true, + example: '2025-01-02', + }) + schedule_date_to: Date; +} + +export class EditDataSchedulingDefaultDto + extends BaseDto + implements DataSchedulingDefaultEntity +{ + @ApiProperty({ type: 'integer', required: true }) + @Transform((body) => { + return typeof body.value == 'string' ? Number(body.value) : body.value; + }) + @ValidateIf((body) => body.default_value) + default_value: number; +} + +export class SetupDataSchedulingDto { + @ApiProperty({ + type: Date, + required: true, + example: '2024-01-01', + }) + schedule_date: Date; +} diff --git a/src/modules/configuration/data-scheduling/infrastructure/dto/filter-data-scheduling.dto.ts b/src/modules/configuration/data-scheduling/infrastructure/dto/filter-data-scheduling.dto.ts new file mode 100644 index 0000000..99a92e0 --- /dev/null +++ b/src/modules/configuration/data-scheduling/infrastructure/dto/filter-data-scheduling.dto.ts @@ -0,0 +1,17 @@ +import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto'; +import { FilterDataSchedulingEntity } from '../../domain/entities/filter-data-scheduling.entity'; +import { ApiProperty } from '@nestjs/swagger'; +import { ValidateIf } from 'class-validator'; + +export class FilterDataSchedulingDto + extends BaseFilterDto + implements FilterDataSchedulingEntity +{ + @ApiProperty({ type: 'string', required: false }) + @ValidateIf((body) => body.schedule_date_from) + schedule_date_from: Date; + + @ApiProperty({ type: 'string', required: false }) + @ValidateIf((body) => body.schedule_date_to) + schedule_date_to: Date; +} diff --git a/src/modules/configuration/data-scheduling/infrastructure/guards/setup-scheduling.guard.ts b/src/modules/configuration/data-scheduling/infrastructure/guards/setup-scheduling.guard.ts new file mode 100644 index 0000000..1be4a0e --- /dev/null +++ b/src/modules/configuration/data-scheduling/infrastructure/guards/setup-scheduling.guard.ts @@ -0,0 +1,26 @@ +import { + CanActivate, + ExecutionContext, + Injectable, + UnprocessableEntityException, +} from '@nestjs/common'; + +@Injectable() +export class SetupSchedulingGuard implements CanActivate { + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest(); + const setupAuth = request.headers['x-setup-authorization']; + + if (setupAuth) { + try { + const setupKey = process.env.SETUP_SCHEDULING_KEY; + if (setupAuth === setupKey) return true; + else new UnprocessableEntityException('Setup Authorization Not Found.'); + } catch (err) { + throw new UnprocessableEntityException('Invalid authentication.'); + } + } + + throw new UnprocessableEntityException('Invalid authentication'); + } +} diff --git a/src/modules/configuration/data-scheduling/infrastructure/helpers/index.ts b/src/modules/configuration/data-scheduling/infrastructure/helpers/index.ts new file mode 100644 index 0000000..9a0049c --- /dev/null +++ b/src/modules/configuration/data-scheduling/infrastructure/helpers/index.ts @@ -0,0 +1,7 @@ +export function encryptionTotal(total: number): string { + return btoa(total.toString()); +} + +export function decryptionTotal(total: string): number { + return Number(atob(total)); +}