# 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-` 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.