How it fits together

Order to cash

An order can reach you three ways — over the counter, through the online store, or as an invoice you raised. They look similar and they behave very differently. Here is what each one does to your stock, your money and your books.

User guide › Order to cash

The one distinction that explains everything

The three entry points differ on two questions: when is stock reduced, and when is revenue recognised. Get those straight and the rest follows.

Entry pointStockMoneyRevenue posts
Register sale Reduced at checkout Taken at the counter Immediately — the sale is the payment
Online store order Reduced when the order is placed (reserved) Now, or later When the order becomes paid — not when it's placed
Invoice Not touched at all Later, as a separate payment record When the invoice is posted; cash follows on the payment
Invoices don't move stock

This catches people out constantly. The Invoices app is a billing document — customer, line items, tax, total, due date. It has no connection to the product catalog or the stock ledger. If you invoice for physical goods and you also want the stock reduced, the goods have to leave through a stock operation as well. See Stock lifecycle.

Entry point 1 — the register

The cashier surface at /pos. Pick a register, open the drawer with an opening float, build the cart by tapping product cards or scanning barcodes, choose a payment method, take the money.

  1. Checkout runs as one transaction

    Nothing is half-done. In a single atomic step it:

    • Computes the totals on the server. Line subtotal, discount, tax, total. What the till showed is informational; the receipt shows what the server calculated.
    • Locks and decrements each product's stock row at the register's warehouse. Two cashiers ringing the last unit serialise — the second waits, then either succeeds or is refused.
    • Writes a sale movement per line into the stock ledger.
    • Creates the Sale and its Sale Lines, with a receipt number of the form REGISTER-YYYYMMDD-NNNN.
    • Snapshots the cost relieved onto every line and as a header total, so a later refund reverses at the cost the goods actually sold at.
    • Bumps the open drawer session's totals, if one is open.

    Every attempt carries an idempotency key, so a retry — a double-click, a dropped connection, a buffered offline mutation firing twice — returns the original sale rather than ringing it again.

  2. Stock impact

    Products with a stock row are decremented. Products without one are untracked — services, prep items, made-to-order dishes — and sell freely with nothing to decrement. A tracked product that's short is refused unless the register has Allow overselling switched on. Products set to make to order consume their recipe's ingredients instead of their own stock; see Make to stock.

  3. Ledger impact

    A completed sale posts a balanced revenue journal — provided you've enabled it, see below:

    • Dr Cash for the total. A cash sale debits cash on hand; card, mixed or other debits the cash-or-bank account you configured.
    • Cr Sales revenue for the total minus tax.
    • Cr VAT payable for the tax, when there is any.

    Revenue is derived as total minus tax, so the entry balances however the till stored its subtotal and discount. Under perpetual inventory the journal gains a second, self-balancing pair: Dr Cost of goods sold / Cr Inventory for the cost the sale relieved. No cost on the products means no cost leg.

  4. End of shift

    The Z report totals the session by status and by payment method, with a sale-by-sale list. Closing the drawer records the counted cash and computes the variance against expected — the over-or-short the cashier reconciles in person. Cash paid in and out during the shift is included in the expected figure.

Entry point 2 — the online store

The storefront sells the same product catalog out of the same warehouses through the same checkout engine as the register. What differs is the timing, because on the web the order and the money don't arrive together.

Every web order creates two linked records: a POS Sale (the transaction that moved the stock) and an Order (the customer-facing document with the fulfilment lifecycle, at /store-orders). The order runs placed → paid → ready → fulfilled, with cancelled available throughout, and it's usually worked as a kanban queue.

  1. The shopper checks out

    Stock is reduced immediately — the same atomic decrement and oversell guard the cashier gets. This is deliberate: reserving at placement means a second shopper can't drain the last unit out from under a pending order.

    No revenue is posted yet. The order sits at placed, which means reserved and awaiting payment.

  2. If you take payment through a gateway

    The shopper is sent to the payment provider before anything is created. Only when the provider confirms the charge — through a signature-verified webhook — is the order placed, at status paid. Stock is decremented for a paid cart only, and revenue posts at creation. Duplicate webhook deliveries are a no-op.

    The gateway is yours: your keys, your account, money straight to you. Store payment settings are completely separate from the platform's own billing.

  3. If the order is offline / manual

    It's placed as reserved. When you take the money — bank transfer landed, cash on collection — you drag the order to Paid (or straight to Ready or Fulfilled; both imply paid). That transition is what posts the revenue journal, using exactly the same posting the cashier's sale uses. It's idempotent, so a double-flip or a gateway retry can't double-book.

  4. Fulfil it

    Ready is the "your order is ready" state for pickup or dispatch; Fulfilled closes it. Each transition sends the customer an email where you've connected a mailbox, and the store posts a staff notification on every new order.

    These are lifecycle flags, not stock events — stock already moved at placement.

  5. If it's cancelled

    Dragging an order to Cancelled voids the linked sale: stock is restored with reversal movements, and the ledger is reversed. If the order was never paid, nothing was posted, so the reversal correctly does nothing to your books.

Entry point 3 — an invoice

