The Odoo purchase module connects procurement with inventory, accounting, and vendor management in a single flow. Done right, a purchase order becomes the controlling document for receiving goods and paying suppliers - with no manual re-entry between steps. Done poorly, each department duplicates work the system was supposed to eliminate.
This guide covers the full purchase cycle as it exists in Odoo 16/17: configuration decisions that matter, the approval workflow, receipt and bill matching, and the five implementation mistakes that come back to bite teams at month-end.
The purchase cycle at a glance#
Vendor Price List → RFQ → Purchase Order → Receipt → Vendor Bill → PaymentEach arrow is a deliberate user action (or an automated trigger you configure). The system does not advance on its own - it waits for confirmation at each step. Understanding what triggers what is the first thing to get right.
Configuration before go-live#
Purchase settings#
In Purchase → Configuration → Settings, the key decisions:
Purchase Order Approval - enable this if any PO above a threshold requires a manager's signature before being sent to the vendor. The threshold and the approver group are both configurable. Without approval routing, any user with purchase rights can confirm any PO.
Lock Confirmed Sales - prevents editing a confirmed PO after it has been sent. Useful for audit trails; annoying when vendors send amended quotes. Enable it if your finance team asks "how do I know the PO total matches what was ordered?"
Purchase Lead Time - a global buffer in days added to all vendor lead times. It shifts the scheduled date on receipts earlier so goods arrive before the production or customer delivery date that actually needs them.
Analytic Accounting - if your company uses analytic accounts for cost center tracking, enable this here so purchase order lines can carry analytic distribution.
Vendor pricelist and lead times#
Vendor pricelists (Purchase → Configuration → Vendor Pricelist) let you store agreed prices per vendor-product combination including minimum order quantities. When a user creates an RFQ and selects a vendor, Odoo populates the unit price from the pricelist automatically.
Lead times on the vendor form set the default delivery time in calendar days. Odoo uses this to calculate the Scheduled Date on the PO and the corresponding receipt. If a vendor's pricelist entry has its own lead time, that overrides the vendor default for that specific product.
Creating a request for quotation#
An RFQ is a draft PO sent to a vendor asking for pricing. Create one from Purchase → Orders → Requests for Quotation → New or from a reorder rule, a make-to-order procurement, or a sale order's dropship route.
Essential header fields#
- Vendor - triggers pricelist lookup and sets the payment terms.
- Purchase Representative - defaults to the current user; appears on printed POs.
- Order Deadline - the date you expect the vendor to respond. Not the delivery date.
- Receipt Date - the date the goods should arrive. This populates the scheduled date on the generated receipt.
Order lines#
Each line needs: product, quantity, unit of measure, and unit price. Taxes default from the product or vendor configuration. The Expected Date on each line can differ from the header receipt date - useful for partial deliveries.
Bill of Materials (BoM) components on POs: if you purchase a product that has a BoM marked "Kit" or "Subcontracting", Odoo may expand the BoM components onto separate PO lines depending on the route configuration. Verify this in staging before go-live - unexpected line expansion surprises users.
Sending and confirming the RFQ#
Click Send by Email to email the vendor a PDF of the RFQ. Once the vendor responds with a quote, update prices on the PO lines. Click Confirm Order to convert the RFQ to a Purchase Order. This action:
- Locks the PO number (PO/YYYY/NNNNN format).
- Triggers approval routing if configured and the total exceeds the threshold.
- Generates the receipt (stock.picking) in the incoming shipments queue.
If approval routing is enabled, the PO moves to status Waiting for Approval. The assigned approver sees it in their Purchase → Orders → Purchase Orders queue with the Approve/Refuse buttons.
Receiving goods#
Navigate to Purchase → Orders → Receipts or open the PO and click the Receipt smart button. The receipt is a stock.picking with the same lines as the PO.
Three-way matching and the Bill Control policy#
Odoo has two bill control policies per product (or globally):
| Policy | When bill is created |
|---|---|
| On Ordered Quantity | Bill the full PO quantity when PO is confirmed |
| On Received Quantity | Bill only what has been physically received |
Most product types default to "On Received Quantity" for stocked goods. Services often default to "On Ordered Quantity" because you can't receive a service.
When the policy is "On Received Quantity", the Received Qty on each PO line updates as receipts are validated. The vendor bill can only be created for quantities that have been received.
Validating a receipt#
Open the receipt, set the Done quantity for each line (either match the demand or enter the actual quantity received), and click Validate. If quantities differ from the PO:
- Less received: the receipt is done; the PO line shows a partial quantity. A backorder receipt is created for the remainder (or cancelled if the vendor won't ship more).
- More received: Odoo prompts you to create an immediate transfer for the excess, which lands in inventory as an unplanned receipt.
Lot and serial number tracking: if the product requires tracking, the Detailed Operations tab appears in the receipt. Enter lot/serial numbers there before validation. Missing tracking information blocks validation.
Creating the vendor bill#
From the PO, click Create Bill. Odoo pre-populates the bill with the received quantities and the agreed prices. The bill is an account.move in draft state. Review:
- Bill Date - the date on the vendor's invoice. This is the accounting date.
- Bill Reference - the vendor's invoice number. Required for reconciliation with vendor statements.
- Quantities - should match what was received (if using received-quantity policy). Edit only if the vendor billed differently.
- Taxes - applied from the product or vendor configuration.
Click Confirm to post the journal entry: debit the expense or asset account; credit the accounts payable account.
Payment#
From the confirmed bill, click Register Payment. Select the bank journal, the payment date, and confirm. Odoo:
- Creates a payment (account.payment) against the AP account.
- Marks the bill as In Payment (money left bank, not yet cleared).
- Reconciles the payment against the bill when the bank statement import confirms the transaction.
If you pay multiple vendor bills in a single bank transfer, use Accounting → Vendors → Payments → Group to batch them under one payment reference.
Approval workflow deep dive#
When approval is enabled and a PO exceeds the threshold, the PO shows status Waiting for Approval and an email goes to the purchase manager group. The approver opens the PO and either:
- Approves - PO moves to status Purchase Order, receipt is generated.
- Refuses with reason - PO stays in RFQ status, reason is logged in the chatter. The buyer must revise and re-send.
Escalation after N days: Odoo does not have built-in approval escalation. If the approver doesn't act, nothing happens. Implement an automated action on purchase.order where state = 'to approve' and create_date < (today - N days) to send a reminder email or escalate to a secondary approver.
Common implementation mistakes#
Not configuring the bill control policy per product category. Mixing "On Ordered Quantity" (services) and "On Received Quantity" (stock) within the same order is fine, but if you don't set these explicitly, Odoo uses the product template default, which often defaults to "On Ordered Quantity" for everything. Stocked goods get billed before they arrive.
Forgetting vendor taxes on the vendor form. The Vendor Taxes field on the vendor form overrides the product's purchase taxes. If a vendor is in a tax-exempt jurisdiction, set their tax to None here - not on every product.
Approving POs by email reply. Odoo does not parse email replies as approval decisions. The approver must click Approve inside Odoo. Forward them the direct URL from the approval email.
Creating vendor bills manually instead of from the PO. Bills created manually bypass the three-way matching linkage. The PO never shows as billed, and the received quantities on PO lines don't update. Always create bills from the PO or from Purchase → Vendors → Bills with the PO reference on each line.
Not reconciling vendor statements. At month-end, the AP account balance for each vendor should match the vendor's statement. Use Accounting → Vendors → Aged Payables to spot mismatches. Unreconciled partial payments and credit notes are the most common culprits.
For the inventory side of receipts and stock moves, see the Odoo inventory operations guide. For the accounting entries behind vendor bills and payments, see the Odoo accounting for developers guide.

