diff --git a/app/Controllers/AbdmGateway.php b/app/Controllers/AbdmGateway.php index d919a97..18af4fa 100644 --- a/app/Controllers/AbdmGateway.php +++ b/app/Controllers/AbdmGateway.php @@ -5080,79 +5080,110 @@ class AbdmGateway extends BaseController } } - // Strategy 0c: Live On-Demand Fresh Generation for Wellness Record - if (preg_match('/^WELLNESS-(?:(\d+)-)?(?:S)?(\d+)/i', $ref, $wMatch)) { - $wPart1 = (int) ($wMatch[1] ?? 0); - $wPart2 = (int) ($wMatch[2] ?? 0); + // Strategy 0c: Live Retrieval & On-Demand Fresh Generation for Wellness Record + if (str_starts_with(strtoupper($ref), 'WELLNESS-')) { + $foundBundle = null; + $foundDisplay = null; - $targetPatientId = 0; - $targetSessionId = 0; + // 1. Check health_records first for this exact care context reference + if ($db->tableExists('health_records')) { + $hrRow = $db->table('health_records') + ->where('care_context_reference', $ref) + ->groupStart() + ->where('record_data IS NOT NULL AND record_data !=', '') + ->orWhere('fhir_bundle_enc IS NOT NULL AND fhir_bundle_enc !=', '') + ->groupEnd() + ->orderBy('id', 'DESC') + ->get(1) + ->getRowArray(); - // Check if part2 is a date (e.g. 20261006) - $isDatePart2 = ($wPart2 >= 19700101 && $wPart2 <= 21001231); - $candidateEntityId = $isDatePart2 ? $wPart1 : $wPart2; - $candidatePatientId = $isDatePart2 ? 0 : $wPart1; - - if ($db->tableExists('opd_prescription')) { - // Try finding by prescription id - if ($candidateEntityId > 0) { - $pRow = $db->table('opd_prescription') - ->select('id, p_id, opd_id') - ->where('id', $candidateEntityId) - ->get(1) - ->getRowArray(); - if ($pRow) { - $targetSessionId = (int) $pRow['id']; - $targetPatientId = (int) $pRow['p_id']; + if ($hrRow && ! empty($hrRow['record_data'])) { + $bundleData = json_decode((string) $hrRow['record_data'], true); + if (is_array($bundleData) && ! empty($bundleData)) { + $foundBundle = $bundleData; + $foundDisplay = $hrRow['care_context_display'] ?? null; + } + } elseif ($hrRow && ! empty($hrRow['fhir_bundle_enc'])) { + try { + $enc = new FhirEncryptionService(); + $decrypted = $enc->decrypt((string) $hrRow['fhir_bundle_enc']); + $bundleData = json_decode($decrypted, true); + if (is_array($bundleData) && ! empty($bundleData)) { + $foundBundle = $bundleData; + $foundDisplay = $hrRow['care_context_display'] ?? null; + } + } catch (\Throwable) { } } - // If not found, check by session_id or opd_id - if ($targetPatientId <= 0 && $candidateEntityId > 0) { - $pRow = $db->table('opd_prescription') - ->select('id, p_id, opd_id') - ->where('session_id', $candidateEntityId) - ->orWhere('opd_id', $candidateEntityId) - ->orderBy('id', 'DESC') - ->get(1) - ->getRowArray(); - if ($pRow) { - $targetSessionId = (int) $pRow['id']; - $targetPatientId = (int) $pRow['p_id']; - } + } + + // 2. Check patient_wellness_records if not found in health_records + if ($foundBundle === null && $db->tableExists('patient_wellness_records')) { + $wRow = $db->table('patient_wellness_records')->where('care_context_reference', $ref)->get(1)->getRowArray(); + if (! $wRow && preg_match('/-W(\d+)/i', $ref, $wIdM)) { + $wRow = $db->table('patient_wellness_records')->where('id', (int) $wIdM[1])->get(1)->getRowArray(); } - // If candidatePatientId is set, or if candidateEntityId was patient_id - if ($targetPatientId <= 0) { - $testPid = $candidatePatientId > 0 ? $candidatePatientId : $candidateEntityId; - if ($testPid > 0) { - $pRow = $db->table('opd_prescription') - ->select('id, p_id, opd_id') - ->where('p_id', $testPid) - ->orderBy('id', 'DESC') - ->get(1) - ->getRowArray(); - if ($pRow) { - $targetPatientId = (int) $pRow['p_id']; - $targetSessionId = (int) $pRow['id']; + if ($wRow) { + if (! empty($wRow['fhir_bundle_json'])) { + $foundBundle = json_decode((string) $wRow['fhir_bundle_json'], true); + } + if (empty($foundBundle)) { + $wellnessPayload = $this->buildWellnessRecordPayload((int) $wRow['patient_id'], (int) $wRow['id'], ''); + if ($wellnessPayload !== null && ! empty($wellnessPayload['bundle'])) { + $foundBundle = $wellnessPayload['bundle']; + $foundDisplay = $wellnessPayload['care_context_display'] ?? null; } } } } - if ($targetPatientId > 0) { - try { - $wellnessPayload = $this->buildWellnessRecordPayload($targetPatientId, $targetSessionId, ''); - if ($wellnessPayload !== null && !empty($wellnessPayload['bundle'])) { - $records[] = [ - 'careContextReference' => $ref, - 'hiType' => 'WellnessRecord', - 'display' => $wellnessPayload['care_context_display'] ?? ('Wellness Record - ' . date('d M Y')), - 'bundle' => $wellnessPayload['bundle'], - ]; - continue; + // 3. Fallback: Parse patient ID and OPD session ID for legacy OPD vitals references + if ($foundBundle === null) { + $targetPatientId = 0; + $targetSessionId = 0; + + if (preg_match('/^WELLNESS-(?:(\d+)-)?(?:S(\d+)|W(\d+)|(\d+))(?:-(\d+))?/i', $ref, $wMatch)) { + $pPart = (int) ($wMatch[1] ?? 0); + $sPart = (int) (! empty($wMatch[2]) ? $wMatch[2] : (! empty($wMatch[3]) ? $wMatch[3] : ($wMatch[4] ?? 0))); + $dPart = (int) ($wMatch[5] ?? 0); + + if ($pPart > 0) { + $targetPatientId = $pPart; + $targetSessionId = $sPart; + } elseif ($sPart > 0) { + if ($db->tableExists('patient_master') && $db->table('patient_master')->where('id', $sPart)->countAllResults() > 0) { + $targetPatientId = $sPart; + } elseif ($db->tableExists('opd_prescription')) { + $pRow = $db->table('opd_prescription')->select('p_id, id')->where('id', $sPart)->get(1)->getRowArray(); + if ($pRow) { + $targetPatientId = (int) $pRow['p_id']; + $targetSessionId = (int) $pRow['id']; + } + } } - } catch (\Throwable $ex) { - log_message('warning', 'Live Wellness FHIR generation in recordsFetch failed: ' . $ex->getMessage()); } + + if ($targetPatientId > 0) { + try { + $wellnessPayload = $this->buildWellnessRecordPayload($targetPatientId, $targetSessionId, ''); + if ($wellnessPayload !== null && ! empty($wellnessPayload['bundle'])) { + $foundBundle = $wellnessPayload['bundle']; + $foundDisplay = $wellnessPayload['care_context_display'] ?? null; + } + } catch (\Throwable $ex) { + log_message('warning', 'Live Wellness FHIR generation in recordsFetch failed: ' . $ex->getMessage()); + } + } + } + + if ($foundBundle !== null && ! empty($foundBundle)) { + $records[] = [ + 'careContextReference' => $ref, + 'hiType' => 'WellnessRecord', + 'display' => $foundDisplay ?? ('Wellness Record - ' . date('d M Y')), + 'bundle' => $foundBundle, + ]; + continue; } } @@ -6584,15 +6615,15 @@ class AbdmGateway extends BaseController ]); } } - if ($this->db->tableExists('opd_prescription')) { - $wopd = $this->db->table('opd_prescription')->where('id', $taskEntityId)->get(1)->getRowArray(); + if (empty($wRec) && $this->db->tableExists('opd_prescription')) { + $wopd = $this->db->table('opd_prescription')->where('id', $taskEntityId)->where('p_id', $patientId)->get(1)->getRowArray(); if (! empty($wopd)) { $vDate = ! empty($wopd['date_opd_visit']) ? $wopd['date_opd_visit'] : date('Y-m-d'); $dateStr = date('d M Y', strtotime((string) $vDate)); $cleanDate = date('Ymd', strtotime((string) $vDate)); // Reference format matching task board (e.g. WELLNESS-33723-20261006) $ccRef = 'WELLNESS-' . $taskEntityId . '-' . $cleanDate; - $display = 'WellnessRecord - ' . $dateStr; + $display = 'Wellness Record - ' . $dateStr; $addContext([ 'careContextId' => $ccRef, 'referenceNumber' => $ccRef, @@ -6632,7 +6663,10 @@ class AbdmGateway extends BaseController if (str_starts_with($ccRef, 'OPD-') || str_starts_with($ccRef, 'INVOICE-')) { continue; } - $hiType = trim((string) ($row['hi_type'] ?? 'HealthDocumentRecord')); + $hiType = trim((string) ($row['hi_type'] ?? '')); + 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 & Vitals Record - ' : ($hiType . ' - ')) . $dateStr; @@ -8478,12 +8512,9 @@ class AbdmGateway extends BaseController } $careContextReference = trim((string) ($data['care_context_reference'] ?? '')); - if (($data['reuse_existing'] ?? false) === true && $careContextReference !== '') { + if ($careContextReference !== '') { $existing = $this->db->table('health_records') ->select('id') - ->where('hi_type', (string) ($data['hi_type'] ?? 'unknown')) - ->where('entity_type', (string) ($data['entity_type'] ?? '')) - ->where('entity_id', (string) ($data['entity_id'] ?? '')) ->where('care_context_reference', $careContextReference) ->orderBy('id', 'DESC') ->get(1) @@ -8491,7 +8522,7 @@ class AbdmGateway extends BaseController if (! empty($existing)) { $existingId = (int) ($existing['id'] ?? 0); $update = $insert; - unset($update['push_status'], $update['push_at'], $update['created_at']); + unset($update['created_at']); $this->db->table('health_records')->where('id', $existingId)->update($update); return $existingId; } @@ -9514,6 +9545,7 @@ class AbdmGateway extends BaseController 'notes' => $ccDisplay, 'queue_id' => $ccRef, 'record_data' => $bundle, + 'skip_auto_link' => true, ]); $this->logGatewayPushResolution('additional_hi_record', $result); $queueId = $this->extractGatewayPushQueueId($result); @@ -9590,14 +9622,21 @@ class AbdmGateway extends BaseController // 1. Check patient_wellness_records first (New M2 Comprehensive Wellness & Vitals) if ($this->db->tableExists('patient_wellness_records')) { - $wBuilder = $this->db->table('patient_wellness_records')->where('patient_id', $patientId); + $wRow = null; if ($opdId > 0) { - $wBuilder->groupStart() - ->where('id', $opdId) - ->orWhere('patient_id', $patientId) - ->groupEnd(); + $wRow = $this->db->table('patient_wellness_records')->where('id', $opdId)->get(1)->getRowArray(); + if ($wRow && (int) ($wRow['patient_id'] ?? 0) !== $patientId) { + $patientId = (int) $wRow['patient_id']; + $patientRow = $this->loadPatientRow($patientId); + } + } + if (empty($wRow)) { + $wRow = $this->db->table('patient_wellness_records') + ->where('patient_id', $patientId) + ->orderBy('id', 'DESC') + ->get(1) + ->getRowArray(); } - $wRow = $wBuilder->orderBy('id', 'DESC')->get(1)->getRowArray(); if (! empty($wRow)) { $bundle = ! empty($wRow['fhir_bundle_json']) ? json_decode((string) $wRow['fhir_bundle_json'], true) : []; $visitDate = date('Y-m-d', strtotime((string) ($wRow['recorded_at'] ?? 'now'))); @@ -9608,6 +9647,25 @@ class AbdmGateway extends BaseController : ('WELLNESS-' . $patientId . '-W' . $entityId . '-' . $cleanDate); $ccDisplay = 'Wellness Record - ' . date('d/m/Y', strtotime($visitDate)); + if (empty($bundle) && class_exists('\App\Controllers\DoctorDocument')) { + try { + $docCtrl = new \App\Controllers\DoctorDocument(); + $wSource = $docCtrl->buildWellnessRecordSource($patientId, (int) $wRow['id'], 'wellness'); + if (! empty($wSource)) { + $wFactory = new FhirGeneratorFactory(); + $wGen = $wFactory->wellness()->generate($wSource); + if (! empty($wGen['bundle'])) { + $bundle = $wGen['bundle']; + $this->db->table('patient_wellness_records')->where('id', (int) $wRow['id'])->update([ + 'fhir_bundle_json' => json_encode($bundle, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + 'care_context_reference' => $ccRef, + ]); + } + } + } catch (\Throwable $e) { + } + } + if (! empty($bundle)) { return [ 'hi_type' => 'WellnessRecord', diff --git a/app/Controllers/DoctorDocument.php b/app/Controllers/DoctorDocument.php index 07d1fd6..95255db 100644 --- a/app/Controllers/DoctorDocument.php +++ b/app/Controllers/DoctorDocument.php @@ -712,7 +712,7 @@ class DoctorDocument extends BaseController ]); } - public function buildWellnessRecordSource(int $patientId, int $opdSessionId = 0): array + public function buildWellnessRecordSource(int $patientId, int $opdSessionId = 0, string $sourceEntity = ''): array { if ($patientId <= 0 || ! $this->db->tableExists('patient_master')) { return []; @@ -723,8 +723,26 @@ class DoctorDocument extends BaseController return []; } + $wRow = []; + $isWellnessDirect = ($sourceEntity === 'wellness'); + if ($this->db->tableExists('patient_wellness_records')) { + if ($opdSessionId > 0) { + $wRow = $this->db->table('patient_wellness_records')->where('id', $opdSessionId)->get(1)->getRowArray() ?? []; + if (! empty($wRow)) { + $isWellnessDirect = true; + if (! empty($wRow['patient_id']) && (int) $wRow['patient_id'] !== $patientId) { + $patientId = (int) $wRow['patient_id']; + $patientRow = $this->db->table('patient_master')->where('id', $patientId)->get(1)->getRowArray() ?? $patientRow; + } + } + } + if (empty($wRow) && $isWellnessDirect) { + $wRow = $this->db->table('patient_wellness_records')->where('patient_id', $patientId)->orderBy('id', 'DESC')->get(1)->getRowArray() ?? []; + } + } + $rxRow = []; - if ($this->db->tableExists('opd_prescription')) { + if (! $isWellnessDirect && $this->db->tableExists('opd_prescription')) { $builder = $this->db->table('opd_prescription')->where('p_id', $patientId); if ($opdSessionId > 0) { $builder->groupStart() @@ -758,53 +776,81 @@ class DoctorDocument extends BaseController } }; - $addVital('8480-6', 'Systolic blood pressure', $rxRow['bp'] ?? null, 'mmHg', 'mm[Hg]'); - $addVital('8462-4', 'Diastolic blood pressure', $rxRow['diastolic'] ?? null, 'mmHg', 'mm[Hg]'); - $addVital('8867-4', 'Heart rate', $rxRow['pulse'] ?? null, '/min', '/min'); - $addVital('8302-2', 'Body height', $rxRow['height'] ?? null, 'cm', 'cm'); - $addVital('29463-7', 'Body weight', $rxRow['weight'] ?? null, 'kg', 'kg'); - $addVital('39156-5', 'Body Mass Index', $rxRow['bmi'] ?? null, 'kg/m2', 'kg/m2'); - - $tempVal = $rxRow['temp'] ?? null; - if ($tempVal !== null && is_numeric($tempVal)) { - $tempVal = (float) $tempVal > 45 ? round((((float) $tempVal - 32) * 5) / 9, 1) : round((float) $tempVal, 1); - } - $addVital('8310-5', 'Body temperature', $tempVal, 'Cel', 'Cel'); - $addVital('9279-1', 'Respiratory rate', $rxRow['rr_min'] ?? null, '/min', '/min'); - $addVital('59408-5', 'Oxygen saturation in Arterial blood by Pulse oximetry', $rxRow['spo2'] ?? null, '%', '%'); - $addVital('2339-0', 'Blood Glucose', $rxRow['glucose'] ?? null, 'mg/dL', 'mg/dL'); - - // If no vitals found in opd_prescription, check patient_wellness_records - if (empty($vitals) && $this->db->tableExists('patient_wellness_records')) { - $wBuilder = $this->db->table('patient_wellness_records')->where('patient_id', $patientId); - if ($opdSessionId > 0) { - $wBuilder->groupStart() - ->where('id', $opdSessionId) - ->orWhere('patient_id', $patientId) - ->groupEnd(); + if (! empty($wRow)) { + // Populate comprehensive vitals directly from patient_wellness_records + $addVital('8480-6', 'Systolic blood pressure', $wRow['bp_systolic'] ?? null, 'mmHg', 'mm[Hg]'); + $addVital('8462-4', 'Diastolic blood pressure', $wRow['bp_diastolic'] ?? null, 'mmHg', 'mm[Hg]'); + $addVital('8867-4', 'Heart rate', $wRow['pulse_rate'] ?? null, '/min', '/min'); + $addVital('8302-2', 'Body height', $wRow['height_cm'] ?? null, 'cm', 'cm'); + $addVital('29463-7', 'Body weight', $wRow['weight_kg'] ?? null, 'kg', 'kg'); + $addVital('39156-5', 'Body Mass Index', $wRow['bmi'] ?? null, 'kg/m2', 'kg/m2'); + $tC = $wRow['temperature_c'] ?? null; + if ($tC === null && ! empty($wRow['temperature_f'])) { + $tC = round((((float) $wRow['temperature_f'] - 32) * 5) / 9, 1); } - $wRow = $wBuilder->orderBy('id', 'DESC')->get(1)->getRowArray(); - if (! empty($wRow)) { - $addVital('8480-6', 'Systolic blood pressure', $wRow['bp_systolic'] ?? null, 'mmHg', 'mm[Hg]'); - $addVital('8462-4', 'Diastolic blood pressure', $wRow['bp_diastolic'] ?? null, 'mmHg', 'mm[Hg]'); - $addVital('8867-4', 'Heart rate', $wRow['pulse_rate'] ?? null, '/min', '/min'); - $addVital('8302-2', 'Body height', $wRow['height_cm'] ?? null, 'cm', 'cm'); - $addVital('29463-7', 'Body weight', $wRow['weight_kg'] ?? null, 'kg', 'kg'); - $addVital('39156-5', 'Body Mass Index', $wRow['bmi'] ?? null, 'kg/m2', 'kg/m2'); - $tC = $wRow['temperature_c'] ?? null; - if ($tC === null && ! empty($wRow['temperature_f'])) { - $tC = round((((float) $wRow['temperature_f'] - 32) * 5) / 9, 1); + $addVital('8310-5', 'Body temperature', $tC, 'Cel', 'Cel'); + $addVital('9279-1', 'Respiratory rate', $wRow['resp_rate'] ?? null, '/min', '/min'); + $addVital('59408-5', 'Oxygen saturation in Arterial blood by Pulse oximetry', $wRow['spo2'] ?? null, '%', '%'); + $addVital('2339-0', 'Random Blood Glucose', $wRow['sugar_random'] ?? null, 'mg/dL', 'mg/dL'); + $addVital('1558-6', 'Fasting Blood Glucose', $wRow['sugar_fasting'] ?? null, 'mg/dL', 'mg/dL'); + $addVital('14760-3', 'Glucose [Mass/volume] in Blood 2 hours post meal', $wRow['sugar_pp'] ?? null, 'mg/dL', 'mg/dL'); + $addVital('4548-4', 'Hemoglobin A1c', $wRow['hba1c'] ?? null, '%', '%'); + $addVital('718-7', 'Hemoglobin', $wRow['hemoglobin'] ?? null, 'g/dL', 'g/dL'); + $addVital('56115-9', 'Waist circumference', $wRow['waist_circumference_cm'] ?? null, 'cm', 'cm'); + $addVital('56114-2', 'Hip circumference', $wRow['hip_circumference_cm'] ?? null, 'cm', 'cm'); + $addVital('8280-0', 'Waist to hip ratio', $wRow['waist_hip_ratio'] ?? null, 'ratio', '{ratio}'); + $addVital('55423-8', 'Number of steps in 24 hour Measured', $wRow['daily_steps'] ?? null, '{steps}', '{steps}'); + $addVital('93832-4', 'Sleep duration', $wRow['sleep_hours'] ?? null, 'h', 'h'); + $addVital('55411-3', 'Exercise duration', $wRow['exercise_min_per_day'] ?? null, 'min/d', 'min/d'); + $addVital('72514-3', 'Pain severity - 0-10 verbal numeric rating', $wRow['pain_score'] ?? null, '{score}', '{score}'); + } else { + // OPD prescription vitals fallback + $addVital('8480-6', 'Systolic blood pressure', $rxRow['bp'] ?? null, 'mmHg', 'mm[Hg]'); + $addVital('8462-4', 'Diastolic blood pressure', $rxRow['diastolic'] ?? null, 'mmHg', 'mm[Hg]'); + $addVital('8867-4', 'Heart rate', $rxRow['pulse'] ?? null, '/min', '/min'); + $addVital('8302-2', 'Body height', $rxRow['height'] ?? null, 'cm', 'cm'); + $addVital('29463-7', 'Body weight', $rxRow['weight'] ?? null, 'kg', 'kg'); + $addVital('39156-5', 'Body Mass Index', $rxRow['bmi'] ?? null, 'kg/m2', 'kg/m2'); + + $tempVal = $rxRow['temp'] ?? null; + if ($tempVal !== null && is_numeric($tempVal)) { + $tempVal = (float) $tempVal > 45 ? round((((float) $tempVal - 32) * 5) / 9, 1) : round((float) $tempVal, 1); + } + $addVital('8310-5', 'Body temperature', $tempVal, 'Cel', 'Cel'); + $addVital('9279-1', 'Respiratory rate', $rxRow['rr_min'] ?? null, '/min', '/min'); + $addVital('59408-5', 'Oxygen saturation in Arterial blood by Pulse oximetry', $rxRow['spo2'] ?? null, '%', '%'); + $addVital('2339-0', 'Blood Glucose', $rxRow['glucose'] ?? null, 'mg/dL', 'mg/dL'); + + // If no vitals found in opd_prescription, check patient_wellness_records + if (empty($vitals) && $this->db->tableExists('patient_wellness_records')) { + $wBuilder = $this->db->table('patient_wellness_records')->where('patient_id', $patientId); + if ($opdSessionId > 0) { + $wBuilder->where('id', $opdSessionId); + } + $wRow = $wBuilder->orderBy('id', 'DESC')->get(1)->getRowArray(); + if (! empty($wRow)) { + $addVital('8480-6', 'Systolic blood pressure', $wRow['bp_systolic'] ?? null, 'mmHg', 'mm[Hg]'); + $addVital('8462-4', 'Diastolic blood pressure', $wRow['bp_diastolic'] ?? null, 'mmHg', 'mm[Hg]'); + $addVital('8867-4', 'Heart rate', $wRow['pulse_rate'] ?? null, '/min', '/min'); + $addVital('8302-2', 'Body height', $wRow['height_cm'] ?? null, 'cm', 'cm'); + $addVital('29463-7', 'Body weight', $wRow['weight_kg'] ?? null, 'kg', 'kg'); + $addVital('39156-5', 'Body Mass Index', $wRow['bmi'] ?? null, 'kg/m2', 'kg/m2'); + $tC = $wRow['temperature_c'] ?? null; + if ($tC === null && ! empty($wRow['temperature_f'])) { + $tC = round((((float) $wRow['temperature_f'] - 32) * 5) / 9, 1); + } + $addVital('8310-5', 'Body temperature', $tC, 'Cel', 'Cel'); + $addVital('9279-1', 'Respiratory rate', $wRow['resp_rate'] ?? null, '/min', '/min'); + $addVital('59408-5', 'Oxygen saturation in Arterial blood by Pulse oximetry', $wRow['spo2'] ?? null, '%', '%'); + $addVital('2339-0', 'Random Blood Glucose', $wRow['sugar_random'] ?? null, 'mg/dL', 'mg/dL'); + $addVital('1558-6', 'Fasting Blood Glucose', $wRow['sugar_fasting'] ?? null, 'mg/dL', 'mg/dL'); + $addVital('14760-3', 'Glucose [Mass/volume] in Blood 2 hours post meal', $wRow['sugar_pp'] ?? null, 'mg/dL', 'mg/dL'); + $addVital('4548-4', 'Hemoglobin A1c', $wRow['hba1c'] ?? null, '%', '%'); + $addVital('718-7', 'Hemoglobin', $wRow['hemoglobin'] ?? null, 'g/dL', 'g/dL'); + $addVital('56115-9', 'Waist circumference', $wRow['waist_circumference_cm'] ?? null, 'cm', 'cm'); + $addVital('56114-2', 'Hip circumference', $wRow['hip_circumference_cm'] ?? null, 'cm', 'cm'); + $addVital('8280-0', 'Waist to hip ratio', $wRow['waist_hip_ratio'] ?? null, 'ratio', '{ratio}'); } - $addVital('8310-5', 'Body temperature', $tC, 'Cel', 'Cel'); - $addVital('9279-1', 'Respiratory rate', $wRow['resp_rate'] ?? null, '/min', '/min'); - $addVital('59408-5', 'Oxygen saturation in Arterial blood by Pulse oximetry', $wRow['spo2'] ?? null, '%', '%'); - $addVital('2339-0', 'Random Blood Glucose', $wRow['sugar_random'] ?? null, 'mg/dL', 'mg/dL'); - $addVital('1558-6', 'Fasting Blood Glucose', $wRow['sugar_fasting'] ?? null, 'mg/dL', 'mg/dL'); - $addVital('4548-4', 'Hemoglobin A1c', $wRow['hba1c'] ?? null, '%', '%'); - $addVital('718-7', 'Hemoglobin', $wRow['hemoglobin'] ?? null, 'g/dL', 'g/dL'); - $addVital('8280-0', 'Waist Circumference', $wRow['waist_circumference_cm'] ?? null, 'cm', 'cm'); - $addVital('98337-9', 'Hip Circumference', $wRow['hip_circumference_cm'] ?? null, 'cm', 'cm'); - $addVital('72287-6', 'Waist-hip ratio', $wRow['waist_hip_ratio'] ?? null, '{ratio}', '{ratio}'); } } @@ -862,21 +908,36 @@ class DoctorDocument extends BaseController $hospitalName = (string) constant('H_Name'); } - $doctorName = trim(trim((string) ($doctorRow['p_fname'] ?? '')) . ' ' . trim((string) ($doctorRow['p_lname'] ?? ''))); + $doctorName = ! empty($wRow['recorded_by']) + ? trim((string) $wRow['recorded_by']) + : trim(trim((string) ($doctorRow['p_fname'] ?? '')) . ' ' . trim((string) ($doctorRow['p_lname'] ?? ''))); if ($doctorName === '') { - $doctorName = 'Doctor'; + $doctorName = 'Attending Medical Officer'; } - $visitDate = ! empty($rxRow['date_opd_visit']) ? date('Y-m-d', strtotime((string) $rxRow['date_opd_visit'])) : date('Y-m-d'); - $completedAt = ! empty($rxRow['insert_date']) ? date(DATE_ATOM, strtotime((string) $rxRow['insert_date'])) : date(DATE_ATOM); + $visitDate = ! empty($wRow['recorded_at']) + ? date('Y-m-d', strtotime((string) $wRow['recorded_at'])) + : (! empty($rxRow['date_opd_visit']) ? date('Y-m-d', strtotime((string) $rxRow['date_opd_visit'])) : date('Y-m-d')); + $completedAt = ! empty($wRow['recorded_at']) + ? date(DATE_ATOM, strtotime((string) $wRow['recorded_at'])) + : (! empty($rxRow['insert_date']) ? date(DATE_ATOM, strtotime((string) $rxRow['insert_date'])) : date(DATE_ATOM)); + + $recId = ! empty($wRow['id']) ? (string) $wRow['id'] : (string) ($rxRow['id'] ?? $patientId); + + $rawGender = strtolower(trim((string) ($patientRow['gender'] ?? ''))); + $cleanGender = match ($rawGender) { + '1', 'm', 'male' => 'male', + '2', 'f', 'female' => 'female', + default => 'unknown', + }; return [ - 'record_id' => (string) ($rxRow['id'] ?? $patientId), + 'record_id' => $recId, 'session_id' => (string) $opdSessionId, 'visit_date' => $visitDate, 'completed_at' => $completedAt, 'encounter' => [ - 'id' => (string) ($rxRow['id'] ?? $patientId), + 'id' => $recId, 'class_code' => 'AMB', 'class_display' => 'ambulatory', 'start' => $completedAt, @@ -897,14 +958,14 @@ class DoctorDocument extends BaseController 'id' => (string) $patientId, 'uhid' => (string) ($patientRow['uhid_no'] ?? $patientRow['uhid'] ?? $patientRow['patient_code'] ?? $patientId), 'name' => $patientName, - 'gender' => strtolower((string) ($patientRow['gender'] ?? '')) === 'm' ? 'male' : (strtolower((string) ($patientRow['gender'] ?? '')) === 'f' ? 'female' : 'unknown'), + 'gender' => $cleanGender, 'dob' => ! empty($patientRow['dob']) ? date('Y-m-d', strtotime((string) $patientRow['dob'])) : '', 'abha_id' => $abhaDigits, 'abha_address' => $abhaAddress, 'mobile' => (string) ($patientRow['mphone1'] ?? ''), ], 'practitioner' => [ - 'id' => (string) $drId, + 'id' => (string) ($wRow['recorded_by_id'] ?? $drId ?: 1), 'name' => $doctorName, ], ]; diff --git a/app/Libraries/Abdm/EAtriaBridgeConnector.php b/app/Libraries/Abdm/EAtriaBridgeConnector.php index cad78b1..6b54250 100644 --- a/app/Libraries/Abdm/EAtriaBridgeConnector.php +++ b/app/Libraries/Abdm/EAtriaBridgeConnector.php @@ -1510,6 +1510,9 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface if ($abhaId !== '') { $recordPushPayload['abha_id'] = $abhaId; } + if (! empty($data['skip_auto_link'])) { + $recordPushPayload['skip_auto_link'] = true; + } $res = $this->post('/v3/records/push', $recordPushPayload); return self::normalizePushRecordResponse($res); diff --git a/app/Libraries/Abdm/Fhir/Generators/WellnessFhirGenerator.php b/app/Libraries/Abdm/Fhir/Generators/WellnessFhirGenerator.php index 7999435..4621f09 100644 --- a/app/Libraries/Abdm/Fhir/Generators/WellnessFhirGenerator.php +++ b/app/Libraries/Abdm/Fhir/Generators/WellnessFhirGenerator.php @@ -91,7 +91,7 @@ class WellnessFhirGenerator extends AbstractModuleFhirGenerator // Body measurement LOINC codes $bodyMeasLoincCodes = ['8302-2', '29463-7', '39156-5', '56115-9', '56114-2', '8280-0']; // General assessment LOINC codes (blood sugar, lab POC, Hb) - $generalAssessLoincCodes = ['2339-0', '1558-6', '1521-4', '4548-4', '718-7', '25428-4', '1753-3']; + $generalAssessLoincCodes = ['2339-0', '1558-6', '1521-4', '14760-3', '2345-7', '4548-4', '718-7', '25428-4', '1753-3']; // Physical activity LOINC codes $activityLoincCodes = ['55423-8', '93832-4', '55411-3', '41981-2']; @@ -216,7 +216,7 @@ class WellnessFhirGenerator extends AbstractModuleFhirGenerator $numericVal = round($numericVal, 1); } elseif ($loincCode === '8280-0' || $loincCode === '4548-4') { $numericVal = round($numericVal, 2); - } elseif (in_array($loincCode, ['8867-4', '59408-5', '9279-1', '2339-0', '1558-6', '1521-4'], true)) { + } elseif (in_array($loincCode, ['8867-4', '59408-5', '9279-1', '2339-0', '1558-6', '1521-4', '14760-3', '2345-7'], true)) { $numericVal = (float) round($numericVal); } else { $numericVal = round($numericVal, 2); diff --git a/app/Views/partials/abdm_hip_link_modal.php b/app/Views/partials/abdm_hip_link_modal.php index 7dea11a..b30b733 100644 --- a/app/Views/partials/abdm_hip_link_modal.php +++ b/app/Views/partials/abdm_hip_link_modal.php @@ -852,6 +852,21 @@ var ref = cb.value; var display = cb.nextElementSibling ? cb.nextElementSibling.textContent : ref; var itemHiType = cb.dataset.hiType || ''; + if (/^WELLNESS-/i.test(ref)) { + itemHiType = 'WellnessRecord'; + } else if (/^DOC-/i.test(ref)) { + itemHiType = 'HealthDocumentRecord'; + } else if (/^INVOICE-/i.test(ref)) { + itemHiType = 'InvoiceRecord'; + } else if (/^(?:LAB|RAD)-/i.test(ref)) { + itemHiType = 'DiagnosticReportRecord'; + } else if (/^IMM-/i.test(ref)) { + itemHiType = 'ImmunizationRecord'; + } else if (/^(?:DISCHARGE|IPD)-/i.test(ref)) { + itemHiType = 'DischargeSummaryRecord'; + } else if (/^(?:OPD|PRESC)-/i.test(ref)) { + itemHiType = 'OPConsultRecord'; + } if (!dominantHiType && itemHiType) { dominantHiType = itemHiType; }