- Fix Undefined variable \ 500 error in Person_Edit_V.php
- Safeguard auth()->user() and variable access in Person_Edit_V.php and Person_profile_V.php
- Enhance getPrescriptionMedicines with fallback dosing, remarks, and SNOMED lookup for OP Consultation FHIR
- Add deep-link SMS notify and link verification in ABDM gateway and task board
- Add PatientEditViewTest covering profile and edit view rendering
- Add Day Care (<24h) and Emergency (Casualty) admission pathways with prefixes DC- and ER-
- Add dedicated physical wards, ESI 5-level triage, MLC tracking, and PADSS day care discharge
- Implement audited 'Convert to IPD' workflow with SBAR handover and automated bed transfer
- Support unified IPD billing with dedicated group headers for Day Care and Emergency charges
- Redesign Hospital Admission Desk with executive card layout and modern triage controls
- Add comprehensive user documentation and SVG flowchart in public/help.html
- Completely remove legacy patient_master.p_lname column from database and application code
- M1: Update Find ABHA via Mobile to compliance flow: Mobile Number -> Profiles -> OTP -> Complete Profile Fetched
- M2: Support walk-in non-ABHA patient discovery via demographic matching (verified mobile, gender, year of birth, name)
- M2: Implement care context linking endpoints (/records/link/init and /records/link/confirm) with OTP verification
- Add abdm_link_transactions database migration
- Support Bearer token and HMAC signature authentication for bridge callbacks over VPN
Use mandatory SNOMED discharge composition and section codings, model completed investigations as DiagnosticReportLab resources, and restore local M3 attachment/value-string rendering.
The bridge reply 'No HIU sessions found matching the criteria' means the facilities have not sent records yet. The consent-status step already handled that wording, but the data-fetch steps surfaced it as 'Auto flow failed'. Share the check via isPendingBridgeSessionError() and report a pending state that keeps polling.
Reconciled status lived only on a separate reconcile row, whose correlation back to a session was rebuilt on every page load, so denied/expired requests reverted to REQUESTED after reopening. Write GRANTED/DENIED/EXPIRED/REVOKED onto the session's own consent_request row and treat a stamped terminal state as authoritative.
consent_request anchor rows only registered their HMS request_id, so reconcile rows (which carry the ABDM consent_request_id) matched nothing and fell back to the newest open session. A DENIED result therefore landed on the granted session, where GRANTED outranks it, and the denied request kept showing REQUESTED. Anchors now publish their ABDM ids, and the open-session fallback applies only when the row names no consent request or that session has not resolved its ABDM id yet.
Check Live Status only reconciled the newest consent request, so requests the patient later denied or let expire in the PHR app stayed at REQUESTED. Reconcile all non-terminal sessions, expose each session request_id, and let a later revoked/expired/denied row override an earlier granted one.
Split official and hospital ABHA cards, preserve profile/photo updates, improve existing-patient matching, require and forward communication mobile data, and show accurate Bridge OTP status and errors.
Load referral master data into patient registration/edit screens, persist patient referby, expose searchable referral inputs in patient and IPD forms, and make referral title editable as free text in referral master CRUD.
- Patient.php: broaden non-fatal-pending detection in abdm_content_auto_flow() to recognize more bridge error wordings (No HIU sessions found / matching the criteria) and HTTP 400, stopping spurious 'Auto flow failed' toasts.
- Opd_prescription.php: remove dead opd.fhir.generated bridge_sync_queue enqueue in storePrescriptionFhirBundle(). This unprefixed event type routed to the CSNOtk terminology bridge which has no consumer for it, always 404ing. Real ABDM sharing already works via DreamsoftConnector::sharePrescriptionBundle() (abdm.fhir.share.requested).
- Fix groupWorkflowRowsIntoSessions() to correlate workflow rows by stable
request_id/abdm_consent_request_id instead of chronological proximity to
the newest CONSENT_REQUEST row. Background polling reconciles all
historical sessions in one batch, so older sessions' rows previously got
silently merged into the newest session, causing 'Show Data' to display
an unrelated older session's single facility instead of all consented
facilities.
- Skip synthetic orphan sessions (stray rows with no owning CONSENT_REQUEST)
in getAbdmConsentRequestsList()/getAbdmConsentArtifactDetail() so they
don't show as phantom history rows or get picked as 'most recent'.
- Fix abdm_documents() consent_request_id filter to match all known sibling
artifact IDs for a session (via abdm_hiu_consent_artifacts), not just an
exact single artifact id, so all facilities under one consent request
appear together.
- Fix CreateAbdmHiuConsentArtifacts migration: reduce VARCHAR(180) to
VARCHAR(100) on consent_request_id/artifact_id to satisfy MySQL's
1000-byte composite key length limit (was silently failing to migrate).
- Add fetchAllArtifactsAfterGrant() cascade in M3HiuWorkflowService to fetch
every known artifact under a granted consent, used by both the cron poll
and a new abdm_check_live_status() endpoint/button.
- getLatestAbdmSyncSnapshot() session-scoping fix to avoid an older granted
session masking a newer in-progress one.
- Relabel Dr. Joshi Clinic documents (previously mislabeled 'Test Hospital'
from the HIP's own FHIR bundle Organization name).
Those operations can store the entire decrypted FHIR bundle (incl. base64 scanned-document attachments, sometimes MB per row) in response_json. fetchAbdmWorkflowRows()/getLatestAbdmSyncSnapshot() only ever read small consent-status/hi_types fields out of response_json, which never appear in bulk data_fetch payloads anyway, so cap it at the SQL level instead of buffering it into PHP memory just to build a list view.
- M3HiuWorkflowService: data_fetch now supports fetch_by_request_id=1, sending request_id (not consent_id) per bridge Method 1 -- targets the current/self consent request's own session, distinct from Method 2 (consent_id, which can resolve to a stale session sharing the same artifact).
- Patient::abdm_content_fetch_only(): tries Method 2 (consent_id) -> Method 1 (request_id, self data) -> Method 3 (abha_address, historical fallback) in order, stopping as soon as real documents are found.
- Fixed a real pre-existing bug this surfaced: getLatestAbdmSyncSnapshot() used the same flawed 'status=SUCCESS implies COMPLETED' check (without requiring workflow_state=DATA_RECEIVED) already fixed elsewhere in computeConsentSessionDetail(). This let broad/historical data_fetch rows (status=success, but decrypted_data=[]) hijack priority-500 'best' selection and silently drift the resolved 'latest granted consent' to an unrelated historical consent_id after Method 3 fallback ran. Now requires workflow_state=DATA_RECEIVED, matching the earlier fix.
Per bridge gateway team guidance, GET /v1/hiu/data/fetch?abha_address=... returns ALL historical decrypted records across every past consent for a patient, unlike the consent/request-scoped Methods 1/2 previously used exclusively. Added M3HiuWorkflowService support for a fetch_by_abha_address flag on the data_fetch operation, and wired abdm_content_fetch_only() to automatically fall back to this broader lookup when the consent-scoped fetch finds nothing new -- this surfaced 14 previously-invisible historical documents (consultation reports, pathology/cytology) for the test patient that were never being fetched before.
abdm_content_fetch_only() always returned phase=COMPLETED and 'Records fetched successfully' whenever the data_fetch API call itself succeeded (fetchResult.ok===1), even when documents_persisted+documents_updated was 0 (bridge/HIP hasn't actually delivered any records yet -- decrypted_data still empty, session status 'requested'). Now check documents_persisted+documents_updated: if 0, report phase=GRANTED with a clear 'not sent any records yet' message instead of falsely claiming success.
computeConsentSessionDetail() treated any data_fetch/hi_data_push_callback row with status=success as proof the session reached COMPLETED. But the DB 'status' column only reflects whether the underlying API call/poll succeeded (no HTTP/transport error) -- NOT whether data was actually received; that's tracked separately via workflow_state (DATA_PENDING vs DATA_RECEIVED). A data_fetch poll that succeeds at the HTTP level but returns decrypted_data=[] (bridge still processing) was incorrectly marked COMPLETED instead of staying at GRANTED. Now also require workflow_state === DATA_RECEIVED for the COMPLETED phase.
When a consent session's overall phase resolves to GRANTED/COMPLETED via a data_fetch or hi_data_push_callback row (proof data was actually fetched), but no consent_reconcile/consent_status row in that session ever recorded which hi_types were granted (e.g. data arrives via async push before any reconcile poll runs), grantedHiTypes stayed empty and every requested HI type was incorrectly marked DENIED. Fall back to treating the full requested set as granted when we have positive proof of GRANTED/COMPLETED but no negative evidence of per-type denial.
- New Patient::abdm_content_request_custom(int \) endpoint builds a custom
consent{} block (purpose, hiTypes, permission.dateRange, dataEraseAt) from
user-submitted hi_types[]/date_from/date_to/purpose form fields, instead of
always using M3HiuWorkflowService::buildDefaultConsent()'s hardcoded
OPConsultation+DiagnosticReport / 365-day defaults. Reuses the existing
requester/hiu-id resolution and hiTypes normalization already built into
preparePayloadForOperation() for the consent_request operation, so no
M3HiuWorkflowService changes were needed.
- New route (POST) patient/abdm_content_request_custom/(:num).
- New 'Custom Request' button + '#abdmCustomConsentModal' form
(Patient_Profile_Opd_V.php) with HI type checkboxes (OPConsultation,
DiagnosticReport, Prescription, DischargeSummary, HealthDocument,
ImmunizationRecord, Wellness, Invoice), Valid From/To date inputs
(defaulted to today-365d..today), and a Purpose text field. On submit,
reuses the existing auto-flow polling loop (runAutoFlowStep) with the
returned request_id to track status through to data fetch.
- Live-verified end-to-end on patient 11 (Devender Singh): submitted a
request for OPConsultation + DiagnosticReport + Prescription; sandbox
granted only OPConsultation/DiagnosticReport, and the Phase 1 consent
detail modal correctly showed Prescription as DENIED alongside the two
GRANTED types, confirming the partial-grant per-HI-type breakdown works
correctly end-to-end.
- New Patient::getAbdmConsentArtifactDetail() helper builds a requested-vs-granted
HI type breakdown for a patient's current ABDM consent artifact, using the
bridge-team-confirmed 'Option A' model: overall status is single-valued
(GRANTED/REVOKED/EXPIRED/DENIED), per-type status is derived by comparing the
requested hiTypes (from the saved consent_request request_json) against the
granted hi_types array (already flattened onto responses by
M3HiuGatewayClient). No bridge changes or DB migrations required.
- New Patient::abdm_consent_detail(int \) JSON endpoint + route
patient/abdm_consent_detail/(:num).
- New 'View Consent' link + Bootstrap modal on the OPD ABDM tab
(Patient_Profile_Opd_V.php) rendering a lifecycle stepper, consent metadata
(Consent ID, Purpose, Valid From/To, Erase Date), and a per-HI-type table
(Document Type / Permission / Status / Timestamp).
- Fixed a bug found during live testing: once a consent reaches COMPLETED
(after a successful data_fetch), the highest-priority workflow row has no
hi_types field (it's a FHIR data bundle), which was causing all granted
types to show as DENIED. Now searches workflow history for the most recent
row that actually carries the granted hi_types payload.
- Live-verified against patient 15 (Meera Bisht): both requested HI types
(OPConsultation, DiagnosticReport) correctly show GRANTED with timestamps.
Previously, clicking 'Fetch ABDM Records' when a prior consent request was
stuck in REQUESTED/PENDING (no GRANTED/DENIED callback ever received from
the ABDM bridge/PHR - e.g. patient never opened/approved it in their PHR
app) would just resume/re-poll that same dead request indefinitely, since
getLatestAbdmSyncSnapshot() always prioritized the existing REQUESTED
request over starting a new one.
Now:
- getLatestAbdmSyncSnapshot() computes the age of a REQUESTED/PENDING
snapshot's updated_at and marks restart_required = true once it has
been pending for more than ABDM_PENDING_STALE_SECONDS (1 hour).
- abdm_content_auto_flow() honors this flag: when the last sync is stale,
it no longer resumes the old request_id and instead falls through to
create a brand-new consent_request against the bridge.
Verified locally: a 6h-old stale REQUESTED request for a test ABHA was
correctly abandoned and a fresh consent_request was created and granted
on the next 'Fetch ABDM Records' click, instead of re-polling the dead
request.