# Orders-Print — Contracts

> Produced by the Reversa **Writer** (phase: generation) · doc_level: `complete`
> Generated on 2026-09-21

**Confidence scale:** 🟢 CONFIRMED · 🟡 INFERRED · 🔴 GAP

External HTTP contract exposed by the `orders-print` unit — the single route `GET /orders/{order}/print` (`OrderController::printOrder`, no route name) under the admin group (`['web','admin']`, empty admin prefix), declared **before** `resource('/orders')` so it is not shadowed by the resource `show` route. It is a read-only **HTML** receipt page; it requires an authenticated admin session; an unauthenticated request gets `302 → auth/login`. The controller performs **no writes**. 🟢 (`routes/web.php:73`, `OrderController.php:394-402`)

---

## GET `/orders/{order}/print` — printable receipt 🟢 (`:394-402`)

- **Auth:** required; anonymous → `302 auth/login`. 🟢 (`routes/web.php:24-28`)
- **Request:**

  | Field | In | Type | Required | Notes |
  |-------|----|------|----------|-------|
  | `order` | path | integer | ✅ | Order id; loaded via `Order::findOrFail` — unknown id → clean `404`. ✅ Fixed 2026-09-21 (was null-safe `find`, causing a fatal view error). 🟢 (`:396`) |
  | `ref` | query | string | ❌ | `ref=orders` switches the receipt's back control to `history.back()`; otherwise it links to `/pos`. 🟢 (`pos-print.blade.php:100`) |

- **Response — `200 text/html`** rendering `pages.pos-print` with:

  | View variable | Type | Meaning |
  |---------------|------|---------|
  | `order` | `Order` | The order to print: `code` (`#QT78-{id}`), `created_at`, `total`, `discount_amount`, optional `customer` (name/phone/live points), and `products` with `pivot.qty/price/unit_id/conversion_qty`. 🟢 (`:396`) |

- **Status codes:** `200` (receipt rendered) · `302 → auth/login` (unauthenticated) · `404` for an unknown id (`findOrFail`). No JSON variant. 🟢 (`:394-402`)
- **CSRF:** not applicable (`GET`). Printing is client-side (`window.print()`). 🟢 (`pos-print.blade.php:110`)

---

## Consumed contracts (owned by other units)

`orders-print` only reads the `orders`/`order_product`/`customers`/`units` tables through Eloquent; it calls no other unit's HTTP endpoint and no external service. 🟢

| Reads | Owner unit | Purpose |
|-------|------------|---------|
| `orders` + appended `code`, `products` (pivot) | `orders-crud` | the order and its priced lines |
| `customers` (via `Order::customer`, live `points`) | `customers-crud` | the receipt's customer block |
| `units` (via `Unit::find(pivot.unit_id)`) | `units` | per-line unit label |

---

## Producer/consumer relationships

| This unit is… | Counterparty | Contract |
|---------------|--------------|----------|
| **Consumer** | `orders-crud` | reads the `Order` model, its `products` pivots, and appended `code` owned by that unit. 🟢 |
| **Consumer** | `customers-crud` | the customer block reads `fullname`/`phone`/`points`. 🟢 |
| **Consumer** | `units` | the per-line label reads `Unit.name`. 🟢 |
| **Shared view** | `orders-crud` (`store`/`update` done path) | both render the same `pages.pos-print`; this route is the standalone re-print, linked from the order list with `?ref=orders`. 🟢 (`OrderController.php:162,334`; `orders.blade.php:74`) |

---

## Cross-cutting contract notes

- **Method surface:** a single `GET`; no other verbs on `/orders/{order}/print`. 🟢 (`routes/web.php:73`)
- **Content type:** `text/html` (an 80mm receipt), not JSON. 🟢 (`:401`)
- **Read-only:** `printOrder` never mutates state. 🟢 (`:394-402`)
- **No status guard:** a `draft` order is printable just like a `done` one. Confirmed intentional 2026-09-25 (`questions.md#question-13`). 🟢 (`:394-402`)
- **`findOrFail`, consistent with `show`:** ✅ Fixed 2026-09-21 — unknown id now returns a clean `404` (was null-safe `find`, causing a fatal render error). 🟢 (`:396`)
- **Live vs. historical:** the printed customer points are the customer's **current** balance, not the balance at sale time — matches the label's own "hiện tại" wording. Snapshotting was considered and deferred 2026-09-25 (would need a schema migration + relabeling); see `questions.md#question-13`. 🟡 (`pos-print.blade.php:48`)
- **Money display:** amounts render at 0 decimals (`number_format(…,0)`) despite decimal storage. 🟡 (`pos-print.blade.php:64-81`)
- **N+1:** one `Unit::find` per printed line. 🟡 (`pos-print.blade.php:57`)
- **Authorization:** authentication only; any admin may print any order. 🟡 (ADR-0009)
- **No observability:** the print path emits no telemetry. 🔴 (`:394-402`, absence)
