Investigation Profile Master: CRUD and consult integration

This commit is contained in:
DevSoftTech Server 2026-04-01 18:44:52 +05:30
parent d06fe77f03
commit 94e1253e40
6 changed files with 615 additions and 50 deletions

View File

@ -601,6 +601,12 @@ $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->get('Opd_prescription/opd_invest_profile_master', 'Opd_prescription::opd_invest_profile_master', ['filter' => 'permission:doctor_work.medicine.manage,doctor_work.access']);
$routes->get('Opd_prescription/opd_invest_profile_master_list', 'Opd_prescription::opd_invest_profile_master_list');
$routes->get('Opd_prescription/opd_invest_profile_master_data', 'Opd_prescription::opd_invest_profile_master_data');
$routes->get('Opd_prescription/opd_invest_profile_master_get/(:num)', 'Opd_prescription::opd_invest_profile_master_get/$1');
$routes->post('Opd_prescription/opd_invest_profile_master_save', 'Opd_prescription::opd_invest_profile_master_save');
$routes->post('Opd_prescription/opd_invest_profile_master_remove/(:num)', 'Opd_prescription::opd_invest_profile_master_remove/$1');
$routes->get('Opd_prescription/medicine_search', 'Opd_prescription::medicine_search');
$routes->get('Opd_prescription/medicine_substitutes', 'Opd_prescription::medicine_substitutes');

View File

