pos-be/src/modules/configuration/data-scheduling/domain/usecases/handlers/data-scheduling-updated.han...

149 lines
4.9 KiB
TypeScript

import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
import { DataSchedulingUpdatedEvent } from '../../entities/event/data-scheduling-updated.event';
import {
DataSchedulingLogEntity,
SCHEDULING_LOG_ACTION_ENUM,
SCHEDULING_LOG_TYPE_ENUM,
} from '../../entities/data-scheduling.entity';
import {
decryptionTotal,
encryptionTotal,
} from '../../../infrastructure/helpers';
import { Logger } from '@nestjs/common';
import { DataSchedulingLogDataService } from '../../../data/services/data-scheduling-log-data.service';
@EventsHandler(DataSchedulingUpdatedEvent)
export class DataSchedulingUpdatedHandler
implements IEventHandler<DataSchedulingUpdatedEvent>
{
private readonly logger = new Logger(DataSchedulingUpdatedHandler.name);
constructor(private service: DataSchedulingLogDataService) {}
// Map for readable labels
private readonly labelMap: { [key: string]: string } = {
name: 'Name',
indexing_key: 'Total Data',
schedule_date_from: 'Start Date',
schedule_date_to: 'End Date',
};
// Relevant keys for comparing changes
private readonly keysToCompare: string[] = [
'name',
'indexing_key',
'schedule_date_from',
'schedule_date_to',
];
async handle(event: DataSchedulingUpdatedEvent) {
const oldData = event?.data?.old;
// Decrypt oldData.indexing_key here before comparison
if (oldData?.indexing_key !== undefined && oldData?.indexing_key !== null) {
oldData.indexing_key = decryptionTotal(oldData.indexing_key);
}
const newData = event?.data?.data;
// Decrypt newData.indexing_key here before comparison
if (newData?.indexing_key !== undefined && newData?.indexing_key !== null) {
newData.indexing_key = decryptionTotal(newData.indexing_key);
}
const changingData = this.getChangingData(oldData, newData);
const description = this.generateDescription(
oldData,
newData,
changingData,
);
const payload: DataSchedulingLogEntity = {
type: SCHEDULING_LOG_TYPE_ENUM.DATA_SCHEDULING,
action: SCHEDULING_LOG_ACTION_ENUM.UPDATE,
log_created_at: new Date().getTime(),
data_id: newData?.id,
name: newData?.name,
indexing_key: encryptionTotal(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,
};
await this.service.create(payload as any);
this.logger.verbose(
`[SCHEDULING LOG] Update data for ID: ${payload.data_id}`,
);
}
/**
* Compares old and new data to find changes.
* @param oldData Data before the change.
* @param newData Data after the change.
* @returns An object containing the old and new changed data.
*/
private getChangingData(oldData: any, newData: any): { old: any; new: any } {
const changingData: { old: any; new: any } = { old: {}, new: {} };
this.keysToCompare.forEach((key) => {
// Ensure comparisons are made on decrypted values if decryption happens before this
if (oldData?.[key] !== newData?.[key]) {
changingData.old[key] = oldData?.[key];
changingData.new[key] = newData?.[key];
}
});
return changingData;
}
/**
* Generates an HTML description string based on data changes.
* Includes the name from oldData for identification.
* @param oldData Old data, used to get the name of the item.
* @param newData New data containing editor information.
* @param changingData An object containing the changed data.
* @returns The HTML string of the change description.
*/
private generateDescription(
oldData: any,
newData: any,
changingData: { old: any; new: any },
): string {
const editorName = newData.editor_name || 'System';
const itemName = oldData?.name || 'an item';
let description = `<p><b>${editorName}</b> has updated schedule for <b>${itemName}</b>.`;
if (Object.keys(changingData.old).length > 0) {
description += ` Change details:<ul>`;
for (const key in changingData.old) {
if (Object.prototype.hasOwnProperty.call(changingData.old, key)) {
const label = this.labelMap[key] || key;
let oldValue = changingData.old[key] || 'empty';
let newValue = changingData.new[key] || 'empty';
// Add '%' suffix if the key is 'indexing_key'
if (key === 'indexing_key') {
oldValue = `${oldValue}%`;
newValue = `${newValue}%`;
}
description += `<li><b>${label}</b> changed from <i>${oldValue}</i> to <i>${newValue}</i>.</li>`;
}
}
description += `</ul></p>`;
} else {
description += ` No significant data detail changes.</p>`;
}
return description;
}
}