Purchase Orders
A purchase order (PO) is how you buy stock from a vendor. It records what you have agreed to buy, follows it from the moment you commit to the vendor through every delivery that arrives, and (when you want it to) feeds what you receive into inventory. A single PO buys either raw materials or finished products, never both. That one choice decides which inventory it touches.
What it does
- Track your vendor orders. At its core a PO is a record: which vendor, what you ordered, at what price, when you placed it, and what has actually shown up so far. That record stands on its own, so a team that just wants its buying organised gets a clean log of commitments and deliveries, with editable dates and costs, and no inventory required.
- Feed inventory. When you do run inventory, the PO keeps your stock honest.
Placing the order books the quantity as on order; receiving it moves that
quantity to on hand. Each PO targets one inventory, set by its
targetType:materialsfor raw inputs,finished_goodsfor resale products.
How it works
A PO is always in exactly one status. What changes that status falls into three buckets: some you control by hand, some happen automatically as deliveries arrive, and two are endpoints. The table below lists them by that grouping; the sections that follow cover what it all does to inventory and to the dates.
The statuses
| Status | Type | What it means |
|---|---|---|
| Planning | Manual | Still preparing the order. Nothing is committed and inventory is untouched. |
| Placed | Manual | Committed to the vendor. The ordered quantity now shows as on order. |
| In Transit | Manual | The goods are on their way. Informational today: it behaves like Placed. |
| Partial | Receipt-driven | The first delivery has arrived and receiving is open. Every receipt lands here, whatever the quantity. |
| Received | Manual | Mark this when you are done taking deliveries, however much arrived. Reverts to Partial to receive more. |
| Completed | Endpoint | A received order that has been closed. |
| Cancelled | Exit | An order stopped before goods arrived (only before Partial). Can be reactivated. |
The manual statuses carry no deliveries yet, so you can move between them freely in either direction to fix a mistake. Partial is the only one the receipts drive.
Moving between them
- By hand, both ways. Planning, Placed and In Transit are yours. Step forward as the order progresses, or step back if you moved too far.
- By receipts. Each delivery is a receipt with its own date and lines. The first one moves the PO to Partial, whatever the quantity, and further receipts keep it there. Delete a receipt and the status walks back on its own, staying in Partial until the last one is gone, then returning to where the order was before anything arrived.
- Closing receiving. When you are done taking deliveries, mark the PO Received by hand. This is yours to decide: it does not wait for the quantities to match, so an order can be closed short or over. Reopen it to Partial if more turns up.
- Completing. A received PO can be marked Completed, and reverted to Received if that was a slip.
- Cancelling. Cancel stops an order any time before goods start arriving (any status before Partial). Once receipts exist it can no longer be cancelled. A cancelled PO can be reactivated, and it returns to wherever it last was.
Effect on inventory
| What you do | Effect on the ledger |
|---|---|
| Place the order (leave Planning) | books the ordered quantity as on order |
| Record a receipt | moves the received quantity to on hand |
| Cancel | reverses the on order quantity back to zero |
It feeds the materials or
finished-goods ledger per targetType, and
every entry carries the PO number as its reference.
One rule keeps the ledger tidy: anything you undo is erased, not stamped with a counter entry. Move a PO back out of Placed and its on order booking is simply removed. Delete a receipt and its on hand movement is removed. The only lasting reversal is a cancellation, and even that disappears if you reactivate the order. The ledger always reflects only what is true right now.
Corrections follow the same idea. A receipt line's quantity, unit cost, lot and expiration are editable in place: edit the quantity and the same stock movement restates to the new figure (no extra rows, no counter entries), and the PO's status and settle recompute as if the delivery had always said so. Lot and expiration travel with the movement the same way. Cost never sits on the ledger at all: it is read live from the receipt line, so a price fix needs no propagation. A Completed PO is closed for good; reopen it before editing or deleting its receipts.
Closing receiving settles the books. When you mark a PO Received it rarely matches the order exactly, so the gap between ordered and received is trued up with a settle entry: close 3 against an order of 10 and the remaining 7 stops counting as on order; receive 12 against 10 and the 2 of excess is cleared the same way. Either direction, on order lands at 0. Reopen the PO to Partial and that settle entry is removed, restoring the open balance. Nothing inflates on hand, only what actually arrived is ever counted as received.
Dates
Every PO carries dates, designed to stay truthful with the least fuss.
- Order date is yours. It defaults to today when you create the PO and you can change it whenever.
- Status dates (placed, in transit, and so on) stamp themselves as the PO reaches each status, but stay editable afterwards so you can correct them.
- Partial date comes straight from the receipts: the first receipt's date. Change that receipt's date and it follows. The Received date stamps when you mark the PO Received and stays editable like the other status dates.
Each ledger entry takes its date from the order event that produced it: the on-order booking from the placed date, each receipt's stock movement from that receipt's own date, and the settle written at close from the received date. These are business dates, so editing one moves its entry with it: change the placed date and the on-order entry re-dates, change a receipt's date and its movement follows. The record-of-entry timestamp never moves. That keeps the stock history reading in true business-date order, which is what positions and the cost model sort by.
See also
Drive purchase orders through the REST API or the MCP server.