diff --git a/app/Controllers/AbdmFhirInspector.php b/app/Controllers/AbdmFhirInspector.php index eda87a8..bd5ce3e 100644 --- a/app/Controllers/AbdmFhirInspector.php +++ b/app/Controllers/AbdmFhirInspector.php @@ -218,9 +218,9 @@ class AbdmFhirInspector extends BaseController $labId = (int) $m[1]; $gw = new \App\Controllers\AbdmGateway(); $gw->initController($this->request, $this->response, service('logger')); - // Simulate request param $_GET['request_id'] = $labId; - return $gw->diagnosisReportFhirPreview(); + $_GET['lab_req_id'] = $labId; + return $gw->diagnosisReportFhirPreview($labId, $patientId, $abha); } // Invoices: INVOICE-OPD-{id}, INVOICE-CHG-{id}, INVOICE-IPD-{id} @@ -238,7 +238,7 @@ class AbdmFhirInspector extends BaseController $_GET['source'] = $source; $_GET['bill_id'] = $billId; $_GET['patient_id'] = $patientId; - return $gw->invoiceFhirPreview(); + return $gw->invoiceFhirPreview($source, $billId, $patientId, $abha); } // Immunization: IMM-{id} or IMM-{patientId}-V{id}-{date} @@ -252,7 +252,7 @@ class AbdmFhirInspector extends BaseController $gw->initController($this->request, $this->response, service('logger')); $_GET['record_id'] = $immId; $_GET['patient_id'] = $patientId; - return $gw->immunizationFhirPreview(); + return $gw->immunizationFhirPreview($immId, $patientId, $abha); } // Discharge Summary: DISCHARGE-{id} @@ -261,7 +261,7 @@ class AbdmFhirInspector extends BaseController $gw = new \App\Controllers\AbdmGateway(); $gw->initController($this->request, $this->response, service('logger')); $_GET['ipd_id'] = $ipdId; - return $gw->ipdDischargeFhirPreview(); + return $gw->ipdDischargeFhirPreview($ipdId, $patientId, $abha); } // Wellness Record: WELLNESS-{id} diff --git a/app/Controllers/AbdmGateway.php b/app/Controllers/AbdmGateway.php index 38557df..9ec7c45 100644 --- a/app/Controllers/AbdmGateway.php +++ b/app/Controllers/AbdmGateway.php @@ -2440,23 +2440,56 @@ class AbdmGateway extends BaseController ]; } - public function diagnosisReportFhirPreview() + public function diagnosisReportFhirPreview(?int $labReqIdParam = null, ?int $patientIdParam = null, ?string $abhaIdParam = null) { - if (! $this->request->isAJAX()) { - return $this->response->setStatusCode(403)->setJSON(['status' => 'error', 'message' => 'AJAX only']); + $hasGet = $this->request && method_exists($this->request, 'getGet'); + $hasPost = $this->request && method_exists($this->request, 'getPost'); + + $labReqId = $labReqIdParam + ?? ($hasGet ? (int) $this->request->getGet('lab_req_id') : 0) + ?: ($hasGet ? (int) $this->request->getGet('request_id') : 0) + ?: ($hasPost ? (int) $this->request->getPost('lab_req_id') : 0) + ?: (int) ($_GET['lab_req_id'] ?? $_GET['request_id'] ?? $_POST['lab_req_id'] ?? 0); + + if ($labReqId <= 0) { + $ref = trim((string) (($hasGet ? $this->request->getGet('ref') : '') + ?: ($hasGet ? $this->request->getGet('care_context_reference') : '') + ?: ($_GET['ref'] ?? $_GET['care_context_reference'] ?? ''))); + if ($ref !== '' && preg_match('/^(?:LAB|RAD)-(\d+)/i', $ref, $m)) { + $labReqId = (int) $m[1]; + } } - $labReqId = (int) ($this->request->getGet('lab_req_id') ?? $this->request->getPost('lab_req_id') ?? 0); - $patientId = (int) ($this->request->getGet('patient_id') ?? $this->request->getPost('patient_id') ?? 0); - $abhaId = trim((string) ($this->request->getGet('abha_id') ?? $this->request->getPost('abha_id') ?? '')); + $patientId = $patientIdParam + ?? ($hasGet ? (int) $this->request->getGet('patient_id') : 0) + ?: ($hasPost ? (int) $this->request->getPost('patient_id') : 0) + ?: (int) ($_GET['patient_id'] ?? $_POST['patient_id'] ?? 0); - if ($labReqId <= 0 || $patientId <= 0 || $abhaId === '') { + $abhaId = trim((string) ($abhaIdParam + ?? ($hasGet ? $this->request->getGet('abha_id') : '') + ?: ($hasPost ? $this->request->getPost('abha_id') : '') + ?: ($_GET['abha_id'] ?? $_GET['abha'] ?? $_POST['abha_id'] ?? ''))); + + if ($labReqId <= 0) { return $this->response->setStatusCode(400)->setJSON([ + 'ok' => 0, 'status' => 'error', - 'message' => 'lab_req_id, patient_id and abha_id are required.', + 'message' => 'lab_req_id is required.', ]); } + if ($patientId <= 0 && $this->db->tableExists('lab_request')) { + $lrRow = $this->db->table('lab_request')->select('patient_id')->where('id', $labReqId)->get(1)->getRowArray(); + if (! empty($lrRow['patient_id'])) { + $patientId = (int) $lrRow['patient_id']; + } + } + + if ($abhaId === '' && $patientId > 0) { + $ident = $this->resolvePatientAbhaIdentity($patientId); + $abhaId = $ident['abha_address'] ?: $ident['abha_id']; + } + $selectCols = ['id', 'patient_name', 'lab_type', 'charge_id', 'report_name', 'Report_Data', 'report_data_Impression', 'status', 'reported_time']; if ($this->db->fieldExists('charge_item_id', 'lab_request')) { $selectCols[] = 'charge_item_id'; @@ -2598,20 +2631,53 @@ class AbdmGateway extends BaseController ]); } - public function immunizationFhirPreview() + public function immunizationFhirPreview(?int $recordIdParam = null, ?int $patientIdParam = null, ?string $abhaIdParam = null) { - $patientId = (int) ($this->request->getGet('patient_id') ?? $this->request->getPost('patient_id') ?? 0); - $recordId = (int) ($this->request->getGet('record_id') ?? $this->request->getPost('record_id') ?? 0); - $abhaId = trim((string) ($this->request->getGet('abha_id') ?? $this->request->getPost('abha_id') ?? '')); - $forceNewRecord = (int) ($this->request->getGet('force_new_record') ?? $this->request->getGet('force_rebuild') ?? $this->request->getPost('force_new_record') ?? 0) === 1; + $hasGet = $this->request && method_exists($this->request, 'getGet'); + $hasPost = $this->request && method_exists($this->request, 'getPost'); + + $recordId = $recordIdParam + ?? ($hasGet ? (int) $this->request->getGet('record_id') : 0) + ?: ($hasPost ? (int) $this->request->getPost('record_id') : 0) + ?: (int) ($_GET['record_id'] ?? $_POST['record_id'] ?? 0); + + if ($recordId <= 0) { + $ref = trim((string) (($hasGet ? $this->request->getGet('ref') : '') + ?: ($hasGet ? $this->request->getGet('care_context_reference') : '') + ?: ($_GET['ref'] ?? $_GET['care_context_reference'] ?? ''))); + if ($ref !== '' && preg_match('/^IMM-(?:PAT-(\d+)|(?:(\d+)-V)?(\d+))/i', $ref, $m)) { + $recordId = (int) (! empty($m[3]) ? $m[3] : (! empty($m[2]) ? $m[2] : ($m[1] ?? 0))); + } + } + + $patientId = $patientIdParam + ?? ($hasGet ? (int) $this->request->getGet('patient_id') : 0) + ?: ($hasPost ? (int) $this->request->getPost('patient_id') : 0) + ?: (int) ($_GET['patient_id'] ?? $_POST['patient_id'] ?? 0); + + $abhaId = trim((string) ($abhaIdParam + ?? ($hasGet ? $this->request->getGet('abha_id') : '') + ?: ($hasPost ? $this->request->getPost('abha_id') : '') + ?: ($_GET['abha_id'] ?? $_GET['abha'] ?? $_POST['abha_id'] ?? ''))); + + $forceNewRecord = (int) (($hasGet ? $this->request->getGet('force_new_record') : 0) + ?: ($hasGet ? $this->request->getGet('force_rebuild') : 0) + ?: ($hasPost ? $this->request->getPost('force_new_record') : 0) + ?: ($_GET['force_rebuild'] ?? 0)) === 1; if ($patientId <= 0 && $recordId > 0 && $this->db->tableExists('immunization_records')) { $immRec = $this->db->table('immunization_records')->select('patient_id')->where('id', $recordId)->get(1)->getRowArray(); $patientId = (int) ($immRec['patient_id'] ?? 0); } + if ($abhaId === '' && $patientId > 0) { + $ident = $this->resolvePatientAbhaIdentity($patientId); + $abhaId = $ident['abha_address'] ?: $ident['abha_id']; + } + if ($patientId <= 0) { return $this->response->setStatusCode(400)->setJSON([ + 'ok' => 0, 'status' => 'error', 'message' => 'patient_id is required.', ]); @@ -2620,18 +2686,22 @@ class AbdmGateway extends BaseController $payload = $this->buildImmunizationGatewayPayload($patientId, $recordId, $abhaId, $forceNewRecord); if ($payload === null) { return $this->response->setStatusCode(404)->setJSON([ + 'ok' => 0, 'status' => 'error', 'message' => 'Unable to prepare ImmunizationRecord FHIR payload.', ]); } + $bundle = (array) ($payload['bundle'] ?? []); return $this->response->setJSON([ - 'status' => 'ok', - 'patient_id' => $patientId, - 'record_id' => $recordId > 0 ? $recordId : null, - 'abha_id' => $abhaId, + 'ok' => 1, + 'status' => 'ok', + 'patient_id' => $patientId, + 'record_id' => $recordId > 0 ? $recordId : null, + 'abha_id' => $abhaId, 'care_context_reference' => (string) ($payload['care_context_reference'] ?? ''), - 'bundle' => (array) ($payload['bundle'] ?? []), + 'bundle' => $bundle, + 'fhir_bundle' => $bundle, ]); } @@ -2924,19 +2994,50 @@ class AbdmGateway extends BaseController return $this->pushAdditionalHiRecord($payload, (int) $payload['patient_id'], $abhaId, $consentHandle); } - public function invoiceFhirPreview() + public function invoiceFhirPreview(?string $sourceParam = null, ?int $billIdParam = null, ?int $patientIdParam = null, ?string $abhaIdParam = null) { - if (! $this->request->isAJAX()) { - return $this->response->setStatusCode(403)->setJSON(['status' => 'error', 'message' => 'AJAX only']); + $hasGet = $this->request && method_exists($this->request, 'getGet'); + $hasPost = $this->request && method_exists($this->request, 'getPost'); + + $source = strtolower(trim((string) ($sourceParam + ?? ($hasGet ? $this->request->getGet('source') : '') + ?: ($hasPost ? $this->request->getPost('source') : '') + ?: ($_GET['source'] ?? $_POST['source'] ?? '')))); + + $billId = $billIdParam + ?? ($hasGet ? (int) $this->request->getGet('bill_id') : 0) + ?: ($hasPost ? (int) $this->request->getPost('bill_id') : 0) + ?: (int) ($_GET['bill_id'] ?? $_POST['bill_id'] ?? 0); + + if ($billId <= 0 || $source === '') { + $ref = trim((string) (($hasGet ? $this->request->getGet('ref') : '') + ?: ($hasGet ? $this->request->getGet('care_context_reference') : '') + ?: ($_GET['ref'] ?? $_GET['care_context_reference'] ?? ''))); + if ($ref !== '' && preg_match('/^INVOICE-([A-Za-z]+)-(\d+)/i', $ref, $m)) { + $typeCode = strtoupper($m[1]); + $billId = (int) $m[2]; + $source = match ($typeCode) { + 'OPD' => 'opd_invoice', + 'CHG' => 'charges_invoice', + 'IPD' => 'ipd_invoice', + default => 'opd_invoice' + }; + } } - $source = strtolower(trim((string) $this->request->getGet('source'))); - $billId = (int) $this->request->getGet('bill_id'); - $patientId = (int) $this->request->getGet('patient_id'); - $abhaId = trim((string) $this->request->getGet('abha_id')); + $patientId = $patientIdParam + ?? ($hasGet ? (int) $this->request->getGet('patient_id') : 0) + ?: ($hasPost ? (int) $this->request->getPost('patient_id') : 0) + ?: (int) ($_GET['patient_id'] ?? $_POST['patient_id'] ?? 0); + + $abhaId = trim((string) ($abhaIdParam + ?? ($hasGet ? $this->request->getGet('abha_id') : '') + ?: ($hasPost ? $this->request->getPost('abha_id') : '') + ?: ($_GET['abha_id'] ?? $_GET['abha'] ?? $_POST['abha_id'] ?? ''))); if (! in_array($source, ['opd_invoice', 'charges_invoice', 'ipd_invoice'], true) || $billId <= 0) { return $this->response->setStatusCode(400)->setJSON([ + 'ok' => 0, 'status' => 'error', 'message' => 'A valid source and bill_id are required.', ]); @@ -2946,25 +3047,30 @@ class AbdmGateway extends BaseController $payload = $this->buildInvoiceSourceRecordPayload($source, $billId, $patientId, $abhaId); } catch (\RuntimeException $e) { return $this->response->setStatusCode(422)->setJSON([ + 'ok' => 0, 'status' => 'error', 'message' => $e->getMessage(), ]); } if ($payload === null) { return $this->response->setStatusCode(404)->setJSON([ + 'ok' => 0, 'status' => 'error', 'message' => 'Invoice not found or patient could not be resolved.', ]); } + $bundle = (array) ($payload['bundle'] ?? []); return $this->response->setJSON([ - 'status' => 'ok', - 'source' => $source, - 'bill_id' => $billId, - 'patient_id' => (int) $payload['patient_id'], - 'hi_type' => 'InvoiceRecord', + 'ok' => 1, + 'status' => 'ok', + 'source' => $source, + 'bill_id' => $billId, + 'patient_id' => (int) $payload['patient_id'], + 'hi_type' => 'InvoiceRecord', 'care_context_reference' => (string) $payload['care_context_reference'], - 'bundle' => (array) $payload['bundle'], + 'bundle' => $bundle, + 'fhir_bundle' => $bundle, ]); } @@ -3003,18 +3109,38 @@ class AbdmGateway extends BaseController return $this->pushAdditionalHiRecord($payload, (int) $payload['patient_id'], $abhaId, $consentHandle); } - public function ipdDischargeFhirPreview() + public function ipdDischargeFhirPreview(?int $ipdIdParam = null, ?int $patientIdParam = null, ?string $abhaIdParam = null) { - if (! $this->request->isAJAX()) { - return $this->response->setStatusCode(403)->setJSON(['status' => 'error', 'message' => 'AJAX only']); + $hasGet = $this->request && method_exists($this->request, 'getGet'); + $hasPost = $this->request && method_exists($this->request, 'getPost'); + + $ipdId = $ipdIdParam + ?? ($hasGet ? (int) $this->request->getGet('ipd_id') : 0) + ?: ($hasPost ? (int) $this->request->getPost('ipd_id') : 0) + ?: (int) ($_GET['ipd_id'] ?? $_POST['ipd_id'] ?? $_REQUEST['ipd_id'] ?? 0); + + if ($ipdId <= 0) { + $ref = trim((string) (($hasGet ? $this->request->getGet('ref') : '') + ?: ($hasGet ? $this->request->getGet('care_context_reference') : '') + ?: ($_GET['ref'] ?? $_GET['care_context_reference'] ?? $_REQUEST['ref'] ?? ''))); + if ($ref !== '' && preg_match('/^DISCHARGE-(\d+)/i', $ref, $m)) { + $ipdId = (int) $m[1]; + } } - $ipdId = (int) ($this->request->getGet('ipd_id') ?? $this->request->getPost('ipd_id') ?? 0); - $patientId = (int) ($this->request->getGet('patient_id') ?? $this->request->getPost('patient_id') ?? 0); - $abhaId = trim((string) ($this->request->getGet('abha_id') ?? $this->request->getPost('abha_id') ?? '')); + $patientId = $patientIdParam + ?? ($hasGet ? (int) $this->request->getGet('patient_id') : 0) + ?: ($hasPost ? (int) $this->request->getPost('patient_id') : 0) + ?: (int) ($_GET['patient_id'] ?? $_POST['patient_id'] ?? $_REQUEST['patient_id'] ?? 0); + + $abhaId = trim((string) ($abhaIdParam + ?? ($hasGet ? $this->request->getGet('abha_id') : '') + ?: ($hasPost ? $this->request->getPost('abha_id') : '') + ?: ($_GET['abha_id'] ?? $_GET['abha'] ?? $_POST['abha_id'] ?? $_REQUEST['abha_id'] ?? ''))); if ($ipdId <= 0) { return $this->response->setStatusCode(400)->setJSON([ + 'ok' => 0, 'status' => 'error', 'message' => 'ipd_id is required.', ]); @@ -3030,12 +3156,17 @@ class AbdmGateway extends BaseController $abhaId = $ident['abha_address'] ?: $ident['abha_id']; } - $forceNewRecord = (int) ($this->request->getGet('force_rebuild') ?? 0); + $forceNewRecord = (int) (($hasGet ? $this->request->getGet('force_rebuild') : 0) ?: ($_GET['force_rebuild'] ?? 0)); try { if ($forceNewRecord !== 1 && $this->db && $this->db->tableExists('health_records')) { $existing = $this->db->table('health_records') - ->where('entity_type', 'ipd') - ->where('entity_id', (string) $ipdId) + ->groupStart() + ->groupStart() + ->where('entity_type', 'ipd') + ->where('entity_id', (string) $ipdId) + ->groupEnd() + ->orWhere('care_context_reference LIKE', 'DISCHARGE-' . $ipdId . '%') + ->groupEnd() ->whereIn('hi_type', ['DischargeSummaryRecord', 'DischargeSummary']) ->orderBy('id', 'DESC') ->get(1) @@ -3050,12 +3181,15 @@ class AbdmGateway extends BaseController $savedBundle = json_decode($raw, true); if (is_array($savedBundle) && ($savedBundle['resourceType'] ?? '') === 'Bundle') { return $this->response->setJSON([ - 'status' => 'ok', - 'ipd_id' => $ipdId, - 'patient_id' => $patientId, - 'abha_id' => $abhaId, - 'bundle' => $savedBundle, - 'source' => 'saved_record', + 'ok' => 1, + 'status' => 'ok', + 'ipd_id' => $ipdId, + 'patient_id' => $patientId, + 'abha_id' => $abhaId, + 'care_context_reference' => $existing['care_context_reference'] ?? ('DISCHARGE-' . $ipdId), + 'bundle' => $savedBundle, + 'fhir_bundle' => $savedBundle, + 'source' => 'saved_record', ]); } } @@ -3065,23 +3199,29 @@ class AbdmGateway extends BaseController $fhirPayload = $this->buildIpdDischargeGatewayPayload($ipdId, $patientId, $abhaId, $forceNewRecord === 1); if ($fhirPayload === null) { return $this->response->setStatusCode(404)->setJSON([ + 'ok' => 0, 'status' => 'error', - 'message' => 'Unable to prepare IPD discharge FHIR payload.', + 'message' => 'Unable to prepare IPD discharge FHIR payload for IPD #' . $ipdId, ]); } $bundle = (array) ($fhirPayload['bundle'] ?? []); return $this->response->setJSON([ - 'status' => 'ok', - 'ipd_id' => $ipdId, - 'patient_id' => $patientId, - 'abha_id' => $abhaId, - 'bundle' => $bundle, + 'ok' => 1, + 'status' => 'ok', + 'ipd_id' => $ipdId, + 'patient_id' => $patientId, + 'abha_id' => $abhaId, + 'care_context_reference' => (string) ($fhirPayload['care_context_reference'] ?? ('DISCHARGE-' . $ipdId)), + 'bundle' => $bundle, + 'fhir_bundle' => $bundle, + 'source' => 'generated', ]); } catch (\Throwable $e) { log_message('error', 'ipdDischargeFhirPreview error for IPD #' . $ipdId . ': ' . $e->getMessage() . "\n" . $e->getTraceAsString()); return $this->response->setStatusCode(500)->setJSON([ + 'ok' => 0, 'status' => 'error', 'message' => 'Error generating IPD discharge FHIR: ' . $e->getMessage(), ]); diff --git a/app/Controllers/Ipd_discharge.php b/app/Controllers/Ipd_discharge.php index 6686f4d..f983f49 100644 --- a/app/Controllers/Ipd_discharge.php +++ b/app/Controllers/Ipd_discharge.php @@ -8793,7 +8793,7 @@ class Ipd_discharge extends BaseController ?? '' )); - if (preg_match('/^\d{14}$/', $abhaId) !== 1) { + if (preg_match('/^\d{14}$/', $abhaId) !== 1 && ! str_contains($abhaId, '@')) { return; } @@ -9807,28 +9807,47 @@ class Ipd_discharge extends BaseController $outbox = new AbdmSyncOutboxService(); $outbox->enqueueRecordSync($syncPayload); - // Also push synchronously to E-Atria bridge so the bundle is immediately accessible to PHR apps + // Save locally to health_records for instant inspector viewing and background 1-minute cron linking try { - $connector = new \App\Libraries\Abdm\EAtriaBridgeConnector(); - $pushData = [ - 'patient_id' => (string) $patientId, - 'patient_name' => (string) ($gatewayPayload['patient_name'] ?? $patientName), - 'abha_id' => (string) ($gatewayPayload['abha_id'] ?? $abhaDigits), - 'abha_address' => (string) ($gatewayPayload['abha_address'] ?? $abhaAddress), - 'hi_type' => 'DischargeSummaryRecord', - 'record_type' => 'DischargeSummaryRecord', - 'visit_date' => (string) ($gatewayPayload['visit_date'] ?? $visitDate), - 'care_context_reference' => $ccRef, - 'care_context_display' => $ccDisplay, - 'notes' => $ccDisplay, - 'queue_id' => $ccRef, - 'bundle' => (array) ($gatewayPayload['fhir_bundle'] ?? []), - 'fhir_bundle' => (array) ($gatewayPayload['fhir_bundle'] ?? []), - 'record_data' => (array) ($gatewayPayload['fhir_bundle'] ?? []), - ]; - $connector->pushRecord($pushData); + $ccRef = (string) ($gatewayPayload['care_context_reference'] ?? ('DISCHARGE-' . $ipdId)); + $ccDisplay = (string) ($gatewayPayload['care_context_display'] ?? ('Discharge Summary #' . $ipdNo)); + $bundleArray = (array) ($gatewayPayload['fhir_bundle'] ?? []); + $bundleJson = json_encode($bundleArray, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + + if ($this->db && $this->db->tableExists('health_records')) { + $existingHr = $this->db->table('health_records') + ->where('entity_type', 'ipd') + ->where('entity_id', (string) $ipdId) + ->whereIn('hi_type', ['DischargeSummaryRecord', 'DischargeSummary']) + ->orderBy('id', 'DESC') + ->get(1) + ->getRowArray(); + + $effectiveAbha = (string) ($gatewayPayload['abha_address'] ?: ($gatewayPayload['abha_id'] ?: $abhaDigits)); + $hrData = [ + 'patient_id' => $patientId, + 'abha_id' => $effectiveAbha, + 'entity_type' => 'ipd', + 'entity_id' => (string) $ipdId, + 'hi_type' => 'DischargeSummaryRecord', + 'care_context_reference' => $ccRef, + 'care_context_display' => $ccDisplay, + 'record_data' => $bundleJson, + 'fhir_bundle' => $bundleJson, + 'bundle' => $bundleJson, + 'push_status' => 'pending', + 'updated_at' => date('Y-m-d H:i:s'), + ]; + + if (! empty($existingHr)) { + $this->db->table('health_records')->where('id', (int) $existingHr['id'])->update($hrData); + } else { + $hrData['created_at'] = date('Y-m-d H:i:s'); + $this->db->table('health_records')->insert($hrData); + } + } } catch (\Throwable $pe) { - log_message('warning', '[enqueueIpdDischargeFhirSync] Direct bridge push error: ' . $pe->getMessage()); + log_message('warning', '[enqueueIpdDischargeFhirSync] health_records store error: ' . $pe->getMessage()); } }