@ -3286,6 +3286,218 @@ class Opd_prescription extends BaseController
]);
}
public function opd_invest_profile_master()
{
return view('billing/opd_invest_profile_master_workspace');
}
public function opd_invest_profile_master_list()
{
if (! $this->db->tableExists('invprofiles') || ! $this->db->tableExists('invtprofiles') || ! $this->db->tableExists('investigation')) {
return $this->response->setJSON(['rows' => []]);
}
$pFields = $this->db->getFieldNames('invprofiles');
$jFields = $this->db->getFieldNames('invtprofiles');
$iFields = $this->db->getFieldNames('investigation');
$pCode = $this->resolveFirstField($pFields, ['Code', 'code', 'id']);
$pName = $this->resolveFirstField($pFields, ['Name', 'name']);
$jProfileCode = $this->resolveFirstField($jFields, ['ProfileCode', 'profile_code']);
$jInvestCode = $this->resolveFirstField($jFields, ['InvestigationCode', 'investigation_code']);
$jPrintOrder = $this->resolveFirstField($jFields, ['printOrder', 'print_order', 'id']);
$iCode = $this->resolveFirstField($iFields, ['Code', 'code']);
$iName = $this->resolveFirstField($iFields, ['Name', 'name']);
if ($pCode === null || $pName === null || $jProfileCode === null || $jInvestCode === null || $iCode === null || $iName === null) {
return $this->response->setJSON(['rows' => []]);
}
$filter = trim((string) $this->request->getGet('filter'));
$sql = 'SELECT '
. 'p.`' . $pCode . '` AS profile_code, '
. 'p.`' . $pName . '` AS profile_name, '
. 'i.`' . $iCode . '` AS investigation_code, '
. 'i.`' . $iName . '` AS investigation_name '
. 'FROM `invprofiles` p '
. 'LEFT JOIN `invtprofiles` j ON p.`' . $pCode . '` = j.`' . $jProfileCode . '` '
. 'LEFT JOIN `investigation` i ON i.`' . $iCode . '` = j.`' . $jInvestCode . '` ';
$params = [];
if ($filter !== '') {
$sql .= 'WHERE p.`' . $pName . '` LIKE ? OR i.`' . $iName . '` LIKE ? ';
$params[] = '%' . $filter . '%';
$params[] = '%' . $filter . '%';
}
$sql .= 'ORDER BY p.`' . $pName . '` ASC';
if ($jPrintOrder !== null) {
$sql .= ', j.`' . $jPrintOrder . '` ASC';
}
$rows = $this->db->query($sql, $params)->getResultArray();
$map = [];
foreach ($rows as $row) {
$profileCode = (int) ($row['profile_code'] ?? 0);
$profileName = trim((string) ($row['profile_name'] ?? ''));
if ($profileCode <= 0 || $profileName === '') {
continue;
}
if (! isset($map[$profileCode])) {
$map[$profileCode] = [
'profile_code' => $profileCode,
'profile_name' => $profileName,
'tests' => [],
];
}
$testCode = trim((string) ($row['investigation_code'] ?? ''));
$testName = trim((string) ($row['investigation_name'] ?? ''));
if ($testCode !== '' && $testName !== '') {
$map[$profileCode]['tests'][] = [
'code' => $testCode,
'name' => $testName,
];
}
}
return $this->response->setJSON(['rows' => array_values($map)]);
}
public function opd_invest_profile_master_data()
{
$rows = $this->opd_invest_profile_master_list()->getJSON(true);
$list = $rows['rows'] ?? [];
$draw = (int) $this->request->getGet('draw');
$start = max(0, (int) $this->request->getGet('start'));
$length = (int) $this->request->getGet('length');
if ($length <= 0) {
$length = 25;
}
$paged = array_slice($list, $start, $length);
foreach ($paged as &$row) {
$row['test_count'] = count($row['tests'] ?? []);
$row['test_names'] = implode(', ', array_map(static function ($item) {
return (string) ($item['name'] ?? '');
}, $row['tests'] ?? []));
}
unset($row);
return $this->response->setJSON([
'draw' => $draw,
'recordsTotal' => count($list),
'recordsFiltered' => count($list),
'data' => $paged,
]);
}
public function opd_invest_profile_master_get(int $profileCode)
{
$response = $this->opd_invest_profile_master_list()->getJSON(true);
$rows = $response['rows'] ?? [];
foreach ($rows as $row) {
if ((int) ($row['profile_code'] ?? 0) === $profileCode) {
return $this->response->setJSON([
'update' => 1,
'row' => $row,
'csrfName' => csrf_token(),
'csrfHash' => csrf_hash(),
]);
}
}
return $this->response->setJSON(['update' => 0, 'error_text' => 'Profile not found']);
}
public function opd_invest_profile_master_save()
{
if (! $this->request->isAJAX()) {
return $this->response->setStatusCode(400)->setJSON(['update' => 0]);
}
if (! $this->db->tableExists('invprofiles') || ! $this->db->tableExists('invtprofiles') || ! $this->db->tableExists('investigation')) {
return $this->response->setJSON(['update' => 0, 'error_text' => 'Profile tables not found']);
}
$profileCode = (int) $this->request->getPost('profile_code');
$profileName = trim((string) $this->request->getPost('profile_name'));
$investigationCodes = array_values(array_filter(array_map('intval', explode(',', (string) $this->request->getPost('investigation_codes')))));
if ($profileName === '') {
return $this->response->setJSON(['update' => 0, 'error_text' => 'Profile name is required']);
}
if (empty($investigationCodes)) {
return $this->response->setJSON(['update' => 0, 'error_text' => 'Select at least one investigation']);
}
$pFields = $this->db->getFieldNames('invprofiles');
$jFields = $this->db->getFieldNames('invtprofiles');
$pCode = $this->resolveFirstField($pFields, ['Code', 'code', 'id']);
$pName = $this->resolveFirstField($pFields, ['Name', 'name']);
$jProfileCode = $this->resolveFirstField($jFields, ['ProfileCode', 'profile_code']);
$jInvestCode = $this->resolveFirstField($jFields, ['InvestigationCode', 'investigation_code']);
$jPrintOrder = $this->resolveFirstField($jFields, ['printOrder', 'print_order', 'id']);
if ($pCode === null || $pName === null || $jProfileCode === null || $jInvestCode === null) {
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid profile table structure']);
}
if ($profileCode > 0) {
$this->db->table('invprofiles')->where($pCode, $profileCode)->update([$pName => $profileName]);
$savedCode = $profileCode;
$this->db->table('invtprofiles')->where($jProfileCode, $savedCode)->delete();
} else {
$this->db->table('invprofiles')->insert([$pName => $profileName]);
$savedCode = (int) $this->db->insertID();
}
$order = 1;
foreach ($investigationCodes as $code) {
$joinRow = [
$jProfileCode => $savedCode,
$jInvestCode => $code,
];
if ($jPrintOrder !== null) {
$joinRow[$jPrintOrder] = $order;
}
$this->db->table('invtprofiles')->insert($joinRow);
$order++;
}
return $this->response->setJSON([
'update' => 1,
'insertid' => $savedCode,
'error_text' => $profileCode > 0 ? 'Profile updated' : 'Profile added',
'csrfName' => csrf_token(),
'csrfHash' => csrf_hash(),
]);
}
public function opd_invest_profile_master_remove(int $profileCode)
{
if (! $this->request->isAJAX()) {
return $this->response->setStatusCode(400)->setJSON(['update' => 0]);
}
if (! $this->db->tableExists('invprofiles') || ! $this->db->tableExists('invtprofiles')) {
return $this->response->setJSON(['update' => 0, 'error_text' => 'Profile tables not found']);
}
$pFields = $this->db->getFieldNames('invprofiles');
$jFields = $this->db->getFieldNames('invtprofiles');
$pCode = $this->resolveFirstField($pFields, ['Code', 'code', 'id']);
$jProfileCode = $this->resolveFirstField($jFields, ['ProfileCode', 'profile_code']);
if ($pCode === null || $jProfileCode === null) {
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid profile table structure']);
}
$this->db->table('invtprofiles')->where($jProfileCode, $profileCode)->delete();
$this->db->table('invprofiles')->where($pCode, $profileCode)->delete();
return $this->response->setJSON([
'update' => 1,
'error_text' => 'Profile deleted',
'csrfName' => csrf_token(),
'csrfHash' => csrf_hash(),
]);
}
// ─────────────────────────────────────────────────────────────────────────
public function opd_medicince_duplicate_report()

