Enhance IPD discharge summary: OPD-style Prescribed Medicines table for B&W printing, auto generic lookup, and suppress empty discharge summary heading
This commit is contained in:
parent
73780ac7dd
commit
2fcfbd922a
|
|
@ -609,6 +609,7 @@ class Ipd_discharge extends BaseController
|
|||
'Personal History',
|
||||
'Drug Allergy / ADR',
|
||||
'Co-Morbidities',
|
||||
'Prescribed Medicines',
|
||||
'Discharge Medications',
|
||||
'Discharge Advice/Instructions/Summary',
|
||||
'Dietary Advice',
|
||||
|
|
@ -631,11 +632,20 @@ class Ipd_discharge extends BaseController
|
|||
$instructionRow = $ipdId > 0 ? $this->firstRowByIpd('ipd_discharge_instructions', $ipdId) : [];
|
||||
$instructionMeta = $this->parseInstructionMetaPayload((string) ($instructionRow['comp_report'] ?? ''));
|
||||
$clinicalSummaryRaw = $this->normalizeRichText((string) ($instructionRow['comp_remark'] ?? ''));
|
||||
$clinicalSummary = $clinicalSummaryRaw !== ''
|
||||
? '<div class="discharge-summary-content">' . $this->renderRichText($clinicalSummaryRaw) . '</div>'
|
||||
: $section(['Discharge Summary']);
|
||||
if ($clinicalSummaryRaw !== '') {
|
||||
$clinicalSummary = '<div class="discharge-summary-content">' . $this->renderRichText($clinicalSummaryRaw) . '</div>';
|
||||
} else {
|
||||
$extracted = $section(['Discharge Summary']);
|
||||
$plainText = trim(strip_tags((string) $extracted));
|
||||
// If the extracted summary only contains the title "Discharge Summary" or is blank, treat as empty
|
||||
if ($plainText === '' || strcasecmp($plainText, 'Discharge Summary') === 0) {
|
||||
$clinicalSummary = '';
|
||||
} else {
|
||||
$clinicalSummary = $extracted;
|
||||
}
|
||||
}
|
||||
|
||||
// Replace "Discharge Summary" header with discharge status
|
||||
// Replace "Discharge Summary" header with discharge status if non-default status exists
|
||||
if ($dischargeStatus !== ''
|
||||
&& strcasecmp(trim($dischargeStatus), 'Discharge Summary') !== 0
|
||||
&& $clinicalSummary !== '') {
|
||||
|
|
@ -663,7 +673,10 @@ class Ipd_discharge extends BaseController
|
|||
);
|
||||
}
|
||||
|
||||
if ($clinicalSummary !== '') {
|
||||
$plainSummary = trim(strip_tags((string) $clinicalSummary));
|
||||
if ($plainSummary === '' || strcasecmp($plainSummary, 'Discharge Summary') === 0) {
|
||||
$clinicalSummary = '';
|
||||
} elseif ($clinicalSummary !== '') {
|
||||
$hasSummaryHeading = preg_match(
|
||||
'/<h[1-6][^>]*>\s*Discharge\s+Summary\s*<\/h[1-6]>|<(?:b|strong)[^>]*>\s*Discharge\s+Summary\s*<\/(?:b|strong)>/i',
|
||||
$clinicalSummary
|
||||
|
|
@ -688,7 +701,21 @@ class Ipd_discharge extends BaseController
|
|||
$clinicalInvestigations = $section(['Clinical Investigation Reports']);
|
||||
$courseInHospital = $section(['Course in the hospital']);
|
||||
$examOnDischarge = $section(['Examination on Discharge']);
|
||||
$dischargeMedications = $section(['Discharge Medications']);
|
||||
$dischargeMedications = $section(['Prescribed Medicines', 'Discharge Medications']);
|
||||
// Always prefer fresh OPD-style table from DB rows when rows exist.
|
||||
// Also replace stale cached HTML that contains old-format columns or form artefacts
|
||||
// (e.g. "Medicine Advice: EditRemove", "Medicine Name | Dosage | Qty | Day").
|
||||
$opdStyleMedHtml = $this->buildOpdStyleMedicationsHtml($ipdId);
|
||||
if ($opdStyleMedHtml !== '') {
|
||||
$dischargeMedications = $opdStyleMedHtml;
|
||||
} elseif ($dischargeMedications !== '') {
|
||||
// Sanitize any leftover action links from cached HTML (Edit/Remove buttons)
|
||||
$dischargeMedications = (string) preg_replace(
|
||||
'/<\s*a\b[^>]*>\s*(?:Edit|Remove|Delete)\s*<\/a>/i',
|
||||
'',
|
||||
$dischargeMedications
|
||||
);
|
||||
}
|
||||
$dietaryAdvice = $section(['Dietary Advice'], ['Review after', 'Review After']);
|
||||
$dietaryAdvice = $this->trimDietaryAdviceTail($dietaryAdvice);
|
||||
$drugAllergyAdr = $section(['Drug Allergy / ADR']);
|
||||
|
|
@ -810,6 +837,9 @@ class Ipd_discharge extends BaseController
|
|||
'EXAMINATION_ON_DISCHARGE' => $examOnDischarge,
|
||||
|
||||
// Discharge instructions and advice
|
||||
'PRESCRIBED_MEDICINES' => $dischargeMedications,
|
||||
'Prescribed_Medicines' => $dischargeMedications,
|
||||
'prescribed_medicines' => $dischargeMedications,
|
||||
'DISCHARGE_MEDICATIONS' => $dischargeMedications,
|
||||
'DIETARY_ADVICE' => $dietaryAdvice,
|
||||
'DISCHARGE_INSTRUCTIONS' => '',
|
||||
|
|
@ -2062,6 +2092,334 @@ class Ipd_discharge extends BaseController
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an OPD-style medication table for the {{DISCHARGE_MEDICATIONS}} template placeholder.
|
||||
*
|
||||
* Output matches the OPD {{medical}} format:
|
||||
* | # | Medicine (bold) + generic (small blue) | Directions (English) + Hindi (orange) |
|
||||
*
|
||||
* Data sources (in priority order):
|
||||
* 1. ipd_discharge_prescrption_prescribed – structured prescription rows (dosage IDs)
|
||||
* 2. ipd_discharge_drug – legacy simple drug rows
|
||||
*/
|
||||
private function buildOpdStyleMedicationsHtml(int $ipdId): string
|
||||
{
|
||||
if ($ipdId <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// ── 1. Try structured prescription rows ─────────────────────────────────
|
||||
$prescTable = $this->findFirstExistingTable([
|
||||
'ipd_discharge_prescrption_prescribed',
|
||||
'ipd_discharge_prescription_prescribed',
|
||||
]);
|
||||
|
||||
$medRows = $prescTable !== null
|
||||
? $this->byIpdRows($prescTable, [
|
||||
'med_name', 'med_salt', 'med_type',
|
||||
'dosage', 'dosage_when', 'dosage_freq',
|
||||
'qty', 'no_of_days', 'remark',
|
||||
], 'id ASC', $ipdId)
|
||||
: [];
|
||||
|
||||
// ── 2. Fallback to legacy ipd_discharge_drug rows ───────────────────────
|
||||
$useLegacy = empty($medRows);
|
||||
if ($useLegacy) {
|
||||
$drugRows = $this->byIpdRows(
|
||||
'ipd_discharge_drug',
|
||||
['drug_name', 'drug_dose', 'drug_day'],
|
||||
'id ASC',
|
||||
$ipdId
|
||||
);
|
||||
// Convert legacy rows to the same shape as prescription rows
|
||||
foreach ($drugRows as $dr) {
|
||||
$name = trim((string) ($dr['drug_name'] ?? ''));
|
||||
if ($name === '') {
|
||||
continue;
|
||||
}
|
||||
$medRows[] = [
|
||||
'med_name' => $name,
|
||||
'med_salt' => '',
|
||||
'med_type' => '',
|
||||
'dosage' => 0,
|
||||
'dosage_when' => 0,
|
||||
'dosage_freq' => 0,
|
||||
'qty' => '',
|
||||
'no_of_days' => trim((string) ($dr['drug_day'] ?? '')),
|
||||
'remark' => trim((string) ($dr['drug_dose'] ?? '')), // dose string goes to remark column
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($medRows)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// ── Hindi lookup maps (mirrors OPD Opd.php maps) ────────────────────────
|
||||
$whenCodeDescMap = [
|
||||
'BF' => 'BF (BEFORE FOOD)', 'AF' => 'AF (AFTER FOOD)',
|
||||
'WF' => 'WF (WITH FOOD)', 'ES' => 'ES (EMPTY STOMACH)',
|
||||
'BBF' => 'BBF (BEFORE BREAKFAST)', 'ABF' => 'ABF (AFTER BREAKFAST)',
|
||||
'BL' => 'BL (BEFORE LUNCH)', 'AL' => 'AL (AFTER LUNCH)',
|
||||
'BD' => 'BD (BEFORE DINNER)', 'AD' => 'AD (AFTER DINNER)',
|
||||
'BT' => 'BT (BED TIME)',
|
||||
];
|
||||
$whenHindiMap = [
|
||||
'BF' => 'भोजन से पहले', 'BEFORE FOOD' => 'भोजन से पहले',
|
||||
'AF' => 'भोजन के बाद', 'AFTER FOOD' => 'भोजन के बाद',
|
||||
'WF' => 'भोजन के साथ', 'WITH FOOD' => 'भोजन के साथ',
|
||||
'ES' => 'सुबह खाली पेट', 'EMPTY STOMACH' => 'सुबह खाली पेट',
|
||||
'BBF'=> 'नाश्ते से पहले', 'BEFORE BREAKFAST' => 'नाश्ते से पहले',
|
||||
'ABF'=> 'नाश्ते के बाद', 'AFTER BREAKFAST' => 'नाश्ते के बाद',
|
||||
'BL' => 'दोपहर के भोजन से पहले', 'BEFORE LUNCH' => 'दोपहर के भोजन से पहले',
|
||||
'AL' => 'दोपहर के भोजन के बाद', 'AFTER LUNCH' => 'दोपहर के भोजन के बाद',
|
||||
'BD' => 'रात के भोजन से पहले', 'BEFORE DINNER'=> 'रात के भोजन से पहले',
|
||||
'AD' => 'रात के भोजन के बाद', 'AFTER DINNER' => 'रात के भोजन के बाद',
|
||||
'BT' => 'रात को सोते समय', 'BED TIME' => 'रात को सोते समय',
|
||||
];
|
||||
$freqHindiMap = [
|
||||
'OD' => 'दिन में एक बार (OD)', 'BD' => 'दिन में दो बार (BD)',
|
||||
'TDS' => 'दिन में तीन बार (TDS)', 'TID' => 'दिन में तीन बार (TID)',
|
||||
'QID' => 'दिन में चार बार (QID)', 'HS' => 'रात को सोते समय (HS)',
|
||||
'SOS' => 'ज़रूरत पड़ने पर (SOS)', 'STAT'=> 'तुरंत एक बार (STAT)',
|
||||
'ALTERNATE DAY' => 'एक दिन छोड़कर',
|
||||
'DAILY' => 'प्रतिदिन',
|
||||
'WEEKLY' => 'हफ़्ते में एक बार',
|
||||
'MONTHLY' => 'महीने में एक बार',
|
||||
];
|
||||
$remarkHindiMap = [
|
||||
'TAKE WITH MILK' => 'दूध के साथ लें',
|
||||
'TAKE WITH WARM WATER' => 'गुनगुने पानी के साथ लें',
|
||||
'AVOID SOUR FOOD AND DAIRY PRODUCTS'=> 'खट्टा और डेयरी उत्पाद न लें',
|
||||
'TAKE AFTER MEALS' => 'भोजन के बाद लें',
|
||||
'TAKE ON AN EMPTY STOMACH EARLY MORNING' => 'सुबह खाली पेट लें',
|
||||
'CHEW WELL BEFORE SWALLOWING' => 'चबाकर खाएं',
|
||||
'DISSOLVE IN HALF GLASS OF WATER' => 'आधे गिलास पानी में घोलकर लें',
|
||||
'APPLY LOCALLY TWICE DAILY' => 'दिन में दो बार लगाएं',
|
||||
'DO NOT CRUSH OR CHEW TABLET' => 'गोली को तोड़े या चबाएं नहीं',
|
||||
'AVOID ALCOHOL WHILE TAKING THIS MEDICINE' => 'शराब का सेवन न करें',
|
||||
'COMPLETE FULL COURSE OF ANTIBIOTICS' => 'एंटीबायोटिक का पूरा कोर्स लें',
|
||||
'DRINK PLENTY OF FLUIDS / WATER' => 'प्रचुर मात्रा में पानी पिएं',
|
||||
];
|
||||
$formulationPrefixMap = [
|
||||
'tablet' => 'TAB', 'tab' => 'TAB',
|
||||
'capsule'=> 'CAP', 'cap' => 'CAP',
|
||||
'syrup' => 'SYP', 'syp' => 'SYP', 'syr' => 'SYP',
|
||||
'injection'=> 'INJ', 'inj'=> 'INJ',
|
||||
'drop' => 'DROP', 'drops' => 'DROPS',
|
||||
'cream' => 'CREAM', 'ointment' => 'OINT', 'gel' => 'GEL',
|
||||
'lotion' => 'LOTION', 'powder' => 'POWDER', 'sachet' => 'SACHET',
|
||||
'spray' => 'SPRAY',
|
||||
];
|
||||
|
||||
// Also load opd_dose_when Hindi labels from DB (same as OPD controller)
|
||||
$doseWhenHindiMap = [];
|
||||
if ($this->db->tableExists('opd_dose_when')) {
|
||||
$whenRows = $this->db->table('opd_dose_when')
|
||||
->select('dose_sign, dose_sign_hindi')->get()->getResultArray();
|
||||
foreach ($whenRows as $r) {
|
||||
$k = strtolower(trim((string) ($r['dose_sign'] ?? '')));
|
||||
$v = trim((string) ($r['dose_sign_hindi'] ?? ''));
|
||||
if ($k !== '' && $v !== '') {
|
||||
$doseWhenHindiMap[$k] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
$doseFreqHindiMap = [];
|
||||
if ($this->db->tableExists('opd_dose_frequency')) {
|
||||
$freqRows = $this->db->table('opd_dose_frequency')
|
||||
->select('dose_sign, dose_sign_hindi')->get()->getResultArray();
|
||||
foreach ($freqRows as $r) {
|
||||
$k = strtolower(trim((string) ($r['dose_sign'] ?? '')));
|
||||
$v = trim((string) ($r['dose_sign_hindi'] ?? ''));
|
||||
if ($k !== '' && $v !== '') {
|
||||
$doseFreqHindiMap[$k] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Build the table ─────────────────────────────────────────────────────
|
||||
$html = '<table width="100%" style="border-collapse:collapse;font-size:12px;border:1px solid #333333;margin-top:5px;margin-bottom:5px;">'
|
||||
. '<thead><tr style="background:#f2f2f2;border-bottom:1px solid #333333;">'
|
||||
. '<th style="padding:6px 8px;text-align:left;width:5%;font-weight:bold;color:#000000;border-right:1px solid #cccccc;">#</th>'
|
||||
. '<th style="padding:6px 8px;text-align:left;width:40%;font-weight:bold;color:#000000;border-right:1px solid #cccccc;">Medicine</th>'
|
||||
. '<th style="padding:6px 8px;text-align:left;width:55%;font-weight:bold;color:#000000;">Directions</th>'
|
||||
. '</tr></thead><tbody>';
|
||||
|
||||
$i = 0;
|
||||
foreach ($medRows as $med) {
|
||||
$rawName = trim((string) ($med['med_name'] ?? ''));
|
||||
if ($rawName === '') {
|
||||
continue;
|
||||
}
|
||||
$i++;
|
||||
$formulationRaw = trim((string) ($med['med_type'] ?? ''));
|
||||
$generic = trim((string) ($med['med_salt'] ?? ''));
|
||||
$remark = trim((string) ($med['remark'] ?? ''));
|
||||
$days = trim((string) ($med['no_of_days'] ?? ''));
|
||||
|
||||
// Auto-resolve generic / salt name from master database if not present on row
|
||||
if ($generic === '' && $this->db->tableExists('opd_med_master')) {
|
||||
$cleanMedName = trim((string) preg_replace('/^(TAB|CAP|SYP|INJ|CREAM|OINT|GEL|DROPS|SPRAY)\s+/i', '', $rawName));
|
||||
if ($cleanMedName !== '') {
|
||||
$masterRow = $this->db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->groupStart()
|
||||
->where('item_name', $cleanMedName)
|
||||
->orLike('item_name', $cleanMedName, 'after')
|
||||
->orLike('item_name', $cleanMedName, 'both')
|
||||
->groupEnd()
|
||||
->limit(1)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if (!empty($masterRow)) {
|
||||
$generic = trim((string) (!empty($masterRow['genericname']) ? $masterRow['genericname'] : ($masterRow['salt_name'] ?? '')));
|
||||
}
|
||||
|
||||
// Fallback to matching first significant keyword (e.g. "PANTOP" or "ACILOC")
|
||||
if ($generic === '') {
|
||||
$words = preg_split('/[\s\-_]+/', $cleanMedName);
|
||||
if (is_array($words)) {
|
||||
foreach ($words as $w) {
|
||||
if (strlen($w) >= 4) {
|
||||
$kwRow = $this->db->table('opd_med_master')
|
||||
->select('genericname, salt_name')
|
||||
->groupStart()
|
||||
->like('item_name', $w, 'after')
|
||||
->orLike('genericname', $w, 'after')
|
||||
->orLike('salt_name', $w, 'after')
|
||||
->groupEnd()
|
||||
->limit(1)
|
||||
->get()
|
||||
->getRowArray();
|
||||
if (!empty($kwRow)) {
|
||||
$generic = trim((string) (!empty($kwRow['genericname']) ? $kwRow['genericname'] : ($kwRow['salt_name'] ?? '')));
|
||||
if ($generic !== '') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine formulation prefix (TAB, CAP, SYP …)
|
||||
$formKey = strtolower($formulationRaw);
|
||||
$formType = $formulationPrefixMap[$formKey] ?? strtoupper($formulationRaw);
|
||||
if ($formType === '') {
|
||||
if (preg_match('/^(TAB|CAP|SYP|INJ|CREAM|OINT|GEL|DROPS|SPRAY)\b/i', $rawName, $m)) {
|
||||
$formType = strtoupper($m[1]);
|
||||
} else {
|
||||
$formType = 'TAB';
|
||||
}
|
||||
}
|
||||
$fullName = $rawName;
|
||||
if ($formType !== '' && preg_match('/^' . preg_quote($formType, '/') . '\b/i', $fullName) !== 1) {
|
||||
$fullName = $formType . ' ' . $fullName;
|
||||
}
|
||||
|
||||
// Medicine column HTML (B&W printer friendly: bold black name with crisp dark-gray italic generic name)
|
||||
$nameHtml = '<strong>' . esc($fullName) . '</strong>';
|
||||
if ($generic !== '') {
|
||||
$nameHtml .= '<div style="font-size:10px;color:#333333;font-style:italic;font-weight:normal;margin-top:2px;">' . esc($generic) . '</div>';
|
||||
}
|
||||
|
||||
// Directions: dosage/dosage_when/dosage_freq are stored as plain text labels
|
||||
// (e.g. "BBF (BEFORE BREAKFAST)", "EMPTY STOMACH", "BD"), NOT integer IDs.
|
||||
$doseText = trim((string) ($med['dosage'] ?? ''));
|
||||
$whenText = trim((string) ($med['dosage_when'] ?? ''));
|
||||
$freqText = trim((string) ($med['dosage_freq'] ?? ''));
|
||||
|
||||
// Sanitize remark: strip known UI action-button artefacts stored by the serializer
|
||||
$rawRemark = trim((string) ($med['remark'] ?? ''));
|
||||
// Remove patterns like "Edit", "Remove", "EditRemove", "Edit Remove" (case-insensitive)
|
||||
$cleanRemark = (string) preg_replace('/^(edit\s*remove|remove\s*edit|edit|remove|delete)\s*$/i', '', $rawRemark);
|
||||
$cleanRemark = trim($cleanRemark);
|
||||
|
||||
$dirParts = [];
|
||||
$dirLocalParts = [];
|
||||
|
||||
// ── When (Relation to Food) ──────────────────────────────────────────
|
||||
if ($whenText !== '') {
|
||||
$upperWhen = strtoupper($whenText);
|
||||
// Expand short codes to descriptive form
|
||||
if (isset($whenCodeDescMap[$upperWhen])) {
|
||||
$dirParts[] = $whenCodeDescMap[$upperWhen];
|
||||
} else {
|
||||
$dirParts[] = $whenText;
|
||||
}
|
||||
// Hindi translation
|
||||
if (isset($whenHindiMap[$upperWhen])) {
|
||||
$dirLocalParts[] = $whenHindiMap[$upperWhen];
|
||||
} elseif (isset($doseWhenHindiMap[strtolower($whenText)])) {
|
||||
$dirLocalParts[] = $doseWhenHindiMap[strtolower($whenText)];
|
||||
}
|
||||
}
|
||||
|
||||
// ── Dose / Schedule (e.g. "BBF (BEFORE BREAKFAST)", "1 Tab") ────────
|
||||
if ($doseText !== '') {
|
||||
$dirParts[] = $doseText;
|
||||
}
|
||||
|
||||
// ── Frequency (OD, BD, TDS …) ────────────────────────────────────────
|
||||
if ($freqText !== '') {
|
||||
$upperFreq = strtoupper($freqText);
|
||||
$dirParts[] = $freqText;
|
||||
if (isset($freqHindiMap[$upperFreq])) {
|
||||
$dirLocalParts[] = $freqHindiMap[$upperFreq];
|
||||
} elseif (isset($doseFreqHindiMap[strtolower($freqText)])) {
|
||||
$dirLocalParts[] = $doseFreqHindiMap[strtolower($freqText)];
|
||||
}
|
||||
}
|
||||
|
||||
// ── Remark (Medicine Advice) — only if clean ─────────────────────────
|
||||
if ($cleanRemark !== '') {
|
||||
$upperRemark = strtoupper($cleanRemark);
|
||||
$dirParts[] = $cleanRemark;
|
||||
if (isset($remarkHindiMap[$upperRemark])) {
|
||||
$dirLocalParts[] = $remarkHindiMap[$upperRemark];
|
||||
}
|
||||
}
|
||||
|
||||
if ($days !== '') {
|
||||
$daysText = is_numeric($days) ? $days . ' Days' : $days;
|
||||
$dirParts[] = $daysText;
|
||||
$daysNum = is_numeric($days) ? (int) $days : 0;
|
||||
if ($daysNum > 0) {
|
||||
$dirLocalParts[] = $daysNum . ' दिन';
|
||||
} elseif (stripos($days, 'week') !== false) {
|
||||
$dirLocalParts[] = '1 हफ़्ता';
|
||||
} elseif (stripos($days, 'month') !== false) {
|
||||
$dirLocalParts[] = '1 महीना';
|
||||
}
|
||||
}
|
||||
|
||||
$directionsText = !empty($dirParts) ? implode(' | ', $dirParts) : '-';
|
||||
$localText = !empty($dirLocalParts)
|
||||
? implode(' | ', array_values(array_unique($dirLocalParts)))
|
||||
: '';
|
||||
|
||||
$html .= '<tr style="border-bottom:1px solid #cccccc;">'
|
||||
. '<td style="padding:6px 8px;vertical-align:middle;text-align:left;border-right:1px solid #e0e0e0;color:#000000;">' . $i . '</td>'
|
||||
. '<td style="padding:6px 8px;vertical-align:middle;text-align:left;border-right:1px solid #e0e0e0;color:#000000;">' . $nameHtml . '</td>'
|
||||
. '<td style="padding:6px 8px;vertical-align:middle;text-align:left;color:#000000;">'
|
||||
. '<div>' . esc($directionsText) . '</div>'
|
||||
. ($localText !== '' ? '<div style="font-size:11px;color:#333333;line-height:1.4;margin-top:2px;" lang="hi">' . esc($localText) . '</div>' : '')
|
||||
. '</td>'
|
||||
. '</tr>';
|
||||
}
|
||||
|
||||
if ($i === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$html .= '</tbody></table>';
|
||||
return '<h4 class="discharge-section-heading">Prescribed Medicines</h4>' . $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build dosage display string from dosage IDs.
|
||||
* Returns format: "BID (TWO TIME A DAY) / दिन में दो बार लेना"
|
||||
|
|
@ -2447,25 +2805,27 @@ class Ipd_discharge extends BaseController
|
|||
// This matches CI3 behavior where template controlled the patient info display.
|
||||
|
||||
// Build Discharge Summary section with status and free-text content
|
||||
// IMPORTANT: Keep "Discharge Summary" heading for template section extraction to work!
|
||||
$dischargeStatusText = $this->getDischargeStatusText($ipd);
|
||||
$isStandardStatus = ($dischargeStatusText === '' || strcasecmp($dischargeStatusText, 'Discharge Summary') === 0);
|
||||
|
||||
// Get discharge summary free-text content from ipd_discharge_instructions.comp_remark
|
||||
// (instructionRowForMeta was already loaded above at line ~1856)
|
||||
$dischargeSummaryText = $this->normalizeRichText((string) ($instructionRowForMeta['comp_remark'] ?? ''));
|
||||
|
||||
if ($dischargeStatusText !== '' || $dischargeSummaryText !== '') {
|
||||
$summaryHtml = '<h4 class="discharge-section-heading">Discharge Summary</h4>';
|
||||
|
||||
if ($dischargeStatusText !== '') {
|
||||
$summaryHtml .= '<div class="discharge-status"><strong>' . esc($dischargeStatusText) . '</strong></div>';
|
||||
}
|
||||
|
||||
// Only include the section if there is actual narrative text OR a non-default status (e.g. LAMA, Dead Summary)
|
||||
if ($dischargeSummaryText !== '' || ! $isStandardStatus) {
|
||||
$summaryHtml = '';
|
||||
if ($dischargeSummaryText !== '') {
|
||||
$summaryHtml = '<h4 class="discharge-section-heading">Discharge Summary</h4>';
|
||||
if (! $isStandardStatus) {
|
||||
$summaryHtml .= '<div class="discharge-status"><strong>' . esc($dischargeStatusText) . '</strong></div>';
|
||||
}
|
||||
$summaryHtml .= '<div class="discharge-summary-content">' . $this->renderRichText($dischargeSummaryText) . '</div>';
|
||||
} elseif (! $isStandardStatus) {
|
||||
$summaryHtml = '<div class="discharge-status"><strong>' . esc($dischargeStatusText) . '</strong></div>';
|
||||
}
|
||||
if ($summaryHtml !== '') {
|
||||
$sections[] = $summaryHtml;
|
||||
}
|
||||
|
||||
$sections[] = $summaryHtml;
|
||||
}
|
||||
|
||||
$complaints = $this->byIpdRows('ipd_discharge_complaint', ['comp_report', 'comp_remark'], 'id ASC', $ipdId);
|
||||
|
|
@ -2773,89 +3133,11 @@ class Ipd_discharge extends BaseController
|
|||
$sections[] = $procedureBlock;
|
||||
}
|
||||
|
||||
$drugRows = $this->byIpdRows('ipd_discharge_drug', ['drug_name', 'drug_dose', 'drug_day'], 'id ASC', $ipdId);
|
||||
if (! empty($drugRows)) {
|
||||
$html = '<h4 class="discharge-section-heading">Discharge Medications</h4>'
|
||||
. '<table class="discharge-medicine-table">'
|
||||
. '<thead><tr><th>Medicine Name</th><th>Dosage</th><th>Qty</th><th>Day</th></tr></thead>'
|
||||
. '<tbody>';
|
||||
foreach ($drugRows as $row) {
|
||||
$drugName = trim((string) ($row['drug_name'] ?? ''));
|
||||
if ($drugName === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dose = trim((string) ($row['drug_dose'] ?? ''));
|
||||
$days = trim((string) ($row['drug_day'] ?? ''));
|
||||
|
||||
$html .= '<tr>'
|
||||
. '<td>' . esc($drugName) . '</td>'
|
||||
. '<td>' . esc($dose) . '</td>'
|
||||
. '<td></td>'
|
||||
. '<td>' . esc($days) . '</td>'
|
||||
. '</tr>';
|
||||
}
|
||||
$html .= '</tbody></table>';
|
||||
$sections[] = $html;
|
||||
} else {
|
||||
$medRows = $this->byIpdRows('ipd_discharge_prescrption_prescribed', ['med_name', 'med_salt', 'med_type', 'dosage', 'dosage_when', 'dosage_freq', 'qty', 'no_of_days', 'remark'], 'id ASC', $ipdId);
|
||||
if (! empty($medRows)) {
|
||||
$html = '<h4 class="discharge-section-heading">Discharge Medications</h4>'
|
||||
. '<table class="discharge-medicine-table">'
|
||||
. '<thead><tr><th>Medicine Name</th><th>Dosage</th><th>Qty</th><th>Day</th></tr></thead>'
|
||||
. '<tbody>';
|
||||
foreach ($medRows as $row) {
|
||||
$medName = trim((string) ($row['med_name'] ?? ''));
|
||||
if ($medName === '') {
|
||||
continue;
|
||||
}
|
||||
$medType = trim((string) ($row['med_type'] ?? ''));
|
||||
$label = ($medType !== '' ? esc($medType) . ' ' : '') . esc($medName);
|
||||
|
||||
// Build dosage display with English + Hindi labels
|
||||
$doseId = (int) ($row['dosage'] ?? 0);
|
||||
$whenId = (int) ($row['dosage_when'] ?? 0);
|
||||
$freqId = (int) ($row['dosage_freq'] ?? 0);
|
||||
$dosageDisplay = $this->buildDosageDisplay($doseId, $whenId, $freqId);
|
||||
|
||||
// Add composition if med_type contains it (for legacy compatibility)
|
||||
$composition = '';
|
||||
if (stripos($medType, ':') !== false) {
|
||||
$parts = explode(':', $medType, 2);
|
||||
if (count($parts) === 2) {
|
||||
$medType = trim($parts[0]);
|
||||
$composition = trim($parts[1]);
|
||||
$label = ($medType !== '' ? esc($medType) . ' ' : '') . esc($medName);
|
||||
}
|
||||
}
|
||||
|
||||
$html .= '<tr>'
|
||||
. '<td>' . $label;
|
||||
|
||||
if ($composition !== '') {
|
||||
$html .= '<br><small class="discharge-composition">Composition : ' . esc($composition) . '</small>';
|
||||
}
|
||||
$advice = trim((string) ($row['remark'] ?? ''));
|
||||
if ($advice !== '') {
|
||||
$html .= '<br><span class="discharge-medicine-advice">Medicine Advice: ' . esc($advice) . '</span>';
|
||||
}
|
||||
|
||||
$html .= '</td>'
|
||||
. '<td>' . ($dosageDisplay !== '' ? esc($dosageDisplay) : '-') . '</td>'
|
||||
. '<td>' . esc((string) ($row['qty'] ?? '')) . '</td>'
|
||||
. '<td>' . esc((string) ($row['no_of_days'] ?? '')) . '</td>'
|
||||
. '</tr>';
|
||||
|
||||
$saltName = trim((string) ($row['med_salt'] ?? ''));
|
||||
if ($saltName !== '') {
|
||||
$html .= '<tr class="discharge-medicine-salt-row">'
|
||||
. '<td colspan="4" class="discharge-medicine-salt">' . esc($saltName) . '</td>'
|
||||
. '</tr>';
|
||||
}
|
||||
}
|
||||
$html .= '</tbody></table>';
|
||||
$sections[] = $html;
|
||||
}
|
||||
// Build Discharge Medications in OPD-style table format
|
||||
// (# | Medicine bold + generic | Directions English + Hindi)
|
||||
$dischargeMedHtml = $this->buildOpdStyleMedicationsHtml($ipdId);
|
||||
if ($dischargeMedHtml !== '') {
|
||||
$sections[] = $dischargeMedHtml;
|
||||
}
|
||||
|
||||
$instructions = $this->byIpdRows('ipd_discharge_instructions', ['comp_report', 'comp_remark', 'review_after', 'footer_text'], 'id DESC', $ipdId);
|
||||
|
|
@ -6963,6 +7245,7 @@ class Ipd_discharge extends BaseController
|
|||
|
||||
$optionalFields = [
|
||||
'med_type' => 'med_type',
|
||||
'med_salt' => 'med_salt',
|
||||
'dosage' => 'dosage',
|
||||
'dosage_when' => 'dosage_when',
|
||||
'dosage_freq' => 'dosage_freq',
|
||||
|
|
@ -8026,6 +8309,19 @@ class Ipd_discharge extends BaseController
|
|||
$out = (string) preg_replace('/\bheader\s*:\s*html[_a-z0-9-]+\s*;?/i', '', $out);
|
||||
$out = (string) preg_replace('/\bfooter\s*:\s*html[_a-z0-9-]+\s*;?/i', '', $out);
|
||||
|
||||
// Clean empty "Discharge Summary" heading stubs that have no narrative content
|
||||
$out = (string) preg_replace(
|
||||
'/<h[1-6]\b[^>]*class="[^"]*discharge-section-heading[^"]*"[^>]*>\s*Discharge\s+Summary\s*<\/h[1-6]>\s*(?:<div class="discharge-status">\s*<strong>\s*Discharge\s+Summary\s*<\/strong>\s*<\/div>\s*)?(?!<div class="discharge-summary-content">)/i',
|
||||
'',
|
||||
$out
|
||||
);
|
||||
// Clean standalone discharge-status tag when it simply says "Discharge Summary"
|
||||
$out = (string) preg_replace(
|
||||
'/<div class="discharge-status">\s*<strong>\s*Discharge\s+Summary\s*<\/strong>\s*<\/div>/i',
|
||||
'',
|
||||
$out
|
||||
);
|
||||
|
||||
if ($this->looksLikeMalformedDischargeHtml($out)) {
|
||||
$out = $this->normalizeMalformedDischargeHtmlForMpdf($out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1488,6 +1488,7 @@ $historyFields = [
|
|||
<input type="hidden" name="discharge_medicine_json" id="discharge_medicine_json" value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card border-secondary mt-3" id="section-instructions">
|
||||
<div class="card-header py-2 d-flex justify-content-between align-items-center">
|
||||
<strong>Discharge Summary</strong>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" id="btn_discharge_manage_food_master">Dietary Master CRUD</button>
|
||||
|
|
@ -1578,6 +1579,7 @@ $historyFields = [
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /#section-instructions -->
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -7001,16 +7003,21 @@ $historyFields = [
|
|||
rows.forEach(function(row) {
|
||||
var cells = row.querySelectorAll('td');
|
||||
// Skip empty state row or rows with insufficient cells
|
||||
if (cells.length >= 8) {
|
||||
if (cells.length >= 7) {
|
||||
var editBtn = row.querySelector('.btn-edit-discharge-med');
|
||||
var rawRemark = cells[6] ? cells[6].textContent.trim() : '';
|
||||
var cleanRemark = rawRemark.replace(/^(edit\s*remove|remove\s*edit|edit|remove|delete)\s*$/i, '').trim();
|
||||
|
||||
var cellData = {
|
||||
med_type: cells[0].textContent.trim(),
|
||||
med_name: cells[1].textContent.trim(),
|
||||
med_salt: editBtn ? (editBtn.getAttribute('data-med-salt') || '') : '',
|
||||
dosage: cells[2].textContent.trim(),
|
||||
dosage_when: cells[3].textContent.trim(),
|
||||
dosage_freq: cells[4].textContent.trim(),
|
||||
no_of_days: cells[5].textContent.trim(),
|
||||
qty: cells[6].textContent.trim(),
|
||||
remark: cells[7].textContent.trim()
|
||||
qty: editBtn ? (editBtn.getAttribute('data-qty') || '') : '',
|
||||
remark: cleanRemark
|
||||
};
|
||||
|
||||
// Only add non-empty medicine names
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user