ABDM: guard repeat OPD submits and dedupe health records
This commit is contained in:
parent
9b00974e4e
commit
e651b18a01
|
|
@ -1164,17 +1164,55 @@ class AbdmGateway extends BaseController
|
||||||
'bundle' => $bundle,
|
'bundle' => $bundle,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Store FHIR payload in health_records before pushing
|
// Reuse the latest matching OPD health record to avoid duplicate rows on repeat submit.
|
||||||
$healthRecordId = $this->storeHealthRecord([
|
$healthRecordId = 0;
|
||||||
'patient_id' => $patientId,
|
if ($this->db->tableExists('health_records')) {
|
||||||
'abha_id' => $hasAbha ? $abhaId : '',
|
$hrFields = $this->db->getFieldNames('health_records') ?? [];
|
||||||
'hi_type' => 'OPConsultRecord',
|
$hrSelectFields = array_values(array_unique(array_filter([
|
||||||
'entity_type' => 'opd',
|
'id',
|
||||||
'entity_id' => (string) $opdId,
|
'push_status',
|
||||||
'fhir_bundle' => $bundleJson,
|
'care_context_reference',
|
||||||
'care_context_reference' => $careContextRef,
|
in_array('record_data', $hrFields, true) ? 'record_data' : null,
|
||||||
'consent_handle' => $consentHandleResolved,
|
in_array('updated_at', $hrFields, true) ? 'updated_at' : null,
|
||||||
]);
|
in_array('created_at', $hrFields, true) ? 'created_at' : null,
|
||||||
|
])));
|
||||||
|
|
||||||
|
$hrBuilder = $this->db->table('health_records')
|
||||||
|
->select(implode(',', $hrSelectFields))
|
||||||
|
->where('entity_type', 'opd')
|
||||||
|
->where('entity_id', (string) $opdId);
|
||||||
|
if (in_array('care_context_reference', $hrFields, true)) {
|
||||||
|
$hrBuilder->where('care_context_reference', $careContextRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
$existingHr = $hrBuilder
|
||||||
|
->orderBy('id', 'DESC')
|
||||||
|
->get(1)
|
||||||
|
->getRowArray();
|
||||||
|
|
||||||
|
if (! empty($existingHr)) {
|
||||||
|
$existingPush = strtolower(trim((string) ($existingHr['push_status'] ?? '')));
|
||||||
|
$existingRecordData = (string) ($existingHr['record_data'] ?? '');
|
||||||
|
$isSameBundle = $existingRecordData !== '' ? hash('sha256', $existingRecordData) === hash('sha256', $bundleJson) : false;
|
||||||
|
if ($isSameBundle || in_array($existingPush, ['queued', 'linked', 'local_discovery_ready', 'local_only'], true)) {
|
||||||
|
$healthRecordId = (int) ($existingHr['id'] ?? 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($healthRecordId <= 0) {
|
||||||
|
// Store FHIR payload in health_records before pushing
|
||||||
|
$healthRecordId = $this->storeHealthRecord([
|
||||||
|
'patient_id' => $patientId,
|
||||||
|
'abha_id' => $hasAbha ? $abhaId : '',
|
||||||
|
'hi_type' => 'OPConsultRecord',
|
||||||
|
'entity_type' => 'opd',
|
||||||
|
'entity_id' => (string) $opdId,
|
||||||
|
'fhir_bundle' => $bundleJson,
|
||||||
|
'care_context_reference' => $careContextRef,
|
||||||
|
'consent_handle' => $consentHandleResolved,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
if (! $hasAbha) {
|
if (! $hasAbha) {
|
||||||
if ($healthRecordId > 0 && $this->db->tableExists('health_records')) {
|
if ($healthRecordId > 0 && $this->db->tableExists('health_records')) {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-sm table-striped mb-0" id="taskTable">
|
<table class="table table-sm table-striped mb-0" id="taskTable">
|
||||||
<thead class="table-light">
|
<thead class="table-light">
|
||||||
<tr>
|
<tr data-push-status="<?= esc((string) ($r['push_status'] ?? '')) ?>">
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
<th>Task</th>
|
<th>Task</th>
|
||||||
<th>Patient</th>
|
<th>Patient</th>
|
||||||
|
|
@ -318,7 +318,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary btn-opd-consult-fhir" data-opd-id="<?= (int) ($r['opd_id'] ?? 0) ?>">Preview FHIR</button>
|
<button type="button" class="btn btn-sm btn-outline-primary btn-opd-consult-fhir" data-opd-id="<?= (int) ($r['opd_id'] ?? 0) ?>">Preview FHIR</button>
|
||||||
<?php if (in_array((string) ($r['push_status'] ?? ''), ['failed', 'local_only'], true)): ?>
|
<?php if ((string) ($r['push_status'] ?? '') === 'failed'): ?>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-sm btn-outline-warning btn-opd-consult-submit-gateway ms-1"
|
class="btn btn-sm btn-outline-warning btn-opd-consult-submit-gateway ms-1"
|
||||||
|
|
@ -2030,6 +2030,7 @@
|
||||||
_fhirSubmitMode = options.submitMode || 'opd';
|
_fhirSubmitMode = options.submitMode || 'opd';
|
||||||
_fhirSubmitTaskRow = options.taskRow || null;
|
_fhirSubmitTaskRow = options.taskRow || null;
|
||||||
_fhirSubmitAbha = (options.abhaId || '').trim();
|
_fhirSubmitAbha = (options.abhaId || '').trim();
|
||||||
|
var rowPushStatus = (options.pushStatus || '').toString().trim().toLowerCase();
|
||||||
|
|
||||||
_fhirOpdId = 0; _fhirSessionId = 0;
|
_fhirOpdId = 0; _fhirSessionId = 0;
|
||||||
if (fhirModalTitle) fhirModalTitle.textContent = title || 'FHIR Preview';
|
if (fhirModalTitle) fhirModalTitle.textContent = title || 'FHIR Preview';
|
||||||
|
|
@ -2044,6 +2045,7 @@
|
||||||
if (fhirModalHttpBadge) { fhirModalHttpBadge.className = 'badge bg-warning text-dark'; fhirModalHttpBadge.textContent = 'HTTP ...'; }
|
if (fhirModalHttpBadge) { fhirModalHttpBadge.className = 'badge bg-warning text-dark'; fhirModalHttpBadge.textContent = 'HTTP ...'; }
|
||||||
|
|
||||||
if (btnSubmitFhirToAbdm) {
|
if (btnSubmitFhirToAbdm) {
|
||||||
|
btnSubmitFhirToAbdm.disabled = false;
|
||||||
if (_fhirSubmitMode === 'task') {
|
if (_fhirSubmitMode === 'task') {
|
||||||
btnSubmitFhirToAbdm.className = 'btn btn-sm btn-outline-warning';
|
btnSubmitFhirToAbdm.className = 'btn btn-sm btn-outline-warning';
|
||||||
btnSubmitFhirToAbdm.innerHTML = '<i class="bi bi-check2-square"></i> Verify & Submit to Gateway';
|
btnSubmitFhirToAbdm.innerHTML = '<i class="bi bi-check2-square"></i> Verify & Submit to Gateway';
|
||||||
|
|
@ -2056,6 +2058,12 @@
|
||||||
btnSubmitFhirToAbdm.className = defaultSubmitBtnClass;
|
btnSubmitFhirToAbdm.className = defaultSubmitBtnClass;
|
||||||
btnSubmitFhirToAbdm.innerHTML = defaultSubmitBtnHtml;
|
btnSubmitFhirToAbdm.innerHTML = defaultSubmitBtnHtml;
|
||||||
btnSubmitFhirToAbdm.title = defaultSubmitBtnTitle;
|
btnSubmitFhirToAbdm.title = defaultSubmitBtnTitle;
|
||||||
|
if (['linked', 'queued', 'local_discovery_ready'].indexOf(rowPushStatus) !== -1) {
|
||||||
|
btnSubmitFhirToAbdm.disabled = true;
|
||||||
|
btnSubmitFhirToAbdm.className = 'btn btn-sm btn-outline-secondary';
|
||||||
|
btnSubmitFhirToAbdm.innerHTML = '<i class="bi bi-check2-circle"></i> Already Submitted';
|
||||||
|
btnSubmitFhirToAbdm.title = 'Record is already queued/linked/discovery-ready. Use retry only on failed rows.';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2300,8 +2308,10 @@
|
||||||
document.querySelectorAll('.btn-opd-consult-fhir').forEach(function (btn) {
|
document.querySelectorAll('.btn-opd-consult-fhir').forEach(function (btn) {
|
||||||
btn.addEventListener('click', function () {
|
btn.addEventListener('click', function () {
|
||||||
var opdId = parseInt(btn.getAttribute('data-opd-id') || '0', 10);
|
var opdId = parseInt(btn.getAttribute('data-opd-id') || '0', 10);
|
||||||
|
var tr = btn.closest('tr');
|
||||||
|
var pushStatus = tr ? (tr.getAttribute('data-push-status') || '') : '';
|
||||||
if (opdId <= 0) return;
|
if (opdId <= 0) return;
|
||||||
openFhirModal('<?= base_url('Opd_prescription/fhir_bundle_preview') ?>/' + opdId, 'FHIR Preview — OPD #' + opdId);
|
openFhirModal('<?= base_url('Opd_prescription/fhir_bundle_preview') ?>/' + opdId, 'FHIR Preview — OPD #' + opdId, { pushStatus: pushStatus });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user