View File

@ -0,0 +1,68 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class CreateInvestigationProfileTables extends Migration
{
public function up()
{
if (! $this->db->tableExists('invprofiles')) {
$this->forge->addField([
'Code' => [
'type' => 'INT',
'constraint' => 11,
'unsigned' => false,
'auto_increment' => true,
],
'Name' => [
'type' => 'VARCHAR',
'constraint' => 150,
'null' => false,
],
]);
$this->forge->addKey('Code', true);
$this->forge->addUniqueKey('Name');
$this->forge->createTable('invprofiles', true);
}
if (! $this->db->tableExists('invtprofiles')) {
$this->forge->addField([
'id' => [
'type' => 'INT',
'constraint' => 11,
'auto_increment' => true,
],
'ProfileCode' => [
'type' => 'INT',
'constraint' => 11,
'null' => false,
],
'InvestigationCode' => [
'type' => 'INT',
'constraint' => 11,
'null' => false,
],
'printOrder' => [
'type' => 'INT',
'constraint' => 11,
'default' => 0,
],
]);
$this->forge->addKey('id', true);
$this->forge->addKey(['ProfileCode', 'InvestigationCode']);
$this->forge->createTable('invtprofiles', true);
}
}
public function down()
{
if ($this->db->tableExists('invtprofiles')) {
$this->forge->dropTable('invtprofiles', true);
}
if ($this->db->tableExists('invprofiles')) {
$this->forge->dropTable('invprofiles', true);
}
}
}

View File

