# Phase 13 — Booking lifecycle **Blocker:** blockers.md § "Booking lifecycle." **Depends on:** 13a's edge case needs a product decision (see below); 13b should use whatever timezone approach you land on in [04-payment-timezone.md](04-payment-timezone.md). --- ## 13a. Stuck partial-missed bookings The domain's own comment (`BookingStatus.cs:19`) states `Completed` means "every session is completed/cancelled/missed" — implying a mixed completed+missed booking should reach `Completed`. The only place that actually checks this is `CheckOutVisitCommand.Handler.cs:64-70` (`allSettled` check, runs after a real check-out). The no-show sweep (`DetectNoShowSessionsCommand.Handler.cs:25-76`, run by `NoShowSweepJob`) marks individual sessions `Missed` but **never re-checks `allSettled`** afterward — so a booking with one completed session and the rest auto-missed later gets permanently stuck at `InProgress`, and `PayoutRepository`'s eligibility query only considers `Status == Completed`, so the nurse's completed-session payout never becomes eligible. An admin can manually rescue this specific case (`TransitionBookingStatusCommand.Handler.cs:43-55` allows `InProgress → Completed`), but nothing does it automatically. **Fix:** extract the `allSettled` check from `CheckOutVisitCommand.Handler.cs:64-70` into a shared helper, call it from `DetectNoShowSessionsCommand.Handler.cs` after marking sessions `Missed`, per affected booking in that sweep batch. **Flag, don't guess:** what should happen to a booking where *zero* sessions were ever completed (all missed straight from `Confirmed`)? `BookingTransitions.cs` has no `Confirmed → Completed` edge today, and `Cancel` is explicitly refused as a substitute (`TransitionBookingStatusCommand.Handler.cs:28-29`). Nothing in `mvp/`/`archive/product/` answers this — it needs a product decision (does it still reach `Completed` with a zero payout, or some other terminal state?) before writing the edge-case code. ## 13b. "Today's visits" is unfiltered by default `ListSessionsForNurseQuery` documents itself as "today's visits by default," but `BookingRepository.cs:185-192` only applies the date filter when `date` is explicitly passed — both real client call sites (`nurse/visits/page.tsx:26`, `NurseDashboardScreen.tsx:85`) omit it, so the entire history returns. The **mock** already implements the intended default correctly (`mockApi.ts:438`: `date ?? isoDate(0)`). **Fix:** default `request.Date` to "today" via `IDateTimeProvider` inside the handler/repository when null, mirroring the mock. **Flag:** "today" needs a timezone decision (Iran local date vs. UTC day boundary) — there's no `Asia/Tehran`-aware date logic anywhere in the codebase yet (same class of gap as [04-payment-timezone.md](04-payment-timezone.md)). Resolve consistently with that fix, not ad hoc here.