Investigation master: add category autofill action and rules

This commit is contained in:
DevSoftTech Server 2026-07-02 19:05:33 +05:30
parent c930a54155
commit 681bb947b3
3 changed files with 114 additions and 0 deletions

View File

@ -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');

View File

@ -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'));

View File

@ -7,6 +7,9 @@ $med_specs = $med_specs ?? [];
<h5 class="mb-0"><i class="bi bi-clipboard2-pulse me-1"></i> Investigation Master</h5>
<span class="badge bg-secondary" id="inv_total_badge">—</span>
<div class="ms-auto d-flex gap-2">
<button type="button" class="btn btn-outline-primary btn-sm" id="btn_inv_autofill_category">
<i class="bi bi-magic"></i> Auto Fill Category
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" id="btn_inv_download_csv">
<i class="bi bi-download"></i> Export CSV
</button>
@ -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('<?= base_url('Opd_prescription/opd_invest_master_backfill_category') ?>', { 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;