Purchasing and receiving

Purchase orders from order to delivery, and Quick Product Buy for one-step purchases.

Purchasing in Smooth POS starts with a purchase order (PO) to a supplier and ends when the stock is in your warehouse and the supplier's bill is matched to it. When you just want to record stock you've already bought and paid for, Quick Product Buy does the whole thing in one step.

This guide walks through both, in the app and through the API.

Which one to use

UseWhen
Purchase orderYou order from a supplier and the stock arrives later, maybe in part. You want to track what's on order, receive it, and match the supplier's bill to it.
Quick Product BuyYou've bought the stock and paid for it already (say, a cash-and-carry run). You want it in stock and in your books straight away.

Purchase orders

Statuses

StatusMeaning
OpenCreated and waiting on the supplier. You can still edit it.
ShippedThe supplier has sent it. You can still edit it, for example to record what arrived.
CompleteReceived. Smooth POS records the actual delivery date.
Partial MatchSome of what was received has been invoiced by the supplier.
MatchedEverything received has been invoiced.
CanceledCalled off.

In the app

Accounts → Purchase Orders lists your POs. Create one, pick the supplier, add items with their quantity and cost, and choose the warehouse each line is going to. Open a PO to edit it while it's Open or Shipped.

Through the API

1. Create the PO. Create a purchase order with POST /purchaseorder.json:

{
  "supplier_id": 12,
  "expected_delivery_date": "2026-11-14T00:00:00Z",
  "tags": ["summer-range"],
  "lines": [
    {"item_id": 5521, "warehouse_id": 3, "quantity": 24, "cost": 8.5, "currency": "AUD", "exchange_rate": 1}
  ]
}

It needs a valid supplier (invalid supplier id) and at least one line (no purchase order lines found). The new PO is Open.

2. Mark it shipped (optional). Ship a purchase order: GET /purchaseorder/{po}/ship.json.

3. Record what arrived. Update the purchase order and set each line's actual_quantity to what you received.

🚧

An update replaces the lines

PUT /purchaseorder.json treats the lines you send as the complete list. Lines you leave out are deleted, and lines without an id are added as new lines. Always start from Get a purchase order, change what you need and send every line back. You can only update a PO while it's Open or Shipped.

4. Complete it. Complete a purchase order: GET /purchaseorder/{po}/complete.json. The PO becomes Complete with today's actual delivery date, a purchaseorder_status_change hook fires, and your stock is updated.

📘

Let Smooth POS move the stock

Receiving a PO updates stock levels for you. Don't adjust stock yourself as well, or it'll be counted twice.

Cancel a purchase order works the same way. Ship, complete, cancel and matched only work while the PO is Open, Shipped or Partial Match. Otherwise they fail with purchase order status must be open or shipped.

Match the supplier's bill

Record the supplier's bill as an AP invoice (Create an AP invoice), and link each line to the PO line it pays for with purchase_order_id and purchase_order_line_id.

When the bill is approved (Approve an AP invoice), its quantities are added to the PO lines as invoiced. Once everything received on the PO has been invoiced, the PO moves to Matched. Until then it's Partial Match.

If you match bills outside Smooth POS, Mark a purchase order matched sets the status by hand.

Inbound shipments

When stock from one or more POs travels together, record it under Product → Shipments, or with Create a shipment. Each shipment line points at a PO line. Mark the shipment shipped, arrived or canceled as it moves. List shipment lines with purchaseorder= shows which shipments a PO is on.

Quick Product Buy

Quick Product Buy is the purchase order process, automated all the way to delivery. In one step it:

  1. creates a purchase order for the lines,
  2. receives every line in full into the warehouse's default location,
  3. records the supplier's bill (an AP invoice, numbered with your receipt number), pays it from the bank account you choose, and
  4. marks the PO Matched.

In the app

Go to Accounts → Quick Product Buy. Pick the supplier, the warehouse, the bank account you paid from and the tax rate, enter the receipt number, and add the items with the quantity and unit cost you paid.

Through the API

Create a quick product buy with POST /quickproductbuy.json:

{
  "supplier_id": 12,
  "warehouse_id": 3,
  "bank_account_id": 101,
  "tax_rate_id": 2,
  "receipt_number": "INV-55821",
  "currency": "AUD",
  "exchange_rate": 1,
  "tags": ["cash-and-carry"],
  "lines": [
    {"item_id": 5521, "quantity": 12, "cost": 8.5}
  ]
}
  • cost is the unit cost excluding tax. Tax is worked out from tax_rate_id.
  • bank_account_id has to be a bank account in your chart of accounts.
  • Always send exchange_rate. Use 1 when you pay in your own currency.
  • A successful call returns an empty object. Look the PO up afterwards if you need its ID.

Common errors are bank account doesent exist, warehouse doesent exist, supplier doesent exist and unable to get tax rate. Nothing is saved when a call fails.

What fires

A quick product buy fires the same hooks as doing it by hand: purchaseorder_create, then purchaseorder_status_change (Open to Complete, then Complete to Matched), inventory_adjust, apinvoice_create, and apinvoice_status_change (to Awaiting Payment, then Paid). The status-change payloads carry "quick_product_buy": true, so a Glue job can tell them apart.

Example: Tell the warehouse when a PO is received

Trigger: System Hook, purchaseorder_status_change.

  1. Script: Read the change

    var change = JSON.parse($.default);
    $.po = change.after;
    $.po_number = change.after.number;
    $.just_received = change.before.status !== "Complete" && change.after.status === "Complete" && change.quick_product_buy !== true;
  2. If Condition: If the PO was just received, Condition $.just_received === true.

  3. Email: Tell the warehouse, nested under THEN: To your warehouse team, Template Custom, Subject PO {{ po_number }} received, Body <p>Purchase order {{ po_number }} has been received. Please put the stock away.</p>


Did this page help you?