Shop It Docs
Developer Resourcesorder

Order Module Feature List

Order feature surfaces, queue behavior, and payment lifecycle.

Order Module - Feature List

1. Feature Overview

Order uses a mixed execution model:

  • synchronous initiation for checkout and buy-now payment start
  • asynchronous processing for cancellation, refund processing, payment reconciliation/retries, and auto-cancel

The customer/mobile surface is authenticated and mounted through the shared mobile composition layer.

2. Route Ownership and Surfaces

SurfaceRoute prefixOwner
Customer API/api/ordersOrderCustomerController
Mobile-composed customer API/api/mobile/ordersMobileModule composition of OrderCustomerModule
Admin API/api/admin/ordersOrderAdminController
Payment redirect callbacks`/api/payments/redirect/:paymentId/successfailure`
Payment result page/api/payments/resultPaymentResultController

Swagger tags used by order controllers:

  • Orders (Mobile)
  • Orders (Admin)

3. Admin Feature Matrix

CapabilityEndpointAuthZ
List orders (paginated + filters)GET /api/admin/ordersOrders_READ
Order detailGET /api/admin/orders/:idOrders_READ
Async request statusGET /api/admin/orders/requests/:requestIdOrders_READ
Cancel order (async command)POST /api/admin/orders/:id/cancelOrders_UPDATE
Process refund approve/reject (async command)POST /api/admin/orders/:id/process-refundOrders_UPDATE
Add admin notePOST /api/admin/orders/:id/notesOrders_UPDATE
Activate care package subscriptionPOST /api/admin/orders/:id/activate-care-packageCarePackageSubscriptions_UPDATE
Assign serial number to order itemPATCH /api/admin/orders/:id/items/:orderItemId/serialOrders_UPDATE

4. Customer/Mobile Feature Matrix

CapabilityEndpointRuntime mode
Checkout from active cartPOST /api/orders/checkoutSynchronous payment-init (200)
Buy now for single productPOST /api/orders/buy-nowSynchronous payment-init (200)
Order historyGET /api/ordersSynchronous read
Order detailGET /api/orders/:idSynchronous read
Async request statusGET /api/orders/requests/:requestIdSynchronous read
Cancel orderPOST /api/orders/:id/cancelAsync command accepted (202)
Request refundPOST /api/orders/:id/request-refundSynchronous mutation

Notes:

  • idempotency-key header is required for checkout and buy-now.
  • Equivalent mobile endpoints are available at /api/mobile/orders/... via routing composition.

5. Key Business Rules

  • Physical products (productKind = "physical") create orders with orderType: "physical"
  • Checkout requires an active cart with at least one valid sellable product.
  • Checkout and buy-now both require shipping district selection on the active cart.
  • Mobile order detail (GET /api/mobile/orders/:id) includes order-level receiver snapshot fields (receiver, contactNumber) and fulfillmentStatus for shipping timeline rendering.
  • Cancellation and refund state transitions are gated by current order status.
  • Monetary values are stored in integer minor units (for Stripe, USD cents) and guarded by DB non-negative constraints.

6. Physical Product Support

6.1 Supported Product Types

Product Type (productKind)Cart AllowedBuy-now AllowedOrder TypeCOD Allowed
physicalphysical
digitaldigital❌ (ORDER_COD_PHYSICAL_ONLY)
care_package✅ (via care-package cart module)care_package (or mixed if combined with physical)❌ (ORDER_COD_PHYSICAL_ONLY)

Buy-now restriction: care_package items are blocked from buy-now. Use cart checkout for care package purchases. Error code: ORDER_BUYNOW_CARE_PACKAGE_NOT_ALLOWED.

6.2 Error Codes

