SRV-16 — Orders module — lifecycle, assisted orders, history, documents
The 11-status state machine (no automatic confirmation — every order is confirmed in the back-office), controls, refusal and controlled modification, assisted orders and confirmations, first-order attribution, cancellation with automatic restock, invoice and delivery-note PDFs.
| Field | Details |
|---|---|
| Task code | SRV-16 |
| Phase | P1 — V1 build & integration |
| Product scope | V1 |
| Status | Done (Mon 19 Oct 2026) |
| Start | Mon 19 Oct 2026 |
| Due | Mon 19 Oct 2026 |
| Responsible | Anis — Full-stack developer |
| Co-responsible | — |
| Effort | 2 person-day(s) planned · 8 from scratch · size M |
| Area · app | Server · server |
| Depends on | SRV-15 |
| Unblocks | SRV-20, SRV-17, SRV-18, SRV-26, SRV-25, WEB-01, SRV-40 |
| Milestones | — |
Summary
The 11-status state machine (no automatic confirmation — every order is confirmed in the back-office), controls, refusal and controlled modification, assisted orders and confirmations, first-order attribution, cancellation with automatic restock, invoice and delivery-note PDFs.
Description
Orders are the core flow of the cahier (§4.4, §5.4, §6.7, §15.2; ORD-04…ORD-12, ORD-14, ORD-15, STK-03, STK-08). This task implements the 11-status OrderStatus state machine with an explicit transition table and actors, and the 17 Oct rule that no order is confirmed automatically: app, web, assisted and phone orders all land in SUBMITTED (or PENDING on hold) and appear in admin.orders.toConfirm until someone with orders.validate confirms them. It covers validation controls (stock, credit, minimums, reseller status) with stock reservation per stock.reserveOn, refusal with a reason, controlled modification with OrderChange history, cancellation by actor and status with automatic restock, assisted orders (delegate draft → reseller confirmation or administration validation, 72 h expiry), back-office orders on behalf of a reseller, first-order flag and attribution to the source delegate, reorder, and invoice/delivery-note PDFs. Every status change emits an outbox event that reaches the reseller live over SSE (SRV-26) and as a notification (ORD-15). Out of scope: delivery records (SRV-17), invoices/payments (SRV-18), returns (SRV-20).
Subtasks
| # | Subtask | Owner |
|---|---|---|
| 1 | Transition table and guard functions for the 11 OrderStatus values (actor, permission, preconditions, side effects); 409 ORDER_TRANSITION_NOT_ALLOWED | Anis |
| 2 | Confirmation queue admin.orders.toConfirm (SUBMITTED, PENDING, assisted confirmed by reseller) with control results per order | Anis |
| 3 | admin.orders.validate: controls (STOCK_INSUFFICIENT with override, CREDIT_LIMIT_EXCEEDED, RESELLER_SUSPENDED), reservation via stock.reserveOn, VALIDATED; admin.orders.refuse with ORDER_REFUSAL_REASON | Anis |
| 4 | Controlled modification admin.orders.modify (lines, quantities, unit price with permission) until PREPARING, re-checks, OrderChange rows and reseller notification | Anis |
| 5 | Cancellation: reseller orders.cancel while status in orders.cancelAllowedStatuses, back-office admin.orders.cancel with ORDER_CANCEL_REASON; reservation release / re-entry hooks | Anis |
| 6 | Assisted orders: delegate.assisted.create/update/submit/discard, AssistedConfirmation AWAITING_RESELLER with assistedExpiresAt = +72 h, orders.confirmAssisted / rejectAssisted, admin.orders.confirmAssisted | Anis |
| 7 | Job orders.expireAssisted every 15 min (EXPIRED → CANCELLED) with the 24-hour reminder | Anis |
| 8 | Back-office order on behalf (admin.orders.create, channel BACK_OFFICE) using the cart validation pipeline, landing in SUBMITTED | Anis |
| 9 | OrderStatusChange and OrderChange writers; first-order flag and source-delegate attribution with revert on refusal/cancel; admin.orders.history | Anis |
| 10 | Invoice and delivery-note PDF generation (BL-YYYY-NNNNNN at READY) and orders.document / admin.orders.documents with signed URLs | Anis |
| 11 | Outbox events order.submitted/validated/refused/modified/status_changed/cancelled with reseller, delegate and staff recipients | Anis |
| 12 | Contract procedures + Zod schemas wired to the module service: orders.list/summary/get/reorder, delegate.orders.*, admin.orders.list/get/transition | Anis |
Deliverables
- apps/server/src/modules/orders/{router,service,repo,state-machine,assisted,events,jobs}.ts
- packages/contracts/src/{orders.ts,delegate/orders.ts,admin/orders.ts}
- apps/server/src/modules/orders/documents/{invoice,delivery-note}.tsx PDF templates
- Order lifecycle table in /docs/srs/lifecycles-and-statuses matching the transition table code
Acceptance criteria
- No code path moves an order to VALIDATED without an explicit admin.orders.validate by a user holding orders.validate (ORD-14)
- Every transition not in the table returns 409 ORDER_TRANSITION_NOT_ALLOWED; a user without the permission gets 403 PERMISSION_DENIED (ORD-04)
- A reseller can cancel only while SUBMITTED or PENDING; cancellation releases reserved stock automatically (ORD-10, STK-03)
- An assisted order not confirmed within 72 h becomes EXPIRED/CANCELLED and the delegate is notified (ORD-08)
- Each status change writes an OrderStatusChange and emits order.status_changed received by the reseller's SSE stream within 2 seconds (ORD-06, ORD-15)
- The first delivered-path order of a reseller is flagged and attributed to the source delegate in reports (ORD-09)
- Invoice and delivery-note PDFs are downloadable by the reseller through a signed URL (ORD-12)
Requirements covered
| Requirement | Title | Release |
|---|---|---|
| ORD-04 | Order lifecycle (11 statuses) with an explicit transition table and actors; no order is ever confirmed automatically | V1 |
| ORD-05 | Back-office processing: automatic controls, validation, controlled modification, refusal with reason | V1 |
| ORD-06 | Every modification and status change is historised, dated and notified | V1 |
| ORD-07 | Reseller order tracking: counters by status, filters, progress, details, invoice download, support, reorder | V1 |
| ORD-08 | Assisted orders prepared by a delegate, confirmed by the reseller or validated by the administration | V1 |
| ORD-09 | First order flagged and attributed to the reseller and the source delegate in reports | V1 |
| ORD-10 | Cancellation rules by actor and status, with stock release | V1 |
| ORD-11 | Back-office order entry on behalf of a reseller (phone orders) | V1 |
| ORD-12 | Order documents: invoice and delivery note PDFs | V1 |
| STK-03 | Reservation and deduction triggered by configurable order statuses; cancellations and returns put quantities back automatically | V1 |
| STK-08 | No order validated beyond available stock unless an authorised override is recorded | V1 |
| ORD-14 | Every order — app, web, assisted or phone — waits for an explicit confirmation by the back-office before preparation | V1 |
| ORD-15 | Order status changes reach the reseller in real time (live update in the app and web) and as a notification | V1 |
Screens
| Screen | Name | App |
|---|---|---|
| BO-38 | Orders list | BO |
| BO-39 | Order detail (controls, actions, history) | BO |
| BO-40 | New order on behalf of a reseller | BO |
| BO-41 | Orders to confirm (new, on hold, assisted) | BO |
API surface
| Endpoint group | Operations |
|---|---|
| Reseller orders | 11 |
| Assisted orders | 6 |
| Orders & delivery | 21 |
Test measures
- Table-driven unit tests over the full transition matrix (status × actor × permission)
- DB tests against real Postgres for validate/cancel stock and credit side effects
- Job test for assisted expiry with a fake clock
- E2E on staging: reseller checkout → back-office confirm → status visible live in the reseller web
Risks
- Back-office becomes a bottleneck since every order needs manual confirmation — to-confirm queue sorted by age with counters and SSE alerts; bulk confirmation of clean orders (all controls green) as a pilot option
- Modification after reservation leaves stock inconsistent — modification re-runs reserve/release deltas in the same transaction
KPI
- Delivered by Mon 19 Oct 2026 within 2 person-day(s).
- Every acceptance criterion above demonstrated before hand-off; linked requirements' acceptance criteria pass.
- Zero open critical defects, permission gaps or data-integrity regressions at sign-off.
Generated from content/plan/tasks.json by scripts/generate-team-tasks.mjs. Dates are computed by the scheduler (Sunday–Thursday weeks, holidays excluded) — change the plan, not this page.
SRV-15 — Cart & checkout rules
Server-side cart, re-validation of price/stock/promotions, minimum amount and quantities, max per order, credit check, checkout options and idempotent checkout.
SRV-39 — Smart notifications — contract & schema (groups, actions, flash sales, complementary products)
Additive contract and Prisma changes for document 03: NotificationGroup and AnnouncementKind enums, group and action on notifications and templates, per-group preferences, Promotion.isFlashSale, ProductComplement, Product.announceAsNew/publishedAt, announcement targets, query and response fields.