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'; import { ObatService } from '../obat/obat.service'; @Injectable() export class ValidationService { constructor( private prisma: PrismaService, private rekamMedisService: RekammedisService, private tindakanDokterService: TindakanDokterService, private obatService: ObatService, ) {} private handlers: Record< string, { approveCreate?: (queue: any) => Promise; approveUpdate?: (queue: any) => Promise; approveDelete?: (queue: any) => Promise; } > = { rekam_medis: { approveCreate: async (queue: any) => { const payload = queue.dataPayload as Partial; 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; return this.rekamMedisService.updateRekamMedisToDBAndBlockchain( queue.record_id, payload as CreateRekamMedisDto, Number(queue.user_id_request), ); }, approveDelete: async (queue: any) => { 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, ); }, }, 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), ); }, approveDelete: async (queue: any) => { return this.obatService.deleteObatFromDBAndBlockchain( Number(queue.record_id), queue.user_id_request, ); }, }, }; async getAllValidationsQueue(params: any) { const { take, skip, page, orderBy, order, search, 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({ take, skip: skipValue, orderBy: orderBy ? { [orderBy]: order || 'asc' } : { created_at: 'desc' }, where: { record_id: search ? { contains: search, } : 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({ where: { record_id: search ? { contains: search, } : 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: { 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; } } }