# SCOUT.md — م8 «الكاشير والفلوس» codebase map (2026-07-08، read-only)

BE = `/home/moonui/moon-erp-be/Modules/Clinic` · FE = `.../features/clinic`. Anchors file:line. المرجع: `topics/clinic-tightening-plan.md` ملحق أ (تدقيق C1-M6).

## Enums (ground truth)
- `OrderLineStatus`: ordered·performed·billed·cancelled (`Enums/OrderLineStatus.php:7-10`).
- `ServiceOrderStatus`: open·partially_billed·billed·closed·cancelled (`:7-11`).
- `PaymentDisposition`: collect_now·send_to_cashier·none (`:14-16`).
- Receipt statuses: pending·paid·partially_paid·voided.

## ✅ EXISTS+FIXED (م0/م4 — مايتعادش)
- **C2/C3/C4** مصلّحين: lab-complete `where status=ordered` فقط · refund يحرس status=paid AND journal_entry_id · collect fail-before-write على `clinic.ar_account_id/revenue_account_id` (+ listener throws).
- **Refund** كامل الحراسة (billed + paid-receipt + non-voided + zero-refuse + open-session + GL-resolve 422 + double-refund re-lock؛ UI: زر يظهر فقط لـstatus=billed + `refundingLineId` in-flight).
- **Session enforcement (BE):** collect+refund يطلبوا open session (`CollectReceptionReceipt.php:237-245`)؛ `Open/CloseCashierSession`؛ `expected_cash=opening_float+Σcash−Σrefunds` (`UpdateCashierSessionTotals.php:49-66`)؛ counted_cash من request (BE صادق).
- **Partial payment (م4):** `clinic.allow_partial_payment` (default true)؛ under-payment مسموح، **over-payment مرفوض**؛ باقي=`partially_paid` + JE guard يرتخي لـpaid≤billable؛ repayment path موجود. TOCTOU شامل (lockForUpdate على order/lines/tender + exact-match + Σ-assert).

## 🔴 STILL-OPEN (شغل م8)
### C1/M1 — performed lifecycle (CORE)
قرار م1 «collect يقبل ordered+performed» **مش منفّذ**. Collect مقصور على `ordered` في ٣ فروع (`CollectReceptionReceipt.php:164,184,98-104`) + JE listener (`PostReceiptJournalEntry.php:116,180`). auto-flip ordered→performed موجود (`MarkEncounterLabComplete.php:30-35`/`MarkEncounterRadComplete.php:38`، scoped ordered) → بند مكتمل قبل الدفع = **performed غير قابل للتحصيل**. `patient_due` **بيضمّه** (`ServiceOrder.php:100-107`) → مستحق بلا سطر قابل للتحديد → زر التحصيل معطّل للأبد. FE: `orderedLines`/`isLineSelectable` (`cashier-collect.component.ts:122-133`) تستثني performed. **الحل (قرار a):** performed يبقى قابل للتحصيل (٣ scopes + JE + flip/ledger + FE).

### M3 — closed/cancelled order (dead)
`ServiceOrderStatus::Closed` **ماتتضبطش أبدًا**؛ `recalculateBillingStatus` يطلّع open/partially_billed/billed بس (`ServiceOrder.php:113-117`). order-level cancelled كذلك. **الحل:** transition close (fully billed + zero outstanding) + order-cancel (كل السطور cancelled).

### H5 — money-truth
`paid_total`=Σ non-voided receipts (`ServiceOrder.php:123-126`) — **مايخصمش credit notes**. مفيش `refunded_total`/`net` (Resource `:22-30`، FE interface `clinic-cashier.service.ts:29-39`). FE `fullyPaid` يكدب بعد refund (`cashier-collect.component.ts:204-207`). Dashboard `collected_today`/`revenue_7d` مايخصمش refunds ومايستثنيش pending (`ClinicDashboardService.php:169-186,228-236`). **الحل:** refunded_total+net على model+resource+header/rail + dashboard net.

### Cashier queue (طابور — groundwork فقط)
`sent_to_cashier_at/by`+`payment_disposition` موجودين (migration `..._000020`، set من `CreateVisit`) لكن **صفر endpoint/شاشة**. `ServiceOrderController::index` يفلتر patient_id/status/encounter_id بس (`:40-50`). FE: صفر استخدام لـsent_to_cashier؛ الكاشير single-order عبر `?order=` (`reception-order.component.ts:673`). **الحل:** endpoint queue (`payment_disposition=send_to_cashier` + غير مُسوّى) + **شاشة جديدة**.

### FE blind-count (فجوة)
close dialog **يعبّي counted_cash بـexpected_cash** (`cashier-collect.component.ts:484-490`) → over_short=0 دائمًا (الـZ يتبطّل بالـUI). **الحل:** ماتعبّيش (blind entry). Z-report كامل بالفئات → **مؤجّل م11**.

### Receipt printing (button يكدب)
«Collect & print» بيحصّل ويعمل reload بس — **مايطبعش** (`cashier-collect.component.ts:336-371`). صفر print في الكلينك (BE بلا print route). **الحل:** FE-HTML (زي طباعة الروشتة/م7 slips).

### M2 — pending rescue (شبه moot)
`VoidReceptionReceipt.php:16-18` يرفض غير paid → pending عالق مايتفكّش. لكن PostReceiptJournalEntry بقى in-txn (مفيش pending جديد؛ م0 remediation عالج القديم). **قرار: moot لـم8** (وثّق، متبنيش).

## migrations (serialize م8 الجديد ≥ `2026_07_08_000030`)
service_orders(030001)·lines(030002)·reception_receipts(080001)·cashier_sessions(080003)·receipt_lines(2026_07_02_150000)·credit_notes(160000)·refund_flag(160001)·is_followup(000010)·cashier_disposition(000020). أحدث overall = `2026_07_08_000020`. **الجديد ≥ `..._000030`.**

## أسئلة العقد (محسومة في LEDGER)
performed=قابل للتحصيل (a) · queue=شاشة جديدة+endpoint · receipt=FE-HTML · close=fully-billed+zero-outstanding · H5=refunded_total/net computed (بلا عمود) · blind-count IN، Z كامل م11 · M2 moot · credit-balance مؤجّل.
