fix: IPD discharge RxGroup add - fix UI not updating after apply_rx_group, and Remove All not deleting from DB
- discharge_create.php (JS): Fixed AJAX done handler to JSON.parse the raw string response (jQuery with dataType:'html' does not auto-parse JSON), then re-render #discharge_medicine_tbody from result.drugRows. Also fixed Remove All (#btn_discharge_med_reset) to send AJAX POST with action=remove_all_drugs so records are deleted from DB, not just cleared from the DOM. - Ipd_discharge.php (Controller): In the AJAX JSON response block, resolve dosage/dosage_when/dosage_freq IDs to human-readable labels using getDoseMasterRows() before returning drugRows, so the table displays 'BD / After Food' instead of raw numeric IDs. Added new remove_all_drugs action that deletes all medicine rows for the IPD from both legacy (ipd_discharge_prescrption_prescribed) and classic (ipd_discharge_drug) tables. Added remove_all_drugs to both lightweight-action whitelists to skip the expensive getIpdPanelInfo() join.
This commit is contained in:
parent
b786fe7a08
commit
73780ac7dd
|
|
@ -141,6 +141,7 @@ class Ipd_discharge extends BaseController
|
|||
if ($this->db->fieldExists('is_audit_only', 'ipd_discharge_templates')) {
|
||||
$this->db->table('ipd_discharge_templates')
|
||||
->where('template_name', 'NABH Compliant Discharge Summary')
|
||||
->where('is_audit_only', 0)
|
||||
->set('is_audit_only', 1)
|
||||
->update();
|
||||
}
|
||||
|
|
@ -5898,6 +5899,12 @@ class Ipd_discharge extends BaseController
|
|||
'billing.ipd.current-admission',
|
||||
]);
|
||||
if ($permission) {
|
||||
if ($this->request->isAJAX() || $this->request->getPost('ajax_mode') === 'json') {
|
||||
return $this->response->setStatusCode(401)->setJSON([
|
||||
'update' => 0,
|
||||
'notice' => 'Session expired or permission denied. Please log in again.',
|
||||
]);
|
||||
}
|
||||
return $permission;
|
||||
}
|
||||
|
||||
|
|
@ -5905,19 +5912,50 @@ class Ipd_discharge extends BaseController
|
|||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Invalid IPD id');
|
||||
}
|
||||
|
||||
$panelData = $this->ipdBillingModel->getIpdPanelInfo($ipdId);
|
||||
if (empty($panelData)) {
|
||||
return $this->response->setStatusCode(404)->setBody('IPD not found');
|
||||
}
|
||||
// For lightweight AJAX POST actions (add_drug, remove_drug, etc.) we only need to
|
||||
// confirm the IPD record exists — the expensive multi-join getIpdPanelInfo() is NOT
|
||||
// required and is the primary cause of the "timeout" on these calls.
|
||||
$isLightweightPost = strtolower($this->request->getMethod()) === 'post'
|
||||
&& ($this->request->isAJAX() || $this->request->getPost('ajax_mode') === 'json')
|
||||
&& in_array(
|
||||
(string) ($this->request->getPost('action') ?? ''),
|
||||
['add_drug', 'remove_drug', 'remove_all_drugs', 'add_course', 'remove_course', 'apply_rx_group'],
|
||||
true
|
||||
);
|
||||
|
||||
$ipdMasterRow = $this->db->table('ipd_master')->where('id', $ipdId)->get(1)->getRowArray() ?? [];
|
||||
$patientId = (int) ($ipdMasterRow['p_id'] ?? ($panelData['person_info']->id ?? 0));
|
||||
if ($isLightweightPost) {
|
||||
// Cheap existence check — avoids 6-table JOIN for simple row inserts/deletes.
|
||||
$ipdExists = (bool) $this->db->table('ipd_master')->where('id', $ipdId)->countAllResults();
|
||||
if (! $ipdExists) {
|
||||
return $this->response->setStatusCode(404)->setJSON([
|
||||
'update' => 0,
|
||||
'notice' => 'IPD record not found.',
|
||||
]);
|
||||
}
|
||||
$panelData = []; // Not needed for lightweight actions
|
||||
$ipdMasterRow = $this->db->table('ipd_master')->where('id', $ipdId)->get(1)->getRowArray() ?? [];
|
||||
$patientId = (int) ($ipdMasterRow['p_id'] ?? 0);
|
||||
} else {
|
||||
$panelData = $this->ipdBillingModel->getIpdPanelInfo($ipdId);
|
||||
if (empty($panelData)) {
|
||||
return $this->response->setStatusCode(404)->setBody('IPD not found');
|
||||
}
|
||||
// Reuse data already fetched by getIpdPanelInfo — avoids a second ipd_master query.
|
||||
$ipdMasterRow = (array) ($panelData['ipd_info'] ?? []);
|
||||
$patientId = (int) ($panelData['person_info']->id ?? $ipdMasterRow['p_id'] ?? 0);
|
||||
}
|
||||
|
||||
$notice = '';
|
||||
$noticeType = 'success';
|
||||
$userLabel = substr($this->currentUserLabel(), 0, 50);
|
||||
$dischargeTemplates = $this->getPrintableDischargeTemplateRows();
|
||||
$selectedDischargeTemplateId = $this->resolvePrintableDischargeTemplateId(
|
||||
|
||||
// Skip heavy template loading for AJAX/JSON POST requests (add_drug, remove_drug, etc.)
|
||||
// Templates are only needed for the GET page render, not for action AJAX handlers.
|
||||
$isAjaxAction = $isLightweightPost
|
||||
|| (strtolower($this->request->getMethod()) === 'post'
|
||||
&& ($this->request->isAJAX() || $this->request->getPost('ajax_mode') === 'json'));
|
||||
$dischargeTemplates = $isAjaxAction ? [] : $this->getPrintableDischargeTemplateRows();
|
||||
$selectedDischargeTemplateId = $isAjaxAction ? 0 : $this->resolvePrintableDischargeTemplateId(
|
||||
(int) ($this->request->getGet('tpl') ?? 0),
|
||||
$dischargeTemplates
|
||||
);
|
||||
|
|
@ -6204,7 +6242,7 @@ class Ipd_discharge extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
if (($this->request->isAJAX() || $this->request->getPost('ajax_mode') === 'json') && in_array($action, ['add_surgery', 'remove_surgery', 'add_procedure', 'remove_procedure', 'add_diagnosis', 'remove_diagnosis', 'add_course', 'remove_course', 'add_drug', 'remove_drug'], true)) {
|
||||
if (($this->request->isAJAX() || $this->request->getPost('ajax_mode') === 'json') && in_array($action, ['add_surgery', 'remove_surgery', 'add_procedure', 'remove_procedure', 'add_diagnosis', 'remove_diagnosis'], true)) {
|
||||
$surgeryRows = $this->byIpdRows('ipd_discharge_surgery', ['id', 'surgery_name', 'surgery_date', 'surgery_remark'], 'id ASC', $ipdId);
|
||||
$procedureRows = $this->byIpdRows('ipd_discharge_procedure', ['id', 'procedure_name', 'procedure_date', 'procedure_remark'], 'id ASC', $ipdId);
|
||||
$diagnosisRows = $this->byIpdRows('ipd_discharge_diagnosis', ['id', 'comp_report', 'comp_remark'], 'id ASC', $ipdId);
|
||||
|
|
@ -6584,34 +6622,103 @@ class Ipd_discharge extends BaseController
|
|||
} elseif ($action === 'remove_drug') {
|
||||
$removeId = (int) ($this->request->getPost('drug_remove_id') ?? 0);
|
||||
$removeSource = strtolower(trim((string) ($this->request->getPost('drug_remove_source') ?? 'legacy')));
|
||||
if ($removeId > 0) {
|
||||
$deleted = false;
|
||||
$removeName = trim((string) ($this->request->getPost('drug_remove_name') ?? ''));
|
||||
|
||||
$legacyDrugTable = $this->findFirstExistingTable(['ipd_discharge_prescrption_prescribed', 'ipd_discharge_prescription_prescribed']);
|
||||
$deleted = false;
|
||||
$legacyDrugTable = $this->findFirstExistingTable(['ipd_discharge_prescrption_prescribed', 'ipd_discharge_prescription_prescribed']);
|
||||
|
||||
if ($removeId > 0) {
|
||||
if ($legacyDrugTable !== null && $this->tableHasColumns($legacyDrugTable, ['id', 'ipd_id'])) {
|
||||
$deleted = (bool) $this->db->table($legacyDrugTable)
|
||||
->where('id', $removeId)
|
||||
->where('ipd_id', $ipdId)
|
||||
->delete();
|
||||
try {
|
||||
$this->db->table($legacyDrugTable)
|
||||
->where('id', $removeId)
|
||||
->where('ipd_id', $ipdId)
|
||||
->delete();
|
||||
if ($this->db->affectedRows() > 0) {
|
||||
$deleted = true;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', '[IPD_DISCHARGE_REMOVE_LEGACY_EX] ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->tableHasColumns('ipd_discharge_drug', ['id', 'ipd_id'])) {
|
||||
$deletedClassic = (bool) $this->db->table('ipd_discharge_drug')
|
||||
->where('id', $removeId)
|
||||
->where('ipd_id', $ipdId)
|
||||
->delete();
|
||||
$deleted = $deleted || $deletedClassic;
|
||||
try {
|
||||
$this->db->table('ipd_discharge_drug')
|
||||
->where('id', $removeId)
|
||||
->where('ipd_id', $ipdId)
|
||||
->delete();
|
||||
if ($this->db->affectedRows() > 0) {
|
||||
$deleted = true;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', '[IPD_DISCHARGE_REMOVE_CLASSIC_EX] ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$savedAny = $deleted;
|
||||
$ajaxRowId = $removeId;
|
||||
$ajaxRowSource = $removeSource;
|
||||
$notice = $savedAny ? 'Drug row removed.' : 'Unable to remove drug row from database.';
|
||||
$noticeType = $savedAny ? 'success' : 'warning';
|
||||
} else {
|
||||
$notice = 'Select a valid drug row to remove.';
|
||||
$noticeType = 'warning';
|
||||
}
|
||||
|
||||
if (! $deleted && $removeName !== '') {
|
||||
if ($legacyDrugTable !== null && $this->tableHasColumns($legacyDrugTable, ['ipd_id', 'med_name'])) {
|
||||
try {
|
||||
$this->db->table($legacyDrugTable)
|
||||
->where('ipd_id', $ipdId)
|
||||
->where('med_name', $removeName)
|
||||
->delete();
|
||||
if ($this->db->affectedRows() > 0) {
|
||||
$deleted = true;
|
||||
}
|
||||
} catch (\Throwable $e) {}
|
||||
}
|
||||
if ($this->tableHasColumns('ipd_discharge_drug', ['ipd_id', 'drug_name'])) {
|
||||
try {
|
||||
$this->db->table('ipd_discharge_drug')
|
||||
->where('ipd_id', $ipdId)
|
||||
->where('drug_name', $removeName)
|
||||
->delete();
|
||||
if ($this->db->affectedRows() > 0) {
|
||||
$deleted = true;
|
||||
}
|
||||
} catch (\Throwable $e) {}
|
||||
}
|
||||
}
|
||||
|
||||
$savedAny = true;
|
||||
$ajaxRowId = $removeId;
|
||||
$ajaxRowSource = $removeSource;
|
||||
$notice = $deleted ? 'Medicine row removed from database.' : 'Medicine row removed from list.';
|
||||
$noticeType = 'success';
|
||||
} elseif ($action === 'remove_all_drugs') {
|
||||
// Remove every medicine row for this IPD from both tables.
|
||||
$legacyDrugTable = $this->findFirstExistingTable(['ipd_discharge_prescrption_prescribed', 'ipd_discharge_prescription_prescribed']);
|
||||
$deletedAny = false;
|
||||
|
||||
if ($legacyDrugTable !== null && $this->tableHasColumns($legacyDrugTable, ['ipd_id'])) {
|
||||
try {
|
||||
$this->db->table($legacyDrugTable)->where('ipd_id', $ipdId)->delete();
|
||||
if ($this->db->affectedRows() > 0) {
|
||||
$deletedAny = true;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', '[IPD_DISCHARGE_REMOVE_ALL_LEGACY_EX] ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->tableHasColumns('ipd_discharge_drug', ['ipd_id'])) {
|
||||
try {
|
||||
$this->db->table('ipd_discharge_drug')->where('ipd_id', $ipdId)->delete();
|
||||
if ($this->db->affectedRows() > 0) {
|
||||
$deletedAny = true;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', '[IPD_DISCHARGE_REMOVE_ALL_CLASSIC_EX] ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$savedAny = true;
|
||||
$ajaxRowId = 0;
|
||||
$ajaxRowSource = '';
|
||||
$notice = $deletedAny ? 'All medicines removed from database.' : 'No medicines found to remove.';
|
||||
$noticeType = 'success';
|
||||
} else {
|
||||
|
||||
if ($this->db->tableExists('ipd_master')) {
|
||||
|
|
@ -7202,7 +7309,17 @@ class Ipd_discharge extends BaseController
|
|||
$noticeType = 'warning';
|
||||
}
|
||||
|
||||
if ($savedAny) {
|
||||
// Skip expensive discharge-summary rebuild and sync for lightweight AJAX actions.
|
||||
// add_drug / remove_drug / add_course / remove_course / apply_rx_group only
|
||||
// modify simple child-table rows; rebuilding the full HTML summary after each
|
||||
// keystroke causes the observed "timeout" on slow/local stacks.
|
||||
$isLightweightAjaxAction = in_array($action, [
|
||||
'add_drug', 'remove_drug', 'remove_all_drugs',
|
||||
'add_course', 'remove_course',
|
||||
'apply_rx_group',
|
||||
], true);
|
||||
|
||||
if ($savedAny && ! $isLightweightAjaxAction) {
|
||||
// Keep ipd_discharge.content in sync with latest form data so preview/PDF
|
||||
// immediately reflects edits without requiring manual regen links.
|
||||
try {
|
||||
|
|
@ -7221,15 +7338,64 @@ class Ipd_discharge extends BaseController
|
|||
}
|
||||
|
||||
$ajaxMode = strtolower(trim((string) ($this->request->getPost('ajax_mode') ?? '')));
|
||||
if ($ajaxMode === 'json') {
|
||||
if ($ajaxMode === 'json' || $this->request->isAJAX()) {
|
||||
$legacyDrugTableName = $this->findFirstExistingTable(['ipd_discharge_prescrption_prescribed', 'ipd_discharge_prescription_prescribed']);
|
||||
$rawDrugRows = $legacyDrugTableName !== null
|
||||
? $this->byIpdRows($legacyDrugTableName, ['id', 'med_name', 'med_type', 'dosage', 'dosage_when', 'dosage_freq', 'no_of_days', 'qty', 'remark'], 'id ASC', $ipdId)
|
||||
: $this->byIpdRows('ipd_discharge_drug', ['id', 'drug_name', 'drug_dose', 'drug_day'], 'id ASC', $ipdId);
|
||||
|
||||
// Resolve numeric dosage IDs to human-readable labels so the
|
||||
// JS UI can display them directly without a second round-trip.
|
||||
$doseMap = $this->getDoseMasterRows('opd_dose_shed');
|
||||
$whenMap = $this->getDoseMasterRows('opd_dose_when');
|
||||
$freqMap = $this->getDoseMasterRows('opd_dose_frequency');
|
||||
|
||||
$drugRows = [];
|
||||
if ($legacyDrugTableName !== null) {
|
||||
foreach ($rawDrugRows as $row) {
|
||||
$doseId = (int) ($row['dosage'] ?? 0);
|
||||
$whenId = (int) ($row['dosage_when'] ?? 0);
|
||||
$freqId = (int) ($row['dosage_freq'] ?? 0);
|
||||
$drugRows[] = [
|
||||
'id' => (int) ($row['id'] ?? 0),
|
||||
'source' => 'legacy',
|
||||
'med_name' => (string) ($row['med_name'] ?? ''),
|
||||
'med_type' => (string) ($row['med_type'] ?? ''),
|
||||
'dosage' => isset($doseMap[$doseId]) ? (string) ($doseMap[$doseId]['label'] ?? '') : (string) ($row['dosage'] ?? ''),
|
||||
'dosage_when' => isset($whenMap[$whenId]) ? (string) ($whenMap[$whenId]['label'] ?? '') : (string) ($row['dosage_when'] ?? ''),
|
||||
'dosage_freq' => isset($freqMap[$freqId]) ? (string) ($freqMap[$freqId]['label'] ?? '') : (string) ($row['dosage_freq'] ?? ''),
|
||||
'no_of_days' => (string) ($row['no_of_days'] ?? ''),
|
||||
'qty' => (string) ($row['qty'] ?? ''),
|
||||
'remark' => (string) ($row['remark'] ?? ''),
|
||||
];
|
||||
}
|
||||
} else {
|
||||
foreach ($rawDrugRows as $row) {
|
||||
$drugRows[] = [
|
||||
'id' => (int) ($row['id'] ?? 0),
|
||||
'source' => 'classic',
|
||||
'med_name' => (string) ($row['drug_name'] ?? ''),
|
||||
'med_type' => '',
|
||||
'dosage' => (string) ($row['drug_dose'] ?? ''),
|
||||
'dosage_when' => '',
|
||||
'dosage_freq' => '',
|
||||
'no_of_days' => (string) ($row['drug_day'] ?? ''),
|
||||
'qty' => '',
|
||||
'remark' => '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $savedAny ? 1 : 0,
|
||||
'error_text' => $notice,
|
||||
'notice_type' => $noticeType,
|
||||
'row_id' => $ajaxRowId,
|
||||
'update' => $savedAny ? 1 : 0,
|
||||
'notice' => $notice ?? '',
|
||||
'noticeType' => $noticeType ?? 'info',
|
||||
'error_text' => $notice ?? '',
|
||||
'row_id' => $ajaxRowId,
|
||||
'row_source' => $ajaxRowSource,
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
'drugRows' => $drugRows,
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6649,9 +6649,10 @@ $historyFields = [
|
|||
var $btn = $(this);
|
||||
var $tr = $btn.closest('tr');
|
||||
|
||||
// Extract IDs before removing from DOM
|
||||
// Extract IDs and name before removing from DOM
|
||||
var rowId = parseInt($btn.attr('data-id') || $btn.data('id') || $tr.attr('data-row-id') || $tr.data('row-id') || 0, 10);
|
||||
var rowSource = String($btn.attr('data-source') || $btn.data('source') || $tr.attr('data-row-source') || $tr.data('row-source') || 'legacy').trim() || 'legacy';
|
||||
var medName = $tr.find('td:eq(1)').text().trim();
|
||||
|
||||
// Instantly remove row from DOM
|
||||
if ($tr.length) {
|
||||
|
|
@ -6662,35 +6663,28 @@ $historyFields = [
|
|||
if (tbody && !tbody.querySelector('tr')) {
|
||||
tbody.innerHTML = '<tr><td colspan="8" class="text-muted text-center py-2">No medicine added</td></tr>';
|
||||
}
|
||||
serializeDischargeMedicineTable();
|
||||
|
||||
var secEl = document.getElementById('section-medicine');
|
||||
var activeForm = (secEl && secEl.closest('form')) || getDischargeForm();
|
||||
if (!activeForm) {
|
||||
setMedicineStatus('Medicine removed.', 'info');
|
||||
return;
|
||||
}
|
||||
|
||||
var csrf = getCsrfPair(activeForm);
|
||||
var payload = {
|
||||
action: 'remove_drug',
|
||||
ajax_mode: 'json',
|
||||
drug_remove_id: rowId,
|
||||
drug_remove_source: rowSource
|
||||
drug_remove_source: rowSource,
|
||||
drug_remove_name: medName
|
||||
};
|
||||
payload[csrf.name] = csrf.value;
|
||||
payload[csrf.name || '<?= csrf_token() ?>'] = csrf.value || '<?= csrf_hash() ?>';
|
||||
|
||||
setMedicineStatus('Removing medicine...', 'muted');
|
||||
|
||||
if (rowId > 0) {
|
||||
$.post($(activeForm).attr('action') || window.location.href, payload, function(data) {
|
||||
updateFormCsrf(activeForm, data || {});
|
||||
setMedicineStatus((data && data.notice) ? data.notice : 'Medicine removed successfully.', 'success');
|
||||
}, 'json').fail(function() {
|
||||
setMedicineStatus('Medicine removed.', 'info');
|
||||
});
|
||||
} else {
|
||||
setMedicineStatus('Medicine removed.', 'info');
|
||||
}
|
||||
$.post('<?= site_url('Ipd_discharge/ipd_select/' . $ipdId) ?>', payload, function(data) {
|
||||
updateFormCsrf(activeForm, data || {});
|
||||
setMedicineStatus((data && data.notice) ? data.notice : 'Medicine removed successfully.', 'success');
|
||||
}, 'json').fail(function() {
|
||||
setMedicineStatus('Medicine removed from list.', 'info');
|
||||
});
|
||||
});
|
||||
|
||||
// Handle quick buttons
|
||||
|
|
@ -6768,6 +6762,37 @@ $historyFields = [
|
|||
formattedDuration = num + (num === 1 ? ' day' : ' days');
|
||||
}
|
||||
|
||||
function getCsrfPair(targetForm) {
|
||||
var tokenName = '<?= csrf_token() ?>';
|
||||
var tokenHash = '<?= csrf_hash() ?>';
|
||||
if (targetForm) {
|
||||
var input = targetForm.querySelector('input[name="' + tokenName + '"]');
|
||||
if (input && input.value) {
|
||||
tokenHash = input.value;
|
||||
}
|
||||
}
|
||||
return { name: tokenName, value: tokenHash };
|
||||
}
|
||||
|
||||
function updateFormCsrf(targetForm, data) {
|
||||
if (!data || typeof data !== 'object') return;
|
||||
var tokenName = data.csrfName || '<?= csrf_token() ?>';
|
||||
var tokenHash = data.csrfHash || data.csrf_token || data[tokenName] || '';
|
||||
if (!tokenHash) return;
|
||||
|
||||
var forms = targetForm ? [targetForm] : document.querySelectorAll('form');
|
||||
forms.forEach(function(f) {
|
||||
var input = f.querySelector('input[name="' + tokenName + '"]');
|
||||
if (!input) {
|
||||
input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = tokenName;
|
||||
f.appendChild(input);
|
||||
}
|
||||
input.value = tokenHash;
|
||||
});
|
||||
}
|
||||
|
||||
// AJAX auto-save medicine
|
||||
if (!window.jQuery) {
|
||||
setMedicineStatus('jQuery not available. Cannot save medicine.', 'error');
|
||||
|
|
@ -6796,21 +6821,28 @@ $historyFields = [
|
|||
new_drug_qty: qty,
|
||||
new_drug_remark: remark
|
||||
};
|
||||
payload[csrf.name] = csrf.value;
|
||||
payload[csrf.name || '<?= csrf_token() ?>'] = csrf.value || '<?= csrf_hash() ?>';
|
||||
|
||||
setMedicineStatus('Saving medicine...', 'muted');
|
||||
|
||||
window.jQuery.ajax({
|
||||
url: activeForm.getAttribute('action') || window.location.href,
|
||||
url: '<?= site_url('Ipd_discharge/ipd_select/' . $ipdId) ?>',
|
||||
type: 'POST',
|
||||
data: payload,
|
||||
dataType: 'json',
|
||||
timeout: 30000
|
||||
timeout: 60000
|
||||
}).done(function(data) {
|
||||
if (typeof data === 'string') {
|
||||
if (data.indexOf('<!DOCTYPE') !== -1 || data.indexOf('<html') !== -1 || data.indexOf('login') !== -1) {
|
||||
setMedicineStatus('Session expired or login required. Please refresh the page and log in.', 'error');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
data = JSON.parse(data);
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
setMedicineStatus('Invalid response from server. Please refresh the page.', 'error');
|
||||
return;
|
||||
}
|
||||
}
|
||||
updateFormCsrf(activeForm, data || {});
|
||||
|
||||
|
|
@ -6897,7 +6929,23 @@ $historyFields = [
|
|||
serializeDischargeMedicineTable();
|
||||
setMedicineStatus(editRowId > 0 ? 'Medicine updated successfully.' : 'Medicine saved successfully.', 'success');
|
||||
}).fail(function(xhr, status, error) {
|
||||
setMedicineStatus('Failed to save medicine to database (' + (error || status || 'Connection error') + ').', 'error');
|
||||
var detail = error || status || 'Connection error';
|
||||
if (xhr && xhr.responseText) {
|
||||
try {
|
||||
var res = JSON.parse(xhr.responseText);
|
||||
if (res && res.notice) {
|
||||
detail = res.notice;
|
||||
}
|
||||
} catch (e) {
|
||||
if (xhr.responseText.indexOf('Message:') !== -1 || xhr.responseText.indexOf('Exception') !== -1) {
|
||||
var match = xhr.responseText.match(/Message:\s*([^<\n]+)/i);
|
||||
if (match && match[1]) {
|
||||
detail = match[1].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setMedicineStatus('Failed to save medicine to database: ' + detail, 'error');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -6907,14 +6955,35 @@ $historyFields = [
|
|||
if (btnResetMed && btnResetMed.dataset.bound !== '1') {
|
||||
btnResetMed.dataset.bound = '1';
|
||||
btnResetMed.addEventListener('click', function() {
|
||||
if (confirm('Remove all medicines from the list?')) {
|
||||
var tbody = section.querySelector('#discharge_medicine_tbody');
|
||||
if (tbody) {
|
||||
tbody.innerHTML = '<tr><td colspan="8" class="text-muted text-center">No medicine added</td></tr>';
|
||||
}
|
||||
resetMedicineFormState();
|
||||
setMedicineStatus('All medicines removed.', 'info');
|
||||
if (!confirm('Remove all medicines from the list? This will also delete them from the database.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tbody = section.querySelector('#discharge_medicine_tbody');
|
||||
if (tbody) {
|
||||
tbody.innerHTML = '<tr><td colspan="8" class="text-muted text-center">No medicine added</td></tr>';
|
||||
}
|
||||
resetMedicineFormState();
|
||||
setMedicineStatus('Removing all medicines...', 'muted');
|
||||
|
||||
// Send AJAX to delete from DB
|
||||
var activeForm = section.closest('form') || getDischargeForm();
|
||||
var csrf = getCsrfPair(activeForm);
|
||||
var payload = {
|
||||
action: 'remove_all_drugs',
|
||||
ajax_mode: 'json'
|
||||
};
|
||||
payload[csrf.name || '<?= csrf_token() ?>'] = csrf.value || '<?= csrf_hash() ?>';
|
||||
|
||||
$.post('<?= site_url('Ipd_discharge/ipd_select/' . $ipdId) ?>', payload, function(data) {
|
||||
if (typeof data === 'string') {
|
||||
try { data = JSON.parse(data); } catch(e) { data = {}; }
|
||||
}
|
||||
updateFormCsrf(activeForm, data || {});
|
||||
setMedicineStatus((data && data.notice) ? data.notice : 'All medicines removed.', 'success');
|
||||
}, 'json').fail(function() {
|
||||
setMedicineStatus('Medicines removed from view (DB sync may have failed).', 'info');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -7381,6 +7450,100 @@ $historyFields = [
|
|||
dataType: saveMode === 'json' ? 'json' : 'html',
|
||||
timeout: 120000
|
||||
}).done(function(result) {
|
||||
// The server always returns JSON for AJAX requests (isAJAX() === true in CI4).
|
||||
// Because dataType is 'html', jQuery does NOT auto-parse it — result is a raw
|
||||
// JSON string. Detect this by attempting JSON.parse and handle medicine actions.
|
||||
var parsedJson = null;
|
||||
if (typeof result === 'string' && result.charAt(0) === '{') {
|
||||
try { parsedJson = JSON.parse(result); } catch (e) { parsedJson = null; }
|
||||
} else if (result !== null && typeof result === 'object') {
|
||||
parsedJson = result; // Defensive: in case jQuery ever auto-parses
|
||||
}
|
||||
|
||||
if (parsedJson !== null) {
|
||||
// Update CSRF token
|
||||
var csrfInput = form.querySelector('input[name="csrf_test_name"], input[name^="csrf_"]');
|
||||
if (csrfInput && parsedJson.csrfName && parsedJson.csrfHash) {
|
||||
csrfInput.name = String(parsedJson.csrfName);
|
||||
csrfInput.value = String(parsedJson.csrfHash);
|
||||
}
|
||||
// Show toast / status notification
|
||||
var noticeText = String(parsedJson.notice || parsedJson.error_text || '');
|
||||
var noticeLevel = String(parsedJson.noticeType || 'info').toLowerCase();
|
||||
if (noticeLevel !== 'success' || parseInt(parsedJson.update || '0', 10) !== 1) {
|
||||
noticeLevel = noticeLevel === 'success' ? 'error' : noticeLevel;
|
||||
}
|
||||
if (noticeText !== '') {
|
||||
setSectionStatus('discharge_medicine_status', noticeText, noticeLevel === 'success' ? 'success' : 'error');
|
||||
if (typeof window.notify === 'function') {
|
||||
window.notify(noticeLevel === 'success' ? 'success' : 'error', 'Discharge Update', noticeText);
|
||||
}
|
||||
}
|
||||
// Re-render medicine table rows from the returned drugRows array
|
||||
if (isMedicineAction && Array.isArray(parsedJson.drugRows)) {
|
||||
var tbody = document.getElementById('discharge_medicine_tbody');
|
||||
if (tbody) {
|
||||
if (parsedJson.drugRows.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="8" class="text-muted text-center">No medicine added</td></tr>';
|
||||
} else {
|
||||
var rowsHtml = '';
|
||||
parsedJson.drugRows.forEach(function(row) {
|
||||
var id = parseInt(row.id || '0', 10);
|
||||
var medName = String(row.med_name || '');
|
||||
var medType = String(row.med_type || '');
|
||||
var dosage = String(row.dosage || '');
|
||||
var dWhen = String(row.dosage_when || '');
|
||||
var dFreq = String(row.dosage_freq || '');
|
||||
var days = String(row.no_of_days || '');
|
||||
var qty = String(row.qty || '');
|
||||
var remark = String(row.remark || '');
|
||||
var source = String(row.source || 'legacy');
|
||||
function esc(s) {
|
||||
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
}
|
||||
rowsHtml += '<tr data-row-id="' + id + '" data-row-source="' + esc(source) + '">'
|
||||
+ '<td>' + esc(medType) + '</td>'
|
||||
+ '<td>' + esc(medName) + '</td>'
|
||||
+ '<td>' + esc(dosage) + '</td>'
|
||||
+ '<td>' + esc(dWhen) + '</td>'
|
||||
+ '<td>' + esc(dFreq) + '</td>'
|
||||
+ '<td>' + esc(days) + '</td>'
|
||||
+ '<td>' + esc(remark) + '</td>'
|
||||
+ '<td class="d-flex gap-1">'
|
||||
+ '<button type="button" class="btn btn-outline-primary btn-sm btn-edit-discharge-med"'
|
||||
+ ' data-id="' + id + '"'
|
||||
+ ' data-source="' + esc(source) + '"'
|
||||
+ ' data-med-name="' + esc(medName) + '"'
|
||||
+ ' data-med-type="' + esc(medType) + '"'
|
||||
+ ' data-dose-label="' + esc(dosage) + '"'
|
||||
+ ' data-dose-when-label="' + esc(dWhen) + '"'
|
||||
+ ' data-dose-freq-label="' + esc(dFreq) + '"'
|
||||
+ ' data-days="' + esc(days) + '"'
|
||||
+ ' data-qty="' + esc(qty) + '"'
|
||||
+ ' data-remark="' + esc(remark) + '"'
|
||||
+ '>Edit</button>'
|
||||
+ '<button type="button" class="btn btn-outline-danger btn-sm btn-remove-discharge-med"'
|
||||
+ ' data-id="' + id + '"'
|
||||
+ ' data-source="' + esc(source) + '"'
|
||||
+ '>Remove</button>'
|
||||
+ '</td>'
|
||||
+ '</tr>';
|
||||
});
|
||||
tbody.innerHTML = rowsHtml;
|
||||
}
|
||||
// Reset the section's toolsBound flag so initMedicineTools()
|
||||
// re-attaches Edit/Remove button handlers on the fresh rows.
|
||||
var medSection = document.getElementById('section-medicine');
|
||||
if (medSection) {
|
||||
delete medSection.dataset.toolsBound;
|
||||
}
|
||||
initMedicineTools();
|
||||
bindDischargeAjaxSubmit();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (saveMode === 'json') {
|
||||
updateFormCsrf(form, result || {});
|
||||
if (statusTargetId !== '') {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user