diff --git a/app/Controllers/Ipd_discharge.php b/app/Controllers/Ipd_discharge.php
index 66e6e6f..89548eb 100644
--- a/app/Controllers/Ipd_discharge.php
+++ b/app/Controllers/Ipd_discharge.php
@@ -6633,30 +6633,41 @@ class Ipd_discharge extends BaseController
$snomedTerm = trim((string) ($this->request->getPost('new_diagnosis_snomed_term') ?? ''));
$diagnosisRemarkText = trim((string) ($this->request->getPost('diagnosis_remark') ?? ''));
if ($name !== '' && $this->tableHasColumns('ipd_discharge_diagnosis', ['ipd_id', 'comp_report'])) {
- $insert = [
- 'ipd_id' => $ipdId,
- 'comp_code' => $masterCode,
- 'comp_report' => $name,
- 'comp_remark' => $remark,
- 'update_by' => $userLabel,
- ];
- if ($this->db->fieldExists('snomed_concept_id', 'ipd_discharge_diagnosis')) {
- $insert['snomed_concept_id'] = $snomedConceptId;
+ // Prevent duplicate row insertion on slow networks or multiple clicks
+ $existing = $this->db->table('ipd_discharge_diagnosis')
+ ->where('ipd_id', $ipdId)
+ ->where('LOWER(TRIM(comp_report))', strtolower($name))
+ ->countAllResults();
+ if ($existing > 0) {
+ $savedAny = true;
+ $notice = 'Diagnosis is already in the list.';
+ $noticeType = 'info';
+ } else {
+ $insert = [
+ 'ipd_id' => $ipdId,
+ 'comp_code' => $masterCode,
+ 'comp_report' => $name,
+ 'comp_remark' => $remark,
+ 'update_by' => $userLabel,
+ ];
+ if ($this->db->fieldExists('snomed_concept_id', 'ipd_discharge_diagnosis')) {
+ $insert['snomed_concept_id'] = $snomedConceptId;
+ }
+ if ($this->db->fieldExists('snomed_term', 'ipd_discharge_diagnosis')) {
+ $insert['snomed_term'] = $snomedTerm;
+ }
+ if ($this->db->fieldExists('snomed_source', 'ipd_discharge_diagnosis')) {
+ $insert['snomed_source'] = $snomedConceptId !== '' ? 'disease_master' : '';
+ }
+ if ($this->db->fieldExists('order_id', 'ipd_discharge_diagnosis')) {
+ $insert['order_id'] = 0;
+ }
+ $savedAny = (bool) $this->db->table('ipd_discharge_diagnosis')->insert($insert);
+ $notice = $savedAny ? 'Diagnosis row added.' : 'Unable to add diagnosis row.';
+ $noticeType = $savedAny ? 'success' : 'warning';
}
- if ($this->db->fieldExists('snomed_term', 'ipd_discharge_diagnosis')) {
- $insert['snomed_term'] = $snomedTerm;
- }
- if ($this->db->fieldExists('snomed_source', 'ipd_discharge_diagnosis')) {
- $insert['snomed_source'] = $snomedConceptId !== '' ? 'disease_master' : '';
- }
- if ($this->db->fieldExists('order_id', 'ipd_discharge_diagnosis')) {
- $insert['order_id'] = 0;
- }
- $savedAny = (bool) $this->db->table('ipd_discharge_diagnosis')->insert($insert);
- $notice = $savedAny ? 'Diagnosis row added.' : 'Unable to add diagnosis row.';
- $noticeType = $savedAny ? 'success' : 'warning';
- if ($this->tableHasColumns('ipd_discharge_diagnosis_remark', ['ipd_id'])) {
+ if ($this->tableHasColumns('ipd_discharge_diagnosis_remark', ['ipd_id']) && $diagnosisRemarkText !== '') {
$savedAny = $this->upsertByIpd('ipd_discharge_diagnosis_remark', $ipdId, [
'comp_report' => '',
'comp_remark' => $diagnosisRemarkText,
@@ -6669,6 +6680,64 @@ class Ipd_discharge extends BaseController
: 'Diagnosis table/columns are missing in database.';
$noticeType = 'warning';
}
+ } elseif ($action === 'update_diagnosis') {
+ $diagId = (int) ($this->request->getPost('diagnosis_row_id') ?? $this->request->getPost('diagnosis_edit_id') ?? 0);
+ $name = trim((string) ($this->request->getPost('new_diagnosis_name') ?? ''));
+ $remark = trim((string) ($this->request->getPost('new_diagnosis_remark') ?? ''));
+ $masterCode = max(0, (int) ($this->request->getPost('new_diagnosis_master_code') ?? 0));
+ $snomedConceptId = trim((string) ($this->request->getPost('new_diagnosis_snomed_concept_id') ?? ''));
+ $snomedTerm = trim((string) ($this->request->getPost('new_diagnosis_snomed_term') ?? ''));
+ $diagnosisRemarkText = trim((string) ($this->request->getPost('diagnosis_remark') ?? ''));
+
+ if ($diagId > 0 && $name !== '' && $this->tableHasColumns('ipd_discharge_diagnosis', ['id', 'ipd_id', 'comp_report'])) {
+ $dupCount = $this->db->table('ipd_discharge_diagnosis')
+ ->where('ipd_id', $ipdId)
+ ->where('id !=', $diagId)
+ ->where('LOWER(TRIM(comp_report))', strtolower($name))
+ ->countAllResults();
+ if ($dupCount > 0) {
+ $savedAny = false;
+ $notice = 'Another row with this diagnosis name already exists.';
+ $noticeType = 'warning';
+ } else {
+ $update = [
+ 'comp_report' => $name,
+ 'comp_remark' => $remark,
+ 'update_by' => $userLabel,
+ ];
+ if ($masterCode > 0) {
+ $update['comp_code'] = $masterCode;
+ }
+ if ($this->db->fieldExists('snomed_concept_id', 'ipd_discharge_diagnosis')) {
+ $update['snomed_concept_id'] = $snomedConceptId;
+ }
+ if ($this->db->fieldExists('snomed_term', 'ipd_discharge_diagnosis')) {
+ $update['snomed_term'] = $snomedTerm;
+ }
+ if ($this->db->fieldExists('snomed_source', 'ipd_discharge_diagnosis')) {
+ $update['snomed_source'] = $snomedConceptId !== '' ? 'disease_master' : '';
+ }
+ $savedAny = (bool) $this->db->table('ipd_discharge_diagnosis')
+ ->where('id', $diagId)
+ ->where('ipd_id', $ipdId)
+ ->update($update);
+ $notice = $savedAny ? 'Diagnosis row updated.' : 'Unable to update diagnosis row.';
+ $noticeType = $savedAny ? 'success' : 'warning';
+ }
+
+ if ($this->tableHasColumns('ipd_discharge_diagnosis_remark', ['ipd_id']) && $diagnosisRemarkText !== '') {
+ $savedAny = $this->upsertByIpd('ipd_discharge_diagnosis_remark', $ipdId, [
+ 'comp_report' => '',
+ 'comp_remark' => $diagnosisRemarkText,
+ 'update_by' => $userLabel,
+ ]) || $savedAny;
+ }
+ } else {
+ $notice = $name === ''
+ ? 'Enter diagnosis before saving.'
+ : 'Select a valid diagnosis row to update.';
+ $noticeType = 'warning';
+ }
} elseif ($action === 'remove_diagnosis') {
$removeId = (int) ($this->request->getPost('diagnosis_remove_id') ?? 0);
$diagnosisRemarkText = trim((string) ($this->request->getPost('diagnosis_remark') ?? ''));
@@ -6693,11 +6762,21 @@ class Ipd_discharge extends BaseController
}
}
- if (($this->request->isAJAX() || $this->request->getPost('ajax_mode') === 'json') && in_array($action, ['add_complaint', 'update_complaint', 'remove_complaint', 'add_surgery', 'remove_surgery', 'add_procedure', 'remove_procedure', 'add_diagnosis', 'remove_diagnosis'], true)) {
+ if (($this->request->isAJAX() || $this->request->getPost('ajax_mode') === 'json') && in_array($action, ['add_complaint', 'update_complaint', 'remove_complaint', 'add_surgery', 'remove_surgery', 'add_procedure', 'remove_procedure', 'add_diagnosis', 'update_diagnosis', 'remove_diagnosis'], true)) {
$complaintRows = $this->getDischargeComplaintRows($ipdId);
$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);
+ $diagCols = ['id', 'comp_report', 'comp_remark'];
+ if ($this->db->fieldExists('comp_code', 'ipd_discharge_diagnosis')) {
+ $diagCols[] = 'comp_code';
+ }
+ if ($this->db->fieldExists('snomed_concept_id', 'ipd_discharge_diagnosis')) {
+ $diagCols[] = 'snomed_concept_id';
+ }
+ if ($this->db->fieldExists('snomed_term', 'ipd_discharge_diagnosis')) {
+ $diagCols[] = 'snomed_term';
+ }
+ $diagnosisRows = $this->byIpdRows('ipd_discharge_diagnosis', $diagCols, 'id ASC', $ipdId);
$courseRows = $this->byIpdRows('ipd_discharge_course', ['id', 'comp_report', 'comp_remark'], 'id ASC', $ipdId);
return $this->response->setJSON([
'update' => ($savedAny ?? false) ? 1 : 0,
@@ -7884,7 +7963,17 @@ class Ipd_discharge extends BaseController
$complaintRows = $this->byIpdRows('ipd_discharge_complaint', ['id', 'comp_report', 'comp_remark'], 'id ASC', $ipdId);
$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);
+ $diagCols = ['id', 'comp_report', 'comp_remark'];
+ if ($this->db->fieldExists('comp_code', 'ipd_discharge_diagnosis')) {
+ $diagCols[] = 'comp_code';
+ }
+ if ($this->db->fieldExists('snomed_concept_id', 'ipd_discharge_diagnosis')) {
+ $diagCols[] = 'snomed_concept_id';
+ }
+ if ($this->db->fieldExists('snomed_term', 'ipd_discharge_diagnosis')) {
+ $diagCols[] = 'snomed_term';
+ }
+ $diagnosisRows = $this->byIpdRows('ipd_discharge_diagnosis', $diagCols, 'id ASC', $ipdId);
$courseRows = $this->byIpdRows('ipd_discharge_course', ['id', 'comp_report', 'comp_remark'], 'id ASC', $ipdId);
$drugRows = $this->byIpdRows('ipd_discharge_drug', ['id', 'drug_name', 'drug_dose', 'drug_day'], 'id ASC', $ipdId);
$legacyDrugRows = $this->byIpdRows('ipd_discharge_prescrption_prescribed', ['id', 'med_name', 'med_salt', 'med_type', 'dosage', 'dosage_when', 'dosage_freq', 'no_of_days', 'qty', 'remark'], 'id ASC', $ipdId);
diff --git a/app/Views/billing/ipd/discharge_create.php b/app/Views/billing/ipd/discharge_create.php
index e5da3cc..4af6237 100644
--- a/app/Views/billing/ipd/discharge_create.php
+++ b/app/Views/billing/ipd/discharge_create.php
@@ -1145,7 +1145,7 @@ $historyFields = [
Diagnosis
Remark
- Action
+ Action
@@ -1153,27 +1153,49 @@ $historyFields = [
No diagnosis rows.
-
-
- = esc((string) ($row['comp_report'] ?? '')) ?>
- = esc((string) ($row['comp_remark'] ?? '')) ?>
- Remove
+
+
+ = esc($dReport) ?>
+
+
+
+ Edit
+ Remove
+
+
+
-
+
-
-
+ADD
+
+
+ +ADD
+ Cancel
+
Type a diagnosis name, SNOMED term, or ICD code to search master data.
@@ -4696,33 +4718,150 @@ $historyFields = [
initSurgeryMasterCrud(form);
}
+ var isDiagnosisSubmitting = false;
+
+ function resetFinalDiagnosisEditMode() {
+ $('#diagnosis_edit_id').val('0');
+ $('#new_diagnosis_name').val('');
+ $('#new_diagnosis_remark').val('');
+ $('#new_diagnosis_master_code').val('0');
+ $('#new_diagnosis_snomed_concept_id').val('');
+ $('#new_diagnosis_snomed_term').val('');
+ $('#discharge_final_diagnosis_tbody tr').removeClass('table-warning');
+ $('#btn_add_final_diagnosis_row').html('+ADD').removeClass('btn-warning fw-bold').addClass('btn-primary');
+ $('#btn_cancel_final_diagnosis_edit').hide();
+ }
+
function renderFinalDiagnosisRows(rows) {
var $tbody = $('#discharge_final_diagnosis_tbody');
if (!rows || !rows.length) {
$tbody.html('
No diagnosis rows. ');
return;
}
+ var currentEditId = parseInt($('#diagnosis_edit_id').val() || '0', 10);
var html = '';
rows.forEach(function(row) {
var id = parseInt(row.id || '0', 10);
- var name = $('
').text(row.comp_report || '').html();
- var remark = $('
').text(row.comp_remark || '').html();
- html += '
'
- + '' + name + ' '
- + '' + remark + ' '
- + 'Remove '
+ var name = (row.comp_report || '').toString();
+ var remark = (row.comp_remark || '').toString();
+ var code = parseInt(row.comp_code || '0', 10);
+ var snomedId = (row.snomed_concept_id || '').toString();
+ var snomedTerm = (row.snomed_term || '').toString();
+
+ var safeName = $('').text(name).html();
+ var safeRemark = $('
').text(remark).html();
+ var safeAttr = function(val) {
+ return String(val || '')
+ .replace(/&/g, '&')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''')
+ .replace(//g, '>');
+ };
+
+ var trClass = (currentEditId > 0 && currentEditId === id) ? ' class="table-warning"' : '';
+
+ html += '
'
+ + '' + safeName + ' '
+ + ''
+ + ''
+ + ''
+ + 'Edit '
+ + 'Remove '
+ + '
'
+ + ' '
+ ' ';
});
$tbody.html(html);
}
+ $(document).on('click', '.btn-edit-final-diagnosis-row', function() {
+ var $btn = $(this);
+ var id = parseInt($btn.data('id') || '0', 10);
+ if (id <= 0) return;
+
+ var name = String($btn.attr('data-name') || $btn.data('name') || '').trim();
+ var remark = String($btn.attr('data-remark') || $btn.data('remark') || '').trim();
+ var code = parseInt($btn.attr('data-code') || $btn.data('code') || '0', 10);
+ var snomedId = String($btn.attr('data-snomed-id') || $btn.data('snomed-id') || '').trim();
+ var snomedTerm = String($btn.attr('data-snomed-term') || $btn.data('snomed-term') || '').trim();
+
+ if (!name) {
+ var $tr = $btn.closest('tr');
+ name = $tr.find('.diag-report-text').text().trim();
+ remark = $tr.find('.diag-remark-text').text().trim();
+ }
+
+ $('#diagnosis_edit_id').val(id);
+ $('#new_diagnosis_name').val(name);
+ $('#new_diagnosis_remark').val(remark);
+ $('#new_diagnosis_master_code').val(code);
+ $('#new_diagnosis_snomed_concept_id').val(snomedId);
+ $('#new_diagnosis_snomed_term').val(snomedTerm);
+
+ $('#discharge_final_diagnosis_tbody tr').removeClass('table-warning');
+ $('#diag_row_' + id).addClass('table-warning');
+
+ $('#btn_add_final_diagnosis_row')
+ .html('
Update')
+ .removeClass('btn-primary')
+ .addClass('btn-warning fw-bold');
+ $('#btn_cancel_final_diagnosis_edit').show();
+
+ setSectionStatus('discharge_diagnosis_status', 'Editing diagnosis: update details and click Update.', 'info');
+ $('#new_diagnosis_name').trigger('focus');
+ });
+
+ $(document).on('click', '#btn_cancel_final_diagnosis_edit', function() {
+ resetFinalDiagnosisEditMode();
+ setSectionStatus('discharge_diagnosis_status', 'Edit cancelled.', 'info');
+ });
+
$(document).on('click', '#btn_add_final_diagnosis_row', function() {
+ if (isDiagnosisSubmitting) {
+ return false;
+ }
+
var form = getDischargeForm();
var name = ($('#new_diagnosis_name').val() || '').toString().trim();
if (!name) {
setSectionStatus('discharge_diagnosis_status', 'Enter diagnosis before adding.', 'error');
- return;
+ $('#new_diagnosis_name').trigger('focus');
+ return false;
}
+
+ var editId = parseInt($('#diagnosis_edit_id').val() || '0', 10);
+ var isEdit = (editId > 0);
+
+ // Client-side duplicate check to prevent duplicates on slow network
+ var normalizedName = name.toLowerCase();
+ var isDuplicate = false;
+ $('#discharge_final_diagnosis_tbody tr').each(function() {
+ var rowId = parseInt($(this).find('.btn-edit-final-diagnosis-row').data('id') || $(this).find('.btn-remove-final-diagnosis-row').data('id') || 0, 10);
+ if (isEdit && rowId === editId) {
+ return; // Skip self when updating
+ }
+ var existingName = $(this).find('.diag-report-text').text().trim().toLowerCase();
+ if (existingName && existingName === normalizedName) {
+ isDuplicate = true;
+ return false;
+ }
+ });
+
+ if (isDuplicate) {
+ var dupMsg = isEdit
+ ? 'Another row with this diagnosis name already exists.'
+ : 'Diagnosis "' + name + '" is already in the list.';
+ setSectionStatus('discharge_diagnosis_status', dupMsg, 'warning');
+ return false;
+ }
+
var remark = ($('#new_diagnosis_remark').val() || '').toString().trim();
var masterCode = parseInt($('#new_diagnosis_master_code').val() || '0', 10);
var snomedConceptId = ($('#new_diagnosis_snomed_concept_id').val() || '').toString().trim();
@@ -4731,7 +4870,9 @@ $historyFields = [
var csrf = getCsrfPair(form);
var payload = {
- action: 'add_diagnosis',
+ action: isEdit ? 'update_diagnosis' : 'add_diagnosis',
+ diagnosis_row_id: editId,
+ diagnosis_edit_id: editId,
new_diagnosis_name: name,
new_diagnosis_remark: remark,
new_diagnosis_master_code: masterCode,
@@ -4741,26 +4882,48 @@ $historyFields = [
};
payload[csrf.name] = csrf.value;
+ // Lock UI against slow network multiple submissions
+ isDiagnosisSubmitting = true;
+ var $btn = $('#btn_add_final_diagnosis_row');
+ var originalHtml = isEdit ? '
Update' : '+ADD';
+ $btn.prop('disabled', true).html('
' + (isEdit ? 'Updating...' : 'Adding...'));
+ $('#btn_cancel_final_diagnosis_edit').prop('disabled', true);
+ $('#new_diagnosis_name, #new_diagnosis_remark').prop('readonly', true);
+
$.post($(form).attr('action') || window.location.href, payload, function(data) {
updateFormCsrf(form, data);
if (data && data.diagnosisRows) {
renderFinalDiagnosisRows(data.diagnosisRows);
}
- $('#new_diagnosis_name').val('');
- $('#new_diagnosis_remark').val('');
- $('#new_diagnosis_master_code').val('0');
- $('#new_diagnosis_snomed_concept_id').val('');
- $('#new_diagnosis_snomed_term').val('');
- setSectionStatus('discharge_diagnosis_status', (data && data.notice) ? data.notice : 'Diagnosis row added.', 'success');
+ resetFinalDiagnosisEditMode();
+ var notice = (data && data.notice) ? data.notice : (isEdit ? 'Diagnosis row updated.' : 'Diagnosis row added.');
+ var noticeType = (data && data.noticeType) ? data.noticeType : (data && data.update ? 'success' : 'warning');
+ setSectionStatus('discharge_diagnosis_status', notice, noticeType);
+ $('#new_diagnosis_name').trigger('focus');
}, 'json').fail(function() {
- setSectionStatus('discharge_diagnosis_status', 'Unable to add diagnosis row.', 'error');
+ setSectionStatus('discharge_diagnosis_status', isEdit ? 'Unable to update diagnosis row.' : 'Unable to add diagnosis row.', 'error');
+ }).always(function() {
+ isDiagnosisSubmitting = false;
+ $btn.prop('disabled', false).html(originalHtml);
+ $('#btn_cancel_final_diagnosis_edit').prop('disabled', false);
+ $('#new_diagnosis_name, #new_diagnosis_remark').prop('readonly', false);
+ if ($('#diagnosis_edit_id').val() === '0') {
+ $btn.html('+ADD').removeClass('btn-warning fw-bold').addClass('btn-primary');
+ }
});
});
$(document).on('click', '.btn-remove-final-diagnosis-row', function() {
+ var $btn = $(this);
+ if ($btn.prop('disabled')) return;
var form = getDischargeForm();
- var id = parseInt($(this).data('id') || '0', 10);
+ var id = parseInt($btn.data('id') || '0', 10);
if (id <= 0) return;
+
+ if (parseInt($('#diagnosis_edit_id').val() || '0', 10) === id) {
+ resetFinalDiagnosisEditMode();
+ }
+
var diagnosisRemarkText = ($('#diagnosis_remark').val() || '').toString().trim();
var csrf = getCsrfPair(form);
var payload = {
@@ -4770,13 +4933,27 @@ $historyFields = [
};
payload[csrf.name] = csrf.value;
+ $btn.prop('disabled', true).text('Removing...');
+
$.post($(form).attr('action') || window.location.href, payload, function(data) {
updateFormCsrf(form, data);
if (data && data.diagnosisRows) {
renderFinalDiagnosisRows(data.diagnosisRows);
}
- setSectionStatus('discharge_diagnosis_status', (data && data.notice) ? data.notice : 'Diagnosis row removed.', 'success');
- }, 'json');
+ var notice = (data && data.notice) ? data.notice : 'Diagnosis row removed.';
+ var noticeType = (data && data.noticeType) ? data.noticeType : 'success';
+ setSectionStatus('discharge_diagnosis_status', notice, noticeType);
+ }, 'json').fail(function() {
+ $btn.prop('disabled', false).text('Remove');
+ setSectionStatus('discharge_diagnosis_status', 'Unable to remove diagnosis row.', 'error');
+ });
+ });
+
+ $(document).on('keydown', '#new_diagnosis_remark', function(e) {
+ if (e.key === 'Enter') {
+ e.preventDefault();
+ $('#btn_add_final_diagnosis_row').trigger('click');
+ }
});
function bindDiagnosisIcdLookup(form) {
@@ -4875,6 +5052,11 @@ $historyFields = [
if ($dd.is(':visible') && ddIdx >= 0 && ddIdx < $items.length) {
e.preventDefault();
$items.eq(ddIdx).trigger('click');
+ setTimeout(function() { $('#new_diagnosis_remark').trigger('focus'); }, 50);
+ } else {
+ e.preventDefault();
+ closeDd();
+ $('#new_diagnosis_remark').trigger('focus');
}
} else if (e.key === 'Escape') {
closeDd();