Files
Zumri-Backend/Documentation/API_ORDERS_PAYMENTS.md
Sathira Sri Sathara cd2c1c6d08
CI / test (push) Successful in 10m27s
feat: Implement return and refund functionality in commerce module
- Added return request handling in return.controller.js
- Implemented webhook handling for PayHere payments in webhook.controller.js
- Created models for coupon redemptions, invoices, orders, order items, payments, payment attempts, payment webhook events, refunds, return items, and return requests.
- Developed services for order management, payment processing, refunds, and returns.
- Introduced validation schemas for payment and return requests.
- Created migration scripts for new database tables related to orders, payments, refunds, and returns.
- Added unit tests for order state transitions and PayHere provider functionality.
2026-09-09 12:39:57 +05:30

2.7 KiB

Orders and Payments API

All /api/v1 customer endpoints derive ownership from authentication.

Orders

  • POST /orders/from-checkout converts an owned READY checkout. Conversion locks the checkout, verifies ACTIVE reservations, copies immutable snapshots, converts the cart, and is idempotent by unique checkout ID.
  • GET /orders and GET /orders/:id provide owner-scoped history/detail.
  • POST /orders/:id/cancel releases unpaid reservations. Paid orders require an explicit refund.
  • Admin: GET /admin/orders, GET /admin/orders/:id, cancel, and mark-processing action endpoints.

Legal transitions are centralized. Payment, order, and fulfillment status are separate.

Payments and webhooks

  • POST /orders/:id/payment, GET /orders/:id/payment
  • POST /payments/webhooks/payhere is unauthenticated at the session layer but requires the PayHere merchant hash.

Online browser redirects are never authoritative. A verified webhook must match local payment reference, currency, and DECIMAL amount. Unique provider event IDs make retries idempotent. A first successful event consumes each reservation once, records coupon redemption, marks payment/order paid, and issues invoice metadata. Failure does not consume inventory.

PayHere configuration uses PAYHERE_MERCHANT_ID, PAYHERE_MERCHANT_SECRET, and notify/return/cancel URLs. Stripe has an explicit disabled adapter until its official SDK and webhook secret are configured. No raw card or provider secret is accepted or returned.

Invoices

  • GET /orders/:id/invoice is owner-scoped.

Invoice numbers use the locked ReferenceNumber sequence. Invoice metadata is created once per paid order. PDF generation is reserved for the existing document worker integration; no second PDF/storage subsystem was introduced.

Refunds

  • POST /admin/orders/:id/refunds requires payments.refund and Idempotency-Key.

Requested item quantities and captured totals are locked and validated. A refund never restocks inventory automatically. Provider refund execution remains disabled until provider API credentials/workflows are validated.

Returns

  • Customer: POST /orders/:orderId/returns, GET /returns, GET /returns/:id.
  • Admin: list, approve, reject, mark-received, and complete actions.

The return window uses RETURN_WINDOW_DAYS (default 30). Quantity cannot exceed the remaining purchased quantity. Only accepted RESTOCKABLE items are added through the inventory service; damaged/non-restockable items are not. EXCHANGE records intent only.

Business credit purchasing is intentionally disabled: no locked credit ledger was added without an approved accounting policy. Delivery, loyalty, support AI, and analytics are outside Phase 7.