Skip to main content

Request a return

Entry. POST /v1/commerce/returns → ReturnCommandService.create. Permission RETURN:CREATE. Tenant scoped.

Source: return-command.service.ts.

Guards before the transaction​

  • type === RTO throws return.error.rtoInternalOnly unless the caller is createFromForwardRto (allowInternalRto).
  • The order must exist for the tenant and not be soft-deleted.
  • A CANCELLED order throws return.error.cannotReturnCancelledOrder.
  • For non-RTO, if the tenant has any ReturnPolicy rows, each line is checked with resolveReturnPolicy (category, then channel, then tenant default). isReturnable false throws return.error.itemNotReturnable. Days since deliveredAt, else fulfilledAt, else orderDate, must be within daysAllowed or the call throws return.error.returnWindowExpired. If no policy matches a line, that line is skipped. If the tenant has no policies at all, the window check does not run.
  • RTO skips the policy block. The comment says a courier inbound must not be refused by a customer window.
  • Each line’s quantityRequested must be greater than 0 and no more than quantityShipped - quantityReturned.

What is written​

  • Return number from allocateDocumentNumber with prefix RET.
  • Status REQUESTED.
  • Lines copy fulfillmentLineItemId and stockLotId from the newest outbound shipment item for that order line, when one exists.
  • shipmentId and warehouseId are set only when every requested line shares one shipment or one fulfillment warehouse. Otherwise the warehouse falls back to order.warehouseId.
  • If the order is not already RETURN_REQUESTED, the order status is set to RETURN_REQUESTED, history is inserted, and order.status.changed is enqueued.
State machine bypass

This write does not call isValidOrderTransition. An order in PENDING can be stored as RETURN_REQUESTED even though the order map does not list that edge. The map is not what this method runs.

return.requested is emitted in-process with the transaction client on the event. It is not an outbox type. No @OnEvent('return.requested') was part of the earlier listener scan.

Failure​

A throw before commit rolls the return and the order status change back together. Policy and quantity errors are HTTP 400 and do not insert a return.