diff --git a/app/Controllers/Ipd_discharge.php b/app/Controllers/Ipd_discharge.php
index 92eafce..fa9bf93 100644
--- a/app/Controllers/Ipd_discharge.php
+++ b/app/Controllers/Ipd_discharge.php
@@ -6109,6 +6109,112 @@ class Ipd_discharge extends BaseController
],
]);
+ $complaintJson = trim((string) ($this->request->getPost('discharge_complaints_json') ?? ''));
+ $decodedComplaints = [];
+ if ($complaintJson !== '') {
+ $decoded = json_decode($complaintJson, true);
+ if (is_array($decoded)) {
+ $decodedComplaints = $decoded;
+ }
+ }
+
+ if (empty($decodedComplaints)) {
+ $postedIds = $this->request->getPost('complaint_row_id');
+ $postedTerms = $this->request->getPost('complaint_term');
+ $postedDurations = $this->request->getPost('complaint_duration');
+ $postedFreq = $this->request->getPost('complaint_frequency');
+ $postedSeverity = $this->request->getPost('complaint_severity');
+
+ if (is_array($postedTerms)) {
+ $count = count($postedTerms);
+ for ($i = 0; $i < $count; $i++) {
+ $decodedComplaints[] = [
+ 'id' => (int) (is_array($postedIds) ? ($postedIds[$i] ?? 0) : 0),
+ 'term' => (string) ($postedTerms[$i] ?? ''),
+ 'duration' => (string) (is_array($postedDurations) ? ($postedDurations[$i] ?? '') : ''),
+ 'frequency' => (string) (is_array($postedFreq) ? ($postedFreq[$i] ?? '') : ''),
+ 'severity' => (string) (is_array($postedSeverity) ? ($postedSeverity[$i] ?? '') : ''),
+ ];
+ }
+ }
+ }
+
+ if (is_array($decodedComplaints) && $this->tableHasColumns('ipd_discharge_complaint', ['ipd_id', 'comp_report'])) {
+ {
+ $existingComplaintRows = $this->db->table('ipd_discharge_complaint')
+ ->select('id')
+ ->where('ipd_id', $ipdId)
+ ->get()
+ ->getResultArray();
+
+ $existingIdSet = [];
+ foreach ($existingComplaintRows as $row) {
+ $existingId = (int) ($row['id'] ?? 0);
+ if ($existingId > 0) {
+ $existingIdSet[$existingId] = true;
+ }
+ }
+
+ $keepIds = [];
+ $orderIndex = 1;
+
+ foreach ($decodedComplaints as $row) {
+ if (! is_array($row)) {
+ continue;
+ }
+
+ $term = trim((string) ($row['term'] ?? ''));
+ if ($term === '') {
+ continue;
+ }
+
+ $duration = trim((string) ($row['duration'] ?? ''));
+ $rowId = (int) ($row['id'] ?? 0);
+
+ $commonData = [
+ 'comp_report' => $term,
+ 'comp_remark' => $duration,
+ 'update_by' => $userLabel,
+ ];
+ if ($this->db->fieldExists('order_id', 'ipd_discharge_complaint')) {
+ $commonData['order_id'] = $orderIndex;
+ }
+
+ if ($rowId > 0 && isset($existingIdSet[$rowId])) {
+ $savedAny = (bool) $this->db->table('ipd_discharge_complaint')
+ ->where('id', $rowId)
+ ->where('ipd_id', $ipdId)
+ ->update($commonData) || $savedAny;
+ $keepIds[$rowId] = $rowId;
+ } else {
+ $insertData = $commonData;
+ $insertData['ipd_id'] = $ipdId;
+ if ($this->db->fieldExists('comp_code', 'ipd_discharge_complaint')) {
+ $insertData['comp_code'] = 0;
+ }
+
+ $inserted = (bool) $this->db->table('ipd_discharge_complaint')->insert($insertData);
+ $savedAny = $inserted || $savedAny;
+ if ($inserted) {
+ $newId = (int) ($this->db->insertID() ?? 0);
+ if ($newId > 0) {
+ $keepIds[$newId] = $newId;
+ }
+ }
+ }
+
+ $orderIndex++;
+ }
+
+ $deleteBuilder = $this->db->table('ipd_discharge_complaint')->where('ipd_id', $ipdId);
+ if (! empty($keepIds)) {
+ $deleteBuilder->whereNotIn('id', array_values($keepIds));
+ }
+
+ $savedAny = (bool) $deleteBuilder->delete() || $savedAny;
+ }
+ }
+
if ($complaintRemark !== '' || $this->tableHasColumns('ipd_discharge_complaint_remark', ['ipd_id'])) {
$savedAny = $this->upsertByIpd('ipd_discharge_complaint_remark', $ipdId, [
'comp_report' => $this->buildComplaintMetaPayload(['pain_value' => $painValue]),
diff --git a/app/Views/billing/ipd/discharge_create.php b/app/Views/billing/ipd/discharge_create.php
index 304b508..6bf9380 100644
--- a/app/Views/billing/ipd/discharge_create.php
+++ b/app/Views/billing/ipd/discharge_create.php
@@ -748,6 +748,22 @@ $historyFields = [
+ (int) ($row['id'] ?? 0),
+ 'term' => (string) ($row['comp_report'] ?? ''),
+ 'frequency' => '',
+ 'severity' => '',
+ 'duration' => (string) ($row['comp_remark'] ?? ''),
+ 'date' => '',
+ ];
+ }
+ }
+ ?>
+
@@ -1908,27 +1924,30 @@ $historyFields = [
var selectedDischargeComplaints = [];
function initDischargeComplaintsTable() {
- // Load existing complaints from PHP (if any)
-
- selectedDischargeComplaints = [
- {
- id: = (int) ($row['id'] ?? 0) ?>,
- term: = json_encode((string) ($row['comp_report'] ?? '')) ?>,
- frequency: '',
- severity: '',
- duration: = json_encode((string) ($row['comp_remark'] ?? '')) ?>,
- date: ''
- }
- = $currentIndex < $itemCount ? ',' : '' ?>
+ // Always reset from server-rendered state to avoid stale rows after section reload.
+ selectedDischargeComplaints = [];
-
- ];
-
+ // Load existing complaints from section-scoped seed JSON.
+ var seedEl = document.getElementById('discharge_complaint_seed_json');
+ if (seedEl) {
+ try {
+ var seedRows = JSON.parse(String(seedEl.value || '[]'));
+ if (Array.isArray(seedRows)) {
+ selectedDischargeComplaints = seedRows.map(function(row) {
+ return {
+ id: parseInt((row && row.id) || 0, 10) || 0,
+ term: String((row && row.term) || ''),
+ frequency: String((row && row.frequency) || ''),
+ severity: String((row && row.severity) || ''),
+ duration: String((row && row.duration) || ''),
+ date: String((row && row.date) || '')
+ };
+ });
+ }
+ } catch (err) {
+ selectedDischargeComplaints = [];
+ }
+ }
renderDischargeComplaintTable();
}
@@ -1941,6 +1960,7 @@ $historyFields = [
if (selectedDischargeComplaints.length === 0) {
tbody.innerHTML = '
| No complaints yet. Add using the input below. |
';
+ syncDischargeComplaintJsonField();
return;
}
@@ -1959,6 +1979,7 @@ $historyFields = [
td2.className = 'p-1';
var nameInput = document.createElement('input');
nameInput.type = 'text';
+ nameInput.name = 'complaint_term[]';
nameInput.className = 'form-control form-control-sm';
nameInput.value = item.term || '';
nameInput.placeholder = 'Complaint…';
@@ -1966,6 +1987,7 @@ $historyFields = [
nameInput.setAttribute('data-idx', idx);
nameInput.addEventListener('input', function() {
selectedDischargeComplaints[idx].term = this.value;
+ syncDischargeComplaintJsonField();
});
td2.appendChild(nameInput);
tr.appendChild(td2);
@@ -1975,12 +1997,14 @@ $historyFields = [
td3.className = 'p-1';
var freqInput = document.createElement('input');
freqInput.type = 'text';
+ freqInput.name = 'complaint_frequency[]';
freqInput.className = 'form-control form-control-sm';
freqInput.value = item.frequency || '';
freqInput.placeholder = 'daily…';
freqInput.style.fontSize = '.82rem';
freqInput.addEventListener('input', function() {
selectedDischargeComplaints[idx].frequency = this.value;
+ syncDischargeComplaintJsonField();
});
td3.appendChild(freqInput);
tr.appendChild(td3);
@@ -1990,12 +2014,14 @@ $historyFields = [
td4.className = 'p-1';
var sevInput = document.createElement('input');
sevInput.type = 'text';
+ sevInput.name = 'complaint_severity[]';
sevInput.className = 'form-control form-control-sm';
sevInput.value = item.severity || '';
sevInput.placeholder = 'mild…';
sevInput.style.fontSize = '.82rem';
sevInput.addEventListener('input', function() {
selectedDischargeComplaints[idx].severity = this.value;
+ syncDischargeComplaintJsonField();
});
td4.appendChild(sevInput);
tr.appendChild(td4);
@@ -2005,16 +2031,24 @@ $historyFields = [
td5.className = 'p-1';
var durInput = document.createElement('input');
durInput.type = 'text';
+ durInput.name = 'complaint_duration[]';
durInput.className = 'form-control form-control-sm';
durInput.value = item.duration || '';
durInput.placeholder = '2 days…';
durInput.style.fontSize = '.82rem';
durInput.addEventListener('input', function() {
selectedDischargeComplaints[idx].duration = this.value;
+ syncDischargeComplaintJsonField();
});
td5.appendChild(durInput);
tr.appendChild(td5);
+ var idInput = document.createElement('input');
+ idInput.type = 'hidden';
+ idInput.name = 'complaint_row_id[]';
+ idInput.value = parseInt(item.id || 0, 10) || 0;
+ tr.appendChild(idInput);
+
// Remove button
var td6 = document.createElement('td');
td6.className = 'p-1 text-center';
@@ -2024,14 +2058,112 @@ $historyFields = [
removeBtn.style.lineHeight = '1';
removeBtn.innerHTML = '×';
removeBtn.addEventListener('click', function() {
+ var rowId = parseInt((item && item.id) || 0, 10) || 0;
+ if (rowId > 0) {
+ var painValue = '';
+ var painHidden = document.getElementById('pain_value');
+ if (painHidden) {
+ painValue = String(painHidden.value || '').trim();
+ }
+
+ saveComplaintRowAjax({
+ action: 'remove_complaint',
+ complaint_remove_id: rowId,
+ complaint_remark: getComplaintEditorText(),
+ pain_value: painValue
+ }, 'Complaint removed.');
+ return;
+ }
+
selectedDischargeComplaints.splice(idx, 1);
renderDischargeComplaintTable();
+ syncDischargeComplaintJsonField();
});
td6.appendChild(removeBtn);
tr.appendChild(td6);
tbody.appendChild(tr);
});
+
+ syncDischargeComplaintJsonField();
+ }
+
+ function syncDischargeComplaintJsonField() {
+ var hidden = document.getElementById('discharge_complaints_json');
+ if (!hidden) {
+ return;
+ }
+
+ var rows = [];
+ selectedDischargeComplaints.forEach(function(item) {
+ var term = String((item && item.term) || '').trim();
+ if (term === '') {
+ return;
+ }
+
+ rows.push({
+ id: parseInt((item && item.id) || 0, 10) || 0,
+ term: term,
+ frequency: String((item && item.frequency) || '').trim(),
+ severity: String((item && item.severity) || '').trim(),
+ duration: String((item && item.duration) || '').trim(),
+ date: String((item && item.date) || '').trim()
+ });
+ });
+
+ hidden.value = JSON.stringify(rows);
+ }
+
+ function refreshComplaintSectionFromServerHtml(html, form, statusText, statusLevel) {
+ var holder = document.createElement('div');
+ holder.innerHTML = String(html || '');
+
+ if (!patchSectionFromHtml(holder, 'section-complaints')) {
+ setComplaintStatus('Unable to refresh complaint section.', 'error');
+ return;
+ }
+
+ updateCsrfFromHtml(holder, form);
+ patchNoticeFromHtml(holder);
+ notifyFromHtml(holder);
+
+ initComplaintEditor();
+ initComplaintTools();
+ bindDischargeAjaxSubmit();
+ initNabhHistorySection(document.querySelector('form[action*="Ipd_discharge/ipd_select/"]'));
+ syncNavOnScroll();
+
+ if (statusText) {
+ window.setTimeout(function() {
+ setComplaintStatus(statusText, statusLevel || 'success');
+ }, 0);
+ }
+ }
+
+ function saveComplaintRowAjax(payload, successText) {
+ var form = getDischargeForm();
+ if (!form || !window.jQuery) {
+ setComplaintStatus('Unable to reach server right now.', 'error');
+ return;
+ }
+
+ var csrf = getCsrfPair(form);
+ payload = payload || {};
+ payload[csrf.name] = csrf.value;
+
+ setComplaintStatus('Saving complaint...', 'muted');
+
+ window.jQuery.ajax({
+ url: form.getAttribute('action') || window.location.href,
+ type: 'POST',
+ data: payload,
+ dataType: 'html',
+ timeout: 30000
+ }).done(function(html) {
+ refreshComplaintSectionFromServerHtml(html, form, successText || 'Complaint saved.', 'success');
+ }).fail(function(xhr, status, error) {
+ setComplaintStatus('Save failed: ' + (error || status), 'error');
+ });
}
function initComplaintTools() {
@@ -2137,25 +2269,18 @@ $historyFields = [
return;
}
- // Add to array
- selectedDischargeComplaints.push({
- id: 0,
- term: inputVal,
- frequency: '',
- severity: '',
- duration: '',
- date: ''
- });
-
- // Refresh table
- renderDischargeComplaintTable();
-
- // Clear input
- if (lookup) {
- lookup.value = '';
+ var painValue = '';
+ if (painHidden) {
+ painValue = String(painHidden.value || '').trim();
}
- // No status message needed - table update is visual confirmation
+ saveComplaintRowAjax({
+ action: 'add_complaint',
+ new_complaint_name: inputVal,
+ new_complaint_remark: '',
+ complaint_remark: getComplaintEditorText(),
+ pain_value: painValue
+ }, 'Complaint added.');
});
}
@@ -3853,6 +3978,25 @@ $historyFields = [
}
section.dataset.toolsBound = '1';
+ function reloadMedicineSectionFromServer() {
+ if (!window.jQuery) {
+ return;
+ }
+
+ var form = getDischargeForm();
+ var url = form ? (form.getAttribute('action') || window.location.href) : window.location.href;
+ window.jQuery.get(url, function(html) {
+ var holder = document.createElement('div');
+ holder.innerHTML = String(html || '');
+ if (patchSectionFromHtml(holder, 'section-medicine')) {
+ patchNoticeFromHtml(holder);
+ initMedicineTools();
+ bindDischargeAjaxSubmit();
+ syncNavOnScroll();
+ }
+ });
+ }
+
if (!window.jQuery) {
return;
}
@@ -4655,11 +4799,29 @@ $historyFields = [
$('#discharge_med_name').focus();
setMedicineStatus(editRowId > 0 ? 'Medicine updated successfully.' : 'Medicine saved successfully.', 'success');
+
+ // Keep UI in sync with actual DB-backed rendering rules.
+ reloadMedicineSectionFromServer();
} else {
var errorMsg = (data && data.error_text) ? data.error_text : 'Unable to save medicine.';
setMedicineStatus(errorMsg, 'error');
}
}).fail(function(xhr, status, error) {
+ // Some environments may return HTML instead of JSON for this endpoint.
+ var responseHtml = xhr && typeof xhr.responseText === 'string' ? xhr.responseText : '';
+ if (responseHtml !== '' && responseHtml.indexOf('section-medicine') !== -1) {
+ var holder = document.createElement('div');
+ holder.innerHTML = responseHtml;
+ if (patchSectionFromHtml(holder, 'section-medicine')) {
+ patchNoticeFromHtml(holder);
+ initMedicineTools();
+ bindDischargeAjaxSubmit();
+ syncNavOnScroll();
+ setMedicineStatus('Medicine saved. Section refreshed from server response.', 'success');
+ return;
+ }
+ }
+
setMedicineStatus('Network error: ' + (error || status), 'error');
});
});
@@ -4718,6 +4880,8 @@ $historyFields = [
}
function syncEditorValues() {
+ syncDischargeComplaintJsonField();
+
if (!window.CKEDITOR) {
return;
}