# 10. Payouts to Nurses [← Business Requirements](index.md) ## (a) Business requirements - Nurses are paid in **weekly batches**. A batch aggregates the amounts owed for completed, payout-eligible bookings/sessions and produces one payout per nurse with earnings in that window. - **Payout eligibility is gated on EVV completion AND a closed dispute window.** A booking/session enters a batch only when `status = 'completed'` AND `dispute_window_ends_at < now()` (the dispute window is config-driven, default 72h post-completion). This deliberately prevents paying a nurse before a dispute can surface, shrinking clawback frequency — important because an Iranian bank transfer, once sent, is effectively irreversible. - The nurse payout amount derives from `gross_price_irr − balinyaar_commission_irr` (never from a BNPL provider's net settlement). - **Clawbacks** (`nurse_clawbacks`) handle the refund-after-payout case: if a booking is refunded/disputed **after** the nurse was already paid, a clawback receivable is recorded (negative ledger entry against the nurse) and recovered by **netting against the nurse's next weekly batch**, or written off if uncollectable. The nurse's payable balance is **derived from the ledger** (it may go negative), and a batch can net prior clawbacks (`gross_earnings`, `clawback_applied`, `net_amount`). - **Each booking is paid at most once** (the payout↔booking link is unique), preventing double-pay across batches. - **Bank-holiday-aware scheduling.** Payout period-end and processing dates are shifted off bank-closed days using a shared `iranian_holidays` calendar — a weekly payout landing on a multi-day Nowruz closure would otherwise fail, since PAYA/SATNA transfers do not settle on closed days. - Payouts go to the nurse's **verified, registered primary IBAN**, with the IBAN snapshotted and a transfer reference stored for reconciliation. Each payout item carries a unique track id + (for batches) a batch id. ## (b) Iran-specific considerations - Payouts are **real bank transfers to registered IBANs** (PAYA/SATNA cycles, next-business-day on holidays) — there is no chargeback-style reversal, which is *why* the dispute window must close before payout and why clawback is a netting/receivable mechanism rather than an automatic reversal. - Provider settlement cut-offs (Toman/Jibit) mean payout must tolerate a provider being unavailable mid-cycle; the batch + reconciliation references survive a swap. - Each nurse must have a Shahkar/KYC-verified, IBAN-ownership-checked account registered as a beneficiary before any payout targets it. ## (c) MVP vs DEFERRED - **MVP:** weekly batches; EVV + dispute-window gating; per-session accrual for engagements; `nurse_clawbacks` with next-batch netting and write-off; unique booking↔payout link; `iranian_holidays`-aware scheduling; verified-IBAN payouts with reconciliation references. - **DEFERRED:** on-demand / instant nurse withdrawal; per-nurse configurable payout frequency; automated clawback recovery beyond netting. ## (d1) Rules confirmed in build (backend b13) These fill gaps the requirements left open; the payout engine was built to them: - **Clawback netting recovers *whole* clawbacks up to a batch's earnings.** A `nurse_clawbacks` row is atomic — it is recovered in full or not at all — so a batch nets the largest set of whole pending clawbacks (oldest first) that fits within the nurse's earnings that week; `net_amount = gross_earnings − clawback_applied ≥ 0` (never negative). A single clawback **larger than a batch's earnings** stays fully `pending` and recovers from a later, larger batch (it is not partially recovered). The recovery is a real ledger movement (`DEBIT nurse_payable / CREDIT nurse_clawback_receivable`), not just a status flag, so the derived balances reconcile. - **A booking with an active (non-failed/-rejected) refund is held out of payout batches** — its money was (partly) reversed, so paying its frozen `nurse_payout_amount` would overpay. It is excluded until resolved (this is the operational reading of "no open dispute", since there is no separate dispute table yet). - **PAYA vs SATNA** is chosen per payout by the `payout_satna_threshold_irr` config (SATNA for net amounts at/above the threshold, else PAYA). - **Optional BNPL settlement gate:** `require_bnpl_settlement_for_payout` (config, **default off**) — when on, a BNPL-paid booking is payout-eligible only once its provider settlement (`settled_at`) is received. - The weekly **cron trigger is DEFERRED** — batches are admin-triggered; the cadence lives in `nurse_payout_interval_days` (default 7) for the future scheduler. ## (d) Supporting database entities `nurse_payout_batches`, `nurse_payouts` (with `gross_earnings_irr`, `clawback_applied_irr`, `net_amount_irr`, `iban_snapshot`), `nurse_payout_booking_links` (unique per booking), **`nurse_clawbacks`**, `ledger_entries`, **`iranian_holidays`**, `bookings.dispute_window_ends_at`, `nurse_bank_accounts`. > **Related:** Data model — [Payouts](../data-model/07-payouts.md).