Align ABDM bridge workflow APIs and add report doctor mapping
This commit is contained in:
parent
e1d9e85e64
commit
b12652d6e0
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
200
app/Controllers/Setting/AbdmReportDoctorSettings.php
Normal file
200
app/Controllers/Setting/AbdmReportDoctorSettings.php
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
|
||||
class AbdmReportDoctorSettings extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var array<string,string>
|
||||
*/
|
||||
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<string,int>
|
||||
*/
|
||||
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<int,array<string,mixed>>
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
99
app/Views/Setting/Admin/abdm_report_doctor_settings.php
Normal file
99
app/Views/Setting/Admin/abdm_report_doctor_settings.php
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<div class="card">
|
||||
<div class="card-header d-flex align-items-center justify-content-between flex-wrap gap-2">
|
||||
<h3 class="card-title mb-0">
|
||||
<i class="bi bi-person-vcard me-2 text-primary"></i>ABDM Report Doctor Mapping
|
||||
</h3>
|
||||
<span class="badge bg-primary">Lab & Radiology</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<div class="alert alert-info py-2 mb-3" style="font-size:13px;">
|
||||
Select which doctor should be used in FHIR <code>Practitioner</code> for each report modality.
|
||||
If a modality-specific doctor is not found, system falls back to default resolution.
|
||||
</div>
|
||||
|
||||
<?php if (empty($doctors ?? [])) : ?>
|
||||
<div class="alert alert-warning">No doctors found in Doctor Master. Add doctors first, then map them here.</div>
|
||||
<?php else : ?>
|
||||
<div class="row g-3">
|
||||
<?php foreach (($mapping_keys ?? []) as $key => $label) : ?>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-semibold"><?= esc($label) ?></label>
|
||||
<select class="form-select abdm-doc-map" id="<?= esc($key) ?>" data-key="<?= esc($key) ?>">
|
||||
<option value="">-- Not mapped --</option>
|
||||
<?php foreach (($doctors ?? []) as $doc) : ?>
|
||||
<option value="<?= (int) ($doc['id'] ?? 0) ?>" <?= ((int) (($selected[$key] ?? 0)) === (int) ($doc['id'] ?? 0)) ? 'selected' : '' ?>>
|
||||
<?= esc((string) ($doc['label'] ?? ('Doctor #' . (int) ($doc['id'] ?? 0)))) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="mt-3 d-flex gap-2 flex-wrap">
|
||||
<button type="button" class="btn btn-primary" id="btn_save_abdm_doc_map">
|
||||
<i class="bi bi-save me-1"></i>Save Mapping
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="abdm_doc_map_msg" class="mt-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function getCsrfPair() {
|
||||
var input = document.querySelector('input[name="<?= csrf_token() ?>"]');
|
||||
if (!input) {
|
||||
return { name: '<?= csrf_token() ?>', value: '<?= csrf_hash() ?>' };
|
||||
}
|
||||
return { name: input.getAttribute('name'), value: input.value };
|
||||
}
|
||||
|
||||
function updateCsrf(data) {
|
||||
if (!data || !data.csrfName || !data.csrfHash) return;
|
||||
var input = document.querySelector('input[name="' + data.csrfName + '"]');
|
||||
if (input) input.value = data.csrfHash;
|
||||
}
|
||||
|
||||
function showMsg(type, html) {
|
||||
var cls = type === 'success' ? 'alert alert-success' : 'alert alert-danger';
|
||||
$('#abdm_doc_map_msg').html('<div class="' + cls + ' py-2">' + html + '</div>');
|
||||
}
|
||||
|
||||
function collectPayload() {
|
||||
var payload = {};
|
||||
document.querySelectorAll('.abdm-doc-map').forEach(function (el) {
|
||||
payload[el.getAttribute('data-key')] = (el.value || '').trim();
|
||||
});
|
||||
return payload;
|
||||
}
|
||||
|
||||
$('#btn_save_abdm_doc_map').on('click', function () {
|
||||
var payload = collectPayload();
|
||||
var csrf = getCsrfPair();
|
||||
payload[csrf.name] = csrf.value;
|
||||
|
||||
var $btn = $(this).prop('disabled', true).text('Saving...');
|
||||
$('#abdm_doc_map_msg').html('');
|
||||
|
||||
$.post('<?= base_url('setting/admin/abdm-report-doctors/save') ?>', payload, function (res) {
|
||||
updateCsrf(res);
|
||||
if (res && parseInt(res.update || '0', 10) === 1) {
|
||||
showMsg('success', '<i class="bi bi-check-circle me-1"></i>' + (res.error_text || 'Saved.'));
|
||||
} else {
|
||||
showMsg('danger', '<i class="bi bi-x-circle me-1"></i>' + ((res && res.error_text) ? res.error_text : 'Save failed.'));
|
||||
}
|
||||
$btn.prop('disabled', false).html('<i class="bi bi-save me-1"></i>Save Mapping');
|
||||
}, 'json').fail(function () {
|
||||
showMsg('danger', '<i class="bi bi-x-circle me-1"></i>Save failed.');
|
||||
$btn.prop('disabled', false).html('<i class="bi bi-save me-1"></i>Save Mapping');
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
|
@ -80,6 +80,12 @@
|
|||
<span>ABDM Gateway</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-6 col-md-2 col-lg-2">
|
||||
<a class="admin-tile" href="javascript:load_form_div('<?= base_url('setting/admin/abdm-report-doctors') ?>','maindiv','ABDM Report Doctors');">
|
||||
<i class="bi bi-person-vcard" style="color:#0d6efd"></i>
|
||||
<span>ABDM Report Doctors</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-6 col-md-2 col-lg-2">
|
||||
<a class="admin-tile" href="javascript:load_form_div('<?= base_url('setting/admin/hospital-profile') ?>','maindiv','Hospital Profile');">
|
||||
<i class="bi bi-building"></i>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user