Orders

One order record, whatever door the sale came through

A sale taken at the counter, a form filled in on a landing page, a checkout on your storefront and an order typed in by a member of staff all become the same record, with the same six statuses, the same money fields and the same effect on stock. That sameness is the whole point: it is what lets one report, one debt ledger and one drawer close describe the entire business.

Most inventory problems are really order problems wearing a disguise. Stock is wrong because an order was counted twice. The day's cash does not balance because a split payment was recorded as a single one. A customer says they already paid because the courier collected money on an order a gateway had already charged. Every one of those is a question about the order record, so the order record is where Akkad puts its precision.

An order in Akkad is deliberately not a thin wrapper around a payment. It carries who it is for, where it is going, what it contains at which pack granularity, what it cost you, what it charged, how it was paid, which storefront it arrived from, which cashier drawer it settled into, and a full log of every change anyone made to it. Nothing downstream — debts, the cashbox, carrier handover, the financial report — has to guess.

01

Six statuses, and only two things they can do to stock

There are exactly six statuses, and they divide into two groups by what they mean for your shelves. That division is the mechanism, not a description of it — moving an order between groups is what deducts or restores stock.

StatusStock groupWhat it means in practice
PendingRestores stockTaken, but not yet committed to. Nothing is held against your available quantity.
ProcessingReduces stockThe default for most orders. The goods are spoken for.
ShippedReduces stockHanded to a courier. Carrier reconciliation can move an order on from here on its own.
DeliveredReduces stockCompleted. The default for counter sales and for supermarket orders from any source.
CancelledRestores stockCalled off. Excluded from debts, so a cancelled order never appears as money owed.
ReturnedRestores stockCame back. Also excluded from debts.

Moving an order from a restoring status to a reducing one re-validates availability first, so you cannot quietly confirm an order you can no longer fulfil. Where an item is batch-tracked, restoring returns the quantities to the exact batches they were taken from — the right lots, not just the right number.

02

Four sources, one order book

Every order records where it came from, and the platform uses that for more than reporting: pricing rules target channels, and the sensible starting status differs by door.

internal

Internal

Typed in by your own staff in the app — phone orders, walk-in bookings, anything a person enters on behalf of a customer.

landing_page

Landing page

A single-product page with its own form, its own default status and its own default payment method.

website

Website

Your storefront checkout. The order also records which storefront it came from, so an organisation running several sites can tell them apart.

cashier

Cashier

A sale rung up at the counter, linked to the cashier's open drawer session so the shift close can account for it.

The default status knows the business

A counter sale starts at delivered, because the customer already walked out with the goods. Supermarket orders start delivered from any source, for the same reason. Everything else starts at processing.

Which storefront, not just “a storefront”

Orders carry the specific website identifier alongside the source. Running a main store and a second site under a slug means you can still read their performance separately.

03

The money on an order

Each component of a total is stored as its own field rather than being folded into one number, because a merchant arguing about a total needs to see which part they are arguing about.

FieldWhat it holds
Products totalThe sum of the lines before anything else happens.
Total costWhat those goods cost you. Where batches are in play this is the weighted average of the lots actually consumed.
Shipping costResolved by the shipping rules, or entered directly.
Discount type and valueA fixed amount or a percentage, applied by the totals engine.
Promo code and promo discountThe code used and what it took off — separate from rule discounts, and additive to them.
Tax type, value and amountApplied only to the taxable portion of the cart. Percentage tax is capped at 100.
Custom amountA manual adjustment for whatever the situation actually is.
Rounding adjustmentWhat cash rounding moved. Null means the order predates the feature; zero means rounding ran and changed nothing.
Order totalThe authoritative figure, recomputed by the server at creation.
Amount paidA cache written only by the debt ledger, always in the same transaction as the ledger row.

Payment method is one of cash, card, bank transfer or split. A split order carries its own cash amount and card amount as separate figures, which is exactly what a drawer close needs to read. Payment status is unpaid, paid, partial or refunded.

Only a verified gateway can mark an order as paid online

There is a separate paid-online flag, and nothing a person clicks can set it — it is written by the payment gateway's verified webhook and nowhere else. That distinction earns its keep at the customer's door: the cash-on-delivery amount handed to the courier is zeroed when an order is genuinely prepaid, and gating that on the gateway flag rather than on payment status means a member of staff marking an order “paid” in the app cannot change what the courier is told to collect. The same flag drives the PAID stamp on a printed receipt.

04

How an order total is built

