Home / Help Center / pos-app / Buy / Purchase / Purchase Orders
📋 Buy / Purchase

Purchase Orders

Purchase Orders is where you formally order stock from suppliers, track the order through approval and shipping, receive the goods into inventory (with batch/expiry/serial capture), and handle any damaged or returned items.

📍 Menu path: Buy / Purchase → Purchase Orders
👤 Who uses it: Owners/Admins and Managers with Purchase permission; Create/Edit/Delete/Export are individually permissioned
🏷️ Plan tier: advanced+

Overview

A Purchase Order moves through a status lifecycle: Draft → Pending Approval → Approved → Sent to Supplier (Ordered) → Partially Received / Fully Received, and can be Cancelled at most stages.

Every PO carries items (product, quantity, unit cost, tax rate), optional Landed Costs (freight, customs duty, handling, insurance) that get proportionally allocated across item costs on receipt, and optional multi-currency support with a manual exchange rate.

The Auto-Generate PO wizard scans every product whose stock has fallen to or below its reorder point and lets you build one or more POs from those suggestions in a few clicks, grouped by supplier.

Receiving stock against a PO updates inventory quantities, can update product cost price (three modes: keep existing, use PO cost, or blend with weighted average), and supports capturing batch numbers, expiry dates and serial numbers per line item.

This page requires the Advanced plan tier and the purchase_orders feature, same as Suppliers.

Before You Start

Step-by-Step Guide

