fix(abdm): prevent system hang on live status check, support 24h/12h hour inputs, and release PHP session lock

This commit is contained in:
DevSoftTech Server 2026-10-08 15:52:50 +05:30
parent 5ad1598c21
commit b05081001e
2 changed files with 98 additions and 42 deletions

View File

@ -2212,6 +2212,10 @@ class Patient extends BaseController
'consent' => $consent,
];
if (session_status() === PHP_SESSION_ACTIVE) {
session_write_close();
}
try {
$result = $service->runOperation('consent_request', $payload);
} catch (\Throwable $e) {
@ -2278,6 +2282,10 @@ class Patient extends BaseController
]);
}
if (session_status() === PHP_SESSION_ACTIVE) {
session_write_close();
}
$service = new \App\Libraries\Abdm\M3HiuWorkflowService();
$flowRefId = trim((string) (
$this->request->getGet('request_id')
@ -2688,6 +2696,10 @@ class Patient extends BaseController
]);
}
if (session_status() === PHP_SESSION_ACTIVE) {
session_write_close();
}
$service = new \App\Libraries\Abdm\M3HiuWorkflowService();
$fetchPayload = [
'abha_address' => $abhaContext['abha_address'],
@ -3020,15 +3032,18 @@ class Patient extends BaseController
];
}
if (session_status() === PHP_SESSION_ACTIVE) {
session_write_close();
}
$service = new \App\Libraries\Abdm\M3HiuWorkflowService();
$reconcileOk = false;
$reconcileError = '';
$granted = false;
$artifactsFetched = 0;
$dataUpdates = 0;
$dataFailed = 0;
foreach ($reconcileJobs as $job) {
// Limit check to the most recent active jobs (max 2) to keep live status instantaneous
$activeJobs = array_slice($reconcileJobs, 0, 2);
foreach ($activeJobs as $job) {
$reconcilePayload = $job['payload'];
try {
$reconcile = $service->runOperation('consent_reconcile', $reconcilePayload);
@ -3044,21 +3059,15 @@ class Patient extends BaseController
$reconcileOk = true;
$this->persistConsentPhaseOnRequestRow((int) $job['anchor_row_id'], $reconcile);
$fetchSummary = ['granted' => false, 'data_updates' => 0, 'failed' => 0, 'artifact_ids' => []];
try {
$fetchSummary = $service->fetchAllArtifactsAfterGrant($reconcilePayload, $reconcile);
} catch (\Throwable $e) {
// Status was successfully reconciled even if the data-fetch
// cascade below fails transiently; don't hide that from the UI.
$dataFailed++;
}
if (! empty($fetchSummary['granted'])) {
$status = strtoupper(trim((string) (
$reconcile['workflow_state']
?? $reconcile['status']
?? $reconcile['consent_status']
?? ''
)));
if ($status === 'GRANTED') {
$granted = true;
$artifactsFetched += count($fetchSummary['artifact_ids'] ?? []) + 1;
}
$dataUpdates += (int) ($fetchSummary['data_updates'] ?? 0);
$dataFailed += (int) ($fetchSummary['failed'] ?? 0);
}
if (! $reconcileOk && $reconcileError === '') {
@ -3067,13 +3076,13 @@ class Patient extends BaseController
return $this->response->setJSON([
'ok' => 1,
'sessions_checked' => count($reconcileJobs),
'sessions_checked' => count($activeJobs),
'reconcile_ok' => $reconcileOk ? 1 : 0,
'reconcile_error' => $reconcileOk ? '' : $reconcileError,
'granted' => $granted ? 1 : 0,
'artifacts_fetched' => $artifactsFetched,
'data_fetch_updates' => $dataUpdates,
'data_fetch_failed' => $dataFailed,
'artifacts_fetched' => 0,
'data_fetch_updates' => 0,
'data_fetch_failed' => 0,
] + $this->getAbdmConsentRequestsList($abhaAddress));
}

View File

@ -1064,7 +1064,7 @@ if ($patientPhotoPath === '') {
<input type="date" class="form-control mb-1" id="abdmCustomDateFrom_date">
<div class="input-group input-group-sm">
<span class="input-group-text bg-light text-muted px-2" title="Time"><i class="fa fa-clock-o"></i></span>
<input type="number" min="1" max="12" class="form-control text-center px-1" id="abdmCustomDateFrom_hour" placeholder="12" title="Hour (1-12)">
<input type="number" min="1" max="12" class="form-control text-center px-1 abdm-hour-input" data-prefix="abdmCustomDateFrom" id="abdmCustomDateFrom_hour" placeholder="12" title="Hour (1-12)">
<span class="input-group-text px-1">:</span>
<input type="number" min="0" max="59" class="form-control text-center px-1" id="abdmCustomDateFrom_minute" placeholder="00" title="Minute (0-59)">
<select class="form-select fw-bold text-primary px-1" id="abdmCustomDateFrom_ampm" style="max-width: 72px;" title="AM/PM">
@ -1078,7 +1078,7 @@ if ($patientPhotoPath === '') {
<input type="date" class="form-control mb-1" id="abdmCustomDateTo_date">
<div class="input-group input-group-sm">
<span class="input-group-text bg-light text-muted px-2" title="Time"><i class="fa fa-clock-o"></i></span>
<input type="number" min="1" max="12" class="form-control text-center px-1" id="abdmCustomDateTo_hour" placeholder="12" title="Hour (1-12)">
<input type="number" min="1" max="12" class="form-control text-center px-1 abdm-hour-input" data-prefix="abdmCustomDateTo" id="abdmCustomDateTo_hour" placeholder="12" title="Hour (1-12)">
<span class="input-group-text px-1">:</span>
<input type="number" min="0" max="59" class="form-control text-center px-1" id="abdmCustomDateTo_minute" placeholder="00" title="Minute (0-59)">
<select class="form-select fw-bold text-primary px-1" id="abdmCustomDateTo_ampm" style="max-width: 72px;" title="AM/PM">
@ -1092,9 +1092,9 @@ if ($patientPhotoPath === '') {
<input type="date" class="form-control mb-1" id="abdmCustomEraseDate_date">
<div class="input-group input-group-sm">
<span class="input-group-text bg-light text-muted px-2" title="Time"><i class="fa fa-clock-o"></i></span>
<input type="number" min="1" max="12" class="form-control text-center px-1" id="abdmCustomEraseDate_hour" placeholder="11" title="Hour (1-12)">
<input type="number" min="1" max="12" class="form-control text-center px-1 abdm-hour-input" data-prefix="abdmCustomEraseDate" id="abdmCustomEraseDate_hour" placeholder="12" title="Hour (1-12)">
<span class="input-group-text px-1">:</span>
<input type="number" min="0" max="59" class="form-control text-center px-1" id="abdmCustomEraseDate_minute" placeholder="59" title="Minute (0-59)">
<input type="number" min="0" max="59" class="form-control text-center px-1" id="abdmCustomEraseDate_minute" placeholder="00" title="Minute (0-59)">
<select class="form-select fw-bold text-primary px-1" id="abdmCustomEraseDate_ampm" style="max-width: 72px;" title="AM/PM">
<option value="AM">AM</option>
<option value="PM" selected>PM</option>
@ -1287,7 +1287,16 @@ $(function() {
$('#abdmRequestsTable tbody').html(html);
}
var abdmLoadingRequests = false;
function loadAbdmConsentRequests() {
if (abdmLoadingRequests) {
return;
}
abdmLoadingRequests = true;
var $btn = $('#btnRefreshAbdmRequests');
var origText = $btn.text();
$btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>Refreshing...');
fetch(abdmConsentRequestsUrl, { credentials: 'same-origin' })
.then(function(resp) { return resp.json(); })
.then(function(data) {
@ -1299,6 +1308,10 @@ $(function() {
})
.catch(function(err) {
$('#abdmRequestsTable tbody').html('<tr><td colspan="7" class="text-danger text-center">' + escHtml('Failed to load consent request history: ' + (err.message || err)) + '</td></tr>');
})
.finally(function() {
abdmLoadingRequests = false;
$btn.prop('disabled', false).text(origText || 'Refresh');
});
}
@ -1671,7 +1684,16 @@ $(function() {
return html;
}
var abdmLoadingDocs = false;
function loadAbdmDocs() {
if (abdmLoadingDocs) {
return;
}
abdmLoadingDocs = true;
var $btn = $('#btnLoadAbdmDocs');
var origText = $btn.text();
$btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>Refreshing...');
var q = ($('#abdmDocSearch').val() || '').toString().trim();
var url = abdmDocumentsUrl + '?limit=200';
if (q !== '') {
@ -1689,6 +1711,10 @@ $(function() {
})
.catch(function(err) {
setAbdmStatus('ABDM load failed: ' + (err.message || err), true);
})
.finally(function() {
abdmLoadingDocs = false;
$btn.prop('disabled', false).text(origText || 'Refresh list');
});
}
@ -1798,7 +1824,8 @@ $(function() {
if (!data.reconcile_ok) {
setAbdmStatus('Refreshed from last saved status (bridge check failed: ' + (data.reconcile_error || 'unknown error') + ').', true);
} else if (data.granted) {
setAbdmStatus('Live status: GRANTED. Fetched data for ' + (data.artifacts_fetched || 0) + ' facility artifact(s)' + (data.data_fetch_failed ? (', ' + data.data_fetch_failed + ' failed') : '') + '.');
setAbdmStatus('Live status: GRANTED. Health records are being synced in the background.');
loadAbdmDocs();
} else {
var latestStatus = ((currentAbdmRequests[0] && currentAbdmRequests[0].status) || '').toString().toUpperCase();
if (latestStatus === 'REVOKED') {
@ -1886,25 +1913,44 @@ $(function() {
if (!dateVal) {
return '';
}
var h = parseInt($('#' + prefix + '_hour').val(), 10);
var m = parseInt($('#' + prefix + '_minute').val(), 10);
if (isNaN(h) || h < 1 || h > 12) {
h = defaultEndOfDay ? 11 : 12;
}
if (isNaN(m) || m < 0 || m > 59) {
m = defaultEndOfDay ? 59 : 0;
}
var rawH = parseInt($('#' + prefix + '_hour').val(), 10);
var rawM = parseInt($('#' + prefix + '_minute').val(), 10);
var ampm = ($('#' + prefix + '_ampm').val() || (defaultEndOfDay ? 'PM' : 'AM')).toUpperCase();
var h24 = h;
if (ampm === 'PM' && h < 12) {
h24 += 12;
} else if (ampm === 'AM' && h === 12) {
var h24 = 0;
if (isNaN(rawH)) {
h24 = defaultEndOfDay ? 23 : 0;
} else if (rawH >= 13 && rawH <= 23) {
// User entered 24-hour format like 15 -> 15:00
h24 = rawH;
} else if (rawH === 12) {
h24 = (ampm === 'AM') ? 0 : 12;
} else if (rawH >= 1 && rawH <= 11) {
h24 = (ampm === 'PM') ? (rawH + 12) : rawH;
} else if (rawH === 0) {
h24 = 0;
} else {
h24 = defaultEndOfDay ? 23 : 0;
}
var m = isNaN(rawM) || rawM < 0 || rawM > 59 ? (defaultEndOfDay ? 59 : 0) : rawM;
var s = defaultEndOfDay ? 59 : 0;
return dateVal + ' ' + pad2(h24) + ':' + pad2(m) + ':' + pad2(s);
}
$(document).off('input change blur', '.abdm-hour-input').on('input change blur', '.abdm-hour-input', function() {
var prefix = $(this).data('prefix');
var val = parseInt($(this).val(), 10);
if (isNaN(val)) return;
if (val >= 13 && val <= 23) {
$(this).val(val - 12);
$('#' + prefix + '_ampm').val('PM');
} else if (val === 0) {
$(this).val(12);
$('#' + prefix + '_ampm').val('AM');
}
});
$('#abdmCustomConsentModal').on('show.bs.modal', function() {
$('#abdmCustomConsentError').addClass('d-none').text('');
@ -1928,14 +1974,15 @@ $(function() {
$('#abdmCustomDateTo_ampm').val(parts.ampm);
}
// Expiry Date: 1 year from now, 11:59:59 PM
// Expiry Date: 1 year from now, matching current time
if (!$('#abdmCustomEraseDate_date').val()) {
var erase = new Date();
erase.setFullYear(erase.getFullYear() + 1);
var eraseParts = get12HourParts(erase);
$('#abdmCustomEraseDate_date').val(formatDateInput(erase));
$('#abdmCustomEraseDate_hour').val('11');
$('#abdmCustomEraseDate_minute').val('59');
$('#abdmCustomEraseDate_ampm').val('PM');
$('#abdmCustomEraseDate_hour').val(eraseParts.hour);
$('#abdmCustomEraseDate_minute').val(eraseParts.minute);
$('#abdmCustomEraseDate_ampm').val(eraseParts.ampm);
}
});