@ -0,0 +1,299 @@
<section class="container-fluid py-3">
<div class="d-flex align-items-center gap-2 mb-3">
<h5 class="mb-0"><i class="bi bi-collection me-1"></i> Investigation Profile Master</h5>
<span class="badge bg-secondary" id="inv_profile_total_badge">—</span>
</div>
<div class="row g-3">
<div class="col-md-8">
<div class="card">
<div class="card-header d-flex flex-wrap gap-2 align-items-center">
<input type="text" id="inv_profile_filter_text" class="form-control form-control-sm" style="max-width:260px;" placeholder="Search profile / test...">
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table id="tbl_inv_profile_master" class="table table-bordered table-sm table-hover mb-0" style="width:100%;">
<thead class="table-light">
<tr>
<th>Profile</th>
<th width="80">Code</th>
<th width="80">Tests</th>
<th>Investigation Names</th>
<th width="100">Action</th>
</tr>
</thead>
<tbody><tr><td colspan="5" class="text-center text-muted py-3">Loading...</td></tr></tbody>
</table>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header"><strong id="inv_profile_form_title">New Profile</strong></div>
<div class="card-body">
<?= csrf_field() ?>
<input type="hidden" id="inv_profile_code" value="0">
<div class="mb-2">
<label class="form-label">Profile Name</label>
<input type="text" id="inv_profile_name_master" class="form-control form-control-sm" placeholder="e.g. Fever Panel, Pre-Op Panel">
</div>
<div class="mb-2">
<label class="form-label">Investigations</label>
<select id="inv_profile_tests_select" class="form-select form-select-sm" multiple="multiple" style="width:100%;"></select>
<div class="small text-muted mt-1">Search and select multiple investigations.</div>
</div>
<div class="d-flex gap-2">
<button type="button" class="btn btn-primary btn-sm" id="btn_inv_profile_save">Save</button>
<button type="button" class="btn btn-outline-secondary btn-sm" id="btn_inv_profile_reset">Reset</button>
</div>
<div class="small mt-2 text-muted" id="inv_profile_msg">Ready.</div>
</div>
</div>
</div>
</div>
</section>
<script>
(function() {
var profileTable = null;
var filterTimer = null;
function getCsrfPair() {
var input = document.querySelector('input[name="<?= csrf_token() ?>"]');
return input
? { name: input.getAttribute('name'), value: input.value }
: { name: '<?= csrf_token() ?>', value: '<?= csrf_hash() ?>' };
}
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 apiPost(url, payload, cb) {
var csrf = getCsrfPair();
payload = payload || {};
payload[csrf.name] = csrf.value;
$.post(url, payload, function(data) {
updateCsrf(data);
cb(data || {});
}, 'json');
}
function apiGet(url, cb) {
$.get(url, function(data) { cb(data || {}); }, 'json');
}
function setMsg(type, text) {
var $msg = $('#inv_profile_msg');
$msg.removeClass('text-success text-danger text-muted');
if (type === 'ok') {
$msg.addClass('text-success');
} else if (type === 'err') {
$msg.addClass('text-danger');
} else {
$msg.addClass('text-muted');
}
$msg.text(text || '');
}
function clearForm() {
$('#inv_profile_code').val('0');
$('#inv_profile_name_master').val('');
$('#inv_profile_tests_select').val(null).trigger('change');
$('#inv_profile_form_title').text('New Profile');
setMsg('normal', 'Ready.');
}
function fillForm(row) {
row = row || {};
$('#inv_profile_code').val(row.profile_code || 0);
$('#inv_profile_name_master').val(row.profile_name || '');
var values = [];
(row.tests || []).forEach(function(test) {
var code = (test.code || '').toString();
var name = (test.name || '').toString();
if (!code || !name) {
return;
}
if (!$('#inv_profile_tests_select option[value="' + code + '"]').length) {
$('#inv_profile_tests_select').append(new Option(name + ' [' + code + ']', code, true, true));
}
values.push(code);
});
$('#inv_profile_tests_select').val(values).trigger('change');
$('#inv_profile_form_title').text('Edit: ' + (row.profile_name || ''));
}
function buildPayload() {
return {
profile_code: parseInt($('#inv_profile_code').val() || '0', 10),
profile_name: ($('#inv_profile_name_master').val() || '').trim(),
investigation_codes: ($('#inv_profile_tests_select').val() || []).join(',')
};
}
function initInvestigationMultiSelect() {
var $select = $('#inv_profile_tests_select');
if (!$.fn || !$.fn.select2 || !$select.length) {
return;
}
$select.select2({
width: '100%',
placeholder: 'Search investigation...',
ajax: {
delay: 250,
transport: function(params, success, failure) {
var term = (params.data && params.data.term) ? params.data.term : '';
$.ajax({
url: '<?= base_url('Opd_prescription/investigation_search') ?>',
dataType: 'json',
data: { q: term },
success: success,
error: failure
});
},
processResults: function(data) {
var rows = (data && data.rows) ? data.rows : [];
return {
results: rows.map(function(row) {
var name = (row.name || '').toString();
var code = (row.code || '').toString();
return {
id: code,
text: name + (code ? ' [' + code + ']' : '')
};
})
};
}
}
});
}
function initTable() {
if (profileTable || !$.fn || typeof $.fn.DataTable !== 'function') {
return;
}
profileTable = $('#tbl_inv_profile_master').DataTable({
serverSide: true,
processing: true,
searching: false,
paging: true,
pageLength: 25,
lengthChange: false,
ajax: {
url: '<?= base_url('Opd_prescription/opd_invest_profile_master_data') ?>',
type: 'GET',
data: function(d) {
d.filter = ($('#inv_profile_filter_text').val() || '').trim();
}
},
columns: [
{ data: 'profile_name' },
{ data: 'profile_code' },
{ data: 'test_count', orderable: false },
{ data: 'test_names', orderable: false },
{
data: 'profile_code', orderable: false,
render: function(code) {
return '<button type="button" class="btn btn-outline-primary btn-sm btn-inv-profile-edit" data-code="' + code + '">Edit</button> '
+ '<button type="button" class="btn btn-outline-danger btn-sm btn-inv-profile-del" data-code="' + code + '">Del</button>';
}
}
],
drawCallback: function(settings) {
var json = settings.json || {};
$('#inv_profile_total_badge').text((json.recordsTotal || 0) + ' total');
}
});
}
function reloadTable() {
if (profileTable) {
profileTable.ajax.reload(null, true);
}
}
$('#btn_inv_profile_save').on('click', function() {
var payload = buildPayload();
if (!payload.profile_name) {
setMsg('err', 'Profile name is required.');
return;
}
if (!payload.investigation_codes) {
setMsg('err', 'Select at least one investigation.');
return;
}
apiPost('<?= base_url('Opd_prescription/opd_invest_profile_master_save') ?>', payload, function(data) {
if ((data.update || 0) != 1) {
setMsg('err', data.error_text || 'Unable to save profile');
return;
}
$('#inv_profile_code').val(data.insertid || 0);
setMsg('ok', data.error_text || 'Saved');
reloadTable();
});
});
$('#btn_inv_profile_reset').on('click', function() {
clearForm();
});
$('#inv_profile_filter_text').on('input', function() {
clearTimeout(filterTimer);
filterTimer = setTimeout(reloadTable, 250);
});
$(document).on('click', '.btn-inv-profile-edit', function() {
var code = parseInt($(this).data('code') || '0', 10);
if (code <= 0) {
return;
}
apiGet('<?= base_url('Opd_prescription/opd_invest_profile_master_get') ?>/' + code, function(data) {
if ((data.update || 0) != 1) {
setMsg('err', data.error_text || 'Unable to load profile');
return;
}
fillForm(data.row || {});
setMsg('normal', 'Profile loaded for edit.');
});
});
$(document).on('click', '.btn-inv-profile-del', function() {
var code = parseInt($(this).data('code') || '0', 10);
if (code <= 0) {
return;
}
if (!confirm('Delete this profile?')) {
return;
}
apiPost('<?= base_url('Opd_prescription/opd_invest_profile_master_remove') ?>/' + code, {}, function(data) {
if ((data.update || 0) != 1) {
setMsg('err', data.error_text || 'Unable to delete profile');
return;
}
setMsg('ok', data.error_text || 'Deleted');
reloadTable();
if (parseInt($('#inv_profile_code').val() || '0', 10) === code) {
clearForm();
}
});
});
$(function() {
initInvestigationMultiSelect();
initTable();
});
})();
</script>

