feat(abdm-m2): add HIP link modal and care context discovery on patient registration
This commit is contained in:
parent
6bd24303e3
commit
a33b376ecd
|
|
@ -6225,6 +6225,39 @@ class AbdmGateway extends BaseController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4b. Query opd_master (OPD consultation appointments/visits not already in prescriptions)
|
||||||
|
if ($this->db->tableExists('opd_master')) {
|
||||||
|
$opdMasterRows = $this->db->table('opd_master')
|
||||||
|
->select('opd_id, p_id, apointment_date, opd_book_date, doc_name')
|
||||||
|
->where('p_id', $patientId)
|
||||||
|
->orderBy('opd_id', 'DESC')
|
||||||
|
->limit(30)
|
||||||
|
->get()
|
||||||
|
->getResultArray();
|
||||||
|
|
||||||
|
foreach ($opdMasterRows as $om) {
|
||||||
|
$visitRaw = ! empty($om['apointment_date']) && $om['apointment_date'] !== '0000-00-00 00:00:00'
|
||||||
|
? $om['apointment_date']
|
||||||
|
: (! empty($om['opd_book_date']) ? $om['opd_book_date'] : date('Y-m-d'));
|
||||||
|
$visitDate = date('Y-m-d', strtotime((string) $visitRaw));
|
||||||
|
$dateStr = date('d M Y', strtotime($visitDate));
|
||||||
|
$opdId = (int) $om['opd_id'];
|
||||||
|
$ccRef = 'OPD-' . $patientId . '-S' . $opdId . '-' . str_replace('-', '', $visitDate);
|
||||||
|
$docName = trim((string) ($om['doc_name'] ?? ''));
|
||||||
|
$display = 'OPConsultRecord - ' . ($docName !== '' ? 'Dr. ' . $docName . ' - ' : '') . $dateStr;
|
||||||
|
|
||||||
|
$addContext([
|
||||||
|
'careContextId' => $ccRef,
|
||||||
|
'referenceNumber' => $ccRef,
|
||||||
|
'display' => $display,
|
||||||
|
'record_type' => 'OPConsultRecord',
|
||||||
|
'patient_id' => $patientId,
|
||||||
|
'is_fhir_ready' => true,
|
||||||
|
'is_primary' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 5. Query ipd_master (Discharge summaries)
|
// 5. Query ipd_master (Discharge summaries)
|
||||||
if ($this->db->tableExists('ipd_master')) {
|
if ($this->db->tableExists('ipd_master')) {
|
||||||
$ipdRows = $this->db->table('ipd_master')
|
$ipdRows = $this->db->table('ipd_master')
|
||||||
|
|
@ -10917,7 +10950,16 @@ class AbdmGateway extends BaseController
|
||||||
if ($patientId > 0) {
|
if ($patientId > 0) {
|
||||||
$builder->where('id', $patientId);
|
$builder->where('id', $patientId);
|
||||||
} elseif ($abhaAddress !== '') {
|
} elseif ($abhaAddress !== '') {
|
||||||
$builder->where('abha_address', $abhaAddress);
|
$cleanAbha = preg_replace('/\D/', '', $abhaAddress);
|
||||||
|
if (strlen($cleanAbha) === 14) {
|
||||||
|
$builder->groupStart()
|
||||||
|
->where('abha_address', $abhaAddress)
|
||||||
|
->orWhere('abha_id', $cleanAbha)
|
||||||
|
->orWhere('abha_id', $abhaAddress)
|
||||||
|
->groupEnd();
|
||||||
|
} else {
|
||||||
|
$builder->where('abha_address', $abhaAddress);
|
||||||
|
}
|
||||||
} elseif ($pCode !== '') {
|
} elseif ($pCode !== '') {
|
||||||
$builder->where('p_code', $pCode);
|
$builder->where('p_code', $pCode);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@
|
||||||
<?= view('partials/abha_create_modal') ?>
|
<?= view('partials/abha_create_modal') ?>
|
||||||
<?= view('partials/abha_qr_modal') ?>
|
<?= view('partials/abha_qr_modal') ?>
|
||||||
<?= view('partials/abha_mobile_modal') ?>
|
<?= view('partials/abha_mobile_modal') ?>
|
||||||
|
<?= view('partials/abdm_hip_link_modal') ?>
|
||||||
<section class="content">
|
<section class="content">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
|
|
@ -105,6 +106,7 @@
|
||||||
<input class="form-control" name="input_abha_id" id="input_abha_id"
|
<input class="form-control" name="input_abha_id" id="input_abha_id"
|
||||||
placeholder="14-digit ABHA ID" type="text" autocomplete="off"
|
placeholder="14-digit ABHA ID" type="text" autocomplete="off"
|
||||||
maxlength="14" data-inputmask='"mask": "99999999999999"' data-mask>
|
maxlength="14" data-inputmask='"mask": "99999999999999"' data-mask>
|
||||||
|
<input type="hidden" name="input_abha_address" id="input_abha_address" value="">
|
||||||
<div id="abha_id_feedback" class="mt-1" style="display:none;"></div>
|
<div id="abha_id_feedback" class="mt-1" style="display:none;"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -410,7 +412,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row g-3 py-3 px-2">
|
<div class="row g-3 py-3 px-2">
|
||||||
<div class="col-lg-4">
|
<div class="col-xl-3 col-md-6">
|
||||||
<div class="card h-100 border-primary">
|
<div class="card h-100 border-primary">
|
||||||
<div class="card-body d-flex flex-column">
|
<div class="card-body d-flex flex-column">
|
||||||
<div class="d-flex align-items-center gap-2 mb-2">
|
<div class="d-flex align-items-center gap-2 mb-2">
|
||||||
|
|
@ -428,7 +430,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-lg-4">
|
<div class="col-xl-3 col-md-6">
|
||||||
<div class="card h-100 border-success">
|
<div class="card h-100 border-success">
|
||||||
<div class="card-body d-flex flex-column">
|
<div class="card-body d-flex flex-column">
|
||||||
<div class="d-flex align-items-center gap-2 mb-2">
|
<div class="d-flex align-items-center gap-2 mb-2">
|
||||||
|
|
@ -449,7 +451,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-lg-4">
|
<div class="col-xl-3 col-md-6">
|
||||||
<div class="card h-100 border-info">
|
<div class="card h-100 border-info">
|
||||||
<div class="card-body d-flex flex-column">
|
<div class="card-body d-flex flex-column">
|
||||||
<div class="d-flex align-items-center gap-2 mb-2">
|
<div class="d-flex align-items-center gap-2 mb-2">
|
||||||
|
|
@ -465,6 +467,31 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xl-3 col-md-6">
|
||||||
|
<div class="card h-100 border-warning">
|
||||||
|
<div class="card-body d-flex flex-column">
|
||||||
|
<div class="d-flex align-items-center gap-2 mb-2">
|
||||||
|
<i class="bi bi-link-45deg fs-3 text-warning"></i>
|
||||||
|
<h6 class="mb-0">Link Records to ABHA (HIP)</h6>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small mb-2">Link hospital visits & diagnostic records to patient's ABHA address using ABDM M2 HIP workflows.</p>
|
||||||
|
<ul class="list-unstyled small text-muted mb-3">
|
||||||
|
<li><i class="bi bi-check-circle-fill text-success me-1"></i>Demographic Auth (Method 4)</li>
|
||||||
|
<li><i class="bi bi-check-circle-fill text-success me-1"></i>Link OPD & Diagnostics</li>
|
||||||
|
<li><i class="bi bi-check-circle-fill text-success me-1"></i>Deep Link SMS to ABHA App</li>
|
||||||
|
</ul>
|
||||||
|
<div class="d-grid gap-2 mt-auto">
|
||||||
|
<button type="button" class="btn btn-warning text-dark fw-semibold" onclick="openAbdmHipLinkModal()">
|
||||||
|
<i class="bi bi-link-45deg me-1"></i>Link Records to ABHA (HIP)
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="openAbdmHipSmsModal()">
|
||||||
|
<i class="bi bi-chat-dots me-1"></i>Send Deep Link SMS
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Legacy inline flows kept hidden; their element IDs are still used by the wizard scripts. -->
|
<!-- Legacy inline flows kept hidden; their element IDs are still used by the wizard scripts. -->
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,14 @@ final class CareContextDiscoveryTest extends CIUnitTestCase
|
||||||
p_datetime TEXT
|
p_datetime TEXT
|
||||||
)");
|
)");
|
||||||
|
|
||||||
|
$db->query("CREATE TABLE IF NOT EXISTS " . $db->prefixTable('opd_master') . " (
|
||||||
|
opd_id INTEGER PRIMARY KEY,
|
||||||
|
p_id INTEGER,
|
||||||
|
apointment_date TEXT,
|
||||||
|
opd_book_date TEXT,
|
||||||
|
doc_name TEXT
|
||||||
|
)");
|
||||||
|
|
||||||
$db->query("CREATE TABLE IF NOT EXISTS " . $db->prefixTable('health_records') . " (
|
$db->query("CREATE TABLE IF NOT EXISTS " . $db->prefixTable('health_records') . " (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
patient_id INTEGER,
|
patient_id INTEGER,
|
||||||
|
|
@ -92,6 +100,7 @@ final class CareContextDiscoveryTest extends CIUnitTestCase
|
||||||
$db->table('charge_master')->emptyTable();
|
$db->table('charge_master')->emptyTable();
|
||||||
$db->table('lab_request')->emptyTable();
|
$db->table('lab_request')->emptyTable();
|
||||||
$db->table('opd_prescription')->emptyTable();
|
$db->table('opd_prescription')->emptyTable();
|
||||||
|
$db->table('opd_master')->emptyTable();
|
||||||
$db->table('health_records')->emptyTable();
|
$db->table('health_records')->emptyTable();
|
||||||
$db->table('patient_master')->emptyTable();
|
$db->table('patient_master')->emptyTable();
|
||||||
$db->table('ipd_master')->emptyTable();
|
$db->table('ipd_master')->emptyTable();
|
||||||
|
|
@ -323,5 +332,26 @@ final class CareContextDiscoveryTest extends CIUnitTestCase
|
||||||
$this->assertSame(1, $body['ok'] ?? 0);
|
$this->assertSame(1, $body['ok'] ?? 0);
|
||||||
$this->assertSame('RAD-31-20260929', $body['care_context_reference'] ?? '');
|
$this->assertSame('RAD-31-20260929', $body['care_context_reference'] ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDiscoversOpdMasterVisitWhenPrescriptionNotCreated(): void
|
||||||
|
{
|
||||||
|
$db = \Config\Database::connect();
|
||||||
|
$db->table('opd_master')->insert([
|
||||||
|
'opd_id' => 77,
|
||||||
|
'p_id' => 12,
|
||||||
|
'apointment_date' => '2026-09-29 14:30:00',
|
||||||
|
'opd_book_date' => '2026-09-29 14:00:00',
|
||||||
|
'doc_name' => 'NIDHI PANDEY',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$refGateway = new ReflectionClass($this->gateway);
|
||||||
|
$method = $refGateway->getMethod('findCareContextsForPatient');
|
||||||
|
$method->setAccessible(true);
|
||||||
|
|
||||||
|
[$v3, $full] = $method->invoke($this->gateway, 12, 'P26071000012', 'KESHAV SINGH');
|
||||||
|
|
||||||
|
$refs = array_column($v3, 'referenceNumber');
|
||||||
|
$this->assertContains('OPD-12-S77-20260929', $refs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user