Pricing is a fixed sequence, not a bag of adjustments applied in whatever order the code happened to reach them. The sequence is the same on the storefront preview, at the counter, in the app and at order creation — which is why the number a customer is shown is the number they are charged.

Products total first. Then the discount — a fixed amount capped at the products total, or a percentage. Then shipping is added. Then tax, applied only to the taxable lines, with the discount apportioned by the taxable share so a discount on non-taxable goods does not quietly reduce tax on taxable ones. Then the promo code comes off, clamped so it can neither go below zero nor exceed the remaining subtotal. Then any custom amount. Then rounding, always last. The result is floored at zero.

  • Tax lands on the taxable subset only, computed per line rather than on the whole cart.
  • Rule discounts and promo codes are separate levers and both apply, each with its own cap.
  • The storefront shows a preview; the server recomputes the authoritative total when the order is created, and client-sent amounts are never trusted.
  1. 01Products total
  2. 02Apply discount rules
  3. 03Add shipping
  4. 04Tax — on the taxable subset only
  5. 05Subtract promo code
  6. 06Add custom amount
  7. 07Cash rounding — after every other adjustment
  8. 08Floor at zero — a guard, never a calculation
A fixed order of operations, run identically by the app, the storefront preview and the server that actually charges.

05

Rounding to the cash you can actually take

In cash markets a total that ends in an amount nobody carries is a problem you solve at the till twenty times a day. Akkad solves it in the totals engine instead, with a direction and a unit set once for the organisation.

Up, down, or to the nearest

You choose the direction and the unit. Rounding up, down, or to the nearest multiple are genuinely different commercial decisions, and merchants in the same market make them differently.

“Nearest” rounds half away from zero, on purpose

The server rounds halves away from zero rather than using banker's rounding, specifically so that the figure it produces is identical to the one the app's own rounding produces on the device. A one-unit disagreement between the receipt and the server is a support call, and this removes the class of them entirely.

Rounding is always the last step

It runs after discounts, shipping, tax, promo codes and custom amounts, so it lands on the figure the customer actually hands over — not on an intermediate subtotal that later arithmetic would knock off the round number again.

A positive total can never be rounded to zero

Rounding down is bounded. An order worth money stays worth money, whatever the unit is set to.

Null and zero mean different things

A null rounding adjustment means the order predates the feature. A zero means rounding ran and had nothing to change. Keeping them distinct means historical orders are never misread as having been rounded to nothing.

06

The one that saves you at the counter

Submit it twice, get one order

A cashier taps Charge and the screen does not react, so they tap it again. A delivery rider's phone loses signal mid-submit and the app re-flushes when it reconnects. A storefront customer double-clicks Place order. Each of these is one sale that a naive system records as two — two order numbers, two stock deductions, two entries in the day's takings, and a merchant who now trusts none of it. Akkad treats this as a correctness problem with a real answer rather than as an interface problem to be papered over with a spinner.

The client names the request, the database enforces it

Every order submission carries a client-generated request identifier, and the database holds a unique index on that identifier within the organisation. A replay does not create a second order — it returns the original order's number and identifier, flagged as a replay, and stock is not deducted a second time.

Round appends are protected separately

In a restaurant, adding a round to an open table has its own request ledger with its own uniqueness constraint. Retrying a round after a dropped connection returns the original round number rather than inventing a second round three.

Debt payments cannot be double-recorded

Payments against a customer's balance carry the same protection. Where two devices genuinely race, the loser's write is caught and resolved to the winner's row instead of producing two records of the same money.

Order numbers come from a locked counter

Numbers are issued from a per-organisation counter row taken under a lock, and the counter self-seeds from the highest existing number if it is ever missing. Two simultaneous sales on two devices cannot be handed the same order number.

07

Editing an order without losing the thread

Orders change. A customer adds an item, a phone number was mistyped, a delivery moves to a different city. Editing is a whole-order resubmit with last-write-wins semantics, guarded by an edit-orders permission — and everything that changed is recorded.

  1. 1

    The order is resubmitted in full

    Rather than patching individual fields from several places, an edit sends the complete order. Last write wins, which is simple to reason about and simple to explain to staff.

  2. 2

    Every field is diffed against what was there

    The server compares the incoming order to the stored one field by field and writes a human-readable change log entry for what actually moved. You get “this changed to that”, not a timestamp with no content.

  3. 3

    The log is written as keys and rendered in the reader's language

    Change-log entries are stored as translation keys with their variables rather than as finished English sentences, so an Arabic-speaking owner reads the same history in Arabic and an English-speaking manager reads it in English. History is not frozen into whichever language the person editing happened to be using.

  4. 4

    Some changes are silent but still committed

    City and region identifiers, the replacement flag, service type, guest count, a table move and the settle fields do not each deserve a log line, but they do force the edit to be saved. This is deliberate: an edit that only toggles one of them must not be discarded as “nothing changed”.

  5. 5

    Stock is rebalanced, not recalculated from scratch

    Quantity changes and status transitions across the reduce and restore groups adjust stock by the delta. Batch-tracked items go back through first-expiry-first-out, and every movement writes an item log carrying the stock before and after.

