From 681bb947b31223c012e394b4b6bad385647f423c Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Thu, 2 Jul 2026 19:05:33 +0530 Subject: [PATCH] Investigation master: add category autofill action and rules --- app/Config/Routes.php | 1 + app/Controllers/Opd_prescription.php | 90 +++++++++++++++++++ .../billing/opd_invest_master_workspace.php | 23 +++++ 3 files changed, 114 insertions(+) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index dd5d3da..543cdc7 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -837,6 +837,7 @@ $routes->get('Opd_prescription/opd_invest_master_get/(:num)', 'Opd_prescription: $routes->post('Opd_prescription/opd_invest_master_save', 'Opd_prescription::opd_invest_master_save'); $routes->post('Opd_prescription/opd_invest_master_remove/(:num)', 'Opd_prescription::opd_invest_master_remove/$1'); $routes->post('Opd_prescription/opd_invest_master_toggle_fav/(:num)', 'Opd_prescription::opd_invest_master_toggle_fav/$1'); +$routes->post('Opd_prescription/opd_invest_master_backfill_category', 'Opd_prescription::opd_invest_master_backfill_category'); $routes->get('Opd_prescription/opd_invest_shortcuts_manager', 'Opd_prescription::opd_invest_shortcuts_manager', ['filter' => 'permission:doctor_work.medicine.manage,doctor_work.access']); $routes->get('Opd_prescription/opd_invest_shortcuts_all', 'Opd_prescription::opd_invest_shortcuts_all'); $routes->post('Opd_prescription/opd_invest_shortcuts_save_item', 'Opd_prescription::opd_invest_shortcuts_save_item'); diff --git a/app/Controllers/Opd_prescription.php b/app/Controllers/Opd_prescription.php index 9416e7a..199377d 100644 --- a/app/Controllers/Opd_prescription.php +++ b/app/Controllers/Opd_prescription.php @@ -3813,6 +3813,96 @@ class Opd_prescription extends BaseController ]); } + private function inferInvestigationCategory(string $name): string + { + $value = strtolower(trim($name)); + if ($value === '') { + return 'Pathology'; + } + + if (preg_match('/\b(x\s*[-]?\s*ray|xray|radiograph|radiology)\b/i', $value) === 1) { + return 'X-Ray'; + } + if (preg_match('/\b(ultra\s*sound|ultrasound|u\.?s\.?g\.?|usg|sonography|doppler)\b/i', $value) === 1) { + return 'Ultra Sound'; + } + if (preg_match('/\b(ct\s*[-]?\s*scan|cect|hrct|ncct|computed tomography)\b/i', $value) === 1) { + return 'CT-Scan'; + } + if (preg_match('/\b(mri|mr\s*i|magnetic resonance)\b/i', $value) === 1) { + return 'MRI'; + } + if (preg_match('/\b(echo|echocardiography|2d\s*echo|doppler\s*echo)\b/i', $value) === 1) { + return 'ECHO'; + } + if (preg_match('/\b(ecg|electrocardiogram|tmt|holter)\b/i', $value) === 1) { + return 'Cardiology'; + } + + return 'Pathology'; + } + + public function opd_invest_master_backfill_category() + { + if (! $this->request->isAJAX()) { + return $this->response->setStatusCode(400)->setJSON(['update' => 0, 'error_text' => 'Invalid request']); + } + if (! $this->db->tableExists('investigation')) { + return $this->response->setJSON(['update' => 0, 'error_text' => 'Investigation table not found']); + } + + $fields = $this->db->getFieldNames('investigation'); + $keyField = $this->resolveFirstField($fields, ['id', 'Code', 'code']); + $nameField = $this->resolveFirstField($fields, ['Name', 'name']); + if ($keyField === null || $nameField === null || !in_array('category_name', $fields, true)) { + return $this->response->setJSON(['update' => 0, 'error_text' => 'Required fields not found']); + } + + $force = ((int) $this->request->getPost('force')) === 1; + + $builder = $this->db->table('investigation') + ->select($keyField . ' as id, ' . $nameField . ' as name, category_name'); + + if (! $force) { + $builder->groupStart() + ->where('category_name IS NULL', null, false) + ->orWhere("TRIM(category_name) = ''", null, false) + ->groupEnd(); + } + + $rows = $builder->get()->getResultArray(); + $updated = 0; + + foreach ($rows as $row) { + $id = (int) ($row['id'] ?? 0); + if ($id <= 0) { + continue; + } + + $name = (string) ($row['name'] ?? ''); + $category = $this->inferInvestigationCategory($name); + + $ok = $this->db->table('investigation') + ->where($keyField, $id) + ->update(['category_name' => $category]); + + if ($ok) { + $updated++; + } + } + + return $this->response->setJSON([ + 'update' => 1, + 'updated_count' => $updated, + 'total_candidates' => count($rows), + 'error_text' => $updated > 0 + ? ('Category updated for ' . $updated . ' investigation(s)') + : 'No rows needed category update', + 'csrfName' => csrf_token(), + 'csrfHash' => csrf_hash(), + ]); + } + public function opd_invest_snomed_search() { $q = trim((string) $this->request->getGet('q')); diff --git a/app/Views/billing/opd_invest_master_workspace.php b/app/Views/billing/opd_invest_master_workspace.php index 8e909b5..b21823e 100644 --- a/app/Views/billing/opd_invest_master_workspace.php +++ b/app/Views/billing/opd_invest_master_workspace.php @@ -7,6 +7,9 @@ $med_specs = $med_specs ?? [];
Investigation Master
—
+ @@ -451,6 +454,26 @@ $med_specs = $med_specs ?? []; }, 'json'); }); + $('#btn_inv_autofill_category').on('click', function() { + var msg = 'Auto-fill blank category values using test name rules?\n\n' + + 'Examples: X-Ray, Ultra Sound, CT-Scan, MRI, ECHO, Cardiology, Pathology.'; + if (!confirm(msg)) { + return; + } + + apiPost('', { force: 0 }, function(data) { + if (parseInt(data.update || 0, 10) !== 1) { + showToast(data.error_text || 'Unable to auto fill categories', 'err'); + return; + } + + var updated = parseInt(data.updated_count || '0', 10); + var total = parseInt(data.total_candidates || '0', 10); + showToast((data.error_text || 'Done') + ' (' + updated + '/' + total + ')', 'ok'); + reloadTable(); + }); + }); + /* ── SNOMED CT search autocomplete ─────────────────────────────── */ (function() { var snomedTimer = null;