diff --git a/app/Config/Routes.php b/app/Config/Routes.php index edb87bc..7cf412e 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -206,6 +206,33 @@ $routes->group('api', function ($routes) { $routes->patch('/', 'Organization\WorkstationController::update'); $routes->delete('/', 'Organization\WorkstationController::delete'); }); + + // HostApp + $routes->group('hostapp', function ($routes) { + $routes->get('/', 'Organization\HostAppController::index'); + $routes->get('(:any)', 'Organization\HostAppController::show/$1'); + $routes->post('/', 'Organization\HostAppController::create'); + $routes->patch('/', 'Organization\HostAppController::update'); + $routes->delete('/', 'Organization\HostAppController::delete'); + }); + + // HostComPara + $routes->group('hostcompara', function ($routes) { + $routes->get('/', 'Organization\HostComParaController::index'); + $routes->get('(:any)', 'Organization\HostComParaController::show/$1'); + $routes->post('/', 'Organization\HostComParaController::create'); + $routes->patch('/', 'Organization\HostComParaController::update'); + $routes->delete('/', 'Organization\HostComParaController::delete'); + }); + + // CodingSys + $routes->group('codingsys', function ($routes) { + $routes->get('/', 'Organization\CodingSysController::index'); + $routes->get('(:num)', 'Organization\CodingSysController::show/$1'); + $routes->post('/', 'Organization\CodingSysController::create'); + $routes->patch('/', 'Organization\CodingSysController::update'); + $routes->delete('/', 'Organization\CodingSysController::delete'); + }); }); // Infrastructure @@ -278,7 +305,7 @@ $routes->group('api', function ($routes) { $routes->delete('/', 'Test\TestMapController::delete'); // Filter routes - $routes->get('by-testsite/(:num)', 'Test\TestMapController::showByTestSite/$1'); + $routes->get('by-testcode/(:any)', 'Test\TestMapController::showByTestCode/$1'); // TestMapDetail nested routes $routes->group('detail', function ($routes) { diff --git a/app/Controllers/Organization/CodingSysController.php b/app/Controllers/Organization/CodingSysController.php new file mode 100644 index 0000000..b87698b --- /dev/null +++ b/app/Controllers/Organization/CodingSysController.php @@ -0,0 +1,97 @@ +db = \Config\Database::connect(); + $this->model = new CodingSysModel(); + } + + public function index() { + $filter = [ + 'CodingSysAbb' => $this->request->getVar('CodingSysAbb'), + 'FullText' => $this->request->getVar('FullText'), + ]; + + $builder = $this->model; + + if (!empty($filter['CodingSysAbb'])) { + $builder->like('CodingSysAbb', $filter['CodingSysAbb'], 'both'); + } + if (!empty($filter['FullText'])) { + $builder->like('FullText', $filter['FullText'], 'both'); + } + + $rows = $builder->findAll(); + + if (empty($rows)) { + return $this->respond(['status' => 'success', 'message' => 'no Data.', 'data' => []], 200); + } + + return $this->respond(['status' => 'success', 'message' => 'fetch success', 'data' => $rows], 200); + } + + public function show($CodingSysID = null) { + $row = $this->model->where('CodingSysID', $CodingSysID)->first(); + + if (empty($row)) { + return $this->respond(['status' => 'success', 'message' => 'no Data.', 'data' => null], 200); + } + + return $this->respond(['status' => 'success', 'message' => 'fetch success', 'data' => $row], 200); + } + + public function delete() { + try { + $input = $this->request->getJSON(true); + $id = $input['CodingSysID'] ?? null; + + if (!$id) { + return $this->failValidationErrors('CodingSysID is required.'); + } + + $this->model->delete($id); + return $this->respondDeleted(['status' => 'success', 'message' => "{$id} deleted successfully."]); + } catch (\Throwable $e) { + return $this->failServerError('Something went wrong: ' . $e->getMessage()); + } + } + + public function create() { + $input = $this->request->getJSON(true); + + try { + $id = $this->model->insert($input, true); + return $this->respondCreated(['status' => 'success', 'message' => 'data created successfully', 'data' => $id], 201); + } catch (\Throwable $e) { + return $this->failServerError('Something went wrong: ' . $e->getMessage()); + } + } + + public function update() { + $input = $this->request->getJSON(true); + + try { + $id = $input['CodingSysID'] ?? null; + + if (!$id) { + return $this->failValidationErrors('CodingSysID is required.'); + } + + $this->model->update($id, $input); + return $this->respondCreated(['status' => 'success', 'message' => 'data updated successfully', 'data' => $id], 201); + } catch (\Throwable $e) { + return $this->failServerError('Something went wrong: ' . $e->getMessage()); + } + } +} diff --git a/app/Controllers/Organization/HostAppController.php b/app/Controllers/Organization/HostAppController.php new file mode 100644 index 0000000..a3ed0f6 --- /dev/null +++ b/app/Controllers/Organization/HostAppController.php @@ -0,0 +1,101 @@ +db = \Config\Database::connect(); + $this->model = new HostAppModel(); + } + + public function index() { + $filter = [ + 'HostAppID' => $this->request->getVar('HostAppID'), + 'HostAppName' => $this->request->getVar('HostAppName'), + ]; + + $builder = $this->model->select('hostapp.*, site.SiteName') + ->join('site', 'site.SiteID = hostapp.SiteID', 'left'); + + if (!empty($filter['HostAppID'])) { + $builder->like('hostapp.HostAppID', $filter['HostAppID'], 'both'); + } + if (!empty($filter['HostAppName'])) { + $builder->like('hostapp.HostAppName', $filter['HostAppName'], 'both'); + } + + $rows = $builder->findAll(); + + if (empty($rows)) { + return $this->respond(['status' => 'success', 'message' => 'no Data.', 'data' => []], 200); + } + + return $this->respond(['status' => 'success', 'message' => 'fetch success', 'data' => $rows], 200); + } + + public function show($HostAppID = null) { + $row = $this->model->select('hostapp.*, site.SiteName') + ->join('site', 'site.SiteID = hostapp.SiteID', 'left') + ->where('hostapp.HostAppID', $HostAppID) + ->first(); + + if (empty($row)) { + return $this->respond(['status' => 'success', 'message' => 'no Data.', 'data' => null], 200); + } + + return $this->respond(['status' => 'success', 'message' => 'fetch success', 'data' => $row], 200); + } + + public function delete() { + try { + $input = $this->request->getJSON(true); + $id = $input['HostAppID'] ?? null; + + if (!$id) { + return $this->failValidationErrors('HostAppID is required.'); + } + + $this->model->delete($id); + return $this->respondDeleted(['status' => 'success', 'message' => "{$id} deleted successfully."]); + } catch (\Throwable $e) { + return $this->failServerError('Something went wrong: ' . $e->getMessage()); + } + } + + public function create() { + $input = $this->request->getJSON(true); + + try { + $id = $this->model->insert($input, true); + return $this->respondCreated(['status' => 'success', 'message' => 'data created successfully', 'data' => $id], 201); + } catch (\Throwable $e) { + return $this->failServerError('Something went wrong: ' . $e->getMessage()); + } + } + + public function update() { + $input = $this->request->getJSON(true); + + try { + $id = $input['HostAppID'] ?? null; + + if (!$id) { + return $this->failValidationErrors('HostAppID is required.'); + } + + $this->model->update($id, $input); + return $this->respondCreated(['status' => 'success', 'message' => 'data updated successfully', 'data' => $id], 201); + } catch (\Throwable $e) { + return $this->failServerError('Something went wrong: ' . $e->getMessage()); + } + } +} diff --git a/app/Controllers/Organization/HostComParaController.php b/app/Controllers/Organization/HostComParaController.php new file mode 100644 index 0000000..462d42d --- /dev/null +++ b/app/Controllers/Organization/HostComParaController.php @@ -0,0 +1,101 @@ +db = \Config\Database::connect(); + $this->model = new HostComParaModel(); + } + + public function index() { + $filter = [ + 'HostAppID' => $this->request->getVar('HostAppID'), + 'HostIP' => $this->request->getVar('HostIP'), + ]; + + $builder = $this->model->select('hostcompara.*, hostapp.HostAppName') + ->join('hostapp', 'hostapp.HostAppID = hostcompara.HostAppID', 'left'); + + if (!empty($filter['HostAppID'])) { + $builder->where('hostcompara.HostAppID', $filter['HostAppID']); + } + if (!empty($filter['HostIP'])) { + $builder->like('hostcompara.HostIP', $filter['HostIP'], 'both'); + } + + $rows = $builder->findAll(); + + if (empty($rows)) { + return $this->respond(['status' => 'success', 'message' => 'no Data.', 'data' => []], 200); + } + + return $this->respond(['status' => 'success', 'message' => 'fetch success', 'data' => $rows], 200); + } + + public function show($HostAppID = null) { + $row = $this->model->select('hostcompara.*, hostapp.HostAppName') + ->join('hostapp', 'hostapp.HostAppID = hostcompara.HostAppID', 'left') + ->where('hostcompara.HostAppID', $HostAppID) + ->first(); + + if (empty($row)) { + return $this->respond(['status' => 'success', 'message' => 'no Data.', 'data' => null], 200); + } + + return $this->respond(['status' => 'success', 'message' => 'fetch success', 'data' => $row], 200); + } + + public function delete() { + try { + $input = $this->request->getJSON(true); + $id = $input['HostAppID'] ?? null; + + if (!$id) { + return $this->failValidationErrors('HostAppID is required.'); + } + + $this->model->delete($id); + return $this->respondDeleted(['status' => 'success', 'message' => "{$id} deleted successfully."]); + } catch (\Throwable $e) { + return $this->failServerError('Something went wrong: ' . $e->getMessage()); + } + } + + public function create() { + $input = $this->request->getJSON(true); + + try { + $id = $this->model->insert($input, true); + return $this->respondCreated(['status' => 'success', 'message' => 'data created successfully', 'data' => $id], 201); + } catch (\Throwable $e) { + return $this->failServerError('Something went wrong: ' . $e->getMessage()); + } + } + + public function update() { + $input = $this->request->getJSON(true); + + try { + $id = $input['HostAppID'] ?? null; + + if (!$id) { + return $this->failValidationErrors('HostAppID is required.'); + } + + $this->model->update($id, $input); + return $this->respondCreated(['status' => 'success', 'message' => 'data updated successfully', 'data' => $id], 201); + } catch (\Throwable $e) { + return $this->failServerError('Something went wrong: ' . $e->getMessage()); + } + } +} diff --git a/app/Controllers/Test/TestMapController.php b/app/Controllers/Test/TestMapController.php index 10cfe66..18dce7c 100644 --- a/app/Controllers/Test/TestMapController.php +++ b/app/Controllers/Test/TestMapController.php @@ -20,7 +20,7 @@ class TestMapController extends BaseController { $this->model = new TestMapModel; $this->modelDetail = new TestMapDetailModel; $this->rules = [ - 'TestSiteID' => 'required|integer', + 'TestCode' => 'required', 'HostID' => 'required|integer', 'ClientID' => 'required|integer', ]; @@ -105,10 +105,10 @@ class TestMapController extends BaseController { } } - public function showByTestSite($testSiteID = null) { - if (!$testSiteID) { return $this->failValidationErrors('TestSiteID is required.'); } + public function showByTestCode($testCode = null) { + if (!$testCode) { return $this->failValidationErrors('TestCode is required.'); } - $rows = $this->model->getMappingsByTestSite($testSiteID); + $rows = $this->model->getMappingsByTestCode($testCode); if (empty($rows)) { return $this->respond([ 'status' => 'success', 'message' => "no Data.", 'data' => [] ], 200); } $rows = ValueSet::transformLabels($rows, [ @@ -116,11 +116,6 @@ class TestMapController extends BaseController { 'ClientType' => 'entity_type', ]); - // Include testmapdetail records for each mapping - foreach ($rows as &$row) { - $row['details'] = $this->modelDetail->getDetailsByTestMap($row['TestMapID']); - } - return $this->respond([ 'status' => 'success', 'message'=> "Data fetched successfully", 'data' => $rows ], 200); } diff --git a/app/Database/Migrations/2026-02-26-090320_AddTestSiteIDToTestmap.php b/app/Database/Migrations/2026-02-26-090320_AddTestSiteIDToTestmap.php deleted file mode 100644 index b0de162..0000000 --- a/app/Database/Migrations/2026-02-26-090320_AddTestSiteIDToTestmap.php +++ /dev/null @@ -1,29 +0,0 @@ -forge->addColumn('testmap', [ - 'TestSiteID' => [ - 'type' => 'INT', - 'unsigned' => true, - 'null' => true, - 'after' => 'TestMapID' - ] - ]); - - // Add foreign key if it doesn't exist - $this->forge->addForeignKey('TestSiteID', 'testdefsite', 'TestSiteID', 'CASCADE', 'CASCADE'); - } - - public function down() - { - $this->forge->dropForeignKey('testmap', 'testmap_TestSiteID_foreign'); - $this->forge->dropColumn('testmap', 'TestSiteID'); - } -} diff --git a/app/Database/Migrations/2026-02-27-001500_CreateHostAppAndCodingSys.php b/app/Database/Migrations/2026-02-27-001500_CreateHostAppAndCodingSys.php new file mode 100644 index 0000000..c52a00a --- /dev/null +++ b/app/Database/Migrations/2026-02-27-001500_CreateHostAppAndCodingSys.php @@ -0,0 +1,50 @@ +forge->addField([ + 'HostAppID' => ['type' => 'VARCHAR', 'constraint' => 5, 'null' => false], + 'HostAppName' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => false], + 'SiteID' => ['type' => 'INT', 'unsigned' => true, 'null' => true], + 'CreateDate' => ['type' => 'DATETIME', 'null' => true], + 'EndDate' => ['type' => 'DATETIME', 'null' => true] + ]); + $this->forge->addKey('HostAppID', true); + $this->forge->createTable('hostapp'); + + // Table: hostcompara + $this->forge->addField([ + 'HostAppID' => ['type' => 'VARCHAR', 'constraint' => 5, 'null' => false], + 'HostIP' => ['type' => 'VARCHAR', 'constraint' => 15, 'null' => true], + 'HostPort' => ['type' => 'VARCHAR', 'constraint' => 6, 'null' => true], + 'HostPwd' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true], + 'CreateDate' => ['type' => 'DATETIME', 'null' => true], + 'EndDate' => ['type' => 'DATETIME', 'null' => true] + ]); + $this->forge->addKey('HostAppID', true); + $this->forge->createTable('hostcompara'); + + // Table: codingsys + $this->forge->addField([ + 'CodingSysID' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true], + 'CodingSysAbb' => ['type' => 'VARCHAR', 'constraint' => 6, 'null' => false, 'unique' => true], + 'FullText' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true], + 'Description' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true], + 'CreateDate' => ['type' => 'DATETIME', 'null' => true], + 'EndDate' => ['type' => 'DATETIME', 'null' => true] + ]); + $this->forge->addKey('CodingSysID', true); + $this->forge->createTable('codingsys'); + } + + public function down() { + $this->forge->dropTable('codingsys'); + $this->forge->dropTable('hostcompara'); + $this->forge->dropTable('hostapp'); + } +} diff --git a/app/Database/Seeds/HostAppCodingSysSeeder.php b/app/Database/Seeds/HostAppCodingSysSeeder.php new file mode 100644 index 0000000..fcd3407 --- /dev/null +++ b/app/Database/Seeds/HostAppCodingSysSeeder.php @@ -0,0 +1,222 @@ +db->table('hostcompara')->emptyTable(); + $this->db->table('hostapp')->emptyTable(); + $this->db->table('codingsys')->emptyTable(); + + // HostApp - Host Applications + $hostAppData = [ + [ + 'HostAppID' => 'LIS01', + 'HostAppName' => 'Laboratory Information System Main', + 'SiteID' => 1, + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'LIS02', + 'HostAppName' => 'Laboratory Information System Backup', + 'SiteID' => 1, + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'EMR01', + 'HostAppName' => 'Electronic Medical Record System', + 'SiteID' => 1, + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'PACS01', + 'HostAppName' => 'Picture Archiving System', + 'SiteID' => 1, + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'BILL01', + 'HostAppName' => 'Billing System', + 'SiteID' => 1, + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'INS01', + 'HostAppName' => 'Insurance System Integration', + 'SiteID' => 1, + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'OLD01', + 'HostAppName' => 'Legacy Laboratory System', + 'SiteID' => 1, + 'CreateDate' => $now, + 'EndDate' => date('Y-m-d H:i:s', strtotime('-1 year')) + ], + ]; + $this->db->table('hostapp')->insertBatch($hostAppData); + + // HostComPara - Host Communication Parameters + $hostComParaData = [ + [ + 'HostAppID' => 'LIS01', + 'HostIP' => '192.168.1.10', + 'HostPort' => '8080', + 'HostPwd' => 'lis_main_pass_2024', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'LIS02', + 'HostIP' => '192.168.1.11', + 'HostPort' => '8081', + 'HostPwd' => 'lis_backup_pass_2024', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'EMR01', + 'HostIP' => '192.168.1.20', + 'HostPort' => '443', + 'HostPwd' => 'emr_secure_2024', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'PACS01', + 'HostIP' => '192.168.1.30', + 'HostPort' => '8042', + 'HostPwd' => 'pacs_dicom_2024', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'BILL01', + 'HostIP' => '192.168.1.40', + 'HostPort' => '8443', + 'HostPwd' => 'bill_payment_2024', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'INS01', + 'HostIP' => '192.168.1.50', + 'HostPort' => '443', + 'HostPwd' => 'ins_claim_2024', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'HostAppID' => 'OLD01', + 'HostIP' => '192.168.1.99', + 'HostPort' => '8080', + 'HostPwd' => 'old_legacy_pass', + 'CreateDate' => $now, + 'EndDate' => date('Y-m-d H:i:s', strtotime('-1 year')) + ], + ]; + $this->db->table('hostcompara')->insertBatch($hostComParaData); + + // CodingSys - Coding Systems + $codingSysData = [ + [ + 'CodingSysAbb' => 'ICD10', + 'FullText' => 'International Classification of Diseases 10th Revision', + 'Description' => 'Medical diagnosis coding system for diseases and health conditions', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'CodingSysAbb' => 'ICD10PCS', + 'FullText' => 'ICD-10 Procedure Coding System', + 'Description' => 'Classification system for inpatient hospital procedures', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'CodingSysAbb' => 'LOINC', + 'FullText' => 'Logical Observation Identifiers Names and Codes', + 'Description' => 'Standard for identifying medical laboratory observations', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'CodingSysAbb' => 'SNOMED', + 'FullText' => 'SNOMED CT', + 'Description' => 'Systematized Nomenclature of Medicine - Clinical Terms', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'CodingSysAbb' => 'CPT', + 'FullText' => 'Current Procedural Terminology', + 'Description' => 'Medical code set for medical procedures and services', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'CodingSysAbb' => 'HCPCS', + 'FullText' => 'Healthcare Common Procedure Coding System', + 'Description' => 'Medical code set for equipment, supplies, and services', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'CodingSysAbb' => 'RXNORM', + 'FullText' => 'RxNorm', + 'Description' => 'Normalized naming system for medications', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'CodingSysAbb' => 'NDC', + 'FullText' => 'National Drug Code', + 'Description' => 'Unique identifier for human drugs in the United States', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'CodingSysAbb' => 'UCUM', + 'FullText' => 'Unified Code for Units of Measure', + 'Description' => 'Standard for units of measurement in clinical and scientific contexts', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'CodingSysAbb' => 'CVX', + 'FullText' => 'Vaccines Administered', + 'Description' => 'Vaccine codes for immunization records', + 'CreateDate' => $now, + 'EndDate' => null + ], + [ + 'CodingSysAbb' => 'ICD9', + 'FullText' => 'International Classification of Diseases 9th Revision', + 'Description' => 'Legacy medical diagnosis coding system', + 'CreateDate' => $now, + 'EndDate' => date('Y-m-d H:i:s', strtotime('-2 years')) + ], + [ + 'CodingSysAbb' => 'ICD9CM', + 'FullText' => 'ICD-9-CM', + 'Description' => 'Legacy procedure coding system', + 'CreateDate' => $now, + 'EndDate' => date('Y-m-d H:i:s', strtotime('-2 years')) + ], + ]; + $this->db->table('codingsys')->insertBatch($codingSysData); + } +} diff --git a/app/Database/Seeds/TestSeeder.php b/app/Database/Seeds/TestSeeder.php index 1e99bb8..f446f9c 100644 --- a/app/Database/Seeds/TestSeeder.php +++ b/app/Database/Seeds/TestSeeder.php @@ -7,6 +7,25 @@ use App\Libraries\ValueSet; class TestSeeder extends Seeder { + private array $entityTypes = []; + + private function loadEntityTypes(): void + { + if (empty($this->entityTypes)) { + $json = file_get_contents(APPPATH . 'Libraries/Data/entity_type.json'); + $data = json_decode($json, true); + foreach ($data['values'] as $item) { + $this->entityTypes[$item['key']] = $item['key']; + } + } + } + + private function getEntityType(string $name): ?string + { + $this->loadEntityTypes(); + return $this->entityTypes[$name] ?? null; + } + private function getKey(string $lookupName, string $key): ?string { $data = ValueSet::getRaw($lookupName); @@ -322,9 +341,14 @@ class TestSeeder extends Seeder ], ]; + // Load entity types for mapping + $entitySite = $this->getEntityType('SITE') ?? 'SITE'; + $entityWst = $this->getEntityType('WST') ?? 'WST'; + $entityInst = $this->getEntityType('INST') ?? 'INST'; + foreach ($testMappings as $mapping) { // Site → Workstation mapping (one header per workstation) - $testMapSiteWsID = $getTestMapID('SITE', '1', 'WORKSTATION', (string)$mapping['siteToWs']['ws']); + $testMapSiteWsID = $getTestMapID($entitySite, '1', $entityWst, (string)$mapping['siteToWs']['ws']); foreach ($mapping['tests'] as $testCode) { $addDetail($testMapSiteWsID, $testCode, $testCode, $mapping['siteToWs']['con'], $testCode, $testCode); } @@ -334,7 +358,7 @@ class TestSeeder extends Seeder // Workstation → Instrument mapping (one header per instrument) if ($mapping['wsToInst'] !== null) { - $testMapWsInstID = $getTestMapID('WORKSTATION', (string)$mapping['wsToInst']['ws'], 'INSTRUMENT', (string)$mapping['wsToInst']['inst']); + $testMapWsInstID = $getTestMapID($entityWst, (string)$mapping['wsToInst']['ws'], $entityInst, (string)$mapping['wsToInst']['inst']); foreach ($mapping['tests'] as $testCode) { $addDetail($testMapWsInstID, $testCode, $testCode, $mapping['wsToInst']['con'], $testCode, $testCode); } diff --git a/app/Models/Organization/CodingSysModel.php b/app/Models/Organization/CodingSysModel.php new file mode 100644 index 0000000..5a2ed9b --- /dev/null +++ b/app/Models/Organization/CodingSysModel.php @@ -0,0 +1,17 @@ +db; + $types = $this->getEntityTypes(); + + $siteType = $types['SITE'] ?? 'SITE'; + $wsType = $types['WST'] ?? 'WST'; + $instType = $types['INST'] ?? 'INST'; $sql = " SELECT tm.TestMapID, - tm.TestSiteID, tm.HostType, tm.HostID, CASE - WHEN tm.HostType = 'SITE' THEN s.SiteName - WHEN tm.HostType = 'WORKSTATION' THEN ws.WorkstationName - WHEN tm.HostType = 'INSTRUMENT' THEN el.InstrumentName + WHEN tm.HostType = ? THEN s.SiteName + WHEN tm.HostType = ? THEN ws.WorkstationName + WHEN tm.HostType = ? THEN el.InstrumentName ELSE tm.HostID END as HostName, tm.ClientType, tm.ClientID, CASE - WHEN tm.ClientType = 'SITE' THEN cs.SiteName - WHEN tm.ClientType = 'WORKSTATION' THEN cws.WorkstationName - WHEN tm.ClientType = 'INSTRUMENT' THEN cel.InstrumentName + WHEN tm.ClientType = ? THEN cs.SiteName + WHEN tm.ClientType = ? THEN cws.WorkstationName + WHEN tm.ClientType = ? THEN cel.InstrumentName ELSE tm.ClientID END as ClientName FROM testmap tm - LEFT JOIN site s ON tm.HostType = 'SITE' AND s.SiteID = tm.HostID - LEFT JOIN workstation ws ON tm.HostType = 'WORKSTATION' AND ws.WorkstationID = tm.HostID - LEFT JOIN equipmentlist el ON tm.HostType = 'INSTRUMENT' AND el.EID = tm.HostID - LEFT JOIN site cs ON tm.ClientType = 'SITE' AND cs.SiteID = tm.ClientID - LEFT JOIN workstation cws ON tm.ClientType = 'WORKSTATION' AND cws.WorkstationID = tm.ClientID - LEFT JOIN equipmentlist cel ON tm.ClientType = 'INSTRUMENT' AND cel.EID = tm.ClientID + LEFT JOIN site s ON tm.HostType = ? AND s.SiteID = tm.HostID + LEFT JOIN workstation ws ON tm.HostType = ? AND ws.WorkstationID = tm.HostID + LEFT JOIN equipmentlist el ON tm.HostType = ? AND el.EID = tm.HostID + LEFT JOIN site cs ON tm.ClientType = ? AND cs.SiteID = tm.ClientID + LEFT JOIN workstation cws ON tm.ClientType = ? AND cws.WorkstationID = tm.ClientID + LEFT JOIN equipmentlist cel ON tm.ClientType = ? AND cel.EID = tm.ClientID WHERE tm.EndDate IS NULL "; - return $db->query($sql)->getResultArray(); + return $db->query($sql, [ + $siteType, $wsType, $instType, + $siteType, $wsType, $instType, + $siteType, $wsType, $instType, + $siteType, $wsType, $instType + ])->getResultArray(); } - /** - * Get test mappings by test site - */ - public function getMappingsByTestSite($testSiteID) { - return $this->where('TestSiteID', $testSiteID) - ->where('EndDate IS NULL') + public function getMappingsByTestCode($testCode) { + return $this->select('testmap.*') + ->join('testmapdetail', 'testmapdetail.TestMapID = testmap.TestMapID', 'inner') + ->groupStart() + ->where('testmapdetail.HostTestCode', $testCode) + ->orWhere('testmapdetail.ClientTestCode', $testCode) + ->groupEnd() + ->where('testmap.EndDate IS NULL') + ->where('testmapdetail.EndDate IS NULL') + ->groupBy('testmap.TestMapID') ->findAll(); } - /** - * Get test mappings with details by test site - */ - public function getMappingsWithDetailsByTestSite($testSiteID) { + public function getMappingsWithDetailsByTestCode($testCode) { return $this->select('testmap.*, testmapdetail.*') - ->join('testmapdetail', 'testmapdetail.TestMapID = testmap.TestMapID', 'left') - ->where('testmap.TestSiteID', $testSiteID) + ->join('testmapdetail', 'testmapdetail.TestMapID = testmap.TestMapID', 'inner') + ->groupStart() + ->where('testmapdetail.HostTestCode', $testCode) + ->orWhere('testmapdetail.ClientTestCode', $testCode) + ->groupEnd() ->where('testmap.EndDate IS NULL') ->where('testmapdetail.EndDate IS NULL') ->findAll(); diff --git a/public/api-docs.bundled.yaml b/public/api-docs.bundled.yaml index 867936f..c3d692d 100644 --- a/public/api-docs.bundled.yaml +++ b/public/api-docs.bundled.yaml @@ -1540,6 +1540,343 @@ paths: responses: '200': description: Workstation details + /api/organization/hostapp: + get: + tags: + - Organization + summary: List host applications + security: + - bearerAuth: [] + parameters: + - name: HostAppID + in: query + schema: + type: string + - name: HostAppName + in: query + schema: + type: string + responses: + '200': + description: List of host applications + content: + application/json: + schema: + type: object + properties: + status: + type: string + message: + type: string + data: + type: array + items: + $ref: '#/components/schemas/HostApp' + post: + tags: + - Organization + summary: Create host application + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/HostApp' + responses: + '201': + description: Host application created + patch: + tags: + - Organization + summary: Update host application + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - HostAppID + properties: + HostAppID: + type: string + HostAppName: + type: string + SiteID: + type: integer + responses: + '200': + description: Host application updated + delete: + tags: + - Organization + summary: Delete host application (soft delete) + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - HostAppID + properties: + HostAppID: + type: string + responses: + '200': + description: Host application deleted + /api/organization/hostapp/{id}: + get: + tags: + - Organization + summary: Get host application by ID + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + '200': + description: Host application details + content: + application/json: + schema: + $ref: '#/components/schemas/HostApp' + /api/organization/hostcompara: + get: + tags: + - Organization + summary: List host communication parameters + security: + - bearerAuth: [] + parameters: + - name: HostAppID + in: query + schema: + type: string + - name: HostIP + in: query + schema: + type: string + responses: + '200': + description: List of host communication parameters + content: + application/json: + schema: + type: object + properties: + status: + type: string + message: + type: string + data: + type: array + items: + $ref: '#/components/schemas/HostComPara' + post: + tags: + - Organization + summary: Create host communication parameters + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/HostComPara' + responses: + '201': + description: Host communication parameters created + patch: + tags: + - Organization + summary: Update host communication parameters + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - HostAppID + properties: + HostAppID: + type: string + HostIP: + type: string + HostPort: + type: string + HostPwd: + type: string + responses: + '200': + description: Host communication parameters updated + delete: + tags: + - Organization + summary: Delete host communication parameters (soft delete) + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - HostAppID + properties: + HostAppID: + type: string + responses: + '200': + description: Host communication parameters deleted + /api/organization/hostcompara/{id}: + get: + tags: + - Organization + summary: Get host communication parameters by HostAppID + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + '200': + description: Host communication parameters details + content: + application/json: + schema: + $ref: '#/components/schemas/HostComPara' + /api/organization/codingsys: + get: + tags: + - Organization + summary: List coding systems + security: + - bearerAuth: [] + parameters: + - name: CodingSysAbb + in: query + schema: + type: string + - name: FullText + in: query + schema: + type: string + responses: + '200': + description: List of coding systems + content: + application/json: + schema: + type: object + properties: + status: + type: string + message: + type: string + data: + type: array + items: + $ref: '#/components/schemas/CodingSys' + post: + tags: + - Organization + summary: Create coding system + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CodingSys' + responses: + '201': + description: Coding system created + patch: + tags: + - Organization + summary: Update coding system + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - CodingSysID + properties: + CodingSysID: + type: integer + CodingSysAbb: + type: string + FullText: + type: string + Description: + type: string + responses: + '200': + description: Coding system updated + delete: + tags: + - Organization + summary: Delete coding system (soft delete) + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - CodingSysID + properties: + CodingSysID: + type: integer + responses: + '200': + description: Coding system deleted + /api/organization/codingsys/{id}: + get: + tags: + - Organization + summary: Get coding system by ID + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: integer + responses: + '200': + description: Coding system details + content: + application/json: + schema: + $ref: '#/components/schemas/CodingSys' /api/patvisit: get: tags: @@ -2781,12 +3118,12 @@ paths: get: tags: - Tests - summary: List all test mappings (unique groupings) + summary: List all test mappings security: - bearerAuth: [] responses: '200': - description: List of unique test mapping groupings + description: List of test mappings content: application/json: schema: @@ -2802,6 +3139,8 @@ paths: items: type: object properties: + TestMapID: + type: integer HostType: type: string HostID: @@ -2827,9 +3166,9 @@ paths: schema: type: object properties: - TestSiteID: - type: integer - description: Test Site ID (required) + TestCode: + type: string + description: Test Code (required) - maps to HostTestCode or ClientTestCode HostType: type: string description: Host type code @@ -2859,7 +3198,7 @@ paths: ClientTestName: type: string required: - - TestSiteID + - TestCode responses: '201': description: Test mapping created @@ -2892,8 +3231,9 @@ paths: TestMapID: type: integer description: Test Map ID (required) - TestSiteID: - type: integer + TestCode: + type: string + description: Test Code - maps to HostTestCode or ClientTestCode HostType: type: string HostID: @@ -2986,23 +3326,23 @@ paths: $ref: '#/components/schemas/TestMap' '404': description: Test mapping not found - /api/test/testmap/by-testsite/{testSiteID}: + /api/test/testmap/by-testcode/{testCode}: get: tags: - Tests - summary: Get test mappings by test site with details + summary: Get test mappings by test code with details security: - bearerAuth: [] parameters: - - name: testSiteID + - name: testCode in: path required: true schema: - type: integer - description: Test Site ID + type: string + description: Test Code (matches HostTestCode or ClientTestCode) responses: '200': - description: List of test mappings with details for the test site + description: List of test mappings with details for the test code content: application/json: schema: @@ -4710,6 +5050,64 @@ components: type: integer DepartmentID: type: integer + HostApp: + type: object + properties: + HostAppID: + type: string + maxLength: 5 + HostAppName: + type: string + SiteID: + type: integer + SiteName: + type: string + CreateDate: + type: string + format: date-time + EndDate: + type: string + format: date-time + HostComPara: + type: object + properties: + HostAppID: + type: string + maxLength: 5 + HostAppName: + type: string + HostIP: + type: string + maxLength: 15 + HostPort: + type: string + maxLength: 6 + HostPwd: + type: string + CreateDate: + type: string + format: date-time + EndDate: + type: string + format: date-time + CodingSys: + type: object + properties: + CodingSysID: + type: integer + CodingSysAbb: + type: string + maxLength: 6 + FullText: + type: string + Description: + type: string + CreateDate: + type: string + format: date-time + EndDate: + type: string + format: date-time Specimen: type: object properties: @@ -5284,8 +5682,6 @@ components: properties: TestMapID: type: integer - TestSiteID: - type: integer HostType: type: string description: Host type code (e.g., SITE, WORKSTATION, INSTRUMENT) diff --git a/public/api-docs.yaml b/public/api-docs.yaml index 73d64bf..1ed150e 100644 --- a/public/api-docs.yaml +++ b/public/api-docs.yaml @@ -113,6 +113,12 @@ components: $ref: './components/schemas/organization.yaml#/Department' Workstation: $ref: './components/schemas/organization.yaml#/Workstation' + HostApp: + $ref: './components/schemas/organization.yaml#/HostApp' + HostComPara: + $ref: './components/schemas/organization.yaml#/HostComPara' + CodingSys: + $ref: './components/schemas/organization.yaml#/CodingSys' # Specimen schemas Specimen: diff --git a/public/components/schemas/organization.yaml b/public/components/schemas/organization.yaml index 66635fb..cd56bcb 100644 --- a/public/components/schemas/organization.yaml +++ b/public/components/schemas/organization.yaml @@ -57,3 +57,64 @@ Workstation: type: integer DepartmentID: type: integer + +HostApp: + type: object + properties: + HostAppID: + type: string + maxLength: 5 + HostAppName: + type: string + SiteID: + type: integer + SiteName: + type: string + CreateDate: + type: string + format: date-time + EndDate: + type: string + format: date-time + +HostComPara: + type: object + properties: + HostAppID: + type: string + maxLength: 5 + HostAppName: + type: string + HostIP: + type: string + maxLength: 15 + HostPort: + type: string + maxLength: 6 + HostPwd: + type: string + CreateDate: + type: string + format: date-time + EndDate: + type: string + format: date-time + +CodingSys: + type: object + properties: + CodingSysID: + type: integer + CodingSysAbb: + type: string + maxLength: 6 + FullText: + type: string + Description: + type: string + CreateDate: + type: string + format: date-time + EndDate: + type: string + format: date-time diff --git a/public/components/schemas/tests.yaml b/public/components/schemas/tests.yaml index 6f45bb6..2d5c454 100644 --- a/public/components/schemas/tests.yaml +++ b/public/components/schemas/tests.yaml @@ -426,8 +426,6 @@ TestMap: properties: TestMapID: type: integer - TestSiteID: - type: integer HostType: type: string description: Host type code (e.g., SITE, WORKSTATION, INSTRUMENT) diff --git a/public/paths/organization.yaml b/public/paths/organization.yaml index f75bb15..0093e04 100644 --- a/public/paths/organization.yaml +++ b/public/paths/organization.yaml @@ -365,3 +365,343 @@ responses: '200': description: Workstation details + +# HostApp +/api/organization/hostapp: + get: + tags: [Organization] + summary: List host applications + security: + - bearerAuth: [] + parameters: + - name: HostAppID + in: query + schema: + type: string + - name: HostAppName + in: query + schema: + type: string + responses: + '200': + description: List of host applications + content: + application/json: + schema: + type: object + properties: + status: + type: string + message: + type: string + data: + type: array + items: + $ref: '../components/schemas/organization.yaml#/HostApp' + + post: + tags: [Organization] + summary: Create host application + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/organization.yaml#/HostApp' + responses: + '201': + description: Host application created + + patch: + tags: [Organization] + summary: Update host application + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - HostAppID + properties: + HostAppID: + type: string + HostAppName: + type: string + SiteID: + type: integer + responses: + '200': + description: Host application updated + + delete: + tags: [Organization] + summary: Delete host application (soft delete) + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - HostAppID + properties: + HostAppID: + type: string + responses: + '200': + description: Host application deleted + +/api/organization/hostapp/{id}: + get: + tags: [Organization] + summary: Get host application by ID + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + '200': + description: Host application details + content: + application/json: + schema: + $ref: '../components/schemas/organization.yaml#/HostApp' + +# HostComPara +/api/organization/hostcompara: + get: + tags: [Organization] + summary: List host communication parameters + security: + - bearerAuth: [] + parameters: + - name: HostAppID + in: query + schema: + type: string + - name: HostIP + in: query + schema: + type: string + responses: + '200': + description: List of host communication parameters + content: + application/json: + schema: + type: object + properties: + status: + type: string + message: + type: string + data: + type: array + items: + $ref: '../components/schemas/organization.yaml#/HostComPara' + + post: + tags: [Organization] + summary: Create host communication parameters + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/organization.yaml#/HostComPara' + responses: + '201': + description: Host communication parameters created + + patch: + tags: [Organization] + summary: Update host communication parameters + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - HostAppID + properties: + HostAppID: + type: string + HostIP: + type: string + HostPort: + type: string + HostPwd: + type: string + responses: + '200': + description: Host communication parameters updated + + delete: + tags: [Organization] + summary: Delete host communication parameters (soft delete) + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - HostAppID + properties: + HostAppID: + type: string + responses: + '200': + description: Host communication parameters deleted + +/api/organization/hostcompara/{id}: + get: + tags: [Organization] + summary: Get host communication parameters by HostAppID + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + '200': + description: Host communication parameters details + content: + application/json: + schema: + $ref: '../components/schemas/organization.yaml#/HostComPara' + +# CodingSys +/api/organization/codingsys: + get: + tags: [Organization] + summary: List coding systems + security: + - bearerAuth: [] + parameters: + - name: CodingSysAbb + in: query + schema: + type: string + - name: FullText + in: query + schema: + type: string + responses: + '200': + description: List of coding systems + content: + application/json: + schema: + type: object + properties: + status: + type: string + message: + type: string + data: + type: array + items: + $ref: '../components/schemas/organization.yaml#/CodingSys' + + post: + tags: [Organization] + summary: Create coding system + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/organization.yaml#/CodingSys' + responses: + '201': + description: Coding system created + + patch: + tags: [Organization] + summary: Update coding system + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - CodingSysID + properties: + CodingSysID: + type: integer + CodingSysAbb: + type: string + FullText: + type: string + Description: + type: string + responses: + '200': + description: Coding system updated + + delete: + tags: [Organization] + summary: Delete coding system (soft delete) + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - CodingSysID + properties: + CodingSysID: + type: integer + responses: + '200': + description: Coding system deleted + +/api/organization/codingsys/{id}: + get: + tags: [Organization] + summary: Get coding system by ID + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: integer + responses: + '200': + description: Coding system details + content: + application/json: + schema: + $ref: '../components/schemas/organization.yaml#/CodingSys' diff --git a/public/paths/testmap.yaml b/public/paths/testmap.yaml index 632e467..684ef64 100644 --- a/public/paths/testmap.yaml +++ b/public/paths/testmap.yaml @@ -24,8 +24,6 @@ properties: TestMapID: type: integer - TestSiteID: - type: integer HostType: type: string HostID: @@ -51,9 +49,9 @@ schema: type: object properties: - TestSiteID: - type: integer - description: Test Site ID (required) + TestCode: + type: string + description: Test Code (required) - maps to HostTestCode or ClientTestCode HostType: type: string description: Host type code @@ -83,7 +81,7 @@ ClientTestName: type: string required: - - TestSiteID + - TestCode responses: '201': description: Test mapping created @@ -116,8 +114,9 @@ TestMapID: type: integer description: Test Map ID (required) - TestSiteID: - type: integer + TestCode: + type: string + description: Test Code - maps to HostTestCode or ClientTestCode HostType: type: string HostID: @@ -211,22 +210,22 @@ '404': description: Test mapping not found -/api/test/testmap/by-testsite/{testSiteID}: +/api/test/testmap/by-testcode/{testCode}: get: tags: [Tests] - summary: Get test mappings by test site with details + summary: Get test mappings by test code with details security: - bearerAuth: [] parameters: - - name: testSiteID + - name: testCode in: path required: true schema: - type: integer - description: Test Site ID + type: string + description: Test Code (matches HostTestCode or ClientTestCode) responses: '200': - description: List of test mappings with details for the test site + description: List of test mappings with details for the test code content: application/json: schema: diff --git a/tests/feature/Organization/CodingSysControllerTest.php b/tests/feature/Organization/CodingSysControllerTest.php new file mode 100644 index 0000000..7f9d4a2 --- /dev/null +++ b/tests/feature/Organization/CodingSysControllerTest.php @@ -0,0 +1,31 @@ +get($this->endpoint); + $result->assertStatus(200); + } + + public function testCreateCodingSys() + { + $payload = [ + 'CodingSysAbb' => 'ICD10', + 'FullText' => 'International Classification of Diseases 10', + 'Description' => 'Medical diagnosis coding system' + ]; + + $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); + $result->assertStatus(201); + } +} diff --git a/tests/feature/Organization/HostAppControllerTest.php b/tests/feature/Organization/HostAppControllerTest.php new file mode 100644 index 0000000..61a9820 --- /dev/null +++ b/tests/feature/Organization/HostAppControllerTest.php @@ -0,0 +1,31 @@ +get($this->endpoint); + $result->assertStatus(200); + } + + public function testCreateHostApp() + { + $payload = [ + 'HostAppID' => 'TEST1', + 'HostAppName' => 'Test Host Application', + 'SiteID' => null + ]; + + $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); + $result->assertStatus(201); + } +} diff --git a/tests/unit/TestDef/TestDefModelsTest.php b/tests/unit/TestDef/TestDefModelsTest.php index 0fd8cd9..a04b848 100644 --- a/tests/unit/TestDef/TestDefModelsTest.php +++ b/tests/unit/TestDef/TestDefModelsTest.php @@ -163,17 +163,11 @@ class TestDefModelsTest extends CIUnitTestCase public function testTestMapModelAllowedFields() { $allowedFields = $this->testMapModel->allowedFields; - - $this->assertContains('TestSiteID', $allowedFields); + $this->assertContains('HostType', $allowedFields); $this->assertContains('HostID', $allowedFields); - $this->assertContains('HostTestCode', $allowedFields); - $this->assertContains('HostTestName', $allowedFields); $this->assertContains('ClientType', $allowedFields); $this->assertContains('ClientID', $allowedFields); - $this->assertContains('ConDefID', $allowedFields); - $this->assertContains('ClientTestCode', $allowedFields); - $this->assertContains('ClientTestName', $allowedFields); } /**