View File

@ -711,9 +711,9 @@
<div class="d-flex flex-wrap gap-2 align-items-center" id="inv_profile_chip_wrap">
<button type="button" class="btn btn-outline-primary btn-sm inv-profile-chip" data-profile="cardiac">Cardiac Profile</button>
<button type="button" class="btn btn-outline-success btn-sm inv-profile-chip" data-profile="viral_infection">Viral Infection</button>
<button type="button" class="btn btn-outline-secondary btn-sm" id="btn_create_inv_profile">Create Profile</button>
<button type="button" class="btn btn-outline-secondary btn-sm" id="btn_create_inv_profile">Profile Master</button>
<select class="form-select form-select-sm" id="inv_custom_profile_select" style="max-width:260px;">
<option value="">Load custom profile...</option>
<option value="">Load profile...</option>
</select>
<button type="button" class="btn btn-outline-secondary btn-sm" id="btn_apply_custom_inv_profile">Apply</button>
</div>
@ -1876,37 +1876,25 @@
}
function refreshCustomProfileSelect() {
var rows = getCustomInvestigationProfiles();
var $sel = $('#inv_custom_profile_select');
if (!$sel.length) {
return;
}
$sel.html('<option value="">Load profile...</option>');
if (legacyInvestigationProfileList.length) {
$sel.append('<optgroup label="Old HMS Profiles"></optgroup>');
var $legacyGroup = $sel.find('optgroup[label="Old HMS Profiles"]');
legacyInvestigationProfileList.forEach(function(row) {
var key = (row && row.key) ? row.key : '';
var name = (row && row.name) ? row.name : '';
if (!key || !name) {
return;
}
$legacyGroup.append('<option value="legacy:' + $('<div>').text(key).html() + '">' + $('<div>').text(name).html() + '</option>');
});
}
if (rows.length) {
$sel.append('<optgroup label="Custom Profiles"></optgroup>');
var $customGroup = $sel.find('optgroup[label="Custom Profiles"]');
rows.forEach(function(row, idx) {
$customGroup.append('<option value="custom:' + idx + '">' + $('<div>').text(row.name || ('Profile ' + (idx + 1))).html() + '</option>');
});
if (!legacyInvestigationProfileList.length) {
return;
}
rows.forEach(function(row, idx) {
$sel.append('<option value="custom:' + idx + '">' + $('<div>').text(row.name || ('Profile ' + (idx + 1))).html() + '</option>');
$sel.append('<optgroup label="Master Profiles"></optgroup>');
var $group = $sel.find('optgroup[label="Master Profiles"]');
legacyInvestigationProfileList.forEach(function(row) {
var key = (row && row.key) ? row.key : '';
var name = (row && row.name) ? row.name : '';
if (!key || !name) {
return;
}
$group.append('<option value="legacy:' + $('<div>').text(key).html() + '">' + $('<div>').text(name).html() + '</option>');
});
}
@ -4052,13 +4040,11 @@
});
$('#btn_create_inv_profile').on('click', function() {
$('#inv_profile_name').val('');
$('#inv_profile_tests').val('');
if (window.bootstrap && window.bootstrap.Modal) {
window.bootstrap.Modal.getOrCreateInstance(document.getElementById('invProfileModal')).show();
} else {
$('#invProfileModal').show();
if (typeof window.load_form === 'function') {
window.load_form('<?= base_url('Opd_prescription/opd_invest_profile_master') ?>', 'Investigation Profile Master');
return;
}
window.location.href = '<?= base_url('Opd_prescription/opd_invest_profile_master') ?>';
});
$('#btn_save_inv_profile').on('click', function() {
@ -4095,25 +4081,14 @@
var legacyKey = selected.substring(7);
var legacyRows = legacyInvestigationProfiles[legacyKey] || [];
if (!legacyRows.length) {
$('.jsError').removeClass('text-success text-muted').addClass('text-danger').text('Selected old HMS profile has no tests.');
$('.jsError').removeClass('text-success text-muted').addClass('text-danger').text('Selected profile has no tests.');
return;
}
batchAddInvestigationRows(legacyRows);
return;
}
if (selected.indexOf('custom:') !== 0) {
$('.jsError').removeClass('text-success text-muted').addClass('text-danger').text('Invalid profile selection.');
return;
}
var idx = parseInt(selected.substring(7), 10);
var rows = getCustomInvestigationProfiles();
if (isNaN(idx) || idx < 0 || idx >= rows.length) {
$('.jsError').removeClass('text-success text-muted').addClass('text-danger').text('Selected custom profile is not available.');
return;
}
batchAddInvestigations(rows[idx].tests || []);
$('.jsError').removeClass('text-success text-muted').addClass('text-danger').text('Invalid profile selection.');
});
$('#advise_investigation_notes').on('input', function() {

View File

@ -238,15 +238,20 @@ if (! $canDiagnosis && $user && method_exists($user, 'inGroup')) {
<span>OPD Medicine</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('Opd_prescription/opd_invest_master') ?>','Investigation Master')">
<i class="bi bi-clipboard2-pulse"></i>
<span>Investigation Master</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('Opd_prescription/opd_invest_profile_master') ?>','Investigation Profile Master')">
<i class="bi bi-collection"></i>
<span>Investigation Profile Master</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('Opd_prescription/opd_advice') ?>','OPD Advice Master')">
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('Opd_prescription/opd_invest_master') ?>','Investigation Master')">
<i class="bi bi-clipboard2-pulse"></i>
<span>Investigation Master</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('Opd_prescription/opd_advice') ?>','OPD Advice Master')">
<i class="bi bi-chat-left-text"></i>
<span>OPD Advice Master</span>
</a>