ABDM task board: show OPD record lifecycle status

This commit is contained in:
DevSoftTech Server 2026-06-27 00:21:02 +05:30
parent c7c18adae2
commit db7ba044b1
2 changed files with 210 additions and 3 deletions

View File

@ -496,6 +496,174 @@ class AbdmTaskBoard extends BaseController
->get()
->getResultArray();
return array_values(array_filter($rows, static fn ($r) => preg_match('/^\d{14}$/', trim((string) ($r['abha_id'] ?? ''))) === 1));
$rows = array_values(array_filter($rows, static fn ($r) => preg_match('/^\d{14}$/', trim((string) ($r['abha_id'] ?? ''))) === 1));
if (empty($rows)) {
return [];
}
$opdIds = array_values(array_unique(array_map(static fn ($r) => (int) ($r['opd_id'] ?? 0), $rows)));
$latestDocByOpd = [];
if (! empty($opdIds) && $this->db->tableExists('opd_fhir_documents')) {
$docRows = $this->db->table('opd_fhir_documents')
->select('id, opd_id, opd_session_id, generated_at, created_at')
->whereIn('opd_id', $opdIds)
->whereIn('bundle_type', ['OPConsultRecord', 'MedicationRequestBundle'])
->orderBy('id', 'DESC')
->get()
->getResultArray();
foreach ($docRows as $doc) {
$k = (int) ($doc['opd_id'] ?? 0);
if ($k <= 0 || isset($latestDocByOpd[$k])) {
continue;
}
$latestDocByOpd[$k] = $doc;
}
}
$latestHrByOpd = [];
if (! empty($opdIds) && $this->db->tableExists('health_records')) {
$hrFields = $this->db->getFieldNames('health_records') ?? [];
$hrSelect = ['id', 'entity_id', 'push_status', 'abdm_txn_id', 'care_context_reference', 'push_at', 'linked_at', 'updated_at'];
if (in_array('bridge_record_id', $hrFields, true)) {
$hrSelect[] = 'bridge_record_id';
}
$opdIdStrings = array_map(static fn ($v) => (string) $v, $opdIds);
$hrRows = $this->db->table('health_records')
->select(implode(',', $hrSelect))
->where('entity_type', 'opd')
->whereIn('entity_id', $opdIdStrings)
->orderBy('id', 'DESC')
->get()
->getResultArray();
foreach ($hrRows as $hr) {
$k = (int) ($hr['entity_id'] ?? 0);
if ($k <= 0 || isset($latestHrByOpd[$k])) {
continue;
}
$latestHrByOpd[$k] = $hr;
}
}
$recordLinksByContext = [];
if ($this->db->tableExists('record_links')) {
$contexts = [];
foreach ($latestHrByOpd as $hr) {
$cc = trim((string) ($hr['care_context_reference'] ?? ''));
if ($cc !== '') {
$contexts[] = $cc;
}
}
$contexts = array_values(array_unique($contexts));
if (! empty($contexts)) {
$rlRows = $this->db->table('record_links')
->select('id, care_context_reference, link_status, linked_at, updated_at')
->whereIn('care_context_reference', $contexts)
->orderBy('id', 'DESC')
->get()
->getResultArray();
foreach ($rlRows as $rl) {
$cc = trim((string) ($rl['care_context_reference'] ?? ''));
if ($cc === '' || isset($recordLinksByContext[$cc])) {
continue;
}
$recordLinksByContext[$cc] = $rl;
}
}
}
$out = [];
foreach ($rows as $row) {
$opdId = (int) ($row['opd_id'] ?? 0);
if ($opdId <= 0) {
continue;
}
$doc = $latestDocByOpd[$opdId] ?? null;
$hr = $latestHrByOpd[$opdId] ?? null;
$sessionId = (int) ($doc['opd_session_id'] ?? 0);
$consultDate = (string) ($row['apointment_date'] ?? '');
$visitDate = $consultDate !== '' ? date('Y-m-d', strtotime($consultDate)) : date('Y-m-d');
$derivedCareContext = 'OPD-' . $opdId . '-S' . ($sessionId > 0 ? $sessionId : 0) . '-' . $visitDate;
$careContextRef = trim((string) ($hr['care_context_reference'] ?? ''));
if ($careContextRef === '') {
$careContextRef = $derivedCareContext;
}
$rl = $recordLinksByContext[$careContextRef] ?? null;
$pushStatus = strtolower(trim((string) ($hr['push_status'] ?? '')));
$linkStatus = strtolower(trim((string) ($rl['link_status'] ?? '')));
$statusLabel = 'Not Registered';
$statusTone = 'secondary';
$statusNote = 'FHIR not registered in health_records yet.';
if ($doc !== null) {
$statusLabel = 'FHIR Generated';
$statusTone = 'info';
$statusNote = 'FHIR bundle generated; awaiting registration.';
}
if ($pushStatus !== '') {
if ($pushStatus === 'local_discovery_ready') {
$statusLabel = 'Discovery Ready';
$statusTone = 'primary';
$statusNote = 'Registered in HMS for M2 discovery/fetch callbacks.';
} elseif ($pushStatus === 'local_only') {
$statusLabel = 'Local Only';
$statusTone = 'secondary';
$statusNote = 'Stored locally only (ABHA/consent not ready).';
} elseif ($pushStatus === 'queued') {
$statusLabel = 'Gateway Queued';
$statusTone = 'warning';
$statusNote = 'Submitted to gateway and waiting for link workflow.';
} elseif ($pushStatus === 'linked') {
$statusLabel = 'Linked';
$statusTone = 'success';
$statusNote = 'Care context linked successfully.';
} elseif ($pushStatus === 'failed') {
$statusLabel = 'Failed';
$statusTone = 'danger';
$statusNote = 'Last registration/share attempt failed.';
}
}
if ($linkStatus === 'linked') {
$statusLabel = 'Linked';
$statusTone = 'success';
$statusNote = 'Care context link confirmed by callback.';
} elseif ($linkStatus === 'pending_discovery' && $statusLabel === 'Discovery Ready') {
$statusNote = 'Waiting for ABDM discovery and consent fetch callbacks.';
} elseif ($linkStatus === 'failed') {
$statusLabel = 'Link Failed';
$statusTone = 'danger';
$statusNote = 'Link callback reported failure.';
}
$queueId = trim((string) ($hr['abdm_txn_id'] ?? ''));
$bridgeRecordId = (int) ($hr['bridge_record_id'] ?? 0);
$out[] = array_merge($row, [
'opd_session_id' => $sessionId,
'care_context_reference' => $careContextRef,
'record_status_label' => $statusLabel,
'record_status_tone' => $statusTone,
'record_status_note' => $statusNote,
'push_status' => $pushStatus,
'link_status' => $linkStatus,
'queue_id' => $queueId,
'bridge_record_id' => $bridgeRecordId > 0 ? $bridgeRecordId : null,
'has_fhir' => $doc !== null ? 1 : 0,
]);
}
return $out;
}
}

