feat: validation delete tindakan
This commit is contained in:
parent
4d4565299d
commit
cbcf4ad897
|
|
@ -112,6 +112,7 @@ export class AuditService {
|
||||||
).filter((record): record is AuditRecordPayload => record !== null);
|
).filter((record): record is AuditRecordPayload => record !== null);
|
||||||
|
|
||||||
if (records.length > 0) {
|
if (records.length > 0) {
|
||||||
|
console.log(records);
|
||||||
await this.prisma.$transaction(
|
await this.prisma.$transaction(
|
||||||
records.map((record) =>
|
records.map((record) =>
|
||||||
this.prisma.audit.upsert({
|
this.prisma.audit.upsert({
|
||||||
|
|
@ -121,7 +122,7 @@ export class AuditService {
|
||||||
event: record.event,
|
event: record.event,
|
||||||
payload: record.payload,
|
payload: record.payload,
|
||||||
timestamp: record.timestamp,
|
timestamp: record.timestamp,
|
||||||
user_id: record.user_id,
|
user_id: BigInt(record.user_id),
|
||||||
last_sync: record.last_sync,
|
last_sync: record.last_sync,
|
||||||
result: record.result,
|
result: record.result,
|
||||||
},
|
},
|
||||||
|
|
@ -133,7 +134,6 @@ export class AuditService {
|
||||||
|
|
||||||
if (nextBookmark === '' || nextBookmark === bookmark) {
|
if (nextBookmark === '' || nextBookmark === bookmark) {
|
||||||
const completeData = { status: 'COMPLETED' };
|
const completeData = { status: 'COMPLETED' };
|
||||||
this.logger.log('Mengirim selesai via WebSocket:', completeData);
|
|
||||||
this.auditGateway.sendComplete(completeData);
|
this.auditGateway.sendComplete(completeData);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -213,6 +213,7 @@ export class AuditService {
|
||||||
const timestamp = this.parseTimestamp(value.timestamp) ?? now;
|
const timestamp = this.parseTimestamp(value.timestamp) ?? now;
|
||||||
const userId = value.user_id;
|
const userId = value.user_id;
|
||||||
const blockchainHash: string | undefined = value.payload;
|
const blockchainHash: string | undefined = value.payload;
|
||||||
|
let data: any = null;
|
||||||
|
|
||||||
if (!blockchainHash) {
|
if (!blockchainHash) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -224,6 +225,7 @@ export class AuditService {
|
||||||
const obatId = this.extractNumericId(logId);
|
const obatId = this.extractNumericId(logId);
|
||||||
if (obatId !== null) {
|
if (obatId !== null) {
|
||||||
const obat = await this.obatService.getObatById(obatId);
|
const obat = await this.obatService.getObatById(obatId);
|
||||||
|
data = obat;
|
||||||
if (obat) {
|
if (obat) {
|
||||||
dbHash = this.obatService.createHashingPayload({
|
dbHash = this.obatService.createHashingPayload({
|
||||||
obat: obat.obat,
|
obat: obat.obat,
|
||||||
|
|
@ -237,6 +239,7 @@ export class AuditService {
|
||||||
if (rekamMedisId) {
|
if (rekamMedisId) {
|
||||||
const rekamMedis =
|
const rekamMedis =
|
||||||
await this.rekamMedisService.getRekamMedisById(rekamMedisId);
|
await this.rekamMedisService.getRekamMedisById(rekamMedisId);
|
||||||
|
data = rekamMedis;
|
||||||
if (rekamMedis) {
|
if (rekamMedis) {
|
||||||
dbHash = this.rekamMedisService.createHashingPayload({
|
dbHash = this.rekamMedisService.createHashingPayload({
|
||||||
dokter_id: 123,
|
dokter_id: 123,
|
||||||
|
|
@ -252,6 +255,7 @@ export class AuditService {
|
||||||
if (tindakanId !== null) {
|
if (tindakanId !== null) {
|
||||||
const tindakanDokter =
|
const tindakanDokter =
|
||||||
await this.tindakanDokterService.getTindakanDokterById(tindakanId);
|
await this.tindakanDokterService.getTindakanDokterById(tindakanId);
|
||||||
|
data = tindakanDokter;
|
||||||
if (tindakanDokter) {
|
if (tindakanDokter) {
|
||||||
dbHash = this.tindakanDokterService.createHashingPayload({
|
dbHash = this.tindakanDokterService.createHashingPayload({
|
||||||
id_visit: tindakanDokter.id_visit,
|
id_visit: tindakanDokter.id_visit,
|
||||||
|
|
@ -270,10 +274,13 @@ export class AuditService {
|
||||||
|
|
||||||
let isNotTampered = false;
|
let isNotTampered = false;
|
||||||
const eventType = logEntry.value.event?.split('_').at(-1);
|
const eventType = logEntry.value.event?.split('_').at(-1);
|
||||||
|
const isDeleteEvent = eventType === 'deleted';
|
||||||
|
const hasRow = Boolean(data);
|
||||||
|
|
||||||
if (eventType === 'deleted') {
|
if (!hasRow) {
|
||||||
isNotTampered = true;
|
isNotTampered = isDeleteEvent;
|
||||||
console.log('Detected deleted event, marking as not tempered');
|
} else if (isDeleteEvent || data.deleted_status === 'DELETED') {
|
||||||
|
isNotTampered = isDeleteEvent && data.deleted_status === 'DELETED';
|
||||||
} else {
|
} else {
|
||||||
const hashesMatch =
|
const hashesMatch =
|
||||||
dbHash && (await this.compareData(blockchainHash, dbHash));
|
dbHash && (await this.compareData(blockchainHash, dbHash));
|
||||||
|
|
@ -287,7 +294,7 @@ export class AuditService {
|
||||||
progress_count: index ?? 0,
|
progress_count: index ?? 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.logger.log('Mengirim progres via WebSocket:', progressData);
|
// this.logger.log('Mengirim progres via WebSocket:', progressData);
|
||||||
this.auditGateway.sendProgress(progressData);
|
this.auditGateway.sendProgress(progressData);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
|
Delete,
|
||||||
Get,
|
Get,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
|
|
@ -69,4 +70,13 @@ export class ObatController {
|
||||||
async getObatLogs(@Param('id') id: string) {
|
async getObatLogs(@Param('id') id: string) {
|
||||||
return await this.obatService.getLogObatById(id);
|
return await this.obatService.getLogObatById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
async deleteObatById(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@CurrentUser() user: ActiveUserPayload,
|
||||||
|
) {
|
||||||
|
return await this.obatService.deleteObat(id, user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,11 @@ export class ObatService {
|
||||||
take: take,
|
take: take,
|
||||||
where: {
|
where: {
|
||||||
obat: obat ? { contains: obat } : undefined,
|
obat: obat ? { contains: obat } : undefined,
|
||||||
|
OR: [
|
||||||
|
{ deleted_status: null },
|
||||||
|
{ deleted_status: 'DELETE_VALIDATION' },
|
||||||
|
{ deleted_status: { not: 'DELETED' } },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
orderBy: orderBy
|
orderBy: orderBy
|
||||||
? { [Object.keys(orderBy)[0]]: order || 'asc' }
|
? { [Object.keys(orderBy)[0]]: order || 'asc' }
|
||||||
|
|
@ -65,6 +70,11 @@ export class ObatService {
|
||||||
const count = await this.prisma.pemberian_obat.count({
|
const count = await this.prisma.pemberian_obat.count({
|
||||||
where: {
|
where: {
|
||||||
obat: obat ? { contains: obat } : undefined,
|
obat: obat ? { contains: obat } : undefined,
|
||||||
|
OR: [
|
||||||
|
{ deleted_status: null },
|
||||||
|
{ deleted_status: 'DELETE_VALIDATION' },
|
||||||
|
{ deleted_status: { not: 'DELETED' } },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -273,6 +283,89 @@ export class ObatService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteObat(id: number, user: ActiveUserPayload) {
|
||||||
|
const existingObat = await this.getObatById(id);
|
||||||
|
if (!existingObat) {
|
||||||
|
throw new BadRequestException(`Obat with id ${id} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.prisma.$transaction(async (tx) => {
|
||||||
|
const createdValidationQueue =
|
||||||
|
await this.prisma.validation_queue.create({
|
||||||
|
data: {
|
||||||
|
table_name: 'pemberian_obat',
|
||||||
|
action: 'DELETE',
|
||||||
|
dataPayload: {
|
||||||
|
...existingObat,
|
||||||
|
},
|
||||||
|
record_id: id.toString(),
|
||||||
|
user_id_request: Number(user.sub),
|
||||||
|
status: 'PENDING',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedObat = await tx.pemberian_obat.update({
|
||||||
|
where: { id: id },
|
||||||
|
data: {
|
||||||
|
deleted_status: 'DELETE_VALIDATION',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return createdValidationQueue;
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting Obat:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteObatFromDBAndBlockchain(id: number, userId: number) {
|
||||||
|
const obatId = Number(id);
|
||||||
|
|
||||||
|
if (isNaN(obatId)) {
|
||||||
|
throw new BadRequestException('ID obat tidak valid');
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingObat = await this.getObatById(obatId);
|
||||||
|
if (!existingObat) {
|
||||||
|
throw new BadRequestException(`Obat dengan ID ${obatId} tidak ditemukan`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const deleteObat = await this.prisma.$transaction(async (tx) => {
|
||||||
|
const deletedObat = await tx.pemberian_obat.update({
|
||||||
|
where: { id: obatId },
|
||||||
|
data: {
|
||||||
|
deleted_status: 'DELETED',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const logPayload = JSON.stringify({
|
||||||
|
obat: existingObat.obat,
|
||||||
|
jumlah_obat: existingObat.jumlah_obat,
|
||||||
|
aturan_pakai: existingObat.aturan_pakai,
|
||||||
|
});
|
||||||
|
const payloadHash = sha256(logPayload);
|
||||||
|
const data = {
|
||||||
|
id: `OBAT_${deletedObat.id}`,
|
||||||
|
event: 'obat_deleted',
|
||||||
|
user_id: userId.toString(),
|
||||||
|
payload: payloadHash,
|
||||||
|
};
|
||||||
|
const logResult = await this.logService.storeLog(data);
|
||||||
|
return {
|
||||||
|
...deletedObat,
|
||||||
|
...logResult,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return deleteObat;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting Obat:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async countObat() {
|
async countObat() {
|
||||||
return this.prisma.pemberian_obat.count();
|
return this.prisma.pemberian_obat.count();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,11 @@ export class RekammedisService {
|
||||||
: undefined,
|
: undefined,
|
||||||
jenis_kelamin: jkCharacter ? { equals: jkCharacter } : undefined,
|
jenis_kelamin: jkCharacter ? { equals: jkCharacter } : undefined,
|
||||||
kode_diagnosa: kode_diagnosa ? { contains: kode_diagnosa } : undefined,
|
kode_diagnosa: kode_diagnosa ? { contains: kode_diagnosa } : undefined,
|
||||||
|
OR: [
|
||||||
|
{ deleted_status: null },
|
||||||
|
{ deleted_status: 'DELETE_VALIDATION' },
|
||||||
|
{ deleted_status: { not: 'DELETED' } },
|
||||||
|
],
|
||||||
...golDarahFilter,
|
...golDarahFilter,
|
||||||
...tindakLanjutFilter,
|
...tindakLanjutFilter,
|
||||||
};
|
};
|
||||||
|
|
@ -469,15 +474,28 @@ export class RekammedisService {
|
||||||
throw new Error(`Rekam Medis with id_visit ${id_visit} not found`);
|
throw new Error(`Rekam Medis with id_visit ${id_visit} not found`);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const response = await this.prisma.validation_queue.create({
|
const response = await this.prisma.$transaction(async (tx) => {
|
||||||
data: {
|
const createdQueue = await tx.validation_queue.create({
|
||||||
table_name: 'rekam_medis',
|
data: {
|
||||||
action: 'DELETE',
|
table_name: 'rekam_medis',
|
||||||
record_id: id_visit,
|
action: 'DELETE',
|
||||||
dataPayload: data,
|
record_id: id_visit,
|
||||||
user_id_request: user.sub,
|
dataPayload: data,
|
||||||
status: 'PENDING',
|
user_id_request: user.sub,
|
||||||
},
|
status: 'PENDING',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedRekamMedis = await tx.rekam_medis.update({
|
||||||
|
where: { id_visit },
|
||||||
|
data: {
|
||||||
|
deleted_status: 'DELETE_VALIDATION',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
...createdQueue,
|
||||||
|
rekam_medis: updatedRekamMedis,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -486,10 +504,39 @@ export class RekammedisService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteRekamMedisFromDB(id_visit: string) {
|
async deleteRekamMedisFromDBAndBlockchain(id_visit: string, userId: number) {
|
||||||
|
const existing = await this.getRekamMedisById(id_visit);
|
||||||
|
if (!existing) {
|
||||||
|
throw new Error(`Rekam Medis with id_visit ${id_visit} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const deletedRekamMedis = await this.prisma.rekam_medis.delete({
|
const deletedRekamMedis = await this.prisma.$transaction(async (tx) => {
|
||||||
where: { id_visit },
|
const deleted = await tx.rekam_medis.update({
|
||||||
|
data: {
|
||||||
|
deleted_status: 'DELETED',
|
||||||
|
},
|
||||||
|
where: { id_visit },
|
||||||
|
});
|
||||||
|
|
||||||
|
const logPayload = {
|
||||||
|
dokter_id: 123,
|
||||||
|
visit_id: id_visit,
|
||||||
|
anamnese: deleted.anamnese,
|
||||||
|
jenis_kasus: deleted.jenis_kasus,
|
||||||
|
tindak_lanjut: deleted.tindak_lanjut,
|
||||||
|
};
|
||||||
|
const logPayloadString = JSON.stringify(logPayload);
|
||||||
|
const payloadHash = sha256(logPayloadString);
|
||||||
|
const logDto = {
|
||||||
|
id: `REKAM_${id_visit}`,
|
||||||
|
event: 'rekam_medis_deleted',
|
||||||
|
user_id: userId.toString(),
|
||||||
|
payload: payloadHash,
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.log.storeLog(logDto);
|
||||||
|
return deleted;
|
||||||
});
|
});
|
||||||
return deletedRekamMedis;
|
return deletedRekamMedis;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,11 @@ export class TindakanDokterService {
|
||||||
kategori_tindakanArray.length > 0
|
kategori_tindakanArray.length > 0
|
||||||
? { in: kategori_tindakanArray }
|
? { in: kategori_tindakanArray }
|
||||||
: undefined,
|
: undefined,
|
||||||
|
OR: [
|
||||||
|
{ deleted_status: null },
|
||||||
|
{ deleted_status: 'DELETE_VALIDATION' },
|
||||||
|
{ deleted_status: { not: 'DELETED' } },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
orderBy: orderBy
|
orderBy: orderBy
|
||||||
? { [Object.keys(orderBy)[0]]: order || 'asc' }
|
? { [Object.keys(orderBy)[0]]: order || 'asc' }
|
||||||
|
|
@ -331,16 +336,36 @@ export class TindakanDokterService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.prisma.validation_queue.create({
|
try {
|
||||||
data: {
|
const validationQueue = await this.prisma.$transaction(async (tx) => {
|
||||||
table_name: 'pemberian_tindakan',
|
const queue = await tx.validation_queue.create({
|
||||||
action: 'DELETE',
|
data: {
|
||||||
dataPayload: existingTindakan,
|
table_name: 'pemberian_tindakan',
|
||||||
record_id: tindakanId.toString(),
|
action: 'DELETE',
|
||||||
user_id_request: user.sub,
|
dataPayload: existingTindakan,
|
||||||
status: 'PENDING',
|
record_id: tindakanId.toString(),
|
||||||
},
|
user_id_request: user.sub,
|
||||||
});
|
status: 'PENDING',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedTindakan = await tx.pemberian_tindakan.update({
|
||||||
|
where: { id: tindakanId },
|
||||||
|
data: {
|
||||||
|
deleted_status: 'DELETE_VALIDATION',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
...queue,
|
||||||
|
tindakan: updatedTindakan,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return validationQueue;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting Tindakan Dokter:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteTindakanDokterFromDBAndBlockchain(id: number, userId: number) {
|
async deleteTindakanDokterFromDBAndBlockchain(id: number, userId: number) {
|
||||||
|
|
@ -359,8 +384,9 @@ export class TindakanDokterService {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const deletedTindakan = await this.prisma.$transaction(async (tx) => {
|
const deletedTindakan = await this.prisma.$transaction(async (tx) => {
|
||||||
const deleted = await tx.pemberian_tindakan.delete({
|
const deleted = await tx.pemberian_tindakan.update({
|
||||||
where: { id: tindakanId },
|
where: { id: tindakanId },
|
||||||
|
data: { deleted_status: 'DELETED' },
|
||||||
});
|
});
|
||||||
const logPayload = JSON.stringify(deleted);
|
const logPayload = JSON.stringify(deleted);
|
||||||
const payloadHash = sha256(logPayload);
|
const payloadHash = sha256(logPayload);
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,10 @@ export class ValidationService {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
approveDelete: async (queue: any) => {
|
approveDelete: async (queue: any) => {
|
||||||
return this.rekamMedisService.deleteRekamMedisFromDB(queue.record_id);
|
return this.rekamMedisService.deleteRekamMedisFromDBAndBlockchain(
|
||||||
|
queue.record_id,
|
||||||
|
Number(queue.user_id_request),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pemberian_tindakan: {
|
pemberian_tindakan: {
|
||||||
|
|
@ -97,6 +100,12 @@ export class ValidationService {
|
||||||
Number(queue.user_id_request),
|
Number(queue.user_id_request),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
approveDelete: async (queue: any) => {
|
||||||
|
return this.obatService.deleteObatFromDBAndBlockchain(
|
||||||
|
Number(queue.record_id),
|
||||||
|
queue.user_id_request,
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -196,7 +205,10 @@ export class ValidationService {
|
||||||
const updated = await this.prisma.validation_queue.update({
|
const updated = await this.prisma.validation_queue.update({
|
||||||
where: { id: validationQueue.id },
|
where: { id: validationQueue.id },
|
||||||
data: {
|
data: {
|
||||||
record_id: approvalResult.id.toString(),
|
record_id:
|
||||||
|
validationQueue.table_name === 'rekam_medis'
|
||||||
|
? approvalResult.id_visit
|
||||||
|
: approvalResult.id.toString(),
|
||||||
status: 'APPROVED',
|
status: 'APPROVED',
|
||||||
user_id_process: Number(user.sub),
|
user_id_process: Number(user.sub),
|
||||||
processed_at: new Date(),
|
processed_at: new Date(),
|
||||||
|
|
|
||||||
|
|
@ -155,14 +155,12 @@ const handleUpdate = (item: ObatData) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (item: ObatData) => {
|
const handleDelete = async (item: ObatData) => {
|
||||||
if (confirm(`Apakah Anda yakin ingin menghapus obat "${item.obat}"?`)) {
|
try {
|
||||||
try {
|
await api.delete(`/obat/${item.id}`);
|
||||||
await api.delete(`/obat/${item.id}`);
|
await fetchData();
|
||||||
await fetchData();
|
} catch (error) {
|
||||||
} catch (error) {
|
console.error("Error deleting obat:", error);
|
||||||
console.error("Error deleting obat:", error);
|
alert("Gagal menghapus data obat");
|
||||||
alert("Gagal menghapus data obat");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user