| Error Code | HTTP | Trigger | |---|---|---|---| | ORDER_BUYNOW_CARE_PACKAGE_NOT_ALLOWED | 422 | Buy-now attempted with care_package productKind | | ORDER_COD_PHYSICAL_ONLY | 400 | COD checkout attempted on digital-only or care-package-only cart or buy-now product | | ORDER_NOT_COD_METHOD | 400 | Admin cash collection attempted on non-COD order | | CART_CARE_PACKAGE_ITEM_NOT_PHYSICAL | 422 | Cart item is not a physical product when attaching care package | | ORDER_FULFILLMENT_NOT_PHYSICAL_TYPE | 400 | Fulfillment advance on non-physical/mixed order | | ORDER_FULFILLMENT_NOT_DIGITAL_TYPE | 400 | Digital delivery on non-digital/mixed order | | ORDER_ACTIVATE_CARE_PACKAGE_NOT_APPLICABLE | 400 | Activate care package on non-care_package order | | ORDER_NOT_PAID | 400 | Action requires paid order status | | ORDER_SERIAL_ITEM_NOT_PHYSICAL | 422 | Serial number assigned to non-physical item | | ORDER_SERIAL_ALREADY_ASSIGNED | 409 | Item already has a serial number assigned | | ORDER_SERIAL_AFTER_DELIVERED | 422 | Serial assignment after order is delivered | | ORDER_SERIAL_DUPLICATE | 409 | Serial number already in use for another item |

6.3 Care Package Product Support

Business rules for care package orders:

  • Care-package-only carts produce orderType = "care_package".
  • No shippingDistrict required; shippingFee = 0 for care-package-only orders.
  • Mixed carts (physical + care_package) produce orderType = "mixed"; shipping required for physical items.
  • Checkout creates care_package_subscriptions rows with status = "pending_activation".
  • Activation is triggered via BullMQ after payment success.

7. State Models

7.1 Order status lifecycle

Online orders: created -> payment_pending -> paid / payment_failed -> cancelled / refund_requested -> refund_approved / refund_rejected

COD orders: created -> payment_pending with paymentStatus = "cod_pending" after reservation. Admin cash collection changes paymentStatus to "cod_collected" without changing orderStatus to "paid".

Warranty coupling:

  • Warranty claims and warranty-status reads are allowed only while the linked order remains warranty-eligible.
  • refund_requested and refund_pending do not block warranty yet.
  • refund_approved, cancelled, and payment_failed block warranty operations.
  • COD orders remain warranty-ineligible until admin collection changes paymentStatus from cod_pending to cod_collected.

7.2 Actor provenance in status history

order_status_history writes use explicit actor model:

  • customer: customer-initiated state changes
  • admin: admin-user initiated changes (includes subadmins)
  • system: background jobs, webhook side effects, auto-cancel/reconciliation markers

7.3 Payment initiation model

Checkout and buy-now return one of:

  • initiationType = form_post
  • initiationType = redirect
  • initiationType = cod — COD only; no gateway redirect. Order remains payment_pending with paymentStatus = "cod_pending" until admin collection. Frontend navigates to returnUrl directly.

That COD pending window is fulfillment-eligible but not warranty-eligible.

8. Caching Strategy

Read-side keyspaces:

  • order:customer:list:
  • order:detail:
  • order:admin:list:
  • order:admin:detail:

Configured TTLs:

  • ORDER_HISTORY_CACHE_TTL_SECONDS (default 120)
  • ORDER_ADMIN_CACHE_TTL_SECONDS (default 60)

Invalidation triggers:

  • customer/admin async mutations invalidate order list/detail keyspaces

9. Rate Limiting

Customer operation limits:

  • ORDER_CHECKOUT_RATE_LIMIT (default 10)
  • ORDER_CANCEL_RATE_LIMIT (default 10)
  • ORDER_REFUND_REQUEST_RATE_LIMIT (default 5)
  • ORDER_CHECKOUT_RATE_WINDOW_SECONDS (default 60)

Admin operation limits:

  • ORDER_ADMIN_OPERATION_RATE_LIMIT (default 120)
  • ORDER_ADMIN_RATE_WINDOW_SECONDS (default 60)

Safety behavior:

  • Redis sliding-window checks are used for customer and admin operations.
  • Limit breaches throw RateLimitExceededException and return RATE_LIMIT_EXCEEDED.
  • Retry/backoff windows and DLQ warning thresholds are environment-controlled in processing runtime.

10. Queue/Worker Features

WorkerQueueJobs
OrderProcessorordersorder.payment_success, order.payment_failed, order.payment_retry, order.cancel, order.process_refund, order.auto_cancel
OrdersMaintenanceProcessororders_maintenanceorders_maintenance.dispatch_outbox, orders_maintenance.cleanup_outbox
CarePackageProcessorcare_packagecare_package.activate_subscription, care_package.send_expiry_reminder, care_package.expire_subscriptions, care_package.cancel_subscription

