diff --git a/package.json b/package.json index ef1f732..bb8761e 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "mathjs": "^13.0.2", "midtrans-client": "^1.3.1", "moment": "^2.30.1", + "moment-timezone": "^0.6.0", "nano": "^10.1.3", "nodemailer": "^6.9.14", "pdfmake": "^0.2.10", diff --git a/src/core/strings/constants/table.constants.ts b/src/core/strings/constants/table.constants.ts index 470fa71..a2a5475 100644 --- a/src/core/strings/constants/table.constants.ts +++ b/src/core/strings/constants/table.constants.ts @@ -12,7 +12,7 @@ export enum TABLE_NAME { NEWS = 'news', PAYMENT_METHOD = 'payment_methods', PRICE_FORMULA = 'price_formulas', - TRANSACTION_SETTING = 'transaction_settings', + REFUND = 'refunds', REFUND_ITEM = 'refund_items', SEASON_TYPE = 'season_types', @@ -27,6 +27,8 @@ export enum TABLE_NAME { TRANSACTION_ITEM_TAX = 'transaction_item_taxes', TRANSACTION_ITEM_BREAKDOWN_TAX = 't_breakdown_item_taxes', TRANSACTION_DEMOGRAPHY = 'transaction_demographies', + TRANSACTION_SETTING = 'api_settings', + USER = 'users', USER_LOGIN = 'users_login', LOG_USER_LOGIN = 'log_users_login', @@ -47,6 +49,7 @@ 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', + + DATA_SCHEDULING = 'event_scheduling', + DATA_SCHEDULING_DEFAULT = 'event_scheduling_default', } diff --git a/src/database/migrations/1745991391299-transaction-setting-model.ts b/src/database/migrations/1745991391299-transaction-setting-model.ts deleted file mode 100644 index f59344a..0000000 --- a/src/database/migrations/1745991391299-transaction-setting-model.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class TransactionSettingModel1745991391299 - implements MigrationInterface -{ - name = 'TransactionSettingModel1745991391299'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TABLE "transaction_settings" ("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, "value" numeric NOT NULL DEFAULT '100', CONSTRAINT "PK_db7fb38a439358b499ebdee4761" PRIMARY KEY ("id"))`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`DROP TABLE "transaction_settings"`); - } -} diff --git a/src/database/migrations/1751455019718-data-scheduling.ts b/src/database/migrations/1751455019718-data-scheduling.ts deleted file mode 100644 index 76f2bc9..0000000 --- a/src/database/migrations/1751455019718-data-scheduling.ts +++ /dev/null @@ -1,23 +0,0 @@ -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/database/migrations/1751942902581-renam-table-config.ts b/src/database/migrations/1751942902581-renam-table-config.ts new file mode 100644 index 0000000..3b6ee5a --- /dev/null +++ b/src/database/migrations/1751942902581-renam-table-config.ts @@ -0,0 +1,35 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class RenamTableConfig1751942902581 implements MigrationInterface { + name = 'RenamTableConfig1751942902581'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "api_settings" ("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, "value" numeric NOT NULL DEFAULT '100', CONSTRAINT "PK_14bbb118ae1b2bd2385186cffb9" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `CREATE TYPE "public"."event_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 "event_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"."event_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_a2ccd3f6ab787b0d7e2af09d30c" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `CREATE TABLE "event_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_9caf65330e76243e9f9285ae2e1" PRIMARY KEY ("id"))`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "event_scheduling_default"`); + await queryRunner.query(`DROP TABLE "event_scheduling"`); + await queryRunner.query( + `DROP TYPE "public"."event_scheduling_status_enum"`, + ); + await queryRunner.query(`DROP TABLE "api_settings"`); + await queryRunner.query( + `ALTER TABLE "item_bundlings" ADD CONSTRAINT "FK_a50e7abf2caba4d0394f3726b86" FOREIGN KEY ("item_bundling_id") REFERENCES "items"("id") ON DELETE CASCADE ON UPDATE CASCADE`, + ); + await queryRunner.query( + `ALTER TABLE "queue_tickets" ADD CONSTRAINT "FK_0e9823b8b7ca9523b3be73878e5" FOREIGN KEY ("order_id") REFERENCES "queue_orders"("id") ON DELETE SET NULL ON UPDATE CASCADE`, + ); + } +} diff --git a/src/modules/configuration/data-scheduling/data-scheduling.module.ts b/src/modules/configuration/data-scheduling/data-scheduling.module.ts index 7e0dd21..3912b44 100644 --- a/src/modules/configuration/data-scheduling/data-scheduling.module.ts +++ b/src/modules/configuration/data-scheduling/data-scheduling.module.ts @@ -7,7 +7,6 @@ import { DataSchedulingReadService } from './data/services/data-scheduling-read. import { DataSchedulingReadController } from './infrastructure/data-scheduling-read.controller'; import { DataSchedulingReadOrchestrator } from './domain/usecases/data-scheduling-read.orchestrator'; import { - DataSchedulingActiveController, DataSchedulingDataController, DataSchedulingDefaultController, DataSchedulingSetupController, @@ -29,6 +28,11 @@ import { BatchInactiveDataSchedulingManager } from './domain/usecases/managers/b import { DataSchedulingModel } from './data/models/data-scheduling.model'; import { DataSchedulingDefaultModel } from './data/models/data-scheduling-default.model'; import { DataSchedulingManager } from './domain/usecases/managers/data-scheduling-default.manager'; +import { SetupSchedulingGuard } from './infrastructure/guards/setup-scheduling.guard'; + +import { JwtModule } from '@nestjs/jwt'; +import { JWT_EXPIRED } from 'src/core/sessions/constants'; +import { JWT_SECRET } from 'src/core/sessions/constants'; @Module({ imports: [ @@ -37,16 +41,20 @@ import { DataSchedulingManager } from './domain/usecases/managers/data-schedulin [DataSchedulingModel, DataSchedulingDefaultModel], CONNECTION_NAME.DEFAULT, ), + JwtModule.register({ + secret: JWT_SECRET, + signOptions: { expiresIn: JWT_EXPIRED }, + }), CqrsModule, ], controllers: [ DataSchedulingDataController, DataSchedulingReadController, DataSchedulingDefaultController, - DataSchedulingActiveController, DataSchedulingSetupController, ], providers: [ + SetupSchedulingGuard, IndexDataSchedulingManager, DetailDataSchedulingManager, CreateDataSchedulingManager, 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 index 7d87a93..040bc97 100644 --- 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 @@ -13,6 +13,9 @@ import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { SelectQueryBuilder } from 'typeorm'; import { DataSchedulingModel } from '../../../data/models/data-scheduling.model'; import { decryptionTotal } from '../../../infrastructure/helpers'; +import * as momentTz from 'moment-timezone'; +import { EventBus } from '@nestjs/cqrs'; +import { DataSchedulingChangeStatusEvent } from '../../entities/event/data-scheduling-change-status.event'; @Injectable() export class DataSchedulingManager { @@ -20,6 +23,8 @@ export class DataSchedulingManager { protected userProvider: UserProvider; constructor( + private eventBus: EventBus, + @InjectRepository(DataSchedulingDefaultModel) private repository: Repository, @@ -72,7 +77,11 @@ export class DataSchedulingManager { return this.queryBuilder().getOne(); } - async getActiveData(date) { + async getActiveData() { + const timeZoneWIB = 'Asia/Jakarta'; + const nowInWIB = momentTz().tz(timeZoneWIB).format('YYYY-MM-DD'); + const date = nowInWIB; + const qb = this.repoSchedule.createQueryBuilder(TABLE_NAME.DATA_SCHEDULING); const findData: DataSchedulingEntity = await qb @@ -86,6 +95,15 @@ export class DataSchedulingManager { return { value: defaultData?.default_value }; } - return { value: decryptionTotal(findData.indexing_key as string) }; + return { value: decryptionTotal(findData.indexing_key as string), date }; + } + + async setupActiveScheduling() { + const activeSchedule = await this.getActiveData(); + await this.eventBus.publish( + new DataSchedulingChangeStatusEvent({ data: activeSchedule } as any), + ); + + return { message: 'Success setup transaction schedule.' }; } } 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 index c94187c..71dcfd2 100644 --- a/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-data.controller.ts +++ b/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-data.controller.ts @@ -7,12 +7,10 @@ import { Patch, Post, Put, - Query, UseGuards, } from '@nestjs/common'; import { DataSchedulingDataOrchestrator } from '../domain/usecases/data-scheduling-data.orchestrator'; import { - SetupDataSchedulingDto, CreateDataSchedulingDto, EditDataSchedulingDto, EditDataSchedulingDefaultDto, @@ -20,7 +18,6 @@ import { import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; import { - DataSchedulingActiveEntity, DataSchedulingDefaultEntity, DataSchedulingEntity, } from '../domain/entities/data-scheduling.entity'; @@ -29,7 +26,6 @@ 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 { DataSchedulingManager } from '../domain/usecases/managers/data-scheduling-default.manager'; -import { FilterActiveDataSchedulingDto } from './dto/filter-data-scheduling.dto'; @ApiTags(`${MODULE_NAME.DATA_SCHEDULING.split('-').join(' ')} - data`) @Controller(`v1/${MODULE_NAME.DATA_SCHEDULING}`) @@ -115,43 +111,19 @@ export class DataSchedulingDefaultController { } } -@ApiTags( - `${MODULE_NAME.DATA_SCHEDULING_ACTIVE.split('-').join(' ')} active - Data`, -) -@Controller(`v1/${MODULE_NAME.DATA_SCHEDULING_ACTIVE}`) -@Public(false) -@ApiBearerAuth('JWT') -export class DataSchedulingActiveController { - constructor(private manager: DataSchedulingManager) {} - - @Get() - async get( - @Query() params: FilterActiveDataSchedulingDto, - ): Promise { - return await this.manager.getActiveData(params?.date); - } -} - @ApiTags( `${MODULE_NAME.DATA_SCHEDULING_SETUP.split('-').join(' ')} setup - Data`, ) @Controller(`v1/${MODULE_NAME.DATA_SCHEDULING_SETUP}`) @Public(true) +@ApiBearerAuth('JWT') export class DataSchedulingSetupController { + constructor(private manager: DataSchedulingManager) {} + @Post() @ExcludePrivilege() @UseGuards(SetupSchedulingGuard) - async setup( - @Body() data: SetupDataSchedulingDto, - ): Promise { - console.log('payload scheduling setup', { data }); - - // TODO: Implement logic for "Send to Black Hole" configuration. - // 1. Retrieve the relevant scheduling configuration based on the date provided in the request body. - // 2. If a specific scheduling configuration is found, apply its values to the main 'configuration' table. - // These values will then be used for the "Send to Black Hole" logic. - // 3. If no specific scheduling configuration is found for the given date, update the 'configuration' table - // with values from the 'data scheduling default' settings instead. - return; + async setup(): Promise<{ message: string }> { + return this.manager.setupActiveScheduling(); } } 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 index 527ec22..868f4e8 100644 --- a/src/modules/configuration/data-scheduling/infrastructure/dto/data-scheduling.dto.ts +++ b/src/modules/configuration/data-scheduling/infrastructure/dto/data-scheduling.dto.ts @@ -83,10 +83,6 @@ export class EditDataSchedulingDefaultDto } export class SetupDataSchedulingDto { - @ApiProperty({ - type: Date, - required: true, - example: '2024-01-01', - }) - schedule_date: Date; + // @ApiProperty({ type: 'string', required: true, example: '2025-01-01' }) + // 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 index 454aea5..ab6a50f 100644 --- 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 @@ -17,7 +17,7 @@ export class FilterDataSchedulingDto } export class FilterActiveDataSchedulingDto { - @ApiProperty({ type: 'string', required: true }) - @ValidateIf((body) => body.schedule_date_from) - date: Date; + // @ApiProperty({ type: 'string', required: true }) + // @ValidateIf((body) => body.schedule_date_from) + // date: 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 index 1be4a0e..4993947 100644 --- a/src/modules/configuration/data-scheduling/infrastructure/guards/setup-scheduling.guard.ts +++ b/src/modules/configuration/data-scheduling/infrastructure/guards/setup-scheduling.guard.ts @@ -4,11 +4,15 @@ import { Injectable, UnprocessableEntityException, } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; @Injectable() export class SetupSchedulingGuard implements CanActivate { + constructor(private readonly jwtService: JwtService) {} + async canActivate(context: ExecutionContext): Promise { const request = context.switchToHttp().getRequest(); + const jwtAuth = request.headers['authorization']; const setupAuth = request.headers['x-setup-authorization']; if (setupAuth) { @@ -19,6 +23,16 @@ export class SetupSchedulingGuard implements CanActivate { } catch (err) { throw new UnprocessableEntityException('Invalid authentication.'); } + } else if (jwtAuth && jwtAuth.startsWith('Bearer ')) { + const token = jwtAuth.split(' ')[1]; + try { + const payload = await this.jwtService.verifyAsync(token); + if (payload) return true; + else new UnprocessableEntityException('Setup Authorization Not Found.'); + return true; + } catch (err) { + throw new UnprocessableEntityException('Invalid JWT token'); + } } throw new UnprocessableEntityException('Invalid authentication'); diff --git a/src/modules/user-related/user-privilege/domain/usecases/user-privilege-configuration/handlers/update-user-privilege-configuration.helper.ts b/src/modules/user-related/user-privilege/domain/usecases/user-privilege-configuration/handlers/update-user-privilege-configuration.helper.ts index 509b891..2efc0a4 100644 --- a/src/modules/user-related/user-privilege/domain/usecases/user-privilege-configuration/handlers/update-user-privilege-configuration.helper.ts +++ b/src/modules/user-related/user-privilege/domain/usecases/user-privilege-configuration/handlers/update-user-privilege-configuration.helper.ts @@ -1,4 +1,8 @@ -import { EventBus, EventsHandler, IEventHandler } from '@nestjs/cqrs'; +import { + EventBus, + // EventsHandler, + IEventHandler, +} from '@nestjs/cqrs'; import { UserPrivilegeConfigUpdatedEvent } from '../../../entities/event/user-privilege-configuration-updated.event'; import { UserPrivilegeConfigurationHelper } from '../helpers/generate-user-privilege-configuration.helper'; import { UserPrivilegeDataService } from 'src/modules/user-related/user-privilege/data/service/user-privilege-data.service'; @@ -8,7 +12,9 @@ import { UserPrivilegeUpdatedEvent } from '../../../entities/event/user-privileg import { OPERATION } from 'src/core/strings/constants/base.constants'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; -@EventsHandler(UserPrivilegeConfigUpdatedEvent) +// FIXME => FIX HANDLER FOR ADD NEW MODULE PRIVILEGE CONFIGURATIONS + +// @EventsHandler(UserPrivilegeConfigUpdatedEvent) export class UserPrivilegeConfigUpdateHandler implements IEventHandler { diff --git a/src/modules/user-related/user-privilege/domain/usecases/user-privilege-configuration/managers/update-user-privilege-configuration.manager.ts b/src/modules/user-related/user-privilege/domain/usecases/user-privilege-configuration/managers/update-user-privilege-configuration.manager.ts index 5a61040..aea46b3 100644 --- a/src/modules/user-related/user-privilege/domain/usecases/user-privilege-configuration/managers/update-user-privilege-configuration.manager.ts +++ b/src/modules/user-related/user-privilege/domain/usecases/user-privilege-configuration/managers/update-user-privilege-configuration.manager.ts @@ -6,6 +6,7 @@ import { } from 'src/core/strings/constants/interface.constants'; import { BaseCustomManager } from 'src/core/modules/domain/usecase/managers/base-custom.manager'; import { UserPrivilegeConfigurationModel } from 'src/modules/user-related/user-privilege/data/models/user-privilege-configuration.model'; +import { UserPrivilegeConfigUpdatedEvent } from '../../../entities/event/user-privilege-configuration-updated.event'; @Injectable() export class UpdateUserPrivilegeConfigurationManager extends BaseCustomManager { @@ -54,10 +55,10 @@ export class UpdateUserPrivilegeConfigurationManager extends BaseCustomManager