Modules / purchasing
Purchasing & suppliers
Agree what you are going to spend before you spend it, check that what a supplier bills you is what you ordered and what actually arrived, and pay it once — so nobody is chasing an invoice nobody recognises, and nothing is paid twice.
People ask for it as: “purchase orders”, “what did we order”, “supplier invoices”, “approve spend”, “who authorised this”, “what do we owe”, “pay the suppliers”
Who uses it
| Role | Does | Sees |
|---|---|---|
| whoever needs something | asks for what they need and sees where the request got to | their own requests |
| budget holder | approves or refuses spend before it is committed, within their limit — and asks for things themselves, like anyone else | requests routed to them, and the orders that came from them |
| whoever places orders | turns approved requests into orders, sends them, records what arrived | every request and order |
| accounts payable | records supplier invoices, matches them, schedules and records payment | every supplier invoice and payment |
| The system | matches bills against orders and receipts, posts to the ledger, derives what is outstanding | everything, through its own service account |
| whoever releases money | approves a payment run, and any bill that failed its match | everything payables sees |
What it has to do
Reference user stories. Each has a test written into it — the given / when / then — which becomes an automated check once it is built. Expect to keep some, change some and drop some.
Things people do
PUR-01As someone who needs something, I want to ask for it and see where my request got to, so that I stop chasing people by email.
Given a request for 4 laptops at 900 each · when the requester submits it · then it is recorded with who asked, what for, and the amount, and it appears in the approver's queue
whoever needs something · screen: Requests
PUR-02As a budget holder, I want to approve or refuse spend before it is committed, so that the first I hear of a cost is not the invoice.
Given a 3,600 request and a 5,000 limit for this approver · when they approve it · then the request is approved with their name, the date and any note, and a buyer can raise an order from it — and an approver whose limit is below the amount cannot approve it at all
budget holder · screen: Requests
Usually different per customer: some businesses approve by amount, some by category, some by both — config, not code
PUR-03As a budget holder, I want to refuse a request with a reason, so that the person asking learns something rather than just waiting.
Given an approved-limit breach or a duplicate request · when the approver refuses it with a reason · then the request is closed as refused, the reason is recorded and visible to the requester, and no order can be raised from it
budget holder · screen: Requests
PUR-04As a buyer, I want to turn an approved request into an order to a supplier, so that nothing is ordered that nobody agreed to.
Given an approved request and a chosen supplier · when the buyer raises the order · then the order carries its number, the supplier, the lines and the approval it came from; raising an order from an unapproved request is refused
whoever places orders · screen: Orders
PUR-05As a buyer, I want the order sent to the supplier and recorded as sent, so that "did they get it?" has an answer.
Given an order in draft · when the buyer sends it · then the send is recorded with when and to whom; sending twice records a second send and does not change the order
whoever places orders · screen: Orders
PUR-06As a buyer, I want to change or cancel an order before it is fulfilled, so that a mistake is not a thing we live with.
Given a sent order with nothing received against it · when the buyer cancels it with a reason · then the order is cancelled, the reason recorded, and no bill can be matched to it — an order with receipts against it cannot be cancelled, only closed short
whoever places orders · screen: Orders
PUR-07As whoever takes delivery, I want to record what actually arrived, so that we only pay for what we got.
Given an order for 10 and a delivery of 7 · when the receipt is recorded · then 7 are received and 3 outstanding, and the order stays open; recording the same delivery note twice does not receive 14
whoever places orders · screen: Receipts
PUR-08As a buyer, I want to close an order that will never be completed, so that the outstanding list means something.
Given an order for 10 with 7 received and the rest cancelled by the supplier · when the buyer closes it short with a reason · then the order is closed, 3 stop being outstanding, and the reason is recorded
whoever places orders · screen: Orders
PUR-10As accounts payable, I want to record a supplier invoice as what it is — their claim, not our document — so that checking it is a step rather than an afterthought.
Given a supplier invoice quoting our order number · when the clerk records it with the supplier's own invoice number · then it is held as a bill awaiting match, and recording the same supplier invoice number for the same supplier again returns the existing bill rather than creating a second
accounts payable · screen: Bills
PUR-12As whoever releases money, I want to accept a bill that failed its match, with a reason, so that a real price rise is not a permanent blockage.
Given a bill failing on price by 50 a unit · when the approver accepts the variance with a reason · then the bill becomes payable, the acceptance is recorded with who and why, and the order is not silently rewritten to match
whoever releases money · screen: Bills
PUR-14As accounts payable, I want to see what is due and when, so that I pay on time without paying early.
Given bills with terms and due dates · when the clerk opens the payables list · then each bill shows what is outstanding and how many days until or past due, derived on read rather than stored
accounts payable · screen: Payables
PUR-15As whoever releases money, I want to approve a payment run, so that one person cannot both enter a supplier and pay it.
Given a run of 12 bills totalling 40,000 · when the approver releases it · then the run is approved with their name and the date, each bill is marked paid for its amount, and the clerk who entered the bills cannot be the approver
whoever releases money · screen: Payments
PUR-16As accounts payable, I want to record a part payment or a payment covering several bills, so that the ledger matches the bank rather than the other way round.
Given one transfer of 5,000 against three bills · when the clerk allocates it · then each bill's outstanding falls by its share, the payment is recorded once, and allocating more than the payment is refused
accounts payable
PUR-22As accounts payable, I want to see whether a supplier is also a customer, so that we can net what we owe against what they owe us rather than paying in full and chasing.
Given a party with both roles and balances on each side · when the clerk opens the supplier · then both balances are shown, each read from the module that owns it
accounts payable · screen: Payables
Things that happen on their own
PUR-11when a bill is recorded or a receipt is posted against its orderThe system matches the bill to the order and the receipt, so that a bill for something nobody ordered or nobody received is caught before it is paid.
Given an order at 900 a unit, 7 received, and a bill for 10 at 950 · when the match runs · then the bill fails on both price and quantity, naming each, and cannot be paid until somebody with authority accepts the difference
Things that cross into other modules
PUR-20when a bill is approved for payment, and when a payment is recordedPurchasing posts the accounting entries to the ledger, so that the books show what is owed to suppliers without anyone re-keying it.
Given an approved bill of 1,200 including 200 tax, and an account map with expense, tax and payables set · when purchasing calls the ledger's own route · then expense 1,000 and tax 200 are debited and payables 1,200 credited; a payment debits payables and credits bank; the journal id is derived from the bill, so a retry posts once and a closed period refuses the posting and says why
· owned by gl
PUR-21when a supplier is needed that does not exist yetPurchasing asks the party master for the supplier, so that the company we buy from and the company we sell to are one record.
Given a supplier known to purchasing only by name and the customer's own reference · when purchasing calls promote with that reference as the bp_key · then one party exists with a supplier role and a derived bp_id; calling again returns the same party, and purchasing never writes the partner tables
· owned by business-partner
How things move
request
draft → awaiting_approval → approved → refused → ordered → closed
- draft → awaiting_approval by requester · when a line, an amount and a reason
- awaiting_approval → approved by approver · when the amount is within this approver's limit
- awaiting_approval → refused by approver · needs reason
- approved → ordered by buyer · an order exists; the approval travels with it
- approved → closed by buyer · needs reason · approved but never ordered
order
draft → sent → part_received → received → closed_short → cancelled
- draft → sent by buyer · number stamped, contents frozen, send recorded
- sent → part_received by buyer · derived from receipts, never set by hand
- part_received → received by buyer · derived: everything ordered has arrived
- part_received → closed_short by buyer · needs reason
- sent → cancelled by buyer · when nothing received against it · needs reason
bill
recorded → matched → match_failed → approved → paid → part_paid → disputed → cancelled
- recorded → matched by system · when within tolerance on price and quantity
- recorded → match_failed by system · the reason names price, quantity or no order at all
- match_failed → approved by payables_approver · needs reason
- matched → approved by payables_approver
- approved → paid by payables_clerk · derived from allocations, never stored
- recorded → disputed by payables_clerk · needs reason
- recorded → cancelled by payables_approver · when nothing paid against it · needs reason
What it keeps
| Thing | Meaning | Identified by | Shared? |
|---|---|---|---|
| purchase request | somebody asked to spend money, and who agreed | request_id, derived from the requester and the moment they asked | module-owned |
| purchase order | what we agreed to buy from a named supplier, at a price | order_id, derived from the source request; order_no is the number the supplier sees | module-owned |
| purchase order line | one thing ordered, at a quantity and a price | (order_id, line_no) | module-owned |
| goods receipt | what actually turned up, and when | (order_id, delivery_note) — what a person re-enters when unsure | module-owned |
| supplier bill | the supplier's claim on us — their document, not ours | (bp_id, supplier_invoice_no, invoice_date) | module-owned |
| payment run | a batch of bills released for payment by one person, on one date | run_id, derived from the approver and the moment of release | module-owned |
| payment allocation | which money settled which bill, and how much of it | (payment_id, bill_id, seq) | module-owned |
| approval limit | how much this person may commit, and to what | (approver, category) | module-owned |
What runs on its own
| Story | When | What |
|---|---|---|
| PUR-11 |
Questions that shape your version
Read these out and let the customer correct one — people rarely recall a policy on demand and can always react to one. Standard is a named authority you can look up and hold us to. Commonly seen is exactly that: arrangements we have met, with no survey behind them. A customer doing none of them is not doing it wrong.
- Does somebody have to agree to a cost before it is committed, or do people just buy what they need?
- under 15 staff
- the owner sees everything anyway — requests are often skipped entirely at first
- construction
- a site manager commits within a limit; anything above goes to the QS or the director
- professional services
- a budget holder per department, one limit each
- warning
- an approval step nobody enforces is worse than none — it teaches people the system lies
- Do you raise purchase orders, or do you just ring the supplier?
- goods and materials
- orders, because the order is what the delivery and the invoice are checked against
- services
- often no order — the engagement letter is the order, and the match is two-way
- When a supplier's invoice does not match the order, who decides?
- common
- the budget holder who approved the spend, not accounts payable
- note
- a tolerance of 2% or a few pounds absorbs rounding and delivery charges without a human
- When do you pay your suppliers?
Standard EU Directive 2011/7/EU and, in the UK, the Late Payment of Commercial Debts (Interest) Act 1998 — 30 days unless expressly agreed, 60 maximum between businesses, and interest is the supplier's statutory right. Large UK companies must also report their payment performance twice a year (Reporting on Payment Practices and Performance Regulations 2017).
- most b2b
- a weekly or fortnightly payment run rather than paying each bill as it lands
- construction
- pay-when-paid clauses are common and are unenforceable in UK construction contracts — check before encoding one
- Do you reclaim VAT on what you buy?
Standard Input tax is only recoverable against a valid VAT invoice carrying the supplier's VAT number and the required particulars (EU VAT Directive 2006/112/EC art. 226; UK VAT Regulations 1995 reg. 14). A scan of a delivery note is not one.
- vat registered
- the bill cannot be approved without the supplier's VAT number on file
- not registered
- tax is just part of the cost — do not model a recoverable element
- Do you buy from anyone you also sell to?
- trade and construction
- common — and both sides are usually settled separately anyway
- warning
- netting what you owe against what you are owed has tax and contract consequences; see known_gaps
What you can change yourself
These are settings, not code: someone in your team changes them on a screen, without a developer and without a release.
Where the platform limits what we can promise
For builders
- Module spec — this page, for agents
- The lifecycle and the design template
- ap-core — requests, approvals, orders, receipts, bills, the three-way match, payments; FastAPI
Known gaps in the reference
- ap-core covers PUR-01 to PUR-12, PUR-15, PUR-16 and PUR-20; the supplier seam (PUR-21), the customer-balance view (PUR-22) and payment RUNS as a batch are not built — payments are one at a time
- contra settlement (netting a supplier balance against a customer balance for the same party) is NOT modelled: it has tax and contract consequences that differ by jurisdiction, and PUR-22 only shows both balances
- no stock or inventory: a receipt records that something arrived, not where it went. A goods-for-resale business needs a stock module before this is the whole story
- no supplier catalogue or contracted pricing — a line is a description and a price
- no landed cost: duty, freight and handling are separate bills rather than being spread across what they were incurred on
- no self-billing, no purchasing cards, no staged payments against a construction application for payment
- pay-when-paid is deliberately not modelled: it is unenforceable in UK construction contracts and encoding it would help a customer do something the law does not allow