Move ABDM sandbox to task board and improve OPD queue handling
This commit is contained in:
parent
2fc3d3ddbc
commit
16f654289e
|
|
@ -50,7 +50,30 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<?php foreach (($tasks ?? []) as $t): ?>
|
||||
<tr data-task-id="<?= (int) ($t['id'] ?? 0) ?>" data-task-type="<?= esc((string) ($t['task_type'] ?? '')) ?>" data-entity-id="<?= esc((string) ($t['entity_id'] ?? '')) ?>">
|
||||
<?php
|
||||
$type = strtolower((string) ($t['task_type'] ?? ''));
|
||||
$abhaId = trim((string) ($t['abha_id'] ?? ''));
|
||||
$hasValidAbha = preg_match('/^\d{14}$/', $abhaId) === 1;
|
||||
|
||||
$payload = json_decode((string) ($t['payload_json'] ?? ''), true);
|
||||
if (! is_array($payload)) {
|
||||
$payload = [];
|
||||
}
|
||||
$meta = (isset($payload['meta']) && is_array($payload['meta'])) ? $payload['meta'] : [];
|
||||
$opdId = (int) ($meta['opd_id'] ?? 0);
|
||||
$opdSessionId = (int) ($meta['opd_session_id'] ?? 0);
|
||||
$showSandbox = ($type === 'opd_prescription_publish' && $hasValidAbha && $opdId > 0);
|
||||
?>
|
||||
<tr
|
||||
data-task-id="<?= (int) ($t['id'] ?? 0) ?>"
|
||||
data-task-type="<?= esc((string) ($t['task_type'] ?? '')) ?>"
|
||||
data-entity-id="<?= esc((string) ($t['entity_id'] ?? '')) ?>"
|
||||
data-patient-id="<?= (int) ($t['patient_id'] ?? 0) ?>"
|
||||
data-abha-id="<?= esc($abhaId) ?>"
|
||||
data-opd-id="<?= $opdId ?>"
|
||||
data-opd-session-id="<?= $opdSessionId ?>"
|
||||
data-sandbox-eligible="<?= $showSandbox ? '1' : '0' ?>"
|
||||
>
|
||||
<td><?= (int) ($t['id'] ?? 0) ?></td>
|
||||
<td>
|
||||
<div><strong><?= esc((string) ($t['task_code'] ?? '')) ?></strong></div>
|
||||
|
|
@ -68,7 +91,6 @@
|
|||
<td><span class="badge bg-secondary status-pill"><?= esc((string) ($t['status'] ?? 'pending')) ?></span></td>
|
||||
<td>
|
||||
<div class="d-flex gap-1 flex-wrap">
|
||||
<?php $type = strtolower((string) ($t['task_type'] ?? '')); ?>
|
||||
<?php if ($type === 'patient_abha_create' || $type === 'patient_abha_link'): ?>
|
||||
<button class="btn btn-sm btn-outline-success action-btn" data-action="create_abha">Create ABHA</button>
|
||||
<?php elseif ($type === 'patient_abha_update'): ?>
|
||||
|
|
@ -76,6 +98,9 @@
|
|||
<?php else: ?>
|
||||
<button class="btn btn-sm btn-outline-warning action-btn" data-action="submit">Submit</button>
|
||||
<?php endif; ?>
|
||||
<?php if ($showSandbox): ?>
|
||||
<button class="btn btn-sm btn-outline-info sandbox-btn">Sandbox</button>
|
||||
<?php endif; ?>
|
||||
<button class="btn btn-sm btn-outline-dark close-btn">Close</button>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -87,6 +112,62 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mt-3 d-none" id="abdmSandboxCard">
|
||||
<div class="card-header py-2 d-flex justify-content-between align-items-center">
|
||||
<strong>ABDM Sandbox Actions</strong>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="btnSandboxHide">Hide</button>
|
||||
</div>
|
||||
<div class="card-body p-3">
|
||||
<div class="small text-muted mb-2" id="abdmSandboxContext">Select eligible OPD Publish task to use sandbox actions.</div>
|
||||
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label mb-1 small">ABHA Number</label>
|
||||
<input type="text" class="form-control form-control-sm" id="tb_abha_id" maxlength="14" placeholder="14-digit ABHA">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label mb-1 small">QR Payload (Scan & Share)</label>
|
||||
<input type="text" class="form-control form-control-sm" id="tb_abdm_qr_payload" placeholder="Paste scanned QR payload">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-wrap gap-2 mb-2">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" id="tb_btn_abdm_scan_lookup">Scan Lookup</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" id="tb_btn_abdm_validate_abha">Validate ABHA</button>
|
||||
</div>
|
||||
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control form-control-sm" id="tb_abdm_purpose_code" placeholder="Purpose (ex: CAREMGT)">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<input type="datetime-local" class="form-control form-control-sm" id="tb_abdm_consent_expires_at">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-wrap gap-2 mb-2">
|
||||
<button type="button" class="btn btn-outline-success btn-sm" id="tb_btn_abdm_consent_request">Request Consent</button>
|
||||
<button type="button" class="btn btn-outline-warning btn-sm" id="tb_btn_abdm_share_fhir">Share FHIR</button>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label mb-1 small">Consent Handle</label>
|
||||
<input type="text" class="form-control form-control-sm" id="tb_abdm_consent_handle" placeholder="Auto-filled after consent request">
|
||||
</div>
|
||||
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-md-7">
|
||||
<input type="number" min="1" class="form-control form-control-sm" id="tb_abdm_claim_document_id" placeholder="Claim Document ID">
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<button type="button" class="btn btn-outline-dark btn-sm w-100" id="tb_btn_abdm_claim_status">Claim Status</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="small text-muted" id="abdmSandboxStatus">Ready</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="small text-muted mt-2" id="statusBox">Ready</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -122,8 +203,18 @@
|
|||
var modalAbhaInput = document.getElementById('modalAbhaInput');
|
||||
var modalTaskSummary = document.getElementById('modalTaskSummary');
|
||||
var modalConfirmBtn = document.getElementById('modalConfirmBtn');
|
||||
var sandboxCard = document.getElementById('abdmSandboxCard');
|
||||
var sandboxContext = document.getElementById('abdmSandboxContext');
|
||||
var sandboxStatus = document.getElementById('abdmSandboxStatus');
|
||||
var sandboxAbhaInput = document.getElementById('tb_abha_id');
|
||||
var sandboxQrPayloadInput = document.getElementById('tb_abdm_qr_payload');
|
||||
var sandboxPurposeCodeInput = document.getElementById('tb_abdm_purpose_code');
|
||||
var sandboxConsentExpiresInput = document.getElementById('tb_abdm_consent_expires_at');
|
||||
var sandboxConsentHandleInput = document.getElementById('tb_abdm_consent_handle');
|
||||
var sandboxClaimDocumentInput = document.getElementById('tb_abdm_claim_document_id');
|
||||
var selectedAction = '';
|
||||
var selectedRow = null;
|
||||
var sandboxRow = null;
|
||||
|
||||
function applyFilter(filter) {
|
||||
var rows = document.querySelectorAll('#taskTable tbody tr');
|
||||
|
|
@ -172,6 +263,74 @@
|
|||
});
|
||||
}
|
||||
|
||||
function setSandboxStatus(msg, level) {
|
||||
if (!sandboxStatus) {
|
||||
return;
|
||||
}
|
||||
sandboxStatus.classList.remove('text-muted', 'text-success', 'text-danger', 'text-warning');
|
||||
if (level === 'success') {
|
||||
sandboxStatus.classList.add('text-success');
|
||||
} else if (level === 'danger') {
|
||||
sandboxStatus.classList.add('text-danger');
|
||||
} else if (level === 'warning') {
|
||||
sandboxStatus.classList.add('text-warning');
|
||||
} else {
|
||||
sandboxStatus.classList.add('text-muted');
|
||||
}
|
||||
sandboxStatus.textContent = msg || 'Ready';
|
||||
}
|
||||
|
||||
function currentSandboxContext() {
|
||||
if (!sandboxRow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
taskId: parseInt(sandboxRow.getAttribute('data-task-id') || '0', 10) || 0,
|
||||
patientId: parseInt(sandboxRow.getAttribute('data-patient-id') || '0', 10) || 0,
|
||||
opdId: parseInt(sandboxRow.getAttribute('data-opd-id') || '0', 10) || 0,
|
||||
opdSessionId: parseInt(sandboxRow.getAttribute('data-opd-session-id') || '0', 10) || 0,
|
||||
abhaId: (sandboxAbhaInput.value || '').trim()
|
||||
};
|
||||
}
|
||||
|
||||
function openSandboxForRow(row) {
|
||||
if (!row || !sandboxCard) {
|
||||
return;
|
||||
}
|
||||
if ((row.getAttribute('data-sandbox-eligible') || '0') !== '1') {
|
||||
setSandboxStatus('Sandbox actions are available only for OPD Publish rows with valid ABHA and printed consult.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
sandboxRow = row;
|
||||
|
||||
var taskCode = '';
|
||||
var patientName = '';
|
||||
var taskCodeEl = row.querySelector('td:nth-child(2) strong');
|
||||
var patientNameEl = row.querySelector('td:nth-child(3) div');
|
||||
if (taskCodeEl) {
|
||||
taskCode = taskCodeEl.textContent.trim();
|
||||
}
|
||||
if (patientNameEl) {
|
||||
patientName = patientNameEl.textContent.trim();
|
||||
}
|
||||
|
||||
var rowAbha = (row.getAttribute('data-abha-id') || '').trim();
|
||||
sandboxAbhaInput.value = rowAbha;
|
||||
sandboxQrPayloadInput.value = '';
|
||||
sandboxPurposeCodeInput.value = sandboxPurposeCodeInput.value || 'CAREMGT';
|
||||
sandboxConsentHandleInput.value = '';
|
||||
sandboxClaimDocumentInput.value = '';
|
||||
|
||||
var opdId = row.getAttribute('data-opd-id') || '0';
|
||||
var opdSessionId = row.getAttribute('data-opd-session-id') || '0';
|
||||
sandboxContext.textContent = 'Task: ' + taskCode + ' | Patient: ' + patientName + ' | OPD: ' + opdId + ' | Session: ' + opdSessionId;
|
||||
sandboxCard.classList.remove('d-none');
|
||||
setSandboxStatus('Ready');
|
||||
sandboxCard.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
|
||||
function runAction(row, action) {
|
||||
var taskId = row.getAttribute('data-task-id');
|
||||
var abha = modalAbhaInput.value.trim();
|
||||
|
|
@ -220,6 +379,12 @@
|
|||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.sandbox-btn').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
openSandboxForRow(btn.closest('tr'));
|
||||
});
|
||||
});
|
||||
|
||||
applyFilter('patient_abha_create');
|
||||
|
||||
modalConfirmBtn.addEventListener('click', function () {
|
||||
|
|
@ -254,12 +419,140 @@
|
|||
setStatus(res.error_text || 'Close failed', true);
|
||||
return;
|
||||
}
|
||||
if (sandboxRow === row && sandboxCard) {
|
||||
sandboxCard.classList.add('d-none');
|
||||
sandboxRow = null;
|
||||
}
|
||||
row.remove();
|
||||
setStatus('Task closed');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('btnSandboxHide').addEventListener('click', function () {
|
||||
if (sandboxCard) {
|
||||
sandboxCard.classList.add('d-none');
|
||||
}
|
||||
sandboxRow = null;
|
||||
});
|
||||
|
||||
document.getElementById('tb_btn_abdm_scan_lookup').addEventListener('click', function () {
|
||||
var qrPayload = (sandboxQrPayloadInput.value || '').trim();
|
||||
if (!qrPayload) {
|
||||
setSandboxStatus('Paste QR payload first.', 'warning');
|
||||
return;
|
||||
}
|
||||
setSandboxStatus('Queuing Scan & Share lookup...');
|
||||
post('<?= base_url('AbdmGateway/scan_share_lookup') ?>', {
|
||||
qr_payload: qrPayload
|
||||
}, function (res) {
|
||||
if (res.ok !== 1) {
|
||||
setSandboxStatus(res.error_text || 'Scan lookup failed.', 'danger');
|
||||
return;
|
||||
}
|
||||
if (res.abha_id_hint) {
|
||||
sandboxAbhaInput.value = (res.abha_id_hint || '').toString().trim();
|
||||
}
|
||||
setSandboxStatus('Scan lookup queued. Queue ID: ' + (res.queue_id || '-'), 'success');
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('tb_btn_abdm_validate_abha').addEventListener('click', function () {
|
||||
var abha = (sandboxAbhaInput.value || '').trim();
|
||||
if (!/^\d{14}$/.test(abha)) {
|
||||
setSandboxStatus('ABHA must be a 14-digit number.', 'warning');
|
||||
return;
|
||||
}
|
||||
setSandboxStatus('Queuing ABHA validation...');
|
||||
post('<?= base_url('AbdmGateway/abha_validate') ?>', {
|
||||
abha_id: abha
|
||||
}, function (res) {
|
||||
if (res.ok !== 1) {
|
||||
setSandboxStatus(res.error_text || 'ABHA validation queue failed.', 'danger');
|
||||
return;
|
||||
}
|
||||
setSandboxStatus('ABHA validation queued. Queue ID: ' + (res.queue_id || '-'), 'success');
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('tb_btn_abdm_consent_request').addEventListener('click', function () {
|
||||
var ctx = currentSandboxContext();
|
||||
if (!ctx || ctx.patientId <= 0) {
|
||||
setSandboxStatus('Select an eligible OPD Publish row first.', 'warning');
|
||||
return;
|
||||
}
|
||||
if (!/^\d{14}$/.test(ctx.abhaId)) {
|
||||
setSandboxStatus('ABHA must be a 14-digit number.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
setSandboxStatus('Requesting consent...');
|
||||
post('<?= base_url('AbdmGateway/consent_request') ?>', {
|
||||
patient_id: ctx.patientId,
|
||||
abha_id: ctx.abhaId,
|
||||
purpose_code: (sandboxPurposeCodeInput.value || '').trim(),
|
||||
expires_at: (sandboxConsentExpiresInput.value || '').trim().replace('T', ' ')
|
||||
}, function (res) {
|
||||
if (res.ok !== 1) {
|
||||
setSandboxStatus(res.error_text || 'Consent request failed.', 'danger');
|
||||
return;
|
||||
}
|
||||
if (res.consent_handle) {
|
||||
sandboxConsentHandleInput.value = (res.consent_handle || '').toString();
|
||||
}
|
||||
setSandboxStatus('Consent requested. Handle: ' + (res.consent_handle || '-'), 'success');
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('tb_btn_abdm_share_fhir').addEventListener('click', function () {
|
||||
var ctx = currentSandboxContext();
|
||||
if (!ctx || ctx.patientId <= 0 || ctx.opdId <= 0) {
|
||||
setSandboxStatus('Select an eligible OPD Publish row first.', 'warning');
|
||||
return;
|
||||
}
|
||||
if (!/^\d{14}$/.test(ctx.abhaId)) {
|
||||
setSandboxStatus('ABHA must be a 14-digit number.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
setSandboxStatus('Checking consent and queuing FHIR share...');
|
||||
post('<?= base_url('AbdmGateway/share_prescription_bundle') ?>', {
|
||||
opd_id: ctx.opdId,
|
||||
opd_session_id: ctx.opdSessionId,
|
||||
patient_id: ctx.patientId,
|
||||
abha_id: ctx.abhaId,
|
||||
consent_handle: (sandboxConsentHandleInput.value || '').trim()
|
||||
}, function (res) {
|
||||
if (res.ok !== 1) {
|
||||
setSandboxStatus(res.error_text || 'FHIR share queue failed.', 'danger');
|
||||
return;
|
||||
}
|
||||
if (res.consent_handle) {
|
||||
sandboxConsentHandleInput.value = (res.consent_handle || '').toString();
|
||||
}
|
||||
setSandboxStatus('FHIR share queued. Queue ID: ' + (res.queue_id || '-'), 'success');
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('tb_btn_abdm_claim_status').addEventListener('click', function () {
|
||||
var docId = parseInt((sandboxClaimDocumentInput.value || '0').toString(), 10) || 0;
|
||||
if (docId <= 0) {
|
||||
setSandboxStatus('Enter Claim Document ID first.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
setSandboxStatus('Queuing claim status request...');
|
||||
post('<?= base_url('AbdmGateway/nhcx_claim_status_request') ?>', {
|
||||
document_id: docId
|
||||
}, function (res) {
|
||||
if (res.ok !== 1) {
|
||||
setSandboxStatus(res.error_text || 'Claim status queue failed.', 'danger');
|
||||
return;
|
||||
}
|
||||
setSandboxStatus('Claim status queued. Queue ID: ' + (res.queue_id || '-'), 'success');
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('btnRefresh').addEventListener('click', function () {
|
||||
window.location.reload();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,16 +21,18 @@ if ($authUser) {
|
|||
</thead>
|
||||
<tbody>
|
||||
<?php if (!empty($rows)) : ?>
|
||||
<?php foreach ($rows as $row) : ?>
|
||||
<?php foreach ($rows as $idx => $row) : ?>
|
||||
<?php $hasVitals = isset($row->has_vitals) && (int) $row->has_vitals === 1; ?>
|
||||
<?php $isBookedTab = ($tabType ?? '') === 'booking'; ?>
|
||||
<?php $isConfirmedForQueue = (int) ($row->is_confirmed_for_queue ?? 0) === 1; ?>
|
||||
<?php $hasPrescription = (int) ($row->has_prescription ?? 0) === 1; ?>
|
||||
<?php $hasQueueNo = (int) ($row->queue_no ?? 0) > 0; ?>
|
||||
<?php $showFullActions = $hasPrescription || $isConfirmedForQueue; ?>
|
||||
<?php $serialNo = ((int) $idx) + 1; ?>
|
||||
<tr data-opd-id="<?= esc((int) ($row->opd_id ?? 0)) ?>" data-has-vitals="<?= esc((int) ($row->has_vitals ?? 0)) ?>" data-has-prescription="<?= esc($showFullActions ? 1 : 0) ?>">
|
||||
<td><?= esc($row->opd_code ?? '') ?></td>
|
||||
<td><?= esc(($row->P_name ?? '') . ' { ' . ($row->p_rname ?? '') . ' }') ?></td>
|
||||
<?php if (!empty($showQueue)) : ?><td><?= $hasPrescription ? esc((int) ($row->queue_no ?? 0)) : '-' ?></td><?php endif; ?>
|
||||
<?php if (!empty($showQueue)) : ?><td><?= esc($serialNo) ?></td><?php endif; ?>
|
||||
<td><?= esc($row->p_code ?? '') ?></td>
|
||||
<td><?= esc($row->opd_type ?? '') ?> / Amt: <?= esc($row->opd_fee_amount ?? '') ?></td>
|
||||
<td>
|
||||
|
|
@ -45,6 +47,11 @@ if ($authUser) {
|
|||
</a>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<?php if (!empty($showQueue) && !$hasQueueNo) : ?>
|
||||
<button type="button" class="btn btn-outline-success btn-sm btn-opd-create-queue" data-opdid="<?= esc((int) ($row->opd_id ?? 0)) ?>" title="Queue">
|
||||
Queue
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if ($canOpenPrescription && $showFullActions) : ?>
|
||||
<a class="btn btn-outline-primary btn-sm" title="Consult" href="javascript:load_form('/Opd_prescription/Prescription/<?= esc((int) ($row->opd_id ?? 0)) ?>','Consult');">
|
||||
Consult
|
||||
|
|
|
|||
|
|
@ -314,48 +314,6 @@
|
|||
value="<?= esc($patient_master[0]->abha_address ?? $patient_master[0]->abha ?? '') ?>"
|
||||
placeholder="Enter ABHA Address">
|
||||
</div>
|
||||
<div class="card mt-2 border-primary-subtle">
|
||||
<div class="card-header py-1"><strong>ABDM Sandbox Actions</strong></div>
|
||||
<div class="card-body p-2">
|
||||
<div class="mb-2">
|
||||
<label class="form-label mb-1 small">QR Payload (Scan & Share)</label>
|
||||
<input type="text" class="form-control form-control-sm" id="abdm_qr_payload" placeholder="Paste scanned QR payload">
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-1 mb-2">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" id="btn_abdm_scan_lookup">Scan Lookup</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" id="btn_abdm_validate_abha">Validate ABHA</button>
|
||||
</div>
|
||||
|
||||
<div class="row g-1 mb-2">
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control form-control-sm" id="abdm_purpose_code" placeholder="Purpose (ex: CAREMGT)">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input type="datetime-local" class="form-control form-control-sm" id="abdm_consent_expires_at">
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-1 mb-2">
|
||||
<button type="button" class="btn btn-outline-success btn-sm" id="btn_abdm_consent_request">Request Consent</button>
|
||||
<button type="button" class="btn btn-outline-warning btn-sm" id="btn_abdm_share_fhir">Share FHIR</button>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label mb-1 small">Consent Handle</label>
|
||||
<input type="text" class="form-control form-control-sm" id="abdm_consent_handle" placeholder="Auto-filled after consent request">
|
||||
</div>
|
||||
|
||||
<div class="row g-1 mb-2">
|
||||
<div class="col-7">
|
||||
<input type="number" min="1" class="form-control form-control-sm" id="abdm_claim_document_id" placeholder="Claim Document ID">
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<button type="button" class="btn btn-outline-dark btn-sm w-100" id="btn_abdm_claim_status">Claim Status</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="small text-muted" id="abdm_action_status">Ready</div>
|
||||
</div>
|
||||
</div>
|
||||
<div><strong>OPD:</strong> <?= esc($opd_master[0]->opd_code ?? '') ?></div>
|
||||
<div><strong>Date:</strong> <?= esc($opd_master[0]->apointment_date ?? '') ?></div>
|
||||
<div><strong>Doctor:</strong> <?= esc($opd_master[0]->doc_name ?? '') ?></div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user