fix(abdm): enforce NRCeS ISO 8601 with Asia/Kolkata timezone offset across FHIR bundles and ABDM APIs to resolve midnight UTC date mismatch

This commit is contained in:
DevSoftTech Server 2026-10-21 03:19:00 +05:30
parent dfd546b2c2
commit 5ba548cbbc
4 changed files with 47 additions and 13 deletions

View File

@ -12284,12 +12284,42 @@ class AbdmGateway extends BaseController
$hospital = $this->getHospitalProfileForFhir();
$hospitalName = trim((string) ($hospital['name'] ?? '')) ?: 'Healthcare Facility';
$hospitalIdentifier = trim((string) ($hospital['hfr_id'] ?? '')) ?: 'local-hospital';
$invoiceDateTimestamp = strtotime((string) ($invoice['inv_date'] ?? ''));
$invoiceDate = $invoiceDateTimestamp !== false ? date('Y-m-d', $invoiceDateTimestamp) : date('Y-m-d');
$encounterStartTimestamp = strtotime((string) ($invoice['encounter_start'] ?? ''));
$encounterEndTimestamp = strtotime((string) ($invoice['encounter_end'] ?? ''));
$encounterStart = $encounterStartTimestamp !== false ? date('Y-m-d', $encounterStartTimestamp) : $invoiceDate;
$encounterEnd = $encounterEndTimestamp !== false ? date('Y-m-d', $encounterEndTimestamp) : $encounterStart;
$rawInvDate = trim((string) ($invoice['inv_date'] ?? ''));
$invoiceDateTimestamp = $rawInvDate !== '' ? strtotime($rawInvDate) : false;
$invoiceDateOnly = $invoiceDateTimestamp !== false ? date('Y-m-d', $invoiceDateTimestamp) : date('Y-m-d');
if ($rawInvDate !== '') {
if (str_contains($rawInvDate, ':')) {
$invoiceDate = (new \DateTime($rawInvDate, new \DateTimeZone('Asia/Kolkata')))->format('Y-m-d\TH:i:sP');
} elseif ($invoiceDateOnly === date('Y-m-d')) {
$invoiceDate = $issuedAt;
} else {
$invoiceDate = $invoiceDateOnly;
}
} else {
$invoiceDate = $issuedAt;
}
$rawStart = trim((string) ($invoice['encounter_start'] ?? ''));
if ($rawStart !== '') {
if (str_contains($rawStart, ':')) {
$encounterStart = (new \DateTime($rawStart, new \DateTimeZone('Asia/Kolkata')))->format('Y-m-d\TH:i:sP');
} else {
$encounterStart = $rawStart;
}
} else {
$encounterStart = $invoiceDate;
}
$rawEnd = trim((string) ($invoice['encounter_end'] ?? ''));
if ($rawEnd !== '') {
if (str_contains($rawEnd, ':')) {
$encounterEnd = (new \DateTime($rawEnd, new \DateTimeZone('Asia/Kolkata')))->format('Y-m-d\TH:i:sP');
} else {
$encounterEnd = $rawEnd;
}
} else {
$encounterEnd = $encounterStart;
}
$netAmount = (float) ($invoice['net_amount'] ?? $invoice['total_amount'] ?? 0);
$grossAmount = (float) ($invoice['total_amount'] ?? $invoice['net_amount'] ?? 0);
$invoiceTypeCode = trim((string) ($invoice['invoice_type_code'] ?? '99')) ?: '99';
@ -12565,7 +12595,7 @@ class AbdmGateway extends BaseController
'text' => [
'status' => 'generated',
'div' => '<div xmlns="http://www.w3.org/1999/xhtml"><p>' . $escape($invoiceTypeDisplay)
. ' visit on ' . $escape($invoiceDate) . ' at ' . $escape($hospitalName) . '</p></div>',
. ' visit on ' . $escape($invoiceDateOnly) . ' at ' . $escape($hospitalName) . '</p></div>',
],
'identifier' => [['system' => $identifierSystem . '/encounter', 'value' => $invoiceNumber]],
'status' => 'finished',

View File

@ -20,8 +20,7 @@ class HealthDocumentFhirGenerator extends AbstractModuleFhirGenerator
$docTitle = 'Medical Certificate';
}
$cleanDate = str_replace('-', '', $visitDate);
$defaultRef = 'DOC-' . $recordId . '-' . $cleanDate;
$defaultRef = 'DOC-' . $recordId . '-' . $visitDate;
$careContextReference = (string) ($source['care_context_reference'] ?? $defaultRef);
$careContextDisplay = (string) ($source['care_context_display'] ?? ($docTitle . ' (' . $visitDate . ')'));

View File

@ -24,6 +24,11 @@ class WellnessFhirGenerator extends AbstractModuleFhirGenerator
$composition = $this->buildBaseComposition($source, 'Wellness Record', '94500-6', 'Health and Wellness Record');
$composition['meta']['profile'] = ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/WellnessRecord'];
$composition['type'] = [
'coding' => [[
'system' => 'http://loinc.org',
'code' => '94500-6',
'display' => 'Wellness Record',
]],
'text' => 'Wellness Record',
];

View File

@ -1607,7 +1607,7 @@ class FhirR4Builder
*/
public function buildClaimBundle(array $patient, array $encounter, array $claim): array
{
$issuedAt = Time::now('Asia/Kolkata')->toDateTimeString();
$issuedAt = $this->isoTimestamp();
$patientRef = 'Patient/' . (string) ($patient['id'] ?? 'unknown');
$encounterRef = 'Encounter/' . (string) ($encounter['id'] ?? 'unknown');
@ -3019,7 +3019,7 @@ class FhirR4Builder
?array $practitioner = null,
?array $organization = null
): array {
$issuedAt = Time::now('Asia/Kolkata')->toDateTimeString();
$issuedAt = $this->isoTimestamp();
$patientRef = 'Patient/' . (string) ($patient['id'] ?? 'unknown');
$reportId = 'lab-rpt-' . (string) ($diagnosticReport['id'] ?? date('YmdHis'));
@ -3290,7 +3290,7 @@ class FhirR4Builder
array $encounter,
array $summary
): array {
$issuedAt = Time::now('Asia/Kolkata')->toDateTimeString();
$issuedAt = $this->isoTimestamp();
$encounterId = (string) ($encounter['id'] ?? 'enc-' . date('YmdHis'));
$patientRef = 'Patient/' . (string) ($patient['id'] ?? 'unknown');
$encounterRef = 'Encounter/' . $encounterId;
@ -3640,7 +3640,7 @@ class FhirR4Builder
array $lifestyle = [],
?array $practitioner = null
): array {
$issuedAt = Time::now('Asia/Kolkata')->toDateTimeString();
$issuedAt = $this->isoTimestamp();
$patientRef = 'Patient/' . (string) ($patient['id'] ?? 'unknown');
$entries = [['resource' => $this->buildPatientResource($patient)]];