08

Working through the day

The orders list is where most people spend most of their time, so filtering and bulk action are treated as core, not as an advanced feature buried in a menu.

Filters that match how you think

Status, date range, source, payment status, service type and creator — combined freely. Date ranges are evaluated in your organisation's own timezone, so “today” means today where you are.

Bulk status updates

Move a selection of orders to a new status in one action, with the same stock consequences as moving them one at a time.

Bulk payment-status updates

Mark a batch of orders paid or partially paid together — the common case after a courier settlement lands.

Dine-in stays out of the way

Restaurant organisations can exclude open dine-in orders, or dine-in entirely, so the delivery desk is not looking at tables mid-service.

Export, search and bulk fetch

Export is permission-gated separately from viewing. Search and bulk fetch back the scan-to-find-an-order flow at the counter.

Attachments and notes

Files attach to an order, and anyone can append a line to its log — so the reason for an unusual order lives on the order rather than in a chat thread.

09

Order tracking that isn't an oracle

Shoppers can check an order themselves, without an account. They supply the order number and a phone number, and the phone has to match one of the two recipient numbers on the order after normalisation. Two facts, both of which a real customer has and a stranger does not.

The design detail worth naming is what happens when it fails. A wrong order number and a wrong phone number return exactly the same response — a plain not-found. That matters, because an endpoint that distinguishes “no such order” from “that order exists but the phone is wrong” is an oracle: anyone can walk the number range and learn how many orders you take. Returning one indistinguishable answer removes that entirely.

The request is a POST rather than a GET for a related reason: query strings end up in web-server access logs, and a customer's phone number should not. When it succeeds, the shopper sees status and timestamps, the carrier's tracking number, recipient name and city, the products total, shipping, the combined discount, any rounding adjustment and the order total, plus the item lines — where a pack line reports the number of packs as its quantity, which is what the customer ordered and how they will count it when the box arrives.

10

Questions

What happens to stock when I move an order from processing back to pending?

It is restored. Pending, cancelled and returned all sit in the restoring group; processing, shipped and delivered all sit in the reducing group. Moving between the groups is what triggers the change, and moving back into a reducing status re-validates that the stock is actually available first.

A cashier tapped Charge twice. Do I now have two orders?

No. The submission carries a client-generated request identifier with a uniqueness constraint in the database. The second submit returns the first order's number, marked as a replay, and stock is not deducted again. The same protection covers restaurant round appends and debt payments.

If I mark an order paid, will the courier stop collecting cash?

No, and that is intentional. The cash-on-delivery amount is zeroed only when the separate paid-online flag is set, and only a verified payment-gateway webhook can set it. Marking an order paid in the app records your side of the money; it does not change what the courier is instructed to collect at the door.

Why is the total on my screen sometimes a few units different from the raw arithmetic?

Cash rounding. Your organisation sets a direction and a unit, and rounding is applied as the final step after discounts, shipping, tax, promo codes and custom amounts. The adjustment is stored as its own field on the order, so you can always see exactly what it moved.

Can I see who changed an order and what they changed?

Yes. Every edit is diffed field by field and written to the order's log in readable form. The entries are stored as translation keys with their values, so each person reads the history in their own language rather than in whichever language the editor was using.

Do orders from my storefront look different from orders taken in the app?

They carry a different source, and storefront orders additionally record which of your websites they came from — but they are the same record with the same fields, the same statuses and the same effect on stock. One list, one export, one set of totals.

Pricing rules

The discount engine that produces the numbers this page's totals engine consumes.

The counter

Drawer sessions, scanning and dine-in — one surface onto this same order book.

Customers and debts

The signed ledger that decides what is actually paid, and what is still owed.

Testez-le sur votre propre catalogue

Commencez par la formule qui vous convient, importez vos articles depuis un tableur, et disposez d'une boutique, d'un comptoir et d'un carnet de commandes opérationnels le jour même.

Formule gratuite disponible. Aucune carte requise pour essayer. L'import amène votre catalogue existant avec vous.