- Add OPD Validity (Days) field in Doctor add/edit forms\n- Save/update doctor_master.opd_valid_no_days from Doctor module\n- Use hospital_setting fallback keys when doctor validity is blank/zero\n- Apply fallback consistently in OPD showfee, print expiry, and running_opd lookup window\n- Supports hospital-wide defaults while preserving doctor-specific overrides
OpdModel.php:
- running_opd_id lookup now uses doctor's configured opd_valid_no_days
instead of hardcoded 4 days (resolveRunningLookupDate helper)
- Doctors with validity > 5 days now correctly link running OPD back
to the original paid OPD even on days 5..N of the window
Opd.php (buildOpdLetterPrintData):
- For running OPD entries (running_opd=1 or opd_fee_type=3), expiry
display now shows "OPD Start Date: [paid visit] | Valid Upto: [paid
visit + validity]" using old_opd record — mirrors Opd_print_1 legacy
behavior and prevents validity window from advancing with each visit
- Make docedit_load/doc_input_list/create_doc flows tolerant when doc_format_sub.active is missing\n- Guard master/sub insert/update payloads by existing DB columns to avoid SQL 500 on old dumps\n- Avoid hard dependency on created_at/updated_at/default_print_type print margin columns\n- Keep behavior unchanged on upgraded schemas while restoring compatibility with legacy production data
- Add paper print settings to IPD templates (page size/custom size/margins)\n- Add Header HTML, Footer HTML, and Style (CSS) support\n- Update IPD PDF renderer to honor template paper settings and header/footer\n- Extend IPD placeholders with logo/QR support: {{H_logo}}, {{H_logo_abs}}, {{hospital_logo_html}}, {{qr_content}}, {{qr_code_html}}\n- Improve token rendering with robust curly placeholder parser for body/header/footer\n- Keep legacy sticker forms aligned with custom label dimensions and migrate old default rows
Root cause: the fallback lookup from opd_med_master used
$labelField = $masterSaltField ?? $masterGenericField
which preferred salt_name (the Substitute / other brand names field) over
genericname (the actual Generic Name / composition). If a prescription row's
inline genericname was empty, the Substitute string was written into it and
then printed as \"Salt/Generic\" in the {{medical}} block.
Fixes applied in three places:
1. Opd.php buildOpdLetterPrintData - master lookup now prefers genericname
2. Opd.php buildOpdLetterPrintData second loop - removed inline salt_name
fallback that overwrote genericname with Substitute value
3. Opd.php buildLegacyDashboardTemplateVars - removed salt_name from the
generic resolution chain used when rendering the medicine table HTML
4. Opd_prescription.php medicine list function - same preferGenericname fix
and removed inline salt_name -> genericname overwrite"
- Queue No (Opd.php::autoCreateOpdQueue, Opd_prescription.php::opd_prescription_save
and ::ensurePrescriptionSession): changed MAX(queue_no) query to JOIN through
opd_master.doc_id instead of trusting opd_prescription.doc_id, ensuring queue
numbering is strictly per-doctor per-day regardless of stale doc_id values in
opd_prescription rows.
- OPD appointment list: replaced auto-reload-on-digest-change with a manual
'Refresh' button. When the 8s digest poll detects new data the button turns
yellow with a 'New' badge; the page only reloads when the user explicitly clicks
it, preventing disruptive mid-session reloads."
Captures:
- Storage key being used
- Payload length
- Which candidate keys are checked
- Persistence verification results
Remove this commit after testing confirms the fix works
- Shortened template-scoped paper setting keys to avoid s_name length limits in legacy schemas
- Added legacy key fallback so existing saved settings still load
- Updated rename/delete/reset flows to handle both new and legacy key aliases safely
- Restored corrupted buildOpdLetterPrintData method that broke class structure
This fixes the 'Unable to save OPD paper print settings' error when saving new templates
- add new permissions:
template.opd_print, template.pathology_print, template.diagnosis_print,
template.document_print, template.ipd_document
- Template controller now accepts new permission keys (with backward-compatible fallbacks)
- IPD Document Master now has independent permission key (template.ipd_document)
- Template index tile visibility updated to use new granular keys
- OPD print template builder now honors template.opd_print permission
- preserve existing behavior via legacy permission fallbacks to avoid role breakage
- new rx_group_delete(int rxId) method in Opd_prescription controller
- deletes linked medicines first (opd_prescrption_prescribed_template), then group row
- POST route: Opd_prescription/rx_group_delete/(:num)
- Delete button (red) added to each row in Rx-Group list table
- confirm dialog before delete (shows group name)
- reloads list after delete; clears form if deleted group was loaded
- consult form medicine Dose/When/Freq changed to dropdowns from dose masters
- added Where dropdown in consult medicine editor and table display
- consult now loads options from Opd_prescription/rx_group_dose_masters
- medicine add/update payload now includes dosage_where
- medicine list now returns dosage_where_label for readable table output
- edit mode supports existing values not present in current master set
- quick chips now map into select options (with safe fallback)
- sttProxy now returns detailed upload error info (code, error string, php limits)
- sttProxy accepts fallback upload field name 'file' in addition to 'audio'
- reject empty audio payloads with explicit message
- client: guard against very short/empty blobs before POST to /stt-proxy
Production runs HTTPS; browser blocks http://139.59.13.39:8000 (mixed content).
Solution: CI4 proxy endpoints forward audio/health check server-side (HTTP→HTTP).
- Home::sttProxy() POST stt-proxy - forwards audio to STT server
- Home::sttProxyHealth() GET stt-proxy/health - pings STT and returns {ok:bool}
- JS: auto-detect window.location.protocol; use proxy URLs on HTTPS,
direct IP URLs on HTTP (local/dev)
- checkComplaintsSttServer: parse {ok:bool} from proxy health response
- Add complaints Speech-to-Text (browser + server STT fallback) with interim preview
- Add Medical Mic (server STT) for examination, diagnosis, provisional diagnosis fields
- Add speech-test route + Home::speechTest() view for STT testing
- OPD prescription: resolve dosage/when/frequency labels from lookup tables
- OPD prescription: show generic/salt name below medicine name in print
- OPD prescription: translate complaints/diagnosis/advice/investigation to Hindi for patient
- Add translateToLocalPatientText() helper with English->Hindi medical term map
- Add 'Remove All' medicines button (btn_clear_medicine)
- Add template search box in Load Template modal
- Fix investigation batch add: dedup + guard against concurrent add
- Fix single investigation add: check duplicate before adding
- Fix rx status text overflow: ellipsis + title tooltip
- Remove unused FHIR History and Back to Invoice buttons from Rx header
- .gitignore: exclude public/uploads/* and writable/ayushman/*
- Redact AIzaSy Gemini key from clinical_audit_trail entries in seed JSON
- Add default never-export denylist to exportMasterSeedData() so that
clinical_audit_trail, lab_log, bridge_sync_queue and session tables are
always skipped when setup.seed.export_tables is not configured.
This prevents API keys set via the admin UI from leaking into git via
the audit trail even after being deleted from hospital_setting.
- Add migration 2026-03-18-000028_CreateCityAutoUTable.php to create
the missing city_auto_u table (city, district, state columns) used
by PatientModel::getCitySuggestions() — resolves 500 on /billing/patient/city
- Fix HospitalProfile::save() to check directory creation success before
moving uploaded logo files; returns clean JSON error instead of
throwing HTTPException when public/assets/images/ is not writable