HOCO B2B
Team tasksAnis

SRV-20 — Returns & after-sales (SAV) module

Return requests on delivered orders, approval, reception with automatic RETURN stock movements, credit notes; after-sales claims as tickets on order items with photos, resolved by replacement order, return, credit note, repair or rejection.

FieldDetails
Task codeSRV-20
PhaseP1 — V1 build & integration
Product scopeV1
StatusDone (Mon 19 Oct 2026)
StartMon 19 Oct 2026
DueMon 19 Oct 2026
ResponsibleAnis — Full-stack developer
Co-responsible—
Effort1.25 person-day(s) planned · 6 from scratch · size S
Area · appServer · server
Depends onSRV-16, SRV-24
UnblocksDSH-13
Milestones—

Summary

Return requests on delivered orders, approval, reception with automatic RETURN stock movements, credit notes; after-sales claims as tickets on order items with photos, resolved by replacement order, return, credit note, repair or rejection.

Description

The 17 Oct decisions move returns and after-sales service into V1 (decisions 9 and 10; ORD-13, SUP-04, STK-03, FIN-08). This task implements return requests on delivered orders (ReturnRequest RET-YYYY-NNNNNN, ReturnItem) with the ReturnStatus lifecycle REQUESTED → APPROVED/REJECTED → IN_TRANSIT → RECEIVED → REFUNDED, within the return window and never above delivered minus already-returned quantities; back-office decision and reception (admin.returns.decide, admin.returns.receive) where reception posts RETURN stock movements automatically through the inventory hook and issues a CreditNote linked to the invoice. It also implements the resolution of after-sales claims (AFTER_SALES tickets with TicketItem lines, AfterSalesIssue and photos, opened through SRV-24) via admin.tickets.resolve with AfterSalesResolution: REPLACEMENT creates a zero-priced replacement order that still goes through the confirmation queue, RETURN creates an approved return, CREDIT_NOTE issues a credit note, REPAIR tracks the repair, REJECTED requires a reason. Out of scope: returns and SAV pages (DSH-13) and the reseller screens (MRA-10, WEB-04/05).

Subtasks

#SubtaskOwner
1returns.create on a DELIVERED order: items, quantities, reason, photos; checks orders.returnWindowDays (RETURN_WINDOW_EXPIRED) and remaining quantities (RETURN_QTY_EXCEEDED); RET numberingAnis
2ReturnStatus transition table and guards; returns.list/get for the reseller; admin.returns.list/get with filtersAnis
3admin.returns.decide: approve or reject with reason; IN_TRANSIT when pickup is arranged or the reseller shipsAnis
4admin.returns.receive: received and accepted quantities per item, condition, target warehouse; RETURN stock movements through the inventory hook in the same transactionAnis
5CreditNote issuance (numbered, lines from order snapshots incl. VAT and pro-rated discounts) linked to the invoice; REFUNDED status; balance effect for billingAnis
6Order status DELIVERED → RETURNED when every line is fully returned; partial returns keep DELIVERED with returned quantitiesAnis
7admin.tickets.resolve for AFTER_SALES tickets: REPLACEMENT order (zero-priced lines, linked to ticket, lands in SUBMITTED), RETURN (approved return), CREDIT_NOTE, REPAIR, REJECTED with reasonAnis
8Outbox events return.requested/approved/rejected/received/refunded and ticket.resolved to the reseller stream, notifications and the back-office streamAnis
9Credit note PDF on the billing PDF baseAnis
10Return and claim payloads review for MRA-10Imad

Deliverables

  • apps/server/src/modules/orders/returns/{router,service,state-machine,events}.ts
  • apps/server/src/modules/billing/credit-notes.{service,pdf}.ts
  • apps/server/src/modules/support/after-sales/resolution.service.ts
  • packages/contracts/src/{returns.ts,admin/returns.ts,admin/support.ts (resolve)}

Acceptance criteria

  • A return request on an order delivered more than orders.returnWindowDays ago returns 422 RETURN_WINDOW_EXPIRED; quantities above delivered minus returned return 422 RETURN_QTY_EXCEEDED (ORD-13)
  • Receiving a return writes one RETURN movement per accepted line and increases physical and available stock automatically (STK-03)
  • Reception issues a credit note whose total equals the returned lines at their order snapshot prices incl. VAT, and the return becomes REFUNDED (FIN-08)
  • Resolving an AFTER_SALES ticket with REPLACEMENT creates a zero-priced order linked to the ticket in the confirmation queue (SUP-04, ORD-14)
  • Resolving with REJECTED without a reason returns 422 VALIDATION_FAILED
  • Each return status change reaches the reseller live and as a notification (ORD-15)

Requirements covered

RequirementTitleRelease
ORD-13Returns: request on a delivered order, back-office approval, reception; returned quantities re-enter stock automaticallyV1
SUP-04After-sales service (SAV): a reseller opens a claim on an order (items, quantities, issue, photos); the back-office handles it from diagnosis to resolution (replacement, return, credit note, rejection)V1
STK-03Reservation and deduction triggered by configurable order statuses; cancellations and returns put quantities back automaticallyV1
FIN-08Credit notes (avoirs) for returns and after-sales refunds; payment receiptsV1

Screens

ScreenNameApp
BO-69Returns & after-sales claimsBO

API surface

Test measures

  • Table-driven tests for the ReturnStatus transitions and quantity rules
  • DB tests against real Postgres for reception: stock movements, credit note totals, idempotent reception
  • E2E on staging: reseller return request → approve → receive → credit note visible in the reseller finance view

Risks

  • Defective returned items should not re-enter sellable stock — reception lets the operator route quantities to a non-selling (quarantine) warehouse; only sellable quantities raise availability
  • Credit note legal format not yet validated — reuse the invoice legal mentions from DQA-09 and confirm with HOCO's accountant

KPI

  • Delivered by Mon 19 Oct 2026 within 1.25 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.

On this page