hospital-log/backend/api/src/modules/validation/validation.service.ts

346 lines
11 KiB
TypeScript
Raw Normal View History

import { BadRequestException, Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { ActiveUserPayload } from '../auth/decorator/current-user.decorator';
import { RekammedisService } from '../rekammedis/rekammedis.service';
import { CreateRekamMedisDto } from '../rekammedis/dto/create-rekammedis.dto';
import { TindakanDokterService } from '../tindakandokter/tindakandokter.service';
2025-11-26 08:28:04 +00:00
import { ObatService } from '../obat/obat.service';
@Injectable()
export class ValidationService {
constructor(
private prisma: PrismaService,
private rekamMedisService: RekammedisService,
private tindakanDokterService: TindakanDokterService,
2025-11-26 08:28:04 +00:00
private obatService: ObatService,
) {}
private handlers: Record<
string,
{
approveCreate?: (queue: any) => Promise<any>;
approveUpdate?: (queue: any) => Promise<any>;
approveDelete?: (queue: any) => Promise<any>;
}
> = {
rekam_medis: {
approveCreate: async (queue: any) => {
const payload = queue.dataPayload as Partial<CreateRekamMedisDto>;
const result =
await this.rekamMedisService.createRekamMedisToDBAndBlockchain(
payload as CreateRekamMedisDto,
Number(queue.user_id_request),
);
return {
...result,
id: result.id_visit,
};
},
approveUpdate: async (queue: any) => {
const payload = queue.dataPayload as Partial<CreateRekamMedisDto>;
return this.rekamMedisService.updateRekamMedisToDBAndBlockchain(
queue.record_id,
payload as CreateRekamMedisDto,
Number(queue.user_id_request),
);
},
approveDelete: async (queue: any) => {
2025-11-28 03:34:50 +00:00
return this.rekamMedisService.deleteRekamMedisFromDBAndBlockchain(
queue.record_id,
Number(queue.user_id_request),
);
},
},
pemberian_tindakan: {
approveCreate: async (queue: any) => {
const payload = queue.dataPayload;
const result =
await this.tindakanDokterService.createTindakanDokterToDBAndBlockchain(
payload,
Number(queue.user_id_request),
);
return {
...result,
id: result.id,
};
},
approveUpdate: async (queue: any) => {
const payload = queue.dataPayload;
return await this.tindakanDokterService.updateTindakanDokterToDBAndBlockchain(
queue.record_id,
payload,
Number(queue.user_id_request),
);
},
approveDelete: async (queue: any) => {
return this.tindakanDokterService.deleteTindakanDokterFromDBAndBlockchain(
Number(queue.record_id),
queue.user_id_request,
);
},
},
2025-11-26 08:28:04 +00:00
pemberian_obat: {
approveCreate: async (queue: any) => {
const payload = queue.dataPayload;
const result = await this.obatService.createObatToDBAndBlockchain(
payload,
Number(queue.user_id_request),
);
return {
...result,
id: result.id,
};
},
approveUpdate: async (queue: any) => {
const payload = queue.dataPayload;
return await this.obatService.updateObatToDBAndBlockchain(
queue.record_id,
payload,
Number(queue.user_id_request),
);
},
2025-11-28 03:34:50 +00:00
approveDelete: async (queue: any) => {
return this.obatService.deleteObatFromDBAndBlockchain(
Number(queue.record_id),
queue.user_id_request,
);
},
2025-11-26 08:28:04 +00:00
},
};
2025-12-01 04:17:47 +00:00
async getAllValidationsQueue(params: any) {
const {
take,
skip,
page,
orderBy,
order,
2025-12-01 04:22:27 +00:00
search,
2025-12-01 04:17:47 +00:00
kelompok_data,
aksi,
status,
} = params;
const skipValue = skip
? parseInt(skip.toString())
: page
? (parseInt(page.toString()) - 1) * take
: 0;
console.log('Params', params);
const result = await this.prisma.validation_queue.findMany({
2025-12-01 04:17:47 +00:00
take,
skip: skipValue,
orderBy: orderBy ? { [orderBy]: order || 'asc' } : { created_at: 'desc' },
where: {
2025-12-01 04:22:27 +00:00
record_id: search
2025-12-01 04:17:47 +00:00
? {
2025-12-01 04:22:27 +00:00
contains: search,
2025-12-01 04:17:47 +00:00
}
: undefined,
table_name:
kelompok_data && kelompok_data !== 'all'
? kelompok_data.toLowerCase()
: undefined,
action: aksi && aksi !== 'all' ? aksi.toUpperCase() : undefined,
status: status && status !== 'all' ? status.toUpperCase() : undefined,
},
});
const totalCount = await this.prisma.validation_queue.count({
2025-12-01 04:17:47 +00:00
where: {
2025-12-01 04:22:27 +00:00
record_id: search
2025-12-01 04:17:47 +00:00
? {
2025-12-01 04:22:27 +00:00
contains: search,
2025-12-01 04:17:47 +00:00
}
: undefined,
table_name:
kelompok_data && kelompok_data !== 'all'
? kelompok_data.toLowerCase()
: undefined,
action: aksi && aksi !== 'all' ? aksi.toUpperCase() : undefined,
status: status && status !== 'all' ? status.toUpperCase() : undefined,
},
});
return { data: result, totalCount };
}
async getAllValidationQueueDashboard() {
const result = await this.prisma.validation_queue.findMany({
where: { status: 'PENDING' },
take: 5,
orderBy: { created_at: 'desc' },
});
const totalCount = await this.prisma.validation_queue.count({
where: { status: 'PENDING' },
});
return { data: result, totalCount };
}
// For service internal use
async getValidationQueueById(id: number) {
return await this.prisma.validation_queue.findUnique({
where: { id },
});
}
// For front-end detail view
async getValidationQueue(id: number) {
const result = await this.getValidationQueueById(id);
if (!result) return null;
if (result.action !== 'UPDATE') return result;
const previousLog = await this.fetchPreviousLog(
result.table_name,
result.record_id,
);
return { previousLog, ...result };
}
private async fetchPreviousLog(tableName: string, recordId: string) {
if (!recordId) return null;
switch (tableName) {
case 'pemberian_tindakan':
return this.prisma.pemberian_tindakan.findUnique({
where: { id: Number(recordId) },
});
case 'rekam_medis':
return this.prisma.rekam_medis.findUnique({
where: { id_visit: recordId },
});
case 'pemberian_obat':
return this.prisma.pemberian_obat.findUnique({
where: { id: Number(recordId) },
});
default:
return null;
}
}
private async approveWithHandler(queue: any) {
const handler = this.handlers[queue.table_name];
if (!handler) throw new Error('Unsupported table');
switch (queue.action) {
case 'CREATE':
if (!handler.approveCreate)
throw new Error('Create not implemented for table');
return handler.approveCreate(queue);
case 'UPDATE':
if (!handler.approveUpdate)
throw new Error('Update not implemented for table');
return handler.approveUpdate(queue);
case 'DELETE':
if (!handler.approveDelete)
throw new Error('Delete not implemented for table');
return handler.approveDelete(queue);
default:
throw new Error('Unknown action');
}
}
async approveValidation(id: number, user: ActiveUserPayload) {
const validationQueue = await this.getValidationQueueById(id);
if (!validationQueue) {
throw new BadRequestException('Validation queue not found');
}
if (!validationQueue.dataPayload) {
throw new Error('Data payload is missing');
}
try {
const approvalResult = await this.approveWithHandler(validationQueue);
console.log('Approval result:', approvalResult);
const updated = await this.prisma.validation_queue.update({
where: { id: validationQueue.id },
data: {
2025-11-28 03:34:50 +00:00
record_id:
validationQueue.table_name === 'rekam_medis'
? approvalResult.id_visit
: approvalResult.id.toString(),
status: 'APPROVED',
user_id_process: Number(user.sub),
processed_at: new Date(),
},
});
return { ...updated, approvalResult };
} catch (error) {
console.error('Error approving validation:', (error as Error).message);
throw error;
}
}
determineIdType(tableName: string, recordId: string) {
if (tableName === 'rekam_medis') {
return recordId;
} else if (
tableName === 'pemberian_tindakan' ||
tableName === 'pemberian_obat'
) {
return Number(recordId); // numeric ID
} else {
throw new Error('Unsupported table for ID determination');
}
}
async rejectValidation(id: number, user: ActiveUserPayload) {
const validationQueue = await this.getValidationQueueById(id);
if (!validationQueue) {
throw new Error('Validation queue not found');
}
let recordId: number | string = '';
if (
validationQueue.status === 'PENDING' &&
validationQueue.action === 'DELETE'
) {
recordId = this.determineIdType(
validationQueue.table_name,
validationQueue.record_id,
);
}
try {
const rejectedResponse = await this.prisma.$transaction(async (tx) => {
let updatedDeleteStatus = null;
if (validationQueue.action === 'DELETE') {
switch (validationQueue.table_name) {
case 'rekam_medis':
updatedDeleteStatus = await tx.rekam_medis.update({
where: { id_visit: recordId as string },
data: { deleted_status: null },
});
break;
case 'pemberian_tindakan':
updatedDeleteStatus = await tx.pemberian_tindakan.update({
where: { id: recordId as number },
data: { deleted_status: null },
});
break;
case 'pemberian_obat':
updatedDeleteStatus = await tx.pemberian_obat.update({
where: { id: recordId as number },
data: { deleted_status: null },
});
break;
default:
throw new Error('Unsupported table for delete rejection');
}
}
const updatedQueue = await tx.validation_queue.update({
where: { id: validationQueue.id },
data: {
status: 'REJECTED',
user_id_process: Number(user.sub),
processed_at: new Date(),
},
});
return {
...updatedQueue,
updatedDeleteStatus,
};
});
return rejectedResponse;
} catch (error) {
console.error('Error rejecting validation:', (error as Error).message);
throw error;
}
}
}