Maintenance behavior:

  • outbox dispatch with queue ownership filtering (orders, orders_maintenance, cart)
  • retention cleanup for completed/failed outbox rows
  • failed-job threshold monitoring with alert logs

Flow diagram:

11. Error UX Mapping

errorCodeTypical HTTPUX action
ORDER_ACTIVE_CART_NOT_FOUND404Prompt user to add items to cart before checkout
ORDER_CART_EMPTY400Show cart-empty message and CTA to browse products
ORDER_PRODUCT_NOT_AVAILABLE400Refresh catalog and hide unavailable product
ORDER_IDEMPOTENCY_MISMATCH400/409Retry with a fresh idempotency key
ORDER_CANCEL_NOT_ALLOWED400Disable cancel CTA for current status
ORDER_NOT_PENDING_REFUND400Show current status and hide process-refund CTA
ORDER_ASYNC_REQUEST_NOT_FOUND404Stop polling and refresh order detail
ORDER_NOT_FOUND404Redirect to order history with not-found notice
RATE_LIMIT_EXCEEDED429Backoff and retry after short delay
ERR_CONFIG_INVALID503Treat as server issue and show generic retry support message

12. Release/QA Checklist

  • Checkout path returns payment-init payload with valid initiationType and gatewayPayload.
  • Buy-now path enforces product eligibility and promo-code validation behavior.
  • Customer cancel returns 202 and request is pollable via /orders/requests/:requestId.
  • Admin cancel/process-refund paths enforce Orders_UPDATE permission.
  • Status history rows capture actor provenance (customer/admin/system) correctly.
  • Processor jobs (order.payment_*, cancel, refund, auto-cancel) update order state and invalidate caches.
  • Outbox dispatch/cleanup cron pipeline runs on orders_maintenance queue.
  • Mobile-composed routes (/api/mobile/orders/...) resolve through MobileModule routing.
  • Payment redirect callbacks and /api/payments/result handoff are functional.
  • Care package items are rejected from buy-now with ORDER_BUYNOW_CARE_PACKAGE_NOT_ALLOWED.
  • Admin POST /:id/activate-care-package validates order type and subscription pending status.
  • Admin PATCH /:id/items/:orderItemId/serial assigns serial number and rejects duplicates with ORDER_SERIAL_DUPLICATE.

13. Integration Flows

13.1 Checkout Flow

A customer completes checkout from an active cart with payment initiation.

  1. Customer calls POST /api/orders/checkout with idempotency-key header.
  2. System validates active cart exists and contains valid sellable products.
  3. System calculates order totals from cart items and applies any applied coupon discount.
  4. System creates order with status payment_pending.
  5. System creates order_status_history entry with actor customer.
  6. System calls payment gateway to initiate payment, returning initiationType (form_post or redirect) with gatewayPayload.
  7. Cart remains visible in customer flow while payment is pending/failed.
  8. Cart is cleared only after payment success processing (order.payment_success -> cart clear job).
  9. Order is now awaiting payment completion via gateway callback or redirect handling.

13.2 Admin Refund Flow

An admin processes a customer refund request after order payment was successful.

  1. Customer calls POST /api/orders/:id/request-refund to submit refund request.
  2. System updates order status to refund_requested.
  3. Admin calls GET /api/admin/orders/:id to review order and refund request.
  4. Admin calls POST /api/admin/orders/:id/process-refund with { action: "approve" | "reject", remarks: string }.
  5. If approve: system immediately sets order to refund_approved (manual refund completed).
  6. If reject: system sets order to refund_rejected, customer can view rejection via order detail.
  7. No payment gateway refund API call is made in this phase.

Warranty effect:

  • Approval makes the order permanently warranty-ineligible.
  • Rejection keeps the order warranty-eligible, subject to the normal payment and expiry checks.

Related payment docs:

  • apps/fumadocs/content/docs/developer/payment/cart-checkout-flow.mdx

Time fields in this module are stored as timezone-aware values and should be handled as ISO-8601 instants by API consumers.


See Also