# P3 — one order executor + full radiology lifecycle

Read `_COMMON.md` first. Spec: `../design.md` §4.2 (row «منفّذ واحد», «التسعير», «النتائج لكل سياق») and §4.3 (whole table: ALTER, «جديد (صغير)» clinical_templates, State machine, images, report+print, pricing, dental decision, FE, permissions/presets, events). Also `../design-visit-shell.md` §2.6 «الطلب ≠ التنفيذ». Migration range `2026_11_03_160000`–`160099`.

## Shared-file rules (IMPORTANT — other agents are live)
- Do NOT edit `Modules/Clinic/routes/api.php` or `Modules/Core/database/seeders/RolePermissionSeeder.php` (other agents own them right now). Instead put in your report: the exact route lines to add and the permission names + the two role presets (radiologist, rad_technologist) to seed. The orchestrator adds them.
- Do NOT edit `DropRadReportOnEncounter.php`, `DropLabReportOnEncounter.php`, `SubmitExternalResult.php` (AF2 owns them), nor prescription files (P1), nor HistoryService.
- FE: only `src/app/features/clinic/radiology/**` and `src/app/features/clinic/encounter/orders/rad-orders.*` plus i18n keys (add keys with small targeted edits under a `RADIOLOGY.*`-style namespace you find there; do NOT bump I18N_VERSION — the orchestrator does at deploy).

## Do (BE)
1. `Modules/Clinic/app/Actions/ExecuteCatalogItem.php`: the single executor = the branch inside `DecideClinicalIntent::executeHere` — input `{catalog_ref_type, catalog_ref_id, order, doctor_id, encounter?}`; dispatch by ClinicCatalogMode / ref type: lis_investigation|lis_package → `OrderLabFromEncounter::handleForOrder`, rad_procedure → `CreateRadOrder::handleForOrder`, clinic_service → `AddServiceOrderLine` (fulfillment self). Refactor `DecideClinicalIntent::executeHere` to call it (keep its cancelled-encounter guard at the top — just added). `CreateVisit.php` lab/radiology items go through it too (read it; keep backward-compatible payloads `investigation_id` / `procedure_id`, and accept `items[] {catalog_ref_type, catalog_ref_id}`).
2. Radiology lifecycle: migration rad_orders + cancel_reason/cancelled_by/cancelled_at, payer_contract_id; rad_procedures + sbscs_code, default_template_id; rad_reports + template_id, body_structured json. New `clinical_templates` table (kind rad_report|note|discharge|sick_leave|medical_report|certificate, scope_ref_type/id nullable, name_ar/en, body_ar/en, fields json, is_active, sort_order, company_id) + model + seed nothing.
   - Status machine: ordered → scheduled (CreateRadStudyOnOrder) → performed (study acquired) → reported (RadReportReleased) → cancelled (new `CancelRadOrder` allowed before performed; fires `RadOrderCancelled` → reuse the lab's refund flagging listener `FlagLinesForRefund` (find it) for the rad line). `MarkEncounterRadComplete` must work without encounter_id and set the service line `result_status=ready`. Worklist hides reported.
   - Coverage: `CreateRadOrder` applies `CoverageService::applyCoverage` the same way a normal line does (read how lab/clinic lines do it).
   - New events `RadStudyAcquired`, `RadOrderCancelled`.
   - `GET rad-reports/{r}/pdf` using the existing DomPDF pattern (find another clinic PDF and mirror), report editor uses the procedure's default template.
3. Inpatient orders: lab/rad orders from an inpatient encounter (encounter.kind inpatient/day_case) work through the same executor (no admission-specific code needed beyond not blocking — verify).

## Do (FE)
- Rad worklist / report editor: cancel button (with reason, before performed), status chips for the full lifecycle, «جاهز» state at reception, PDF print button, template picker in the editor.
- `ng build --base-href /app/` green.

## Tests
`Modules/Clinic/tests/Feature/P3ExecutorRadiologyTest.php`: executor dispatches lab/rad/service; decide-here goes through it; CreateVisit with items[]; rad full lifecycle incl. cancel before performed (and 422 after performed) + refund flag; coverage applied on rad line; MarkEncounterRadComplete without encounter; PDF endpoint 200 (call the controller via the route ONLY if the orchestrator has added it — otherwise test the action/service directly). Run also existing `*Rad*Test.php`, `*Intent*Test.php`, `CreateVisitTest.php`, `OrderLabFromEncounterTest.php` and keep them green.

## Report
Files, test output, the route lines + permissions/presets to add, anything not done.
