# P1-BE — Prescription v2 (backend)

Read `_COMMON.md` first. Spec = `../design.md` §4.1 (read it fully — table rows "ALTER prescriptions", "ALTER prescription_items", "ALTER clinic_drug_alerts", "قاعدة التحقق", "State machine", "API", "Settings", "Permissions", "Events"). Also `../design-visit-shell.md` §2.6 "مصدر كل picker" and `../legacy-obgy-options-analysis.md` (drug + default sentence + Duplicate). Migration timestamps `2026_11_03_120000`–`120099`.

## Decisions already made (do not re-litigate)
- Drug source = `Modules\Clinic\Support\PharmacySource::for($companyId)`: `products` → `drug_id` (Core products) required; `standalone_formulary` → `clinic_drug_id` (clinic_drugs) required and `ResolveDrugProduct` must NOT auto-create a product in that mode. Default is `products` (orchestrator is fixing the default right now — read the class, don't edit it).
- Item = **(sentence) OR (dose+frequency+duration)** — at least one.
- Order ≠ dispense: `prescriptions.dispense_status` separate from `status`.
- Signed encounter lock already exists: `Encounter::assertEditable()` (call it in every new write path, incl. update).

## Do
1. Migration: `prescriptions` + `kind` (outpatient|inpatient|discharge|home, default outpatient), `subject` (patient|spouse|other, default patient), `subject_name` nullable, `dispense_status` (pending|partial|dispensed|not_applicable, default pending), `admission_id` nullable. `prescription_items`: dose/frequency/duration → nullable; + `sentence` text, `frequency_code` string(12), `times` json, `prn` bool, `starts_at`/`ends_at`/`stopped_at` + `stopped_by`, `item_status` (active|stopped|completed), `dosage_form_id` nullable, `form` string(100), `drug_id` → nullable, `clinic_drug_id` nullable, `drug_name` string(191), `dispensed_qty` decimal(12,3) nullable. `clinic_drug_alerts`: `drug_id` nullable + `clinic_drug_id` nullable, unique becomes (company_id, drug_id, clinic_drug_id). Guard every change (hasColumn) and handle the existing FK on clinic_drug_alerts.drug_id carefully (drop/re-add nullable).
2. Enums: `MedicationRoute` → the 13 routes design.md lists (add the missing ones; keep existing values unchanged); `MedicationFrequency` (exists) → add `timesPerDay(): ?int` and `defaultTimes(): array` (e.g. bd → ['08:00','20:00']); new `PrescriptionKind`, `PrescriptionSubject`, `DispenseStatus`, `PrescriptionItemStatus` enums.
3. `IssuePrescription` + `StorePrescriptionRequest`: new rules above (xor by pharmacy_source; sentence OR structured; snapshot drug_name/form; route in MedicationRoute; frequency_code in MedicationFrequency when given; kind/subject/subject_name).
4. `PUT /clinic/prescriptions/{id}` (new `UpdatePrescriptionRequest` + controller method): allowed only while status=issued (not printed/cancelled) AND encounter editable; replaces items; audited. `GET /clinic/prescriptions/{id}/pdf` via the existing print engine/DomPDF pattern used by other clinic PDFs (find one, mirror it) — bilingual, RTL, sentence shown per item, subject line when spouse. `POST /clinic/prescriptions/{p}/items/{i}/stop` (inpatient).
5. Unified drug search `GET /clinic/drugs/search?q=` → rows `{source: product|formulary, id, name, form, dosage_form_id, alert_note, presets: [{form, ready_sentence, is_default}]}` per pharmacy_source (formulary mode searches clinic_drugs (+presets by drug_name/product_id); products mode searches Core products flagged as drugs (+presets by product_id)). Replace nothing in FE.
6. `ClinicDrugAlert::notesFor()` accepts both keys. `ResolveDrugProduct` guarded by mode.
7. Permissions: add `clinic.prescriptions.update` and `clinic.prescriptions.inpatient` to `Modules/Core/database/seeders/RolePermissionSeeder.php` next to the other clinic.prescriptions.* entries (you own this edit — the orchestrator already finished his edit there).
8. Events: `PrescriptionUpdated`, `PrescriptionItemStopped` (no listeners needed).
9. Routes: add your 3 new routes to `Modules/Clinic/routes/api.php` next to the existing prescription routes (you are the only agent editing routes now), with permissions clinic.prescriptions.update / .print / .inpatient and `clinic.prescriptions.view` for drug search.
10. `PrescriptionResource` (and item resource): expose the new fields.
11. CHANGELOG: do NOT edit — report the user-facing summary in 2 lines (EN + AR) and the orchestrator adds it.

## Tests
`Modules/Clinic/tests/Feature/P1PrescriptionV2Test.php`: sentence-only item ok; neither sentence nor structured → 422; formulary mode requires clinic_drug_id and does not create a product; products mode requires drug_id; update before print ok, after print 422, on signed encounter 422; spouse subject persisted; drug search returns both shapes per mode with presets; stop item. Run also the existing `IssuePrescriptionTest.php` and any `*Prescription*Test.php` / `*ClinicDrug*Test.php` in Modules/Clinic/tests — keep green; if an old test asserted the old required dose/frequency, update it to the new rule and report it.

## Out of scope
FE (P1-FE later), NursingService/hospital MAR (P2), PharmacySource class, ClinicSettingDefinitionSeeder (orchestrator adds `clinic.rx.item_model`), HistoryService, attachments.