1 Create a Purchase Order manually

  1. Click New PO.
  2. Select a Supplier (required) and optionally a Reference (the supplier's own invoice/PO number) and Expected Delivery date.
  3. Choose a Currency — defaults to INR; selecting a foreign currency reveals an Exchange Rate field (1 [currency] = ? INR).
  4. If this purchase is subject to Reverse Charge Mechanism, check RCM Applicable and pick the relevant RCM Section from the dropdown (required once RCM is checked).
  5. Add one or more Items: pick a Product (its cost price auto-fills the Unit Cost), set Quantity, adjust Unit Cost if needed, and pick a Tax % (0/5/12/18/28). Use + Add Item for more lines.
  6. Optionally add Landed Costs — Freight, Import Duty, Customs, Handling, Insurance or Other, each with an amount and note; these get proportionally spread across item unit costs once the PO is received.
  7. Review the live Subtotal / Tax / Landed Costs / Total at the bottom.
  8. Choose how to save: Save as Draft (no approval needed yet, fully editable later), Submit for Approval (moves straight to Pending Approval), or Place Order (moves straight to Ordered/sent-to-supplier, skipping approval).
💡 If your organisation has a purchase budget configured, saving may show a budget-warning toast — the PO still saves, but flags that you are approaching or exceeding a spending limit.

2 Move a PO through the approval workflow

  1. Open a PO (click its row) to see the status-specific action buttons at the bottom.
  2. From Draft, click Submit for Approval to send it for review.
  3. From Pending Approval, click Approve to move it forward, or Return to Draft to send it back for edits.
  4. From Approved, click Send to Supplier to mark it Ordered — this is the point at which you'd actually place the order with your vendor.
  5. At any stage before Received, click Cancel PO (with Delete permission) to abandon the order.

3 Auto-generate Purchase Orders from low-stock suggestions

  1. Click Auto-Generate PO.
  2. Step 1 lists every product at or below its reorder point, with current stock, reorder point, unit cost and a suggested order quantity — untick any you don't want to order, and adjust quantities inline.
  3. Products with no default supplier show an amber — Assign — dropdown; you must assign a supplier to every selected item before continuing.
  4. Click Review Orders to move to Step 2, which groups the selected items into one draft PO per supplier and shows an estimated total.
  5. Click Create N POs to generate all of them at once as Draft purchase orders — Step 3 confirms how many were created (and reports any that failed).
💡 Orders left without a valid supplier are silently skipped at creation time — assign a supplier first if you want that product included.

4 Receive stock against a PO

  1. Open a PO with status Ordered or Partially Received and click Receive Items.
  2. Optionally tap Scan Barcode to scan each incoming carton — matching products auto-increment their Receiving Now quantity.
  3. If you use multiple warehouses, pick a destination under Receive Into Warehouse (or leave "No specific location").
  4. Choose a Cost Price Update mode: Keep existing, Use PO cost, or Weighted average (recommended — blends current stock cost with the new incoming cost).
  5. For each pending line item, enter the quantity Receiving Now, and optionally a Damaged quantity (damaged units are automatically filed as a return and never added to sellable stock), a Unit Cost override, Batch #, Expiry Date, and — for serial-tracked products — one serial number per line in the textarea.
  6. The progress bar at the top shows units received so far out of units ordered.
  7. Click Confirm Receipt to update inventory. The PO status becomes Partially Received or Fully Received depending on whether everything ordered has now arrived.
💡 An expiry date in the past is flagged in red with an "Already expired" warning right in the receiving form, before you confirm.

5 Record a return to supplier

  1. Open a PO with status Partial or Received and click Return Items.
  2. Pick a global Return Reason (Damaged, Incorrect item, Expired, Excess quantity, Quality issue, Other) — you can override the reason per line item if needed.
  3. For each received item, enter the Return Qty (capped at what was actually received), an optional Batch #, and an optional per-item reason override.
  4. Add an optional Notes field for context (e.g. "Driver confirmed damage on delivery").
  5. Click Submit Return — this creates a Purchase Return record and adjusts inventory back down.

6 Adjust landed costs after a PO is placed

  1. Open a PO that is not yet Received or Cancelled.
  2. In the Landed Costs panel, click + Add (or Edit if costs already exist).
  3. Add/edit rows with Type (Freight, Import Duty, Customs, Handling, Insurance, Other), Amount and an optional note.
  4. Click Save & Allocate — the amounts are proportionally spread across each item's unit cost so your true landed cost per unit is reflected when you receive stock.

7 Search, filter, sort and export the PO list

  1. Use the search box to match PO number or supplier name.
  2. Filter by Status (all 7 lifecycle states) or by a specific Supplier using the dropdowns.
  3. Click any of the 8 stat cards at the top (Draft, Pending Approval, Approved, Sent to Supplier, Partially Received, Fully Received, Cancelled, Total Spent) to instantly filter the list to that status — click again to clear.
  4. Sort by clicking column headers (PO Number, Date, Expected date, Total, Status) — click again to reverse direction.
  5. Switch between Table and Grid card views with the view toggle.
  6. Click the export icon (Export permission required) to download the current filtered list as a spreadsheet, or use the print/share bar inside an open PO to email or print a formatted PO document.

Every Field & Button, Explained

Field / ButtonWhat it does
Supplier *The vendor this PO is placed with; required to save any PO.
ReferenceFree-text field for the supplier's own invoice/PO number.
Expected DeliveryOptional target delivery date, shown on the PO document and in the list.
Currency / Exchange RateDefaults to INR; choosing a foreign currency (USD, EUR, GBP, AED, CNY, JPY) reveals a manual exchange-rate field used to compute an approximate INR total.
RCM Applicable / RCM SectionMarks the purchase as Reverse Charge Mechanism liable and records which GST RCM section applies.
Items (Product, Qty, Unit Cost, Tax %)One row per product ordered; selecting a product auto-fills its current cost price which you can override.
Landed Costs (Type, Amount, Note)Freight/duty/handling/insurance/other costs that get proportionally allocated to item unit costs when stock is received.
Save as Draft / Submit for Approval / Place OrderThree ways to save a new PO, corresponding to DRAFT, PENDING_APPROVAL, and ORDERED status respectively.
Status badgeOne of Draft, Pending Approval, Approved, Sent to Supplier, Partially Received, Fully Received, Cancelled — colour-coded throughout the page.
Auto-Generate POOpens the reorder-suggestion wizard that builds draft POs from products at or below their reorder point.
Receive ItemsOpens the stock-receiving modal for POs in Ordered or Partially Received status.
Return ItemsOpens the supplier-return modal for POs in Partial or Received status.
Cost Price Update modeKeep existing / Use PO cost / Weighted average — controls how receiving stock affects the product's stored cost price.
Damaged (receiving)Units received in damaged condition; still counts toward the received quantity for progress tracking but is auto-filed as a return rather than added to sellable stock.
Batch #, Expiry Date, Serial NumbersOptional per-line traceability fields captured at receiving time, most relevant for perishable or serial-tracked products.
Total Spent (stat card)Running total of PO spending across all statuses shown in the page header stats.

Tips & Best Practices

Troubleshooting & FAQ

Why can't I select a supplier for one of my auto-generated reorder suggestions?
That product has no default supplier configured. Assign one from the "— Assign —" dropdown in Step 1 of the Auto-Generate wizard, or add a default supplier to the product from the Products page.
I received stock but the cost price on the product didn't change.
Check which Cost Price Update mode you selected — "Keep existing" deliberately does not touch cost price. Re-open the PO and use Receive Items again with "Use PO cost" or "Weighted average" if you want the price to update.
The RCM Section dropdown is empty.
RCM sections are configured in your GST settings. If none appear, ask your Admin to add applicable RCM sections under GST configuration before marking a PO as RCM Applicable.
Can I delete a Purchase Order?
Only Draft or Pending Approval POs can be deleted (with Delete permission); once a PO has moved to Approved or beyond, use Cancel PO instead to preserve the audit trail.
My foreign-currency PO total looks different from what I expect.
Foreign-currency POs store the exchange rate you entered at creation time. Check the "≈ INR equivalent" line and the "Exchange Rate" shown on the PO — these are fixed at the rate you typed, not a live market rate.

🧑‍💻 Developer Notes

Source component(s):

  • frontend-app/packages/pos-react-lib/src/pages/PurchaseOrdersPage.jsx

Backend endpoints used:

  • GET /purchase-orders
  • POST /purchase-orders
  • GET /purchase-orders/:id
  • DELETE /purchase-orders/:id
  • GET /purchase-orders/stats
  • GET /purchase-orders/suggested-reorder
  • POST /purchase-orders/auto-generate
  • POST /purchase-orders/:id/receive
  • POST /purchase-orders/:id/returns
  • GET /purchase-orders/:id/returns
  • POST /purchase-orders/:id/landed-costs
  • PATCH /purchase-orders/:id/status
  • GET /rcm/sections
  • GET /warehouses
  • GET /suppliers
  • GET /products

Related tables (db-core repositories):

  • PurchaseOrder
  • PurchaseOrderItem
  • PurchaseReturn
  • Supplier
  • Product
  • Warehouse

Redux slices:

  • auth
  • scope (selectCurrentScope / getScopeQueryParams)

Feature flag key: purchase_orders (requires advanced plan tier or above)

PO documents (for print/email/WhatsApp share) are built client-side as a standalone HTML string via buildPOHtml() rather than server-rendered. Damaged units on receipt are unioned from two separate quantity maps (good vs damaged) because a line can be fully damaged with zero good units — see the comment above handleConfirm in ReceiveItemsModal. Landed cost allocation and weighted-average costing are computed server-side in the /receive and /landed-costs endpoints.