Files
baya-monorepo/dev/shared-working-context/backend/handoff/after-backend-phase-11.md
T
2026-07-09 02:13:30 +03:30

47 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Handoff — after backend-phase-11 (Refunds, clawbacks & invoices)
**The reversal leg of the payments arc is live.** Money can now flow *backwards*: an admin reverses a captured
booking payment across both fee legs, the balanced reversal posts to the append-only ledger, and the flow forks
on whether the nurse was already paid (clean `nurse_payable` reversal vs a first-class `nurse_clawbacks`
receivable). The minimal commission **invoice** (VAT on the commission line, sequential number, mocked مودیان)
ships too.
## What the frontend (f10-b11) can now build
- **Admin refund console** — create a refund (`POST admin_refunds`: full/partial by percentage or explicit legs),
the refund worklist (`GET admin_refunds` — channel, decomposed legs, status, ETA, policy snapshot), and the
clawback write-off (`POST admin_clawbacks/{id}/write_off`).
- **Admin invoice issuance** — `POST admin_invoices` (sequential number, VAT on commission, مودیان pending).
- **Customer cancellation/refund-status view** — `GET refunds/{id}/status` (tenancy-scoped; status, channel,
amount, **`expected_customer_refund_eta`** for the BNPL 710-business-day window, masked reference). This is the
**only** customer-visible refund surface — refunds are admin-initiated, there is no self-service initiation.
- **Customer/admin invoice view** — `GET invoices/{booking_id}` (number, gross, commission, VAT, مودیان status,
PDF URL when present).
## Live endpoints / contract
- Contract: **`dev/contracts/domains/refunds-invoices.md`** (enums, DTO shapes, IRR digit-strings, masked
references, failure codes, side-effects). Machine schema: `dev/contracts/openapi/swagger.v1.json` **refreshed**.
- All money is IRR integer, on the wire as a **digit-string**. `expected_customer_refund_eta` is a **date**.
- Admin endpoints are behind the admin policy and **rate-limited** (sensitive). Refunds are **never** customer
self-service.
## What is mocked / waiting
- **سامانه مودیان** is mocked behind **`IMoadianClient`** (pending/no-ref by default; a config switch forces a
registered 22-digit ref). See `reports/mocks-registry.md`.
- **BNPL revert** runs against **`IBnplProvider`** — a **thin local stub** now; **b12 owns the real seam** and its
adapter. The `bnpl_revert` ledger legs are already identical to the card path.
- **"Was the nurse paid?"** is derived from the booking's dispute-window close (`INursePayoutStatus`) until **b13**
ships `nurse_payouts`; **clawback recovery/netting is b13** (this phase only opens the `pending` receivable +
supports write-off).
- **`tickets`** arrives in **b15**: `refunds.ticket_id` is a nullable column (no FK yet); the "ticket required"
rule is config-gated off (`refund_ticket_required = false`).
- **Deferred crons** (thin/manual today): the مودیان reconciliation job (`pending → registered`) and the
BNPL-revert reconciliation job that clears `refund_payable ↔ escrow_held` for a `processing` refund.
## Notes for the next backend phases
- **b12 (BNPL):** owns the real `IBnplProvider`; the refund `bnpl_revert` path already calls it through the seam.
- **b13 (payouts):** implement the real `INursePayoutStatus` (`nurse_payout_booking_links`) and net `pending`
`nurse_clawbacks` out of a payout batch (set `recovered_in_payout_id` / `original_payout_id`, post `DEBIT
nurse_payable / CREDIT nurse_clawback_receivable`).
- **b15 (tickets/partner centers):** wire the real `refunds.ticket_id` FK + flip `refund_ticket_required` on;
wire `invoices.partner_center_id` + `nurse_clawbacks` payout FKs.