diff --git a/src/core/strings/constants/module.constants.ts b/src/core/strings/constants/module.constants.ts index 912eae8..64fedc4 100644 --- a/src/core/strings/constants/module.constants.ts +++ b/src/core/strings/constants/module.constants.ts @@ -34,6 +34,7 @@ export enum MODULE_NAME { OTP_VERIFIER = 'otp-verifier', DATA_SCHEDULING = 'data-scheduling', + DATA_SCHEDULING_LOG = 'data-scheduling-log', DATA_SCHEDULING_DEFAULT = 'data-scheduling-default', DATA_SCHEDULING_ACTIVE = 'data-scheduling-active', DATA_SCHEDULING_SETUP = 'data-scheduling-setup', diff --git a/src/modules/configuration/data-scheduling/data-scheduling.module.ts b/src/modules/configuration/data-scheduling/data-scheduling.module.ts index a47c394..4c39a05 100644 --- a/src/modules/configuration/data-scheduling/data-scheduling.module.ts +++ b/src/modules/configuration/data-scheduling/data-scheduling.module.ts @@ -4,7 +4,10 @@ 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 { + DataSchedulingLogReadController, + DataSchedulingReadController, +} from './infrastructure/data-scheduling-read.controller'; import { DataSchedulingReadOrchestrator } from './domain/usecases/data-scheduling-read.orchestrator'; import { DataSchedulingDataController, @@ -39,8 +42,10 @@ import { JwtModule } from '@nestjs/jwt'; import { JWT_EXPIRED } from 'src/core/sessions/constants'; import { JWT_SECRET } from 'src/core/sessions/constants'; -import { DataSchedulingLogService } from './data/services/data-scheduling-log.service'; +import { DataSchedulingLogDataService } from './data/services/data-scheduling-log-data.service'; import { DataSchedulingLogModel } from './data/models/data-scheduling-log.model'; +import { DataSchedulingLogReadService } from './data/services/data-scheduling-log-read.service'; +import { IndexDataSchedulingLogManager } from './domain/usecases/managers/index-data-scheduling-log.manager'; @Module({ imports: [ @@ -60,6 +65,7 @@ import { DataSchedulingLogModel } from './data/models/data-scheduling-log.model' DataSchedulingReadController, DataSchedulingDefaultController, DataSchedulingSetupController, + DataSchedulingLogReadController, ], providers: [ SetupSchedulingGuard, @@ -76,7 +82,8 @@ import { DataSchedulingLogModel } from './data/models/data-scheduling-log.model' BatchConfirmDataSchedulingManager, BatchInactiveDataSchedulingManager, - DataSchedulingLogService, + DataSchedulingLogDataService, + DataSchedulingLogReadService, DataSchedulingDataService, DataSchedulingReadService, @@ -84,6 +91,7 @@ import { DataSchedulingLogModel } from './data/models/data-scheduling-log.model' DataSchedulingReadOrchestrator, DataSchedulingManager, + IndexDataSchedulingLogManager, DataSchedulingChangeStatusHandler, DataSchedulingCreatedHandler, diff --git a/src/modules/configuration/data-scheduling/data/services/data-scheduling-log.service.ts b/src/modules/configuration/data-scheduling/data/services/data-scheduling-log-data.service.ts similarity index 92% rename from src/modules/configuration/data-scheduling/data/services/data-scheduling-log.service.ts rename to src/modules/configuration/data-scheduling/data/services/data-scheduling-log-data.service.ts index b714c40..170e091 100644 --- a/src/modules/configuration/data-scheduling/data/services/data-scheduling-log.service.ts +++ b/src/modules/configuration/data-scheduling/data/services/data-scheduling-log-data.service.ts @@ -5,7 +5,7 @@ import { DataSchedulingLogModel } from '../models/data-scheduling-log.model'; import { Repository } from 'typeorm'; @Injectable() -export class DataSchedulingLogService { +export class DataSchedulingLogDataService { constructor( @InjectRepository(DataSchedulingLogModel, CONNECTION_NAME.DEFAULT) private repo: Repository, diff --git a/src/modules/configuration/data-scheduling/data/services/data-scheduling-log-read.service.ts b/src/modules/configuration/data-scheduling/data/services/data-scheduling-log-read.service.ts new file mode 100644 index 0000000..21943ab --- /dev/null +++ b/src/modules/configuration/data-scheduling/data/services/data-scheduling-log-read.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { DataSchedulingLogEntity } from '../../domain/entities/data-scheduling.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { BaseReadService } from 'src/core/modules/data/service/base-read.service'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; +import { DataSchedulingLogModel } from '../models/data-scheduling-log.model'; + +@Injectable() +export class DataSchedulingLogReadService extends BaseReadService { + constructor( + @InjectRepository(DataSchedulingLogModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} 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 index b27759c..1f4da92 100644 --- 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 @@ -1,18 +1,25 @@ 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 { + DataSchedulingEntity, + DataSchedulingLogEntity, +} 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'; +import { IndexDataSchedulingLogManager } from './managers/index-data-scheduling-log.manager'; +import { DataSchedulingLogReadService } from '../../data/services/data-scheduling-log-read.service'; @Injectable() export class DataSchedulingReadOrchestrator extends BaseReadOrchestrator { constructor( private indexManager: IndexDataSchedulingManager, + private indexLogManager: IndexDataSchedulingLogManager, private detailManager: DetailDataSchedulingManager, private serviceData: DataSchedulingReadService, + private logServiceData: DataSchedulingLogReadService, ) { super(); } @@ -24,6 +31,16 @@ export class DataSchedulingReadOrchestrator extends BaseReadOrchestrator> { + this.indexLogManager.setFilterParam(params); + this.indexLogManager.setService( + this.logServiceData, + TABLE_NAME.DATA_SCHEDULING_LOG, + ); + await this.indexLogManager.execute(); + return this.indexLogManager.getResult(); + } + async detail(dataId: string): Promise { this.detailManager.setData(dataId); this.detailManager.setService(this.serviceData, TABLE_NAME.DATA_SCHEDULING); diff --git a/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-change-status.handler.ts b/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-change-status.handler.ts index b7c95dd..59cb7da 100644 --- a/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-change-status.handler.ts +++ b/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-change-status.handler.ts @@ -7,7 +7,7 @@ import { SCHEDULING_LOG_TYPE_ENUM, } from '../../entities/data-scheduling.entity'; import { Logger } from '@nestjs/common'; -import { DataSchedulingLogService } from '../../../data/services/data-scheduling-log.service'; +import { DataSchedulingLogDataService } from '../../../data/services/data-scheduling-log-data.service'; @EventsHandler(DataSchedulingChangeStatusEvent) export class DataSchedulingChangeStatusHandler @@ -15,43 +15,46 @@ export class DataSchedulingChangeStatusHandler { private readonly logger = new Logger(DataSchedulingChangeStatusHandler.name); - constructor(private service: DataSchedulingLogService) {} + constructor(private service: DataSchedulingLogDataService) {} async handle(event: DataSchedulingChangeStatusEvent) { - const oldData = event?.data?.old; - const newData = event?.data?.data; + // Prevent execution if the event data is null, which can happen if triggered from the default percentage update service. + if (event.data?.data) { + const oldData = event?.data?.old; + const newData = event?.data?.data; - const oldStatus = capitalizeEachWord(oldData?.status); - const newStatus = capitalizeEachWord(newData.status); + const oldStatus = capitalizeEachWord(oldData?.status); + const newStatus = capitalizeEachWord(newData?.status); - const scheduleName = newData?.name || 'an item'; - const editorName = newData.editor_name || 'System'; - const description = `

${editorName} changed the status of ${scheduleName} from ${oldStatus} to ${newStatus}.

`; + const scheduleName = newData?.name || 'an item'; + const editorName = newData.editor_name || 'System'; + const description = `

${editorName} changed the status of ${scheduleName} from ${oldStatus} to ${newStatus}.

`; - const payload: DataSchedulingLogEntity = { - type: SCHEDULING_LOG_TYPE_ENUM.DATA_SCHEDULING, - action: SCHEDULING_LOG_ACTION_ENUM.CHANGE_STATUS, - log_created_at: new Date().getTime(), + const payload: DataSchedulingLogEntity = { + type: SCHEDULING_LOG_TYPE_ENUM.DATA_SCHEDULING, + action: SCHEDULING_LOG_ACTION_ENUM.CHANGE_STATUS, + log_created_at: new Date().getTime(), - data_id: newData?.id, - name: newData?.name, - indexing_key: newData?.indexing_key, - schedule_date_from: newData?.schedule_date_from, - schedule_date_to: newData?.schedule_date_to, + data_id: newData?.id, + name: newData?.name, + indexing_key: newData?.indexing_key, + schedule_date_from: newData?.schedule_date_from, + schedule_date_to: newData?.schedule_date_to, - status: newData?.status, - creator_id: newData?.creator_id, - creator_name: newData?.creator_name, - editor_id: newData?.editor_id, - editor_name: newData?.editor_name, - created_at: newData?.created_at, - updated_at: newData?.updated_at, - description: description, - }; + status: newData?.status, + creator_id: newData?.creator_id, + creator_name: newData?.creator_name, + editor_id: newData?.editor_id, + editor_name: newData?.editor_name, + created_at: newData?.created_at, + updated_at: newData?.updated_at, + description: description, + }; - await this.service.create(payload as any); - this.logger.verbose( - `[SCHEDULING LOG] Change status data for ID: ${payload.data_id}`, - ); + await this.service.create(payload as any); + this.logger.verbose( + `[SCHEDULING LOG] Change status data for ID: ${payload.data_id}`, + ); + } } } diff --git a/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-created.handler.ts b/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-created.handler.ts index b1c6c1d..155d8f1 100644 --- a/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-created.handler.ts +++ b/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-created.handler.ts @@ -7,7 +7,7 @@ import { } from '../../entities/data-scheduling.entity'; import { decryptionTotal } from '../../../infrastructure/helpers'; import { Logger } from '@nestjs/common'; -import { DataSchedulingLogService } from '../../../data/services/data-scheduling-log.service'; +import { DataSchedulingLogDataService } from '../../../data/services/data-scheduling-log-data.service'; @EventsHandler(DataSchedulingCreatedEvent) export class DataSchedulingCreatedHandler @@ -15,7 +15,7 @@ export class DataSchedulingCreatedHandler { private readonly logger = new Logger(DataSchedulingCreatedHandler.name); - constructor(private service: DataSchedulingLogService) {} + constructor(private service: DataSchedulingLogDataService) {} async handle(event: DataSchedulingCreatedEvent) { const data = event?.data?.data; diff --git a/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-deleted.handler.ts b/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-deleted.handler.ts index d9a13b7..4ad1d42 100644 --- a/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-deleted.handler.ts +++ b/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-deleted.handler.ts @@ -6,7 +6,7 @@ import { SCHEDULING_LOG_TYPE_ENUM, } from '../../entities/data-scheduling.entity'; import { Logger } from '@nestjs/common'; -import { DataSchedulingLogService } from '../../../data/services/data-scheduling-log.service'; +import { DataSchedulingLogDataService } from '../../../data/services/data-scheduling-log-data.service'; @EventsHandler(DataSchedulingDeletedEvent) export class DataSchedulingDeletedHandler @@ -14,7 +14,7 @@ export class DataSchedulingDeletedHandler { private readonly logger = new Logger(DataSchedulingDeletedHandler.name); - constructor(private service: DataSchedulingLogService) {} + constructor(private service: DataSchedulingLogDataService) {} async handle(event: DataSchedulingDeletedEvent) { const deletedData = event?.data?.data; diff --git a/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-updated.handler.ts b/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-updated.handler.ts index 2d45674..67b7cf8 100644 --- a/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-updated.handler.ts +++ b/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-updated.handler.ts @@ -10,7 +10,7 @@ import { encryptionTotal, } from '../../../infrastructure/helpers'; import { Logger } from '@nestjs/common'; -import { DataSchedulingLogService } from '../../../data/services/data-scheduling-log.service'; +import { DataSchedulingLogDataService } from '../../../data/services/data-scheduling-log-data.service'; @EventsHandler(DataSchedulingUpdatedEvent) export class DataSchedulingUpdatedHandler @@ -18,7 +18,7 @@ export class DataSchedulingUpdatedHandler { private readonly logger = new Logger(DataSchedulingUpdatedHandler.name); - constructor(private service: DataSchedulingLogService) {} + constructor(private service: DataSchedulingLogDataService) {} // Map for readable labels private readonly labelMap: { [key: string]: string } = { 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 5866538..97d68ba 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 @@ -2,7 +2,12 @@ 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 { + DataSchedulingDefaultEntity, + DataSchedulingLogEntity, + SCHEDULING_LOG_ACTION_ENUM, + SCHEDULING_LOG_TYPE_ENUM, +} from '../../entities/data-scheduling.entity'; import { InjectRepository } from '@nestjs/typeorm'; import { DataSchedulingDefaultModel } from '../../../data/models/data-scheduling-default.model'; import { Repository } from 'typeorm'; @@ -10,6 +15,7 @@ import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { SelectQueryBuilder } from 'typeorm'; import { EventBus } from '@nestjs/cqrs'; import { DataSchedulingChangeStatusEvent } from '../../entities/event/data-scheduling-change-status.event'; +import { DataSchedulingLogModel } from '../../../data/models/data-scheduling-log.model'; @Injectable() export class DataSchedulingManager { @@ -21,6 +27,9 @@ export class DataSchedulingManager { @InjectRepository(DataSchedulingDefaultModel) private repository: Repository, + + @InjectRepository(DataSchedulingLogModel) + private repositoryLog: Repository, ) {} private getUser(): UsersSession { @@ -60,7 +69,35 @@ export class DataSchedulingManager { created_at: dateNow, updated_at: dateNow, }; + const saveData = await this.repository.save(payload); + + if (existData?.default_value !== saveData?.default_value) { + const description = existData?.id + ? `

${saveData.editor_name} mengubah pengaturan Default Percentage dari ${existData.default_value}% menjadi ${saveData.default_value}%.

` + : `

${saveData.creator_name} membuat pengaturan Default Percentage dengan value ${saveData.default_value}%.

`; + + const logPayload: DataSchedulingLogEntity = { + type: SCHEDULING_LOG_TYPE_ENUM.DEFAULT_PERCENTAGE, + action: existData?.id + ? SCHEDULING_LOG_ACTION_ENUM.UPDATE + : SCHEDULING_LOG_ACTION_ENUM.CREATE, + log_created_at: new Date().getTime(), + status: undefined, + + data_id: saveData?.id, + creator_id: saveData?.creator_id, + creator_name: saveData?.creator_name, + editor_id: saveData?.editor_id, + editor_name: saveData?.editor_name, + created_at: saveData?.created_at, + updated_at: saveData?.updated_at, + default_value: saveData?.default_value, + description: description, + }; + + await this.repositoryLog.save(logPayload as any); + } await this.publishEventUpdates(); return saveData; } diff --git a/src/modules/configuration/data-scheduling/domain/usecases/managers/index-data-scheduling-log.manager.ts b/src/modules/configuration/data-scheduling/domain/usecases/managers/index-data-scheduling-log.manager.ts new file mode 100644 index 0000000..124727d --- /dev/null +++ b/src/modules/configuration/data-scheduling/domain/usecases/managers/index-data-scheduling-log.manager.ts @@ -0,0 +1,95 @@ +import { Injectable } from '@nestjs/common'; +import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; +import { DataSchedulingLogEntity } 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 IndexDataSchedulingLogManager 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}.type`, + `${this.tableName}.action`, + `${this.tableName}.log_created_at`, + `${this.tableName}.data_id`, + `${this.tableName}.default_value`, + `${this.tableName}.description`, + + `${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 { + if (this.filterParam.schedule_date_from) { + const dateFrom = this.filterParam.schedule_date_from; + queryBuilder.andWhere('schedule_date_from >= :dateFrom', { + dateFrom: dateFrom, + }); + } + + if (this.filterParam.schedule_date_to) { + const dateTo = this.filterParam.schedule_date_to; + queryBuilder.andWhere('schedule_date_from <= :dateTo', { + dateTo: dateTo, + }); + } + 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/infrastructure/data-scheduling-read.controller.ts b/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-read.controller.ts index 4d1f17f..669c12f 100644 --- a/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-read.controller.ts +++ b/src/modules/configuration/data-scheduling/infrastructure/data-scheduling-read.controller.ts @@ -2,11 +2,14 @@ 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 { + DataSchedulingEntity, + DataSchedulingLogEntity, +} 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'; +import { ExcludePrivilege, Public } from 'src/core/guards'; @ApiTags(`${MODULE_NAME.DATA_SCHEDULING.split('-').join(' ')} - read`) @Controller(`v1/${MODULE_NAME.DATA_SCHEDULING}`) @@ -28,3 +31,20 @@ export class DataSchedulingReadController { return await this.orchestrator.detail(id); } } + +@ApiTags(`${MODULE_NAME.DATA_SCHEDULING_LOG.split('-').join(' ')} - read`) +@Controller(`v1/${MODULE_NAME.DATA_SCHEDULING_LOG}`) +@Public(false) +@ApiBearerAuth('JWT') +export class DataSchedulingLogReadController { + constructor(private orchestrator: DataSchedulingReadOrchestrator) {} + + @Get() + @Pagination() + @ExcludePrivilege() + async index( + @Query() params: FilterDataSchedulingDto, + ): Promise> { + return await this.orchestrator.indexLog(params); + } +}