From 337c18b0b266d2e19d6b5f78e157e8d8fdce4134 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Tue, 3 Nov 2026 15:18:54 +0530 Subject: [PATCH] fix(opd): print multi-line complaints with frequency, severity, duration and date in {{Complaint}} --- app/Controllers/Opd.php | 46 ++++++++++++-- app/Views/billing/opd_letter_head_pdf.php | 29 +++++++++ app/Views/billing/opd_prescription_basic.php | 67 +++++++++++++++++++- 3 files changed, 135 insertions(+), 7 deletions(-) diff --git a/app/Controllers/Opd.php b/app/Controllers/Opd.php index 9961ad5..a7669f4 100644 --- a/app/Controllers/Opd.php +++ b/app/Controllers/Opd.php @@ -3939,6 +3939,9 @@ class Opd extends BaseController foreach ($detailMap as $detailKey => $detailLabel) { $value = trim((string) ($item[$detailKey] ?? '')); if ($value !== '') { + if ($detailKey === 'date' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $value) === 1 && ($ts = strtotime($value)) !== false) { + $value = date('d-m-Y', $ts); + } $details[] = $detailLabel . ': ' . $value; } } @@ -3966,6 +3969,19 @@ class Opd extends BaseController $tokens['next_visit_raw'] = (string) ($tokens['next_visit'] ?? ''); $complaintItems = $parseClinicalJsonItems((string) ($tokens['complaint_snomed_json'] ?? '')); + if (empty($complaintItems)) { + $complaintItems = $splitClinicalText((string) ($tokens['Complaint_raw'] ?? '')); + if (! empty($complaintItems)) { + $legacySev = trim((string) ($tokens['complaint_severity'] ?? '')); + $legacyDur = trim((string) ($tokens['complaint_duration_days'] ?? '')); + if ($legacySev !== '' && empty($complaintItems[0]['severity'])) { + $complaintItems[0]['severity'] = $legacySev; + } + if ($legacyDur !== '' && empty($complaintItems[0]['duration'])) { + $complaintItems[0]['duration'] = is_numeric($legacyDur) ? ($legacyDur . ' days') : $legacyDur; + } + } + } if (empty($complaintItems)) { $complaintItems = $splitClinicalText((string) ($tokens['Complaint_raw'] ?? '')); } @@ -3999,7 +4015,19 @@ class Opd extends BaseController foreach ($diagnosisItems as $item) { $term = trim((string) ($item['term'] ?? '')); if ($term !== '') { - $diagnosisTerms[] = $term; + $dxDetails = []; + $dxDur = trim((string) ($item['duration'] ?? '')); + $dxDate = trim((string) ($item['date'] ?? '')); + if ($dxDur !== '') { + $dxDetails[] = 'Duration: ' . $dxDur; + } + if ($dxDate !== '') { + if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $dxDate) === 1 && ($ts = strtotime($dxDate)) !== false) { + $dxDate = date('d-m-Y', $ts); + } + $dxDetails[] = 'Date: ' . $dxDate; + } + $diagnosisTerms[] = $term . (! empty($dxDetails) ? ' (' . implode(' | ', $dxDetails) . ')' : ''); } } $tokens['diagnosis_list_compact'] = implode(', ', array_values(array_unique($diagnosisTerms))); @@ -4008,11 +4036,21 @@ class Opd extends BaseController $vitalCoreRaw = (string) ($tokens['vital_content_raw'] ?? ''); $tokens['vital_content'] = $vitalCoreRaw; $tokens['vital_content_block'] = $formatBlock('Vitals', $vitalCoreRaw, false); - $complaintBlockValue = trim((string) ($tokens['complaint_list_compact'] ?? '')); + $complaintBlockValue = trim((string) ($tokens['complaint_list'] ?? '')); if ($complaintBlockValue === '') { - $complaintBlockValue = trim((string) ($tokens['Complaint_raw'] ?? '')); + $rawComplaintFallback = trim(str_replace(["\r\n", "\r"], "\n", (string) ($tokens['Complaint_raw'] ?? ''))); + $complaintBlockValue = $rawComplaintFallback !== '' ? nl2br($escape($rawComplaintFallback)) : ''; } - $tokens['Complaint'] = $formatBlock('Complaint', $escape($complaintBlockValue), false); + $tokens['Complaint'] = $formatBlock('Complaint', $complaintBlockValue, true); + $tokens['complaint'] = $tokens['Complaint']; + $tokens['complaints'] = $tokens['Complaint']; + if ($complaintBlockValue === '') { + if ($complaintBlockValue === '') { + $rawComplaintFallback = trim(str_replace(["\r\n", "\r"], "\n", (string) ($tokens['Complaint_raw'] ?? ''))); + $complaintBlockValue = $rawComplaintFallback !== '' ? nl2br($escape($rawComplaintFallback)) : ''; + } + } + // Keep multi-line complaint list with Frequency, Severity, Duration, Date intact. $tokens['complaint'] = $tokens['Complaint']; $diagnosisBlockValue = trim((string) ($tokens['diagnosis_list_compact'] ?? '')); if ($diagnosisBlockValue === '') { diff --git a/app/Views/billing/opd_letter_head_pdf.php b/app/Views/billing/opd_letter_head_pdf.php index 20940d6..b08047e 100644 --- a/app/Views/billing/opd_letter_head_pdf.php +++ b/app/Views/billing/opd_letter_head_pdf.php @@ -285,7 +285,36 @@ $toLocalText = static function (string $input): string { + +
+ Complaint : + +
+
Complaint :
+ diff --git a/app/Views/billing/opd_prescription_basic.php b/app/Views/billing/opd_prescription_basic.php index 9c05909..b4c2a67 100644 --- a/app/Views/billing/opd_prescription_basic.php +++ b/app/Views/billing/opd_prescription_basic.php @@ -4023,6 +4023,9 @@ } function getPayload() { + if (typeof syncComplaintSnomedJson === 'function') { + syncComplaintSnomedJson(); + } var normalizedVitals = normalizeVitalsInputs(true); var morbidities = []; var morbiditiesText = []; @@ -4398,6 +4401,9 @@ }); function openLegacyPrescriptionPrint(printType) { + if (typeof syncComplaintSnomedJson === 'function') { + syncComplaintSnomedJson(); + } var openPrint = function() { var opdId = $('#opd_id').val() || '0'; var sessionId = $('#opd_session_id').val() || '0'; @@ -5266,6 +5272,22 @@ } function syncComplaintSnomedJson() { + $('#complaint_tbody tr[data-idx]').each(function() { + var $tr = $(this); + var idx = parseInt($tr.attr('data-idx'), 10); + if (!isNaN(idx) && idx >= 0 && idx < selectedComplaintItems.length) { + var $nameInp = $tr.find('.complaint-name-input'); + var $freqInp = $tr.find('.complaint-freq-input'); + var $sevInp = $tr.find('.complaint-sev-input'); + var $durInp = $tr.find('.complaint-dur-input'); + var $dateInp = $tr.find('.complaint-date-input'); + if ($nameInp.length) selectedComplaintItems[idx].term = ($nameInp.val() || '').toString().trim(); + if ($freqInp.length) selectedComplaintItems[idx].frequency = ($freqInp.val() || '').toString().trim(); + if ($sevInp.length) selectedComplaintItems[idx].severity = ($sevInp.val() || '').toString().trim(); + if ($durInp.length) selectedComplaintItems[idx].duration = ($durInp.val() || '').toString().trim(); + if ($dateInp.length) selectedComplaintItems[idx].date = ($dateInp.val() || '').toString().trim(); + } + }); var json = JSON.stringify(selectedComplaintItems.map(function(item) { return { term: item.term, @@ -5579,7 +5601,16 @@ var _freqDdIdx = -1; - $(document).on('input focus', '.complaint-freq-input', function() { + $(document).on('input focus', '.complaint-freq-input', function(e) { + if (e && e.type === 'input') { + var idxInp = parseInt($(this).attr('data-idx'), 10); + if (!isNaN(idxInp) && idxInp >= 0 && idxInp < selectedComplaintItems.length) { + selectedComplaintItems[idxInp].frequency = ($(this).val() || '').trim(); + syncComplaintSnomedJson(); + markDirty('Complaint detail updated'); + scheduleAutoSave(); + } + } _freqDdIdx = -1; var $inp = $(this); var q = ($inp.val() || '').trim().toLowerCase(); @@ -5594,6 +5625,9 @@ if (idx >= 0 && idx < selectedComplaintItems.length) { selectedComplaintItems[idx].frequency = val; syncComplaintSnomedJson(); + markDirty('Complaint detail updated'); + scheduleAutoSave(); + syncComplaintSnomedJson(); } $('#_freq_dd').remove(); _freqDdIdx = -1; @@ -5630,6 +5664,9 @@ if (idx >= 0 && idx < selectedComplaintItems.length) { selectedComplaintItems[idx].frequency = ($(this).val() || '').trim(); syncComplaintSnomedJson(); + markDirty('Complaint detail updated'); + scheduleAutoSave(); + syncComplaintSnomedJson(); } setTimeout(function() { $('#_freq_dd').remove(); }, 150); }); @@ -5653,7 +5690,16 @@ }); // ─── Duration: event delegation on table rows ──────────────────────────── - $(document).on('input focus', '.complaint-dur-input', function() { + $(document).on('input focus', '.complaint-dur-input', function(e) { + if (e && e.type === 'input') { + var idxInp = parseInt($(this).attr('data-idx'), 10); + if (!isNaN(idxInp) && idxInp >= 0 && idxInp < selectedComplaintItems.length) { + selectedComplaintItems[idxInp].duration = ($(this).val() || '').trim(); + syncComplaintSnomedJson(); + markDirty('Complaint detail updated'); + scheduleAutoSave(); + } + } _durDdIdx = -1; var $inp = $(this); var sugs = getDurationSuggestions($inp.val()); @@ -5666,6 +5712,9 @@ if (idx >= 0 && idx < selectedComplaintItems.length) { selectedComplaintItems[idx].duration = val; syncComplaintSnomedJson(); + markDirty('Complaint detail updated'); + scheduleAutoSave(); + syncComplaintSnomedJson(); } $dd.hide().empty(); // Done with this row — move to lookup for next complaint @@ -5716,7 +5765,16 @@ return _SEVERITY_OPTIONS.filter(function(s) { return s.startsWith(q); }); } - $(document).on('input focus', '.complaint-sev-input', function() { + $(document).on('input focus', '.complaint-sev-input', function(e) { + if (e && e.type === 'input') { + var idxInp = parseInt($(this).attr('data-idx'), 10); + if (!isNaN(idxInp) && idxInp >= 0 && idxInp < selectedComplaintItems.length) { + selectedComplaintItems[idxInp].severity = ($(this).val() || '').trim(); + syncComplaintSnomedJson(); + markDirty('Complaint detail updated'); + scheduleAutoSave(); + } + } _sevDdIdx = -1; var $inp = $(this); var sugs = getSeveritySuggestions($inp.val()); @@ -5729,6 +5787,9 @@ if (idx >= 0 && idx < selectedComplaintItems.length) { selectedComplaintItems[idx].severity = val; syncComplaintSnomedJson(); + markDirty('Complaint detail updated'); + scheduleAutoSave(); + syncComplaintSnomedJson(); } $dd.hide().empty(); // Move focus to Duration input in same row