# W1-BE-A — patient read fixes, inpatient stay data, server flow state (BE)

Read _COMMON.md first. Review rows: B-shell-chrome B1, B2, #4, #9, #20, #29, #35, #45; D-specialties I8, I9.

## Goal
Fix the BE data the visit-shell header/rails read wrong or don't have, and add the small endpoints the FE needs for the inpatient header, the stay bill and the server-side flow state.

## Tasks
1. **Insurance (B1).** `Modules/Clinic/app/Services/PatientReadService.php:~91` returns raw `insurance_info` (LIS writes `[{contract_id, contract_name}]`). Return a normalized object `insurance: {company_name, contract_id, contract_name, coverage_percent|null}` built from the first contract (company_name = contract_name, or the insurance company name if the contract model has one — check LIS InsuranceContract/Partner). null when not insured. Keep it the single shared mapping (the classic header and the shell header both read `summary.insurance.company_name`). Test.
2. **Latest results flags (B2).** `lastLabsList()` (~245-262): add `flag` ('H'|'L'|'HH'|'LL'|'A'|null from the LIS result's abnormal/critical flag columns), `unit`, `date` (result/approval date) to each row. Test.
3. **Rh-negative alert (#4).** In `Services/Facts/PatientFactsReader.php` derived alerts: when `blood_group` ends with '-' or '−' (e.g. O-, A−, 'O neg'), add a derived alert `{code:'rh_negative', label 'Rh سالب'/'Rh negative', severity info, source 'blood'}` deduped like the other derived alerts. Test.
4. **Signer name (#45).** Make sure EncounterResource exposes `signed_by_name` (or `signer: {id,name}`) with `signed_at`. Add if missing.
5. **Inpatient stay header (I8, #9).** The FE `visit-shell/contexts/inpatient-stay.service.ts` builds the chip from `GET hospital/admissions/{id}` which needs `hospital.beds.view…`; users without it get a bare chip. Add `GET clinic/encounters/{id}/stay` (permission: whatever lets a user open the encounter — follow the encounter show route's middleware) returning `{admission_id, admission_no, kind, ward, room, bed, admitted_at, day_n, expected_nights, expected_discharge_on, attending_doctor: {id,name}, status}` from the encounter's admission (Admission::attending_doctor_id → LabDoctor). 404/empty when the encounter has no admission. Test.
6. **Stay bill (#35 «حساب الإقامة»).** Add `GET clinic/encounters/{id}/stay-bill` returning a read-only summary of the admission's running bill: `{currency, total, paid, deposit, balance, lines:[{label, qty, amount, date}] (latest 8), lines_count, can_open_bill}`. Reuse the Hospital module's existing bill computation (find what `admissions/{id}/close-bill` / the admission bill screen uses — do NOT reimplement money math). Permission: hospital.billing.manage | hospital.admissions.manage | clinic.cashier.* (whichever cashier view perm exists) — users without it get 403 and the FE hides the card. [FIN] read-only: no writes. Test.
7. **Server flow state (#20).** Migration: `encounters.shell_state` JSON nullable. Endpoints `GET clinic/encounters/{id}/shell-state` and `PUT …/shell-state` body `{done: string[] (card ids, max 60, each ≤40 chars alnum/_), active: string|null}`; PUT refused (422/423 like other edits) when the encounter is locked/signed; permission = the encounter record/edit permission used by vitals/complaint saves. Run the migration on dev. Test.
8. **Inpatient ordering mode (I9).** Investigate: prototype says inpatient context = intent ordering. Find where `ordering_mode` is computed for EncounterResource (`Support/OrderingMode.php`) and how lab/rad orders on an admission encounter are billed (to the admission bill?). If the Hospital flow already turns intents into admission charges, return `ordering_mode='intent'` for kind inpatient/day_case regardless of the company setting, with a test. If doing so would break admission billing, DON'T change it — explain in the report.

## Out of scope
FE files; HistoryService; lookup/catalog files; VisitLayoutController; settings seeders (other agents).
