- EAtriaBridgeConnector: fix OPConsultRecord hi_type normalization (was wrongly
mapping to PrescriptionRecord); allow push with either abha_address or abha_id;
add careContextId alias for care_context_reference in pushRecord payload
- AbdmGateway: migrate OPD share to records/push semantics with unique
care_context_reference, ABHA id/address resolution, bridge_record_id capture,
and 409 DUPLICATE_RECORD non-fatal handling
- AbdmGateway: add non-ABHA local-only storage path for OPD/IPD/Lab share
(push_status=local_only, no bridge call, audit logged)
- AbdmGateway: add POST /records/discover endpoint with ABHA-first + fallback
matching by mobile, hospital ID, patient UHID+birthYear (PHR-compatible)
- AbdmGateway: add GET /records/fetch/{careContextId} endpoint returning
decrypted FHIR payload from health_records
- AbdmGateway: dual-write consent artefacts to abdm_consent_records AND
consents table when both present; getActiveConsentRecord falls back to
consents table when abdm_consent_records is absent
- AbdmAuditService: write to audit_logs (generic schema) when present,
fallback to abdm_audit_logs; field-aware insert supports both schemas
- Routes: register /records/discover and /records/fetch/(:any)
- Webhook signature validator: check EKA_WEBHOOK_SECRET then HMS_WEBHOOK_SECRET
for gateway compatibility
- Add ?html=1 parameter to show_discharge to output HTML directly
- Shows debug info: IPD ID, template name, content lengths
- Bypass PDF generation to see rendered HTML content
- Helps diagnose PHP/rendering errors before PDF conversion
Usage: /Ipd_discharge/show_discharge/1007168/1?html=1&tpl=3
- Restore "Discharge Summary" heading for template extraction to work
- Show status as strong text below heading (not as replacement)
- Include discharge summary HTML editor content (instruction_remark)
- Section extraction requires consistent heading names
Previous fix broke section extraction by changing heading text
- Include ipd_discharge_instructions.comp_remark in discharge summary section
- Previously only showed status header, missing actual discharge narrative
- Reuse existing instructionRowForMeta query to avoid duplicate DB calls
- Apply renderRichText() to properly display HTML editor content
Fixes missing discharge summary text for IPD 1007168 and similar cases
- Enhanced normalizeRichText() to detect and preserve HTML from HTML editors
- Added renderRichText() helper to safely render HTML vs plain text content
- Updated 4 rendering locations (narrative sections, systemic exams, investigations)
- Backward compatible: plain textarea fields still work correctly
- Fixes issue where strip_tags() removed all HTML formatting from editor content
Resolves blank discharge summaries in PDF when content saved from TinyMCE/HTML editors
- Replace all patient_master_exten checks with patient_master across Medical.php
- Fixes blank patient info in multiple pharmacy pages:
* /Medical/ipd_print/{id}/credit - IPD print bills (UHID, Patient name)
* Counter sale forms and invoice editing
* Patient search functionality
* IPD group print consolidated views
* Auto UHID lookup endpoints
- patient_master_exten table exists but lacks core patient fields (p_fname, p_rname, p_code)
- Ensures consistent patient data display throughout pharmacy module
- Matches earlier fixes for billing and invoice list pages
- Use patient_master directly in list_med_inv and list_med_orginv methods
- patient_master_exten exists but lacks p_fname, p_rname, p_code fields
- Fixes blank Name/Age/Gender/P Code in /Medical/list_med_inv page
- Consistent with earlier fix for list_org_ipd
- Use patient_master table directly instead of patient_master_exten
- patient_master_exten may exist but lacks p_fname, p_rname fields
- Matches pattern used in IpdBillingModel::baseIpdListQuery()
- Fixes blank patient names/codes in /Medical/list_org_ipd page
- Change getById() to find() - IpdBillingModel doesn't have getById method
- Use ipdEditModel (IpdModel extends Model) which has standard find() method
- Fixes 500 error: Call to undefined method IpdBillingModel::getById
- Rename toggleIpdStatus() to updateDischargeToggleStatus() to match naming pattern
- Add route mapping for /billing/ipd/panel/{id}/discharge/toggle-status endpoint
- Fixes 404 error when clicking toggle button in discharge panel
- Follows same pattern as other discharge operations (discount, charge, update)
- Update isIpdDischargedInvoice to check ONLY ipd_status field (remove fallback checks)
- Add IPD status toggle UI in discharge panel (Active/Discharged control)
- Create toggleIpdStatus controller method with permission check
- Add billing.ipd.status.manage permission for controlling bill edit lock
- Allows editing bills when needed by toggling status independently of discharge_date
- Auto-releases bed when setting status to discharged
- Fix dose columns showing IDs instead of labels (OD, BID, TDS, etc.)
- Add Rx-Group functionality with modal, search, and bulk add
- Add substitute medicine suggestions with one-click use
- Improve medicine autocomplete with debouncing and scope=all
- Load dose master maps in controller and pass to view
- Match OPD Consult UI/UX patterns for consistency
- Implemented automatic bed release on patient discharge
- Added bed transfer functionality in nursing workspace
- Added date/time tracking for bed assignments with duration calculation
- Fixed bed_master.current_ipd_id as source of truth for occupancy
- Created data fix scripts for existing records
- Added bed assignment history with duration display (hours/minutes)
- Fixed display issues in bed assignment tab
- Added route for bed transfer endpoint
- Supports custom assignment datetime for backdated entries
- Automatically marks previous bed as released on transfer
- Clear all output buffers before sending PDF binary to prevent corruption
- Add X-Content-Type-Options: nosniff to force Chrome to treat response as PDF
- Apply fixes to main, fallback, and ultimate fallback PDF response paths
- Fixes issue where Chrome fails to open PDF while Firefox/Edge work
- Critical for PDFs with Hindi/UTF-8 content where output buffering can corrupt binary data
ISSUE 1: {{SIGNATURE_BLOCK}} placeholder not working
- Signature extraction was using wrong end markers
- Start: 'Signature of Consultant'
- End: 'Signature of Medical Officer', 'Signature of Receiver / Date'
- Problem: All three texts are in SAME table row
- Extraction cut off too early (found end marker immediately after start)
FIX: Remove end markers for signature block extraction
- Signature table is LAST element in content
- Extract from 'Signature of Consultant' to end of content
- Now captures entire signature table correctly
ISSUE 2: Other Advice not showing in PDF
- Cached content was generated BEFORE 'Other Advice:' label was added
- Database has data but cached HTML doesn't include label
FIX: Created cache clearing utility
- clear_discharge_cache.php script
- Clears cached content for specified IPD
- Forces regeneration with new labels
DEBUG TOOLS ADDED:
- debug_discharge_content.php - Check what's in cached content
- clear_discharge_cache.php - Clear cache to force regeneration
TESTING:
1. php clear_discharge_cache.php 1
2. Visit /Ipd_discharge/preview_discharge_report/1?regen=1
3. Verify PDF shows Other Advice: and Discharge Summary: labels
4. Verify {{SIGNATURE_BLOCK}} placeholder works in templates
ISSUE 1: Discharge Summary showing in PDF but without label
ISSUE 2: Need separate placeholders for Other Advice and Discharge Summary
FIX 1: Added label to instruction_remark in PDF
- Added Discharge Summary: label before instruction_remark content
FIX 2: Added new placeholders for template flexibility
- OTHER_ADVICE - Shows only Other Advice field
- INSTRUCTION_REMARK or DISCHARGE_ADVICE - Shows only Discharge Summary field
- DISCHARGE_INSTRUCTIONS - Shows full section with all advice
Now templates can control what appears where using specific placeholders.
CHANGES:
1. Line 2248 - Added Discharge Summary: label
2. Line 574-575 - Extract new tokens from content
3. Line 579-581 - Add tokens to vars array
4. Line 520-522 - Add markers to extraction list
TESTING: Go to discharge PDF and verify labels show correctly
ISSUE: instruction_remark (Discharge Summary) data appearing in instruction_other (Other Advice) field after save
ROOT CAUSE: Legacy table sync was writing wrong variable
- Save handler at line 5478 was writing \ to legacy food_text
- Should have been writing \
- When legacy fallback loads (if food_ids empty), wrong data copied to instruction_other
FIX: Changed line 5478 in Ipd_discharge.php
- Before: \['food_text'] = \;
- After: \['food_text'] = \;
FILES MODIFIED:
1. app/Controllers/Ipd_discharge.php - Fixed legacy save handler
2. app/Views/billing/ipd/discharge_create.php - Removed debug comments
TESTING STEPS:
1. Clear corrupt legacy data: php clear_legacy_food.php 1
2. Go to /Ipd_discharge/ipd_select/1
3. Clear both fields
4. Type 'Hello Other' in Other Advice
5. Type 'Hello Discharge' in Discharge Summary
6. Click 'Save Discharge Advice'
7. After reload: Other Advice should show 'Hello Other', NOT 'Hello Discharge'
SCRIPTS ADDED:
- check_instruction_db.php - Check database values
- check_legacy_food.php - Check legacy table
- clear_legacy_food.php - Clean corrupt legacy data
- list_instruction_records.php - List all records
Added sanitizeCKEditorSpecialChars() method to handle smart quotes, zero-width spaces, em/en dashes, and other special characters that can break mPDF.
Removes invisible Unicode chars, replaces special punctuation with ASCII equivalents, cleans HTML comments.
ISSUE: Templates auto-regenerate when deleted
User deletes template ID 3, page reload creates template ID 4 automatically
ROOT CAUSE: ensureDefaultDischargeTemplateSeeded() called on EVERY page load
- discharge_templates() method called it on every view
- getDischargeTemplateRows() called it on every discharge PDF generation
- When count=0, it auto-inserted default templates
- Made it impossible to delete all templates
SOLUTION: Changed to manual opt-in template creation
1. Removed auto-seeding calls:
- Setting/Template::discharge_templates() - removed ensureDefaultDischargeTemplateSeeded()
- Ipd_discharge::getDischargeTemplateRows() - removed ensureDefaultDischargeTemplateSeeded()
- Both now only call ensureDischargeTemplateTable() (structure check only)
2. Added manual template creation:
- New 'Create Default Templates' button shown when table is empty
- New endpoint: discharge_templates_seed() - creates defaults on demand
- Route: POST /setting/template/discharge_templates_seed
- Button confirms before creating, shows success message, reloads page
3. Preserved seeding functions:
- ensureDefaultDischargeTemplateSeeded() kept but not auto-called
- Can be manually triggered via new button
- Creates 'Default Discharge Template' and 'NABH Compliant Discharge Summary'
BEHAVIOR NOW:
- Users can delete ALL templates - they stay deleted
- Empty table shows helpful message with creation button
- Templates only created when user explicitly requests them
- No more surprise template regeneration
TESTING:
- Delete all templates
- Page reloads showing empty table with button
- Click 'Create Default Templates'
- 2 templates created (ID 1 and 2)
ISSUE: Template delete returns success but record appears not deleted
ROOT CAUSE: Delete WAS working (verified in database), but page wasn't refreshing properly after success
CHANGES:
1. JavaScript fix (discharge_templates.php):
- Replaced conditional load_form_div / location.assign logic
- Now uses simple location.reload() after 500ms delay
- Ensures page always refreshes after successful delete
2. Controller debug logging (Template.php):
- Added comprehensive debug logs to trace delete flow
- Logs: request ID, row fetch, query compilation, affected rows
- Logs error codes and messages for troubleshooting
- Will help diagnose future issues
VERIFIED:
- Database confirmed template ID 2 was deleted
- Only frontend refresh was failing
- Now forces reload to show updated list
ISSUE: Medicines were being saved twice - once via Add button AJAX, and again when clicking 'Save Discharge Advice' button.
ROOT CAUSE:
1. Legacy code in save_main handler (lines 5489-5538) read 'discharge_medicine_json' POST field
2. JavaScript serializeDischargeMedicineTable() collected all medicine table rows into JSON
3. On form submit (Save Discharge Advice), JSON was sent and controller re-inserted all medicines
4. Result: duplicate entries in ipd_discharge_prescrption_prescribed table
SOLUTION:
- DISABLED controller code that processes discharge_medicine_json in save_main handler
- DISABLED JavaScript call to serializeDischargeMedicineTable() on form submit
- Medicines now saved ONLY via Add button AJAX (action='add_drug')
- Save Discharge Advice button now only saves dietary advice, instructions, review after, etc.
TESTING:
1. Add medicines via Add button (saves immediately)
2. Click Save Discharge Advice (does NOT save medicines again)
3. No duplicate entries in database
- Add getDoseMasterRows() to load dose masters (opd_dose_shed, opd_dose_when, opd_dose_frequency)
- Add buildDosageDisplay() to format dosage: 'BID (TWO TIME A DAY) / दिन में दो बार लेना'
- Update buildAutoDischargeContent() medication table query to include dosage, dosage_when, dosage_freq fields
- Change table columns from '#|Medicine|Qty|Days|Notes' to 'Medicine Name|Dosage|Qty|Day' matching old CI3 format
- Dosage column shows full text labels from master tables, not numeric IDs
- Add composition support as small text under medicine name for legacy compatibility
- Remove # serial number column and Notes column to match old HMS format