# F-189 — Implementer evidence

## Delivered

- Migration `056_pos_return_lines.js`:
  - Adds `orders_items.returned_quantity integer NOT NULL DEFAULT 0` with CHECK.
  - Extends `inventory_movements.operation` CHECK to allow `'return'`.
  - Creates `pos_returns` ledger with UNIQUE `(order_id, idempotency_key)` for replay.
- New `ApplyPosReturnUseCase`:
  - Locks order and stock rows.
  - Validates per-line return bounds; rejects over-return with `POS_RETURN_EXCEEDS_AVAILABLE`.
  - Requires full return for free items with `POS_RETURN_FREE_ITEM_PARTIAL`.
  - Restores inventory, decrements cash session expected cash proportionally.
  - Emits `reporting_payment_lines` row with `status='refund'` / `'partial_refund'`.
  - Inserts `orders_order_history`, `pos_returns`, audit events.
  - Idempotent via `pos_returns.idempotency_key`.
- New `buildPosReturnReceipt` returning an `R-<original>` numbered receipt with negative totals and `originalReceiptNumber`.
- New `POST /pos/sales/:id/returns` endpoint (POS roles + `x-terminal-id` binding).
- New `GET /pos/sales/:id/items` endpoint returning order items with `returnedQuantity`.
- Removed legacy `POST /pos/sales/:id/refund`.
- POS cashier UI: new `ReturnModal` exposed via a `Devolver artículos` button on the receipt modal; shows per-line steppers, reason and refund total; on success replaces the active receipt with the return receipt.
- Type updates so both POS, admin and backend see `originalReceiptNumber` / `isReturn` flags.

## Validation

- Backend, POS, admin typecheck: PASS.
- Real PostgreSQL sequential suite: 365/365 PASS (5 new in `pos-returns.itest.ts`).
- Migration cycle (`fresh up / second no-op / full down / re-up`): 4/4 PASS.
- Targeted ESLint + Prettier on every changed file: PASS.
- `./scripts/verify.sh`: PASS.

## Baselines
- Backend global lint remains unchanged; no new errors.
- Boundary check stays at one pre-existing security import violation; F-189 introduces none.
- Untracked upload JPGs excluded from the feature commit.