View File

@ -266,24 +266,63 @@
<div class="table-responsive">
<table class="table table-sm mb-0">
<thead class="table-light">
<tr><th>OPD ID</th><th>Patient</th><th>ABHA</th><th>Consult Date</th><th>Doctor</th><th>Action</th></tr>
<tr><th>OPD ID</th><th>Patient</th><th>ABHA</th><th>Consult Date</th><th>Doctor</th><th>Record Status</th><th>Details</th><th>Action</th></tr>
</thead>
<tbody>
<?php if (! empty($opd_consult_rows ?? [])): ?>
<?php foreach (($opd_consult_rows ?? []) as $r): ?>
<?php
$statusTone = trim((string) ($r['record_status_tone'] ?? 'secondary'));
$allowedTones = ['secondary', 'primary', 'info', 'success', 'warning', 'danger', 'dark'];
if (! in_array($statusTone, $allowedTones, true)) {
$statusTone = 'secondary';
}
$statusLabel = trim((string) ($r['record_status_label'] ?? 'Not Registered'));
$statusNote = trim((string) ($r['record_status_note'] ?? ''));
$queueId = trim((string) ($r['queue_id'] ?? ''));
$careContext = trim((string) ($r['care_context_reference'] ?? ''));
$linkStatus = trim((string) ($r['link_status'] ?? ''));
$bridgeRecordId = trim((string) ($r['bridge_record_id'] ?? ''));
$hasFhir = (int) ($r['has_fhir'] ?? 0) === 1;
$statusBadgeClass = 'badge bg-' . $statusTone;
if ($statusTone === 'warning') {
$statusBadgeClass .= ' text-dark';
}
?>
<tr>
<td>#<?= (int) ($r['opd_id'] ?? 0) ?></td>
<td><?= esc((string) ($r['P_name'] ?? '')) ?></td>
<td><span class="text-primary small"><?= esc((string) ($r['abha_id'] ?? '')) ?></span></td>
<td><?= esc(substr((string) ($r['apointment_date'] ?? ''), 0, 16)) ?></td>
<td><?= esc((string) ($r['doc_name'] ?? '')) ?></td>
<td><span class="<?= esc($statusBadgeClass) ?>"><?= esc($statusLabel) ?></span></td>
<td class="small text-muted" style="min-width:260px;max-width:340px;">
<?php if ($statusNote !== ''): ?>
<div><?= esc($statusNote) ?></div>
<?php endif; ?>
<?php if ($queueId !== ''): ?>
<div><strong>Queue:</strong> <?= esc($queueId) ?></div>
<?php endif; ?>
<?php if ($bridgeRecordId !== ''): ?>
<div><strong>Bridge:</strong> #<?= esc($bridgeRecordId) ?></div>
<?php endif; ?>
<?php if ($linkStatus !== ''): ?>
<div><strong>Link:</strong> <?= esc(strtoupper($linkStatus)) ?></div>
<?php endif; ?>
<?php if ($careContext !== ''): ?>
<div class="text-truncate" title="<?= esc($careContext) ?>"><strong>CC:</strong> <?= esc($careContext) ?></div>
<?php endif; ?>
<?php if (! $hasFhir): ?>
<div class="text-danger">FHIR bundle not generated yet.</div>
<?php endif; ?>
</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>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="6" class="text-muted px-2 py-2">No done OPD with ABHA found in last 30 days.</td></tr>
<tr><td colspan="8" class="text-muted px-2 py-2">No done OPD with ABHA found in last 30 days.</td></tr>
<?php endif; ?>
</tbody>
</table>