diff --git a/app/Config/Routes.php b/app/Config/Routes.php index de8bf45..d1c7a94 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -597,6 +597,8 @@ $routes->post('AbdmGateway/push_health_record', 'AbdmGateway::pushHealthRecord', $routes->get('AbdmGateway/health_records_list', 'AbdmGateway::healthRecordsList', ['filter' => $abdmPermFilter]); $routes->get('AbdmGateway/bridge_record_status/(:num)', 'AbdmGateway::bridgeRecordStatus/$1', ['filter' => $abdmPermFilter]); $routes->post('AbdmGateway/bridge_record_share/(:num)', 'AbdmGateway::bridgeRecordShare/$1', ['filter' => $abdmPermFilter]); +$routes->post('AbdmGateway/bridge_record_link_share/(:num)', 'AbdmGateway::bridgeRecordLinkShare/$1', ['filter' => $abdmPermFilter]); +$routes->get('AbdmGateway/bridge_record_workflow_status/(:num)', 'AbdmGateway::bridgeRecordWorkflowStatus/$1', ['filter' => $abdmPermFilter]); $routes->get('AbdmGateway/opd_running_token_status', 'AbdmGateway::opdRunningTokenStatus', ['filter' => $abdmPermFilter]); $routes->get('AbdmGateway/gateway_status', 'AbdmGateway::gatewayStatus', ['filter' => $abdmPermFilter]); $routes->get('AbdmGateway/bridge_records_list', 'AbdmGateway::bridgeRecordsList', ['filter' => $abdmPermFilter]); @@ -1086,6 +1088,8 @@ $routes->group('setting', static function($routes) { $routes->get('admin/abdm-gateway', 'Setting\\AbdmGatewaySettings::index', ['filter' => $settingsAdminFilter]); $routes->post('admin/abdm-gateway/save', 'Setting\\AbdmGatewaySettings::save', ['filter' => $settingsAdminFilter]); $routes->post('admin/abdm-gateway/test', 'Setting\\AbdmGatewaySettings::testConnection', ['filter' => $settingsAdminFilter]); + $routes->get('admin/abdm-report-doctors', 'Setting\\AbdmReportDoctorSettings::index', ['filter' => $settingsAdminFilter]); + $routes->post('admin/abdm-report-doctors/save', 'Setting\\AbdmReportDoctorSettings::save', ['filter' => $settingsAdminFilter]); $routes->get('admin/hospital-profile', 'Setting\\HospitalProfile::index'); $routes->post('admin/hospital-profile/save', 'Setting\\HospitalProfile::save'); $routes->post('admin/hospital-profile/delete-logo', 'Setting\\HospitalProfile::deleteLogo'); diff --git a/app/Controllers/AbdmGateway.php b/app/Controllers/AbdmGateway.php index ac6e7ce..5647ed3 100644 --- a/app/Controllers/AbdmGateway.php +++ b/app/Controllers/AbdmGateway.php @@ -1851,7 +1851,12 @@ class AbdmGateway extends BaseController return $this->response->setStatusCode(400)->setJSON(['ok' => 0, 'error_text' => 'Invalid request']); } - $result = $this->connector->getRecord($bridgeId); + try { + $result = $this->connector->workflowStatus($bridgeId); + } catch (\Throwable $e) { + // Backward compatibility with older connectors. + $result = $this->connector->getRecord($bridgeId); + } return $this->response->setJSON($result); } @@ -1866,10 +1871,29 @@ class AbdmGateway extends BaseController return $this->response->setStatusCode(400)->setJSON(['ok' => 0, 'error_text' => 'Invalid request']); } - $result = $this->connector->triggerShare($bridgeId); + try { + $result = $this->connector->linkAndShare($bridgeId); + } catch (\Throwable $e) { + // Backward compatibility with older connectors. + $result = $this->connector->triggerShare($bridgeId); + } return $this->response->setJSON($result); } + // ========================================================================= + // Explicit e-Atria orchestration aliases for HMS integration docs. + // ========================================================================= + + public function bridgeRecordLinkShare(int $bridgeId) + { + return $this->bridgeRecordShare($bridgeId); + } + + public function bridgeRecordWorkflowStatus(int $bridgeId) + { + return $this->bridgeRecordStatus($bridgeId); + } + // ========================================================================= // OPD running token status — GET /api/v3/opd/running-token-status // GET /AbdmGateway/opd_running_token_status @@ -2494,6 +2518,8 @@ class AbdmGateway extends BaseController $doctorId = 0; $doctorName = ''; $doctorRegNo = ''; + $labType = 0; + $chargeId = 0; $candidateIdCols = ['doctor_id', 'dr_id', 'doc_id', 'r_doc_id', 'consultant_id', 'reported_by_doctor_id']; $candidateNameCols = ['doctor_name', 'dr_name', 'doc_name', 'r_doc_name', 'consultant_name', 'reported_by_name', 'reported_by']; @@ -2501,6 +2527,8 @@ class AbdmGateway extends BaseController // Try immediate row first (if caller passed a richer row object/array). if (is_object($labReqRow)) { + $labType = (int) ($labReqRow->lab_type ?? 0); + $chargeId = (int) ($labReqRow->charge_id ?? 0); foreach ($candidateIdCols as $c) { if (isset($labReqRow->{$c}) && (int) $labReqRow->{$c} > 0) { $doctorId = (int) $labReqRow->{$c}; @@ -2522,6 +2550,8 @@ class AbdmGateway extends BaseController } } } elseif (is_array($labReqRow)) { + $labType = (int) ($labReqRow['lab_type'] ?? 0); + $chargeId = (int) ($labReqRow['charge_id'] ?? 0); foreach ($candidateIdCols as $c) { if (isset($labReqRow[$c]) && (int) $labReqRow[$c] > 0) { $doctorId = (int) $labReqRow[$c]; @@ -2544,6 +2574,31 @@ class AbdmGateway extends BaseController } } + // Priority 1: explicit admin mapping by modality (Pathology/X-Ray/CT/USG/etc.). + $testTitle = ''; + if ($chargeId > 0 && $this->db->tableExists('charge_master')) { + try { + $chargeRow = $this->db->table('charge_master') + ->select('charge_name') + ->where('id', $chargeId) + ->get(1) + ->getRowArray() ?? []; + $testTitle = trim((string) ($chargeRow['charge_name'] ?? '')); + } catch (\Throwable $e) { + $testTitle = ''; + } + } + + $mappedDoctorId = $this->resolveMappedDoctorIdForLabContext($labType, $testTitle); + if ($mappedDoctorId > 0) { + $mappedDoctor = $this->loadDoctorIdentityById($mappedDoctorId); + if ($mappedDoctor !== null) { + $doctorId = $mappedDoctorId; + $doctorName = trim((string) ($mappedDoctor['name'] ?? '')); + $doctorRegNo = trim((string) ($mappedDoctor['registration_number'] ?? '')); + } + } + try { $labFields = $this->db->getFieldNames('lab_request') ?? []; $selectCols = ['id']; @@ -2635,6 +2690,107 @@ class AbdmGateway extends BaseController ]; } + private function resolveMappedDoctorIdForLabContext(int $labType, string $testTitle): int + { + if (! $this->db->tableExists('hospital_setting')) { + return 0; + } + + $title = strtolower(trim($testTitle)); + if ($labType === 6) { + if ($title !== '') { + if (preg_match('/\bx\s*-?\s*ray\b|\bxray\b|\bradiograph\b/', $title) === 1) { + return $this->readMappedDoctorId('ABDM_DOC_XRAY'); + } + if (preg_match('/\bct\b|\bct\s*scan\b|\bhrct\b|\bcect\b/', $title) === 1) { + return $this->readMappedDoctorId('ABDM_DOC_CTSCAN'); + } + if (preg_match('/\busg\b|\bultra\s*sound\b|\bultrasound\b|\bsonograph\b/', $title) === 1) { + return $this->readMappedDoctorId('ABDM_DOC_ULTRASOUND'); + } + if (preg_match('/\bmri\b|\bmr\b/', $title) === 1) { + return $this->readMappedDoctorId('ABDM_DOC_MRI'); + } + } + + $radDefault = $this->readMappedDoctorId('ABDM_DOC_RADIOLOGY'); + if ($radDefault > 0) { + return $radDefault; + } + } + + return $this->readMappedDoctorId('ABDM_DOC_PATHOLOGY'); + } + + private function readMappedDoctorId(string $settingKey): int + { + if ($settingKey === '' || ! $this->db->tableExists('hospital_setting')) { + return 0; + } + + $row = $this->db->table('hospital_setting') + ->select('s_value') + ->where('s_name', $settingKey) + ->get(1) + ->getRowArray(); + + return (int) ($row['s_value'] ?? 0); + } + + /** + * @return array{name:string,registration_number:string}|null + */ + private function loadDoctorIdentityById(int $doctorId): ?array + { + if ($doctorId <= 0 || ! $this->db->tableExists('doctor_master')) { + return null; + } + + try { + $dFields = $this->db->getFieldNames('doctor_master') ?? []; + $dSelect = ['id']; + foreach (['p_title', 'p_fname', 'p_lname', 'doctor_reg_no', 'registration_no', 'reg_no', 'doc_reg_no', 'nmc_reg_no', 'mci_reg_no'] as $f) { + if (in_array($f, $dFields, true)) { + $dSelect[] = $f; + } + } + + $dRow = $this->db->table('doctor_master') + ->select(implode(',', array_unique($dSelect))) + ->where('id', $doctorId) + ->get(1) + ->getRowArray() ?? []; + + if (empty($dRow)) { + return null; + } + + $name = trim( + trim((string) ($dRow['p_title'] ?? '')) . ' ' . + trim((string) ($dRow['p_fname'] ?? '')) . ' ' . + trim((string) ($dRow['p_lname'] ?? '')) + ); + if ($name === '') { + return null; + } + + $reg = ''; + foreach (['doctor_reg_no', 'registration_no', 'reg_no', 'doc_reg_no', 'nmc_reg_no', 'mci_reg_no'] as $f) { + if (! empty($dRow[$f])) { + $reg = trim((string) $dRow[$f]); + break; + } + } + + return [ + 'name' => $name, + 'registration_number' => $reg, + ]; + } catch (\Throwable $e) { + return null; + } + } + /** * Map numeric lab_type code to a human-readable title. */ diff --git a/app/Controllers/Setting/AbdmReportDoctorSettings.php b/app/Controllers/Setting/AbdmReportDoctorSettings.php new file mode 100644 index 0000000..1bcced2 --- /dev/null +++ b/app/Controllers/Setting/AbdmReportDoctorSettings.php @@ -0,0 +1,200 @@ + + */ + private array $mappingKeys = [ + 'ABDM_DOC_PATHOLOGY' => 'Pathology / Lab Default', + 'ABDM_DOC_XRAY' => 'X-Ray', + 'ABDM_DOC_CTSCAN' => 'CT Scan', + 'ABDM_DOC_ULTRASOUND' => 'Ultrasound (USG)', + 'ABDM_DOC_MRI' => 'MRI', + 'ABDM_DOC_RADIOLOGY' => 'Radiology Default (fallback)', + ]; + + public function index() + { + if (! $this->canManageSettings()) { + return $this->response->setStatusCode(403)->setBody('Access denied'); + } + + return view('Setting/Admin/abdm_report_doctor_settings', [ + 'mapping_keys' => $this->mappingKeys, + 'selected' => $this->readExistingMappings(), + 'doctors' => $this->fetchDoctorOptions(), + ]); + } + + public function save() + { + if (! $this->request->isAJAX()) { + return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']); + } + + if (! $this->canManageSettings()) { + return $this->response->setStatusCode(403)->setJSON(['update' => 0, 'error_text' => 'Access denied']); + } + + if (! $this->db->tableExists('hospital_setting')) { + return $this->response->setJSON(['update' => 0, 'error_text' => 'hospital_setting table not found']); + } + + foreach ($this->mappingKeys as $key => $label) { + $doctorId = (int) ($this->request->getPost($key) ?? 0); + if ($doctorId > 0) { + $this->upsertSettingValue($key, (string) $doctorId); + } else { + $this->deleteSettingValue($key); + } + } + + return $this->response->setJSON([ + 'update' => 1, + 'error_text' => 'ABDM report doctor mapping saved.', + 'csrfName' => csrf_token(), + 'csrfHash' => csrf_hash(), + ]); + } + + /** + * @return array + */ + private function readExistingMappings(): array + { + $output = []; + foreach (array_keys($this->mappingKeys) as $key) { + $output[$key] = 0; + } + + if (! $this->db->tableExists('hospital_setting')) { + return $output; + } + + $rows = $this->db->table('hospital_setting') + ->select('s_name, s_value') + ->whereIn('s_name', array_keys($this->mappingKeys)) + ->get() + ->getResultArray(); + + foreach ($rows as $row) { + $name = trim((string) ($row['s_name'] ?? '')); + if ($name === '' || ! array_key_exists($name, $output)) { + continue; + } + $output[$name] = (int) ($row['s_value'] ?? 0); + } + + return $output; + } + + /** + * @return array> + */ + private function fetchDoctorOptions(): array + { + if (! $this->db->tableExists('doctor_master')) { + return []; + } + + $fields = $this->db->getFieldNames('doctor_master') ?? []; + $select = ['id']; + foreach (['p_title', 'p_fname', 'p_lname', 'doctor_reg_no', 'registration_no', 'reg_no', 'doc_reg_no', 'nmc_reg_no', 'mci_reg_no'] as $f) { + if (in_array($f, $fields, true)) { + $select[] = $f; + } + } + + $builder = $this->db->table('doctor_master')->select(implode(',', array_unique($select))); + if (in_array('is_active', $fields, true)) { + $builder->where('is_active', 1); + } elseif (in_array('status', $fields, true)) { + $builder->where('status', 1); + } + + if (in_array('p_fname', $fields, true)) { + $builder->orderBy('p_fname', 'ASC'); + } else { + $builder->orderBy('id', 'DESC'); + } + + $rows = $builder->get()->getResultArray(); + $out = []; + foreach ($rows as $row) { + $id = (int) ($row['id'] ?? 0); + if ($id <= 0) { + continue; + } + + $title = trim((string) ($row['p_title'] ?? '')); + $first = trim((string) ($row['p_fname'] ?? '')); + $last = trim((string) ($row['p_lname'] ?? '')); + $name = trim($title . ' ' . $first . ' ' . $last); + if ($name === '') { + $name = 'Doctor #' . $id; + } + + $regNo = ''; + foreach (['doctor_reg_no', 'registration_no', 'reg_no', 'doc_reg_no', 'nmc_reg_no', 'mci_reg_no'] as $rf) { + $v = trim((string) ($row[$rf] ?? '')); + if ($v !== '') { + $regNo = $v; + break; + } + } + + $label = $name; + if ($regNo !== '') { + $label .= ' (' . $regNo . ')'; + } + + $out[] = [ + 'id' => $id, + 'name' => $name, + 'reg_no' => $regNo, + 'label' => $label, + ]; + } + + return $out; + } + + private function canManageSettings(): bool + { + if (! function_exists('auth') || ! auth()->loggedIn()) { + return false; + } + + return true; + } + + private function upsertSettingValue(string $name, string $value): bool + { + $existing = $this->db->table('hospital_setting') + ->select('id') + ->where('s_name', $name) + ->get(1) + ->getRowArray(); + + if ($existing) { + return (bool) $this->db->table('hospital_setting') + ->where('id', (int) $existing['id']) + ->update(['s_value' => $value]); + } + + return (bool) $this->db->table('hospital_setting')->insert([ + 's_name' => $name, + 's_value' => $value, + ]); + } + + private function deleteSettingValue(string $name): bool + { + return (bool) $this->db->table('hospital_setting')->where('s_name', $name)->delete(); + } +} diff --git a/app/Libraries/Abdm/AbdmConnectorInterface.php b/app/Libraries/Abdm/AbdmConnectorInterface.php index 75c3d9d..9dc82e1 100644 --- a/app/Libraries/Abdm/AbdmConnectorInterface.php +++ b/app/Libraries/Abdm/AbdmConnectorInterface.php @@ -197,6 +197,16 @@ interface AbdmConnectorInterface */ public function triggerShare(int $bridgeId): array; + /** + * POST /api/v3/records/{id}/link-and-share — orchestrated care-context link + share. + */ + public function linkAndShare(int $bridgeId): array; + + /** + * GET /api/v3/records/{id}/workflow-status — end-to-end workflow status. + */ + public function workflowStatus(int $bridgeId): array; + /** * GET /api/v3/records — list stored bridge records with optional filters. * diff --git a/app/Libraries/Abdm/DreamsoftConnector.php b/app/Libraries/Abdm/DreamsoftConnector.php index 29dc322..4a97169 100644 --- a/app/Libraries/Abdm/DreamsoftConnector.php +++ b/app/Libraries/Abdm/DreamsoftConnector.php @@ -189,6 +189,50 @@ class DreamsoftConnector implements AbdmConnectorInterface return $this->sharePrescriptionBundle($data, (string) ($data['entity_id'] ?? '')); } + public function getRecord(int $bridgeId): array + { + // No direct pull API in Dreamsoft async adapter; return queued placeholder. + return [ + 'ok' => 1, + 'id' => $bridgeId, + 'status' => 'queued', + 'message' => 'Dreamsoft connector does not provide synchronous record fetch.', + ]; + } + + public function triggerShare(int $bridgeId): array + { + // Keep compatibility with older UI actions. + return [ + 'ok' => 1, + 'id' => $bridgeId, + 'status' => 'queued', + 'message' => 'Dreamsoft connector does not provide synchronous share trigger.', + ]; + } + + public function linkAndShare(int $bridgeId): array + { + // New e-Atria orchestration API is not available in Dreamsoft adapter. + return [ + 'ok' => 1, + 'id' => $bridgeId, + 'status' => 'queued', + 'message' => 'Dreamsoft connector does not provide synchronous link-and-share orchestration.', + ]; + } + + public function workflowStatus(int $bridgeId): array + { + // No synchronous status API in Dreamsoft adapter. + return [ + 'ok' => 1, + 'id' => $bridgeId, + 'status' => 'queued', + 'next_action' => 'Track status via bridge queue/callback events.', + ]; + } + public function nhcxClaimStatusRequest( int $documentId, string $externalRef, @@ -209,4 +253,96 @@ class DreamsoftConnector implements AbdmConnectorInterface ); return ['ok' => 1, 'queue_id' => $queueId, 'status' => 'queued']; } + + public function getRecords(array $filters = []): array + { + return [ + 'ok' => 1, + 'records' => [], + 'status' => 'queued', + 'message' => 'Dreamsoft connector does not provide synchronous records listing.', + ]; + } + + public function gatewayStatus(): array + { + return [ + 'ok' => 1, + 'status' => 'queued', + 'connector' => $this->getConnectorName(), + 'message' => 'Dreamsoft connector does not expose synchronous gateway status.', + ]; + } + + public function hipLinkToken(array $payload): array + { + return [ + 'ok' => 0, + 'error_text' => 'HIP link-token flow is not supported by DreamsoftConnector. Use eatria_bridge connector.', + ]; + } + + public function hipLinkCareContext(array $payload): array + { + return [ + 'ok' => 0, + 'error_text' => 'HIP link care-context flow is not supported by DreamsoftConnector. Use eatria_bridge connector.', + ]; + } + + public function hipGetPatientLinks(array $filters = []): array + { + return [ + 'ok' => 0, + 'error_text' => 'HIP patient links flow is not supported by DreamsoftConnector. Use eatria_bridge connector.', + ]; + } + + public function hipLinkNotify(array $payload): array + { + return [ + 'ok' => 0, + 'error_text' => 'HIP link notify flow is not supported by DreamsoftConnector. Use eatria_bridge connector.', + ]; + } + + public function hipSmsNotify(array $payload): array + { + return [ + 'ok' => 0, + 'error_text' => 'HIP SMS notify flow is not supported by DreamsoftConnector. Use eatria_bridge connector.', + ]; + } + + public function opdQueueFetch(string $date = '', string $status = '', int $page = 1, int $limit = 100): array + { + return [ + 'ok' => 0, + 'error_text' => 'OPD queue API is not supported by DreamsoftConnector. Use eatria_bridge connector.', + ]; + } + + public function opdTokenCreate(array $payload): array + { + return [ + 'ok' => 0, + 'error_text' => 'OPD token API is not supported by DreamsoftConnector. Use eatria_bridge connector.', + ]; + } + + public function opdTokenUpdateStatus(int $tokenId, string $status): array + { + return [ + 'ok' => 0, + 'error_text' => 'OPD token status API is not supported by DreamsoftConnector. Use eatria_bridge connector.', + ]; + } + + public function opdRunningTokenStatus(): array + { + return [ + 'ok' => 0, + 'error_text' => 'OPD running token status API is not supported by DreamsoftConnector. Use eatria_bridge connector.', + ]; + } } diff --git a/app/Libraries/Abdm/EAtriaBridgeConnector.php b/app/Libraries/Abdm/EAtriaBridgeConnector.php index 51da195..9a8a03b 100644 --- a/app/Libraries/Abdm/EAtriaBridgeConnector.php +++ b/app/Libraries/Abdm/EAtriaBridgeConnector.php @@ -338,16 +338,16 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface public function pushRecord(array $data): array { - // Normalise to the 8 official ABDM HI types that the gateway validates. - // Valid values: OPConsultRecord, PrescriptionRecord, DiagnosticReportRecord, - // DischargeSummaryRecord, ImmunizationRecord, WellnessRecord, + // Normalise to gateway accepted HI types from integration docs. + // Valid values: OPConsultation, Prescription, DiagnosticReport, + // DischargeSummary, ImmunizationRecord, WellnessRecord, // HealthDocumentRecord, InvoiceRecord $hiTypeRaw = (string) ($data['hi_type'] ?? ''); $hiType = match ($hiTypeRaw) { - 'OPConsultRecord', 'OPConsultation' => 'OPConsultRecord', - 'PrescriptionRecord' => 'PrescriptionRecord', - 'DiagnosticReportRecord', 'DiagnosticReport' => 'DiagnosticReportRecord', - 'DischargeSummaryRecord', 'DischargeSummary' => 'DischargeSummaryRecord', + 'OPConsultRecord', 'OPConsultation' => 'OPConsultation', + 'PrescriptionRecord', 'Prescription' => 'Prescription', + 'DiagnosticReportRecord', 'DiagnosticReport' => 'DiagnosticReport', + 'DischargeSummaryRecord', 'DischargeSummary' => 'DischargeSummary', 'WellnessRecord' => 'WellnessRecord', 'ImmunizationRecord' => 'ImmunizationRecord', 'InvoiceRecord' => 'InvoiceRecord', @@ -364,9 +364,9 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface } else { // Derive record_type from hi_type $recordType = match ($hiType) { - 'OPConsultRecord', 'PrescriptionRecord' => 'prescription', - 'DiagnosticReportRecord' => 'lab_report', - 'DischargeSummaryRecord' => 'discharge_summary', + 'OPConsultation', 'Prescription' => 'prescription', + 'DiagnosticReport' => 'lab_report', + 'DischargeSummary' => 'discharge_summary', 'WellnessRecord', 'ImmunizationRecord' => 'wellness_record', default => 'health_document', }; @@ -376,9 +376,9 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface // Gateway requires hi_type with the exact ABDM HI type name. if ($hiType === '') { $hiType = match ($recordType) { - 'prescription' => 'OPConsultRecord', - 'lab_report' => 'DiagnosticReportRecord', - 'discharge_summary' => 'DischargeSummaryRecord', + 'prescription' => 'OPConsultation', + 'lab_report' => 'DiagnosticReport', + 'discharge_summary' => 'DischargeSummary', 'wellness_record' => 'WellnessRecord', default => 'HealthDocumentRecord', }; @@ -392,6 +392,7 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface 'hi_type' => $hiType, 'visit_date' => (string) ($data['visit_date'] ?? date('Y-m-d')), 'record_data' => $data['record_data'] ?? $data['bundle'] ?? (object) [], + 'fhir_bundle' => $data['record_data'] ?? $data['bundle'] ?? (object) [], ]; // hfr_id is required in every push request alongside the Bearer token. @@ -399,7 +400,7 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface $body['hfr_id'] = $this->hfrId; } - foreach (['abha_id', 'abha_address', 'doctor_name', 'department', 'care_context_reference', 'notes', 'queue_id'] as $optional) { + foreach (['abha_id', 'abha_address', 'doctor_name', 'department', 'care_context_reference', 'care_context_display', 'notes', 'queue_id', 'gender', 'year_of_birth'] as $optional) { if (! empty($data[$optional])) { $body[$optional] = (string) $data[$optional]; } @@ -458,12 +459,38 @@ class EAtriaBridgeConnector implements AbdmConnectorInterface public function getRecord(int $bridgeId): array { - return $this->get('/v3/records/' . $bridgeId); + $query = []; + if ($this->hfrId !== '') { + $query['hfr_id'] = $this->hfrId; + } + return $this->get('/v3/records/' . $bridgeId, $query); } public function triggerShare(int $bridgeId): array { - return $this->post('/v3/records/' . $bridgeId . '/share', []); + $body = []; + if ($this->hfrId !== '') { + $body['hfr_id'] = $this->hfrId; + } + return $this->post('/v3/records/' . $bridgeId . '/share', $body); + } + + public function linkAndShare(int $bridgeId): array + { + $body = []; + if ($this->hfrId !== '') { + $body['hfr_id'] = $this->hfrId; + } + return $this->post('/v3/records/' . $bridgeId . '/link-and-share', $body); + } + + public function workflowStatus(int $bridgeId): array + { + $query = []; + if ($this->hfrId !== '') { + $query['hfr_id'] = $this->hfrId; + } + return $this->get('/v3/records/' . $bridgeId . '/workflow-status', $query); } public function opdQueueFetch(string $date = '', string $status = '', int $page = 1, int $limit = 100): array diff --git a/app/Views/Setting/Admin/abdm_report_doctor_settings.php b/app/Views/Setting/Admin/abdm_report_doctor_settings.php new file mode 100644 index 0000000..65d8c70 --- /dev/null +++ b/app/Views/Setting/Admin/abdm_report_doctor_settings.php @@ -0,0 +1,99 @@ +
+
+

+ ABDM Report Doctor Mapping +

+ Lab & Radiology +
+
+ + +
+ Select which doctor should be used in FHIR Practitioner for each report modality. + If a modality-specific doctor is not found, system falls back to default resolution. +
+ + +
No doctors found in Doctor Master. Add doctors first, then map them here.
+ +
+ $label) : ?> +
+ + +
+ +
+ + +
+ +
+ +
+
+
+ + diff --git a/app/Views/Setting/Admin/index.php b/app/Views/Setting/Admin/index.php index 6e85633..64d57eb 100644 --- a/app/Views/Setting/Admin/index.php +++ b/app/Views/Setting/Admin/index.php @@ -80,6 +80,12 @@ ABDM Gateway +