@devx-retailos/order
v0.0.4
Published
Order module for retailOS. Manages POS orders, line items, and payments with built-in discount validation.
Downloads
629
Keywords
Readme
@devx-retailos/order
POS order management for Medusa v2: orders, line items, payments, discount validation, advance orders with deposits and fulfillment stages, and daily / day-close reporting.
Part of retailOS, a Medusa v2 SDK for offline-store POS systems. Each @devx-retailos/* package is an independently installable Medusa plugin; a brand backend composes the ones it needs in medusa-config.ts.
Installation
npm install @devx-retailos/orderPeer dependencies: @medusajs/framework and @medusajs/medusa ^2.15.0. @devx-retailos/discount is an optional peer — required only if you place orders with discount_id or coupon_code.
Setup
// medusa-config.ts
module.exports = defineConfig({
plugins: [
{ resolve: "@devx-retailos/rbac", options: {} },
{ resolve: "@devx-retailos/order", options: {} },
],
})The module registers under the key retailos_order (exported as ORDER_MODULE) and registers its permission keys with @devx-retailos/rbac at boot.
Usage
import { ORDER_MODULE, type OrderModuleService } from "@devx-retailos/order"
const orders: OrderModuleService = container.resolve(ORDER_MODULE)
// Place a standard order (discount validated via @devx-retailos/discount if provided)
const { order } = await orders.placeOrder({
organization_id: "org_...",
store_id: "store_...",
currency: "INR",
line_items: [{ id: "tmp-1", name: "T-Shirt", quantity: 2, unit_price: 499 }],
coupon_code: "WELCOME10",
placed_by_employee_id: "emp_...",
})
// Confirm: records the payment, sets status "confirmed", and pushes the order
// to the registered ecommerce adapter (status becomes "synced_to_ecommerce")
const result = await orders.confirmOrder(order.id, {
payment: { method: "cash", amount: 998 },
})Advance orders
Passing advance_deposit_amount to placeOrder creates an advance order: the deposit is recorded, balance_due is tracked, and the order enters the first stage of its stage provider. Advance orders cannot use confirmOrder — collect the remainder with collectBalance:
const { order } = await orders.placeOrder({
// ...as above
advance_deposit_amount: 500,
promised_fulfillment_date: new Date("2026-07-01"),
})
await orders.transitionStage(order.id, "processing", { changed_by_employee_id: "emp_..." })
await orders.collectBalance(order.id, [{ method: "card", amount: 1500 }])listAdvanceOrders({ organization_id, fulfillment_stage?, promised_before?, promised_after? }) queries open advance orders.
Reports
const daily = await orders.dailyReport({ organization_id: "org_...", store_id: "store_...", date: "2026-06-11" })
// → order_count, subtotal, discount_total, tax_total, grand_total, payment_methods[]
const close = await orders.dayCloseReport({ organization_id: "org_...", store_id: "store_...", date: "2026-06-11" })
// → daily report + closed_at, opening_total, closing_total, variancetotalsForStore({ organization_id, store_id?, status? }) returns simple revenue aggregates.
Extension points
OrderEcommerceAdapter
Pushes confirmed POS orders to an ecommerce platform (Shopify, WooCommerce, …). Register an implementation in the container under the ORDER_ECOMMERCE_ADAPTER key ("order_ecommerce_adapter"). If no adapter is registered, confirmed orders stay at status "confirmed" and can be retried later; sync failures are recorded in the order's metadata.
import type { OrderEcommerceAdapter, NormalizedOrderForEcommerce } from "@devx-retailos/order"
const adapter: OrderEcommerceAdapter = {
async createOrder(order: NormalizedOrderForEcommerce) {
return { ecommerce_order_id: "ext_123" }
},
async cancelOrder(ecommerce_order_id: string) {},
}AdvanceOrderStageProvider
Defines the fulfillment stages of advance orders. The built-in DefaultStageProvider ships stages pending → processing → ready → fulfilled / cancelled (fulfilled and cancelled are terminal).
import type { AdvanceOrderStageProvider } from "@devx-retailos/order"
const madeToOrder: AdvanceOrderStageProvider = {
name: "made-to-order",
stages: () => ["pending", "in_production", "qc", "ready", "fulfilled", "cancelled"],
isTransitionAllowed: (from, to) => from !== "fulfilled" && from !== "cancelled",
}
orders.registerStageProvider(madeToOrder)
// then: placeOrder({ ..., advance_deposit_amount: 500, stage_provider: "made-to-order" })Permissions
Registered via @devx-retailos/rbac (also exported as ORDER_PERMISSIONS from @devx-retailos/order/permissions):
| Key | Description |
| --- | --- |
| order.read | View orders and order details |
| order.create | Place new orders |
| order.update | Update order status, notes, and metadata |
| order.cancel | Cancel orders |
| order.refund | Mark orders as refunded |
| order.void | Void orders |
| order.report | View order totals and revenue aggregates |
| order.discount_apply | Place orders with a discount or coupon attached |
| order.advance_stage | Transition an advance order's fulfillment stage |
| order.collect_balance | Capture balance payment on an advance order |
| order.invoice | Generate and download GST-compliant PDF invoices |
| order.report.daily | View daily sales report and revenue aggregates |
| order.report.day-close | Run the end-of-day Z-report and close the trading session |
API routes
All routes live under the authenticated Medusa admin scope. The report routes enforce their permission via @devx-retailos/rbac.
| Method | Path | Purpose | Permission |
| --- | --- | --- | --- |
| GET | /admin/retailos/orders | List orders (filterable) | — |
| POST | /admin/retailos/orders | Place an order (standard or advance) | — |
| GET | /admin/retailos/orders/:id | Retrieve order + line items + payments | — |
| POST | /admin/retailos/orders/:id | Update status / notes / metadata | — |
| DELETE | /admin/retailos/orders/:id | Cancel an order | — |
| POST | /admin/retailos/orders/:id/confirm | Confirm + push to ecommerce adapter | — |
| POST | /admin/retailos/orders/:id/balance | Collect balance on an advance order | order.collect_balance |
| PUT | /admin/retailos/orders/:id/stage | Transition an advance order's stage | order.advance_stage |
| GET | /admin/retailos/orders/totals | Revenue aggregates per org/store | — |
| GET | /admin/retailos/orders/reports/daily | Daily sales report | order.report.daily |
| POST | /admin/retailos/orders/reports/day-close | End-of-day close report | order.report.day-close |
Errors
All extend RetailOSError from @devx-retailos/core; switch on err.code:
RETAILOS_ORDER_NOT_FOUNDRETAILOS_ORDER_INVALID_STATUSRETAILOS_ORDER_DEPOSIT_EXCEEDS_TOTALRETAILOS_ORDER_INVALID_STAGE_TRANSITIONRETAILOS_ORDER_NOT_ADVANCERETAILOS_ORDER_CONFIRM_BLOCKED_FOR_ADVANCE
Related packages
@devx-retailos/core— shared types,RetailOSError,Logger, permission registry.@devx-retailos/rbac— roles and permission checks the order routes rely on.@devx-retailos/discount— discount/coupon validation used byplaceOrder(optional).@devx-retailos/payments— pluggable payment adapters, split tenders, refunds.@devx-retailos/invoice— GST-compliant PDF invoices generated from these orders.@devx-retailos/products— catalog mirror that supplies product/variant data.
License
MIT