Invoices are for work you bill rather than sell over a counter: services, project milestones, business customers on terms. An invoice carries a customer, line items, currency, subtotal, tax, total, issued and due dates, and a status of draft, sent, paid, overdue or void.

  1. Raise the invoice

    Create the invoice, add line items, issue it. Stock: nothing happens. There is no link between an invoice line and the product catalog's stock ledger.

  2. Post it to the ledger

    Posting an invoice recognises the receivable and the revenue: Dr Accounts receivable for the total, Cr Sales revenue for the net, and Cr VAT payable for the tax.

    If the invoice carries an explicit tax amount, that number is used as-is — your figures are never re-derived. If it carries none and your workspace has a default VAT treatment configured, the total is split or grossed up according to that setting.

  3. Record the payment

    Payment is a separate record on the Payments entity, linked to the invoice, with an amount, a date, a method (bank, card, cash, cheque, other) and a reference. That's what closes the loop: Dr Cash / Cr Accounts receivable — cash method hits cash on hand, anything else hits the configured bank account.

    Because payment is its own record, part payments are natural: several payments against one invoice, each posting its own journal, and the receivable balance tells you what's left.

The invoice's own status field is a workflow flag you drive — marking one Paid doesn't move money. The payment record does.

Getting revenue into the ledger

None of these post to accounting until you switch posting on. That's on purpose: plenty of workspaces run the operational side for months before anyone wires up books, and silently generating journals for them would be worse than useless.

There are three ways to post, and they can be combined:

MethodWhereFires when
Auto-action toggle Settings → Reconciliation → Auto-actions The record is created. One toggle per document type — POS sale, invoice, payment, bill, expense, goods receipt, supplier return — and every one starts off.
An automation you build The entity's automations Any trigger you like. This is how you post an invoice on "status becomes Sent" rather than the moment a draft is created.
The manual button On the record itself When you click it. Useful for backfilling, or for workspaces that want a human in the loop.
Posting is idempotent

A journal is keyed to the record it came from. Re-firing an automation, clicking the manual button on something already posted, retrying a checkout, or receiving the same gateway webhook twice all collapse onto the same single journal. You can't double-count by trying twice.

Everything about which accounts get used lives in Accounting — the chart comes from your country pack, and the receivable, payable, cash, VAT, revenue, COGS and inventory accounts are all settings you can re-point.

Money going back out

ActionStockLedger
Void a sale — the whole receipt was a mistake Every line goes back on the shelf with reversal movements; the sale flips to voided The original journal is reversed in full and marked as reversed, with the two linked.
Refund a sale — line by line, part or all The returned quantities go back, with return movements. Returned quantity is tracked per line so later partial refunds know what's left. The sale only flips to refunded when every line is fully returned. A new journal for exactly what was refunded: Dr Revenue, Dr VAT, Cr Cash — plus Cr COGS / Dr Inventory for the goods, under perpetual. Several partials sum to the full reversal without overlapping.
Cancel a store order The linked sale is voided — stock restored Reversed if the order had been paid and posted; nothing to do if it hadn't.

All of this is guarded: if the original sale never reached the ledger — because posting was off when it sold — no reversal is posted either. You can't create a one-sided entry by refunding something the books never saw.

When the money doesn't line up

"Sales are ringing but Journals is empty"

The Post POS sale to ledger auto-action is off. Every posting toggle ships off; switch it on under Settings → Reconciliation → Auto-actions and the next sale appears. Sales made before that point won't back-fill automatically — post them from the record if you need them.

Also check that Accounting is installed and configured, and that the sale's date lands in a period that's still open. Posting is deliberately best-effort: if the period is locked, the sale still completes and the journal doesn't. Your takings are never held hostage to the books.

"A web order was placed but there's no revenue"

Correct, and intended. A placed order is reserved, awaiting payment — the stock is held for the customer but no revenue is recognised, because nobody has paid. Move the order to Paid (or Ready, or Fulfilled) and the journal posts then.

"A reserved order is already in my POS sales total"

It is, and this is a known asymmetry. Reserving stock creates the sale record at placement, so it counts in POS sales and session totals from that moment, while its revenue is correctly deferred to payment. The money is right; the unit count runs ahead. If you reconcile takings against the sales list, work from the ledger or from order status rather than the raw sale count.

"The invoice is marked Paid but cash never moved"

The status field is a label. Cash moves when you create a Payment record against the invoice — that's what posts Dr Cash / Cr Receivables. If your receivables balance looks too high, look for invoices marked paid with no payment record behind them.

"I invoiced for goods and stock didn't change"

Invoices have no stock side. If you bill for physical goods, the goods still need to leave through a stock operation — sell them at the register, or record the despatch as a stock adjustment. Deciding which one is a workflow choice worth making once and applying consistently.

"The sale posted to the bank account, not the till"

The payment method drives the cash side. A cash sale debits cash on hand; card, mixed and other debit whatever you've configured as the cash-or-bank account. If you want card takings in their own clearing account, re-point the cash account setting or split them with a manual journal at end of day.

"There's no cost-of-sales leg on my sales"

Three things all have to be true: inventory method is perpetual, the products carry a cost, and the goods were actually in stock when they sold. Any of them missing and the sale relieves nothing. Untracked products and the oversold portion of a backordered line both relieve zero by design — cost is never relieved for units that were never capitalised.

"Two journals for one sale"

Shouldn't be possible from the same document — posting is deduplicated per record. Two journals almost always means two records: a sale rung twice, or an order and a separate manual invoice for the same transaction. Check the receipt numbers.

"A partial refund didn't change the sale's status"

Working as intended. A sale stays completed until every line is fully returned, at which point it flips to refunded. The refunded quantities are tracked per line, so the sale record always knows what's still outstanding — and the ledger has a separate refund journal for each portion.

"The customer's email never arrived"

Store order emails send through the workspace's transactional sender. If no mailbox is connected they skip silently — the store keeps taking orders, it just doesn't email. Connect a mailbox under integrations and the confirmations start flowing. Receipts from the register are a separate, on-demand send from the receipt screen.

Where to go next