From e86e73d792499f510d693d59a9457882ea4b051b Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Thu, 8 Oct 2026 09:34:34 +0530 Subject: [PATCH] fix(abdm): isolate care context hi_types during linking and prevent multiple DocumentReference in DiagnosticReport --- app/Controllers/AbdmGateway.php | 14 +++- app/Libraries/FhirR4Builder.php | 80 ++++++++++++---------- app/Views/partials/abdm_hip_link_modal.php | 10 +-- 3 files changed, 60 insertions(+), 44 deletions(-) diff --git a/app/Controllers/AbdmGateway.php b/app/Controllers/AbdmGateway.php index b52b6a3..46dea12 100644 --- a/app/Controllers/AbdmGateway.php +++ b/app/Controllers/AbdmGateway.php @@ -7070,8 +7070,18 @@ class AbdmGateway extends BaseController if ($hiType === '' || ($hiType === 'HealthDocumentRecord' && str_starts_with($ccRef, 'WELLNESS-'))) { $hiType = str_starts_with($ccRef, 'WELLNESS-') ? 'WellnessRecord' : 'HealthDocumentRecord'; } - $dateStr = date('d M Y', strtotime((string) ($row['created_at'] ?? $row['updated_at'] ?? 'now'))); - $display = ($hiType === 'WellnessRecord' ? 'Wellness Record - ' : ($hiType . ' - ')) . $dateStr; + $friendlyType = match ($hiType) { + 'DiagnosticReportRecord' => 'Diagnostic Report - ', + 'PrescriptionRecord' => 'Prescription - ', + 'OPConsultRecord' => 'OP Consultation - ', + 'DischargeSummaryRecord' => 'Discharge Summary - ', + 'ImmunizationRecord' => 'Immunization Record - ', + 'WellnessRecord' => 'Wellness Record - ', + 'HealthDocumentRecord' => 'Health Document - ', + 'InvoiceRecord' => 'Invoice - ', + default => $hiType . ' - ', + }; + $display = $friendlyType . $dateStr; $addContext([ 'careContextId' => $ccRef, diff --git a/app/Libraries/FhirR4Builder.php b/app/Libraries/FhirR4Builder.php index ee6a328..0774a4c 100644 --- a/app/Libraries/FhirR4Builder.php +++ b/app/Libraries/FhirR4Builder.php @@ -981,52 +981,31 @@ class FhirR4Builder $observationEntries[] = ['fullUrl' => $obsRef, 'resource' => $obsResource]; } - // ── Binary + DocumentReference for HTML report ───────────────────────── + // ── Single DocumentReference (prefer PDF attachment if available, otherwise HTML) ───── $docRefEntry = null; $docRefRef = null; - $pdfDocRefRef = null; - $mediaRef = null; - $reportHtml = trim((string) ($diagnosticReport['report_html'] ?? '')); - if ($reportHtml !== '') { - $binaryUuid = $this->generateUuid(); - $docRefUuid = $this->generateUuid(); - $docRefRef = 'urn:uuid:' . $docRefUuid; - $contentType = trim((string) ($diagnosticReport['report_content_type'] ?? 'text/html; charset=utf-8')); + $pdfBinaryRef = null; + $pdfData = ''; + $mediaRef = null; - $resourceEntries[] = ['fullUrl' => 'urn:uuid:' . $binaryUuid, 'resource' => [ - 'resourceType' => 'Binary', - 'id' => $binaryUuid, - 'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/Binary']], - 'contentType' => $contentType, - 'data' => base64_encode($reportHtml), - ]]; + $hasAttachment = ($attachment !== null && ! empty($attachment['data_base64'])); + $docRefSnomedCode = $isImaging ? '371531008' : '4241000179101'; + $docRefSnomedDisplay = $isImaging ? 'Report of radiological study' : 'Laboratory report'; - $docRefEntry = [ - 'resourceType' => 'DocumentReference', - 'id' => $docRefUuid, - 'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/DocumentReference']], - 'status' => 'current', - 'type' => ['coding' => [['system' => 'http://snomed.info/sct', 'code' => '721981007', 'display' => 'Diagnostic studies report']]], - 'subject' => ['reference' => $patientRef], - 'content' => [['attachment' => ['contentType' => $contentType, 'url' => 'urn:uuid:' . $binaryUuid, 'data' => base64_encode($reportHtml), 'title' => $reportTitle]]], - ]; - $resourceEntries[] = ['fullUrl' => $docRefRef, 'resource' => $docRefEntry]; - } - - // ── Optional PDF attachment as Binary + DocumentReference ─────────── - if ($attachment !== null && ! empty($attachment['data_base64'])) { + if ($hasAttachment) { $pdfData = trim((string) ($attachment['data_base64'] ?? '')); if ($pdfData !== '') { $pdfBinaryUuid = $this->generateUuid(); + $pdfBinaryRef = 'urn:uuid:' . $pdfBinaryUuid; $pdfDocRefUuid = $this->generateUuid(); - $pdfDocRefRef = 'urn:uuid:' . $pdfDocRefUuid; + $docRefRef = 'urn:uuid:' . $pdfDocRefUuid; $pdfContentType = trim((string) ($attachment['content_type'] ?? 'application/pdf')) ?: 'application/pdf'; - $pdfTitle = trim((string) ($attachment['title'] ?? 'Lab Report PDF')) ?: 'Lab Report PDF'; + $pdfTitle = trim((string) ($attachment['title'] ?? ($isImaging ? 'Radiology Report PDF' : 'Lab Report PDF'))) ?: ($isImaging ? 'Radiology Report PDF' : 'Lab Report PDF'); $pdfBytes = base64_decode($pdfData, true); $pdfSize = (int) ($attachment['size'] ?? (is_string($pdfBytes) ? strlen($pdfBytes) : 0)); $pdfHash = trim((string) ($attachment['hash'] ?? (is_string($pdfBytes) ? base64_encode(sha1($pdfBytes, true)) : ''))); - $resourceEntries[] = ['fullUrl' => 'urn:uuid:' . $pdfBinaryUuid, 'resource' => [ + $resourceEntries[] = ['fullUrl' => $pdfBinaryRef, 'resource' => [ 'resourceType' => 'Binary', 'id' => $pdfBinaryUuid, 'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/Binary']], @@ -1034,17 +1013,17 @@ class FhirR4Builder 'data' => $pdfData, ]]; - $resourceEntries[] = ['fullUrl' => $pdfDocRefRef, 'resource' => [ + $resourceEntries[] = ['fullUrl' => $docRefRef, 'resource' => [ 'resourceType' => 'DocumentReference', 'id' => $pdfDocRefUuid, 'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/DocumentReference']], 'status' => 'current', - 'type' => ['coding' => [['system' => 'http://snomed.info/sct', 'code' => '721981007', 'display' => 'Diagnostic studies report']]], + 'type' => ['coding' => [['system' => 'http://snomed.info/sct', 'code' => $docRefSnomedCode, 'display' => $docRefSnomedDisplay]]], 'subject' => ['reference' => $patientRef], 'content' => [[ 'attachment' => array_filter([ 'contentType' => $pdfContentType, - 'url' => 'urn:uuid:' . $pdfBinaryUuid, + 'url' => $pdfBinaryRef, 'data' => $pdfData, 'title' => $pdfTitle, 'size' => $pdfSize > 0 ? $pdfSize : null, @@ -1066,17 +1045,42 @@ class FhirR4Builder 'createdDateTime' => $reportedAt, 'content' => [ 'contentType' => $pdfContentType, - 'url' => 'urn:uuid:' . $pdfBinaryUuid, + 'url' => $pdfBinaryRef, 'data' => $pdfData, 'title' => $pdfTitle, ], ]]; } } + } elseif ($reportHtml !== '') { + $binaryUuid = $this->generateUuid(); + $binaryRef = 'urn:uuid:' . $binaryUuid; + $docRefUuid = $this->generateUuid(); + $docRefRef = 'urn:uuid:' . $docRefUuid; + $contentType = trim((string) ($diagnosticReport['report_content_type'] ?? 'text/html; charset=utf-8')); + + $resourceEntries[] = ['fullUrl' => $binaryRef, 'resource' => [ + 'resourceType' => 'Binary', + 'id' => $binaryUuid, + 'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/Binary']], + 'contentType' => $contentType, + 'data' => base64_encode($reportHtml), + ]]; + + $docRefEntry = [ + 'resourceType' => 'DocumentReference', + 'id' => $docRefUuid, + 'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/DocumentReference']], + 'status' => 'current', + 'type' => ['coding' => [['system' => 'http://snomed.info/sct', 'code' => $docRefSnomedCode, 'display' => $docRefSnomedDisplay]]], + 'subject' => ['reference' => $patientRef], + 'content' => [['attachment' => ['contentType' => $contentType, 'url' => $binaryRef, 'data' => base64_encode($reportHtml), 'title' => $reportTitle]]], + ]; + $resourceEntries[] = ['fullUrl' => $docRefRef, 'resource' => $docRefEntry]; } // Pick a single DocumentReference for Composition.section slicing (0..1). - $effectiveDocRefRef = $pdfDocRefRef !== null ? $pdfDocRefRef : $docRefRef; + $effectiveDocRefRef = $docRefRef; // ── DiagnosticReport ────────────────────────────────────────────────── $reportRes = [ diff --git a/app/Views/partials/abdm_hip_link_modal.php b/app/Views/partials/abdm_hip_link_modal.php index b6ebbc0..1e965dc 100644 --- a/app/Views/partials/abdm_hip_link_modal.php +++ b/app/Views/partials/abdm_hip_link_modal.php @@ -635,9 +635,9 @@ ctxTaskType = 'health_document_publish'; var dm = firstRef.match(/^DOC-(?:file-)?(\d+)/i); if (dm && !ctxEntityId) ctxEntityId = dm[1]; - } else if (/^(?:OPD|PRESCRIPTION)-/i.test(firstRef)) { + } else if (/^(?:OPD|PRESCRIPTION|PRESC)-/i.test(firstRef)) { ctxTaskType = 'opd_prescription_publish'; - var om = firstRef.match(/^(?:OPD|PRESCRIPTION)-(\d+)/i); + var om = firstRef.match(/^(?:OPD|PRESC)-(?:\d+)-S(\d+)/i) || firstRef.match(/^(?:OPD|PRESCRIPTION|PRESC)-(\d+)/i); if (om && !ctxEntityId) ctxEntityId = om[1]; } else if (/^WELLNESS-/i.test(firstRef)) { ctxTaskType = 'wellness_record_publish'; @@ -686,7 +686,7 @@ if (!targetOpdId || targetOpdId === '0') { var refToParse = firstRef || (window.currentHipTaskContext ? window.currentHipTaskContext.careContext : ''); if (refToParse) { - var mOpd = refToParse.match(/OPD-(?:\d+)-S(\d+)/i) || refToParse.match(/OPD-(\d+)/i); + var mOpd = refToParse.match(/(?:OPD|PRESC)-(?:\d+)-S(\d+)/i) || refToParse.match(/(?:OPD|PRESC|PRESCRIPTION)-(\d+)/i); if (mOpd && mOpd[1]) { targetOpdId = mOpd[1]; } @@ -874,7 +874,9 @@ itemHiType = 'ImmunizationRecord'; } else if (/^(?:DISCHARGE|IPD)-/i.test(ref)) { itemHiType = 'DischargeSummaryRecord'; - } else if (/^(?:OPD|PRESC)-/i.test(ref)) { + } else if (/^(?:PRESC|PRESCRIPTION)-/i.test(ref)) { + itemHiType = 'PrescriptionRecord'; + } else if (/^OPD-/i.test(ref)) { itemHiType = 'OPConsultRecord'; } if (!dominantHiType && itemHiType) {