diff --git a/backend/api/src/modules/obat/obat.service.ts b/backend/api/src/modules/obat/obat.service.ts index cc1815e..dd7df5b 100644 --- a/backend/api/src/modules/obat/obat.service.ts +++ b/backend/api/src/modules/obat/obat.service.ts @@ -367,6 +367,14 @@ export class ObatService { } async countObat() { - return this.prisma.pemberian_obat.count(); + return this.prisma.pemberian_obat.count({ + where: { + OR: [ + { deleted_status: null }, + { deleted_status: 'DELETE_VALIDATION' }, + { deleted_status: { not: 'DELETED' } }, + ], + }, + }); } } diff --git a/backend/api/src/modules/rekammedis/rekammedis.service.ts b/backend/api/src/modules/rekammedis/rekammedis.service.ts index 4309aed..62b5138 100644 --- a/backend/api/src/modules/rekammedis/rekammedis.service.ts +++ b/backend/api/src/modules/rekammedis/rekammedis.service.ts @@ -563,6 +563,11 @@ export class RekammedisService { waktu_visit: { gte: sevenDaysAgo, }, + OR: [ + { deleted_status: null }, + { deleted_status: 'DELETE_VALIDATION' }, + { deleted_status: { not: 'DELETED' } }, + ], }, _count: { id_visit: true, @@ -596,6 +601,14 @@ export class RekammedisService { } async countRekamMedis() { - return this.prisma.rekam_medis.count(); + return this.prisma.rekam_medis.count({ + where: { + OR: [ + { deleted_status: null }, + { deleted_status: 'DELETE_VALIDATION' }, + { deleted_status: { not: 'DELETED' } }, + ], + }, + }); } } diff --git a/backend/api/src/modules/tindakandokter/tindakandokter.service.ts b/backend/api/src/modules/tindakandokter/tindakandokter.service.ts index e1d9e83..b17c59f 100644 --- a/backend/api/src/modules/tindakandokter/tindakandokter.service.ts +++ b/backend/api/src/modules/tindakandokter/tindakandokter.service.ts @@ -102,6 +102,11 @@ export class TindakanDokterService { kategori_tindakanArray.length > 0 ? { in: kategori_tindakanArray } : undefined, + OR: [ + { deleted_status: null }, + { deleted_status: 'DELETE_VALIDATION' }, + { deleted_status: { not: 'DELETED' } }, + ], }, }); @@ -411,6 +416,14 @@ export class TindakanDokterService { } async countTindakanDokter() { - return this.prisma.pemberian_tindakan.count(); + return this.prisma.pemberian_tindakan.count({ + where: { + OR: [ + { deleted_status: null }, + { deleted_status: 'DELETE_VALIDATION' }, + { deleted_status: { not: 'DELETED' } }, + ], + }, + }); } } diff --git a/backend/api/src/modules/validation/validation.service.ts b/backend/api/src/modules/validation/validation.service.ts index 60ce9f1..ed12bc7 100644 --- a/backend/api/src/modules/validation/validation.service.ts +++ b/backend/api/src/modules/validation/validation.service.ts @@ -221,19 +221,81 @@ export class ValidationService { } } + 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'); } - const updated = await this.prisma.validation_queue.update({ - where: { id: validationQueue.id }, - data: { - status: 'REJECTED', - user_id_process: Number(user.sub), - processed_at: new Date(), - }, - }); - return updated; + + 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; + } } } diff --git a/frontend/hospital-log/src/components/dashboard/DataTable.vue b/frontend/hospital-log/src/components/dashboard/DataTable.vue index 2637d0e..c490d27 100644 --- a/frontend/hospital-log/src/components/dashboard/DataTable.vue +++ b/frontend/hospital-log/src/components/dashboard/DataTable.vue @@ -31,7 +31,6 @@ const hasUserIdProcessColumn = () => const formatCellValue = (item: T, columnKey: keyof T) => { const value = item[columnKey]; - if (columnKey === "event" && typeof value === "string") { const segments = value.split("_"); @@ -123,10 +122,12 @@ const handleDeleteCancel = () => { :key="item.id" :class="[ 'hover:bg-dark hover:text-light transition-colors', - (item as Record).isTampered ? 'bg-red-300 text-dark' : '' + (item as Record).isTampered ? 'bg-red-300 text-dark' : item.deleted_status ? + item.deleted_status === 'DELETE_VALIDATION' ? 'bg-yellow-100 text-dark' : 'bg-gray-300 text-dark' : '', ]" > +
+ + {{ formatCellValue(item, column.key) }} + + + + + + +
+
+ + {{ formatCellValue(item, column.key) }} + + + + + + +
+ {{ + column.key !== columns[0]?.key + ? formatCellValue(item, column.key) + : "" + }} +