Add ABDM M3 fetch option to Ayushman claim sheet

This commit is contained in:
DevSoftTech Server 2026-07-19 01:19:56 +05:30
parent 7a547eb443
commit 2bd52532a0
2 changed files with 261 additions and 0 deletions

View File

@ -1918,6 +1918,7 @@ class Ipd extends BaseController
'person_info' => $panelData['person_info'] ?? null,
'checklist_items' => $checklistItems,
'generated_at' => date('d-m-Y H:i:s'),
'output' => $output,
];
$content = view('billing/ipd/ayushman_claim_sheet', $data);

View File

@ -3,6 +3,13 @@ $ipd = $ipd_info ?? null;
$person = $person_info ?? null;
$items = $checklist_items ?? [];
$generatedAt = $generated_at ?? date('d-m-Y H:i:s');
$isExport = (int) ($output ?? 0) === 1;
$patientId = (int) (($person->id ?? null) ?: ($ipd->p_id ?? 0));
$abhaNumber = trim((string) (($person->abha_id ?? '') ?: ($person->abha_no ?? '') ?: ($person->abha ?? '')));
$abhaAddress = trim((string) ($person->abha_address ?? ''));
$abhaVerifiedRaw = strtolower(trim((string) (($person->abha_verified_status ?? '') ?: ($person->abha_status ?? '') ?: ($person->abha_verified ?? ''))));
$abhaLooksVerified = in_array($abhaVerifiedRaw, ['1', 'verified', 'yes', 'y', 'true'], true);
$canUseM3 = $patientId > 0 && $abhaAddress !== '';
?>
<section class="content">
@ -32,6 +39,58 @@ $generatedAt = $generated_at ?? date('d-m-Y H:i:s');
<div class="col-md-12"><strong>Remark:</strong> <?= esc((string) ($ipd->remark ?? '')) ?></div>
</div>
<?php if (! $isExport) : ?>
<div class="card border-info mb-3 d-print-none" id="ayushmanAbdmM3Panel">
<div class="card-header py-2 d-flex justify-content-between align-items-center flex-wrap gap-2">
<div>
<div class="fw-semibold">ABDM M3 Related Data</div>
<div class="small text-muted">
ABHA Number: <strong><?= $abhaNumber !== '' ? esc($abhaNumber) : 'Not available' ?></strong>
&nbsp;|&nbsp; ABHA Address: <strong><?= $abhaAddress !== '' ? esc($abhaAddress) : 'Not available' ?></strong>
&nbsp;|&nbsp; Status: <?= $abhaLooksVerified ? '<span class="badge bg-success">Verified</span>' : '<span class="badge bg-secondary">Not verified in HMS</span>' ?>
</div>
</div>
<div class="d-flex gap-2 flex-wrap">
<button type="button" class="btn btn-sm btn-outline-primary" id="btnAyushmanLoadAbdmDocs" <?= $patientId > 0 ? '' : 'disabled' ?>>Load Fetched Data</button>
<button type="button" class="btn btn-sm btn-success" id="btnAyushmanFetchAbdmM3" <?= $canUseM3 ? '' : 'disabled' ?>>Fetch From ABDM M3</button>
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="load_form('<?= site_url('AbdmHiu') ?>','ABDM HIU M3')">Open M3 Console</button>
</div>
</div>
<div class="card-body">
<div class="small text-muted mb-2" id="ayushmanAbdmStatus">
<?= $canUseM3 ? 'Use Fetch From ABDM M3 to request consent and poll approved records, or load already fetched documents.' : 'ABHA address is required before M3 fetch can be started.' ?>
</div>
<div class="row g-3">
<div class="col-lg-5">
<div class="input-group input-group-sm mb-2">
<input type="text" class="form-control" id="ayushmanAbdmSearch" placeholder="Search title, care context, doctor">
<button class="btn btn-outline-secondary" type="button" id="btnAyushmanSearchAbdmDocs">Search</button>
</div>
<div class="table-responsive border rounded" style="max-height: 260px;">
<table class="table table-sm table-hover mb-0" id="ayushmanAbdmDocTable">
<thead class="table-light">
<tr>
<th>Date</th>
<th>Title</th>
<th>Care Context</th>
</tr>
</thead>
<tbody>
<tr><td colspan="3" class="text-muted text-center">No ABDM records loaded.</td></tr>
</tbody>
</table>
</div>
</div>
<div class="col-lg-7">
<div class="border rounded p-3 bg-light h-100" id="ayushmanAbdmDetailBox">
<div class="text-muted">Select a fetched ABDM document to view claim-supporting clinical summary.</div>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
<?php if (empty($items)) : ?>
<div class="alert alert-warning">No Ayushman procedures linked to this IPD package list.</div>
<?php else : ?>
@ -68,3 +127,204 @@ $generatedAt = $generated_at ?? date('d-m-Y H:i:s');
</div>
</div>
</section>
<?php if (! $isExport) : ?>
<script>
(function () {
var patientId = <?= (int) $patientId ?>;
var docsUrl = '<?= site_url('billing/patient/abdm_documents/' . (int) $patientId) ?>';
var detailBaseUrl = '<?= site_url('billing/patient/abdm_document_detail/' . (int) $patientId) ?>';
var autoFlowUrl = '<?= site_url('billing/patient/abdm_content_auto_flow/' . (int) $patientId) ?>';
var currentRequestId = '';
var pollTimer = null;
var pollAttempts = 0;
var maxPollAttempts = 15;
function esc(value) {
return $('<div>').text(value == null ? '' : String(value)).html();
}
function setStatus(message, isError) {
$('#ayushmanAbdmStatus')
.toggleClass('text-danger', !!isError)
.toggleClass('text-muted', !isError)
.text(message || '');
}
function formatDate(value) {
var text = (value || '').toString().trim();
return text !== '' ? text.replace('T', ' ') : '-';
}
function renderRows(rows) {
var html = '';
if (!rows || !rows.length) {
$('#ayushmanAbdmDocTable tbody').html('<tr><td colspan="3" class="text-muted text-center">No ABDM fetched records found.</td></tr>');
$('#ayushmanAbdmDetailBox').html('<div class="text-muted">No fetched ABDM documents are mapped to this patient yet.</div>');
return;
}
rows.forEach(function (row) {
html += '<tr class="ayushman-abdm-doc-row" data-id="' + esc(row.id) + '">' +
'<td>' + esc(formatDate(row.document_date || row.created_at)) + '</td>' +
'<td>' + esc(row.document_title || '-') + '</td>' +
'<td>' + esc(row.care_context_reference || '-') + '</td>' +
'</tr>';
});
$('#ayushmanAbdmDocTable tbody').html(html);
}
function renderDetail(item) {
if (!item) {
$('#ayushmanAbdmDetailBox').html('<div class="text-muted">Document detail unavailable.</div>');
return;
}
var summary = item.summary || {};
var conditions = Array.isArray(summary.conditions) ? summary.conditions : [];
var vitals = Array.isArray(summary.vitals) ? summary.vitals : [];
var meds = Array.isArray(summary.medications) ? summary.medications : [];
var html = '';
html += '<div class="fw-semibold mb-1">' + esc(item.document_title || 'ABDM Document') + '</div>';
html += '<div class="small text-muted mb-2">' + esc(formatDate(item.document_date || item.created_at)) + ' | ' + esc(item.bundle_type || '-') + '</div>';
html += '<div class="small mb-2">Care Context: <strong>' + esc(item.care_context_reference || '-') + '</strong></div>';
html += '<div class="small mb-3">Doctor: <strong>' + esc(item.practitioner_name || '-') + '</strong> | Organization: <strong>' + esc(item.organization_name || '-') + '</strong></div>';
html += '<div class="row g-2">';
html += renderList('Diagnoses', conditions, function (row) { return row && row.text ? row.text : '-'; });
html += renderList('Vitals', vitals, function (row) { return ((row && row.name) || '-') + ': ' + ((row && row.value) || '-'); });
html += renderList('Medications', meds, function (row) { return ((row && row.name) || '-') + ((row && row.dose) ? (' | ' + row.dose) : ''); });
html += '</div>';
$('#ayushmanAbdmDetailBox').html(html);
}
function renderList(title, rows, formatter) {
var list = Array.isArray(rows) ? rows : [];
var html = '<div class="col-md-4"><div class="border rounded p-2 h-100 bg-white"><div class="fw-semibold small mb-1">' + esc(title) + '</div><ul class="mb-0 small ps-3">';
if (!list.length) {
html += '<li class="text-muted">No data</li>';
} else {
list.forEach(function (row) {
html += '<li>' + esc(formatter(row)) + '</li>';
});
}
html += '</ul></div></div>';
return html;
}
function loadDocs() {
if (patientId <= 0) {
setStatus('Patient ID not available for ABDM document lookup.', true);
return;
}
var q = ($('#ayushmanAbdmSearch').val() || '').toString().trim();
var url = docsUrl + '?limit=100';
if (q !== '') {
url += '&q=' + encodeURIComponent(q);
}
setStatus('Loading fetched ABDM records...', false);
fetch(url, { credentials: 'same-origin' })
.then(function (response) { return response.json(); })
.then(function (data) {
if (!data || parseInt(data.ok || 0, 10) !== 1) {
throw new Error((data && data.error) || 'Unable to load ABDM records.');
}
var rows = Array.isArray(data.items) ? data.items : [];
renderRows(rows);
setStatus('Loaded ' + rows.length + ' fetched ABDM record(s).', false);
})
.catch(function (error) {
setStatus('ABDM load failed: ' + (error.message || error), true);
});
}
function loadDetail(docId) {
if (!docId) {
return;
}
$('#ayushmanAbdmDetailBox').html('<div class="text-muted">Loading document detail...</div>');
fetch(detailBaseUrl + '/' + encodeURIComponent(docId), { credentials: 'same-origin' })
.then(function (response) { return response.json(); })
.then(function (data) {
if (!data || parseInt(data.ok || 0, 10) !== 1) {
throw new Error((data && data.error) || 'Unable to load document detail.');
}
renderDetail(data.item || null);
})
.catch(function (error) {
$('#ayushmanAbdmDetailBox').html('<div class="text-danger">' + esc('Detail load failed: ' + (error.message || error)) + '</div>');
});
}
function stopPolling() {
if (pollTimer) {
clearTimeout(pollTimer);
pollTimer = null;
}
}
function runM3AutoFlow() {
var url = autoFlowUrl;
if (currentRequestId !== '') {
url += '?request_id=' + encodeURIComponent(currentRequestId);
}
fetch(url, { credentials: 'same-origin' })
.then(function (response) { return response.json(); })
.then(function (data) {
if (!data || parseInt(data.ok || 0, 10) !== 1) {
throw new Error((data && data.error) || 'M3 fetch failed.');
}
currentRequestId = (data.request_id || currentRequestId || '').toString();
var phase = (data.phase || '').toString();
var message = (data.message || ('Phase: ' + (phase || 'UNKNOWN'))).toString();
setStatus(message + (currentRequestId ? (' | Request ID: ' + currentRequestId) : ''), false);
if (parseInt(data.poll_again || 0, 10) === 1 && pollAttempts < maxPollAttempts) {
pollAttempts += 1;
pollTimer = setTimeout(runM3AutoFlow, 8000);
return;
}
$('#btnAyushmanFetchAbdmM3').prop('disabled', false).text('Fetch From ABDM M3');
if (phase === 'COMPLETED') {
loadDocs();
}
})
.catch(function (error) {
stopPolling();
$('#btnAyushmanFetchAbdmM3').prop('disabled', false).text('Fetch From ABDM M3');
setStatus('M3 fetch failed: ' + (error.message || error), true);
});
}
$(document).off('click.ayushmanAbdm', '#btnAyushmanLoadAbdmDocs').on('click.ayushmanAbdm', '#btnAyushmanLoadAbdmDocs', loadDocs);
$(document).off('click.ayushmanAbdm', '#btnAyushmanSearchAbdmDocs').on('click.ayushmanAbdm', '#btnAyushmanSearchAbdmDocs', loadDocs);
$(document).off('keypress.ayushmanAbdm', '#ayushmanAbdmSearch').on('keypress.ayushmanAbdm', '#ayushmanAbdmSearch', function (event) {
if (event.which === 13) {
event.preventDefault();
loadDocs();
}
});
$(document).off('click.ayushmanAbdm', '#ayushmanAbdmDocTable .ayushman-abdm-doc-row').on('click.ayushmanAbdm', '#ayushmanAbdmDocTable .ayushman-abdm-doc-row', function () {
$('#ayushmanAbdmDocTable .ayushman-abdm-doc-row').removeClass('table-active');
$(this).addClass('table-active');
loadDetail($(this).data('id'));
});
$(document).off('click.ayushmanAbdm', '#btnAyushmanFetchAbdmM3').on('click.ayushmanAbdm', '#btnAyushmanFetchAbdmM3', function () {
var $button = $(this);
if ($button.prop('disabled')) {
return;
}
stopPolling();
currentRequestId = '';
pollAttempts = 0;
$button.prop('disabled', true).text('Fetching...');
setStatus('Starting ABDM M3 consent and data fetch flow...', false);
runM3AutoFlow();
});
})();
</script>
<?php endif; ?>