Procurement
BOM-shortfall driven quotes, vendor selection, grouped POs, and delivery -> inventory credit
Last updated: 2026-05-27
Procurement in S3Suite starts from a real production need - a lot in manufacturing that has a BOM-line shortfall - and walks you through the smallest workflow that gets parts ordered and credited: collect quotes from up to three vendors, pick a winner per line, group winning lines into one PO per vendor, mark delivered when parts arrive. Delivery automatically credits the inventory pool.
There is no separate "Procurement project" or RFP system. Procurement is anchored to a lot and only surfaces parts whose required quantity for that lot exceeds current inventory.
Why anchor procurement to a lot
A generic "let's buy some parts" flow drifts into a mini-ERP. Anchoring to a lot keeps it answering one question: what does this lot need that we do not have?
- The procurement plan is computed from
(BOM quantity x lot units) - inventory on hand - Only lines with shortfall > 0 appear
- The result is a focused worklist, not a parts catalog
- When the PO arrives, the credit lands in the same inventory pool any future lot will draw from
Concepts
| Term | What it means |
|---|---|
| Procurement plan | The per-lot shortfall list: BOM line + required qty + current inventory + shortage. |
| Quote | A single vendor's price + lead time for one BOM line on one lot. Max 3 quotes per line. |
| Winner | The selected quote for a line. Only one winner per line. |
| Purchase Order (PO) | A grouped order, one per vendor, with one or more winning lines. |
| PO status | issued -> partial -> delivered, or cancelled. |
| Per-line CAS | Mark-delivered writes per-line atomically; concurrent operators get a 409 instead of double-crediting. |
Quick start (5 minutes)
1. Open the procurement plan for a lot
- Open the project: Projects -> your project -> Manufacturing -> Production Variants
- Open the variant, then the lot that needs parts
- Click Procurement in the lot view
- The shortfall plan loads. Each row is a BOM line needing parts.
2. Add quotes (up to 3 per line)
- On a shortfall row, click Add quote
- Fill in vendor name, unit price, currency, lead time (days), and an optional note
- Save. The quote appears under the line.
- Repeat for up to 3 vendors per line.
3. Pick a winner
- Compare quotes by price + lead time + your sourcing notes
- Click Mark winner on the chosen quote
- The other quotes for that line stay visible but are flagged as not selected
4. Create grouped POs
- Once every required line has a winner, click Create POs
- The system groups winning lines by vendor and creates one PO per vendor
- Each PO gets a generated PO number (
PO-YYYYMMDD-NNN) - POs land under Procurement -> Purchase Orders for the project
5. Mark delivered when parts arrive
- Open the PO detail page
- For each line, enter the received quantity (can be partial or full)
- Click Mark delivered for that line
- Per line: the receivedQty advances atomically (Compare-And-Set), an inventory ledger row is written with source
po-delivered, and the PO's overall status auto-rolls betweenpartialanddelivered
Tip: Partial deliveries are first-class. Receive 80 of 100 today, the remaining 20 next week; each receipt writes its own ledger row.
Workflow: cancelling a PO
A vendor missed delivery, or a lot got scrapped.
- Open the PO detail page
- Click Cancel PO
- Enter a reason (required)
- Confirm
cancelled. Any lines already partially received stay credited (you have those parts in hand); no further deliveries can be recorded against this PO.
Workflow: re-quoting after a winner is wrong
You picked the winner, then realized vendor A is on backorder.
- Go back to the procurement plan
- On the line, click Unselect winner (or Mark winner on a different quote)
- The line returns to "needs winner". The PO that was about to include this line is not yet created until you click Create POs again.
Reference
Concurrency safety
- Mark-delivered uses per-line CAS. Each line's
receivedQtyis updated with a$elemMatch: { bomItemIndex, receivedQty: snapshotBefore }predicate. If another operator wrote first, the update misses and the API returns 409CONCURRENT_UPDATEtelling the user to refresh. - Inventory credits fire only on successful CAS. Double-receive of the same line never double-credits inventory.
- PO number generation retries up to 5 times on duplicate-key collisions, so two operators creating POs at the same date will not blow up.
Project scoping
- Every quote / PO / line operation filters by
(organizationId, projectId, lotId). Project A users cannot operate on Project B's lots even within the same org.
Permissions
- Read: any authenticated org member with project access
- Quote / Winner / Create PO / Mark delivered / Cancel: project writer roles
- All mutations write audit log rows (action prefixes
procurement_quote_,procurement_po_)
Module gate
- Procurement is gated by the
massProductionmodule. Enable it in Project settings -> Suites if the lot view does not show a Procurement tab.
Common pitfalls
- "Plan is empty even though we need parts." The plan only surfaces lines where
(BOM qty x lot units) - inventory > 0. If inventory was over-counted, the shortfall is hidden. Recount stock; the plan will refresh. - "Cannot mark delivered." Some other operator already advanced this line. Refresh the PO page to see the current receivedQty.
- "Created PO grouped lines from the wrong vendors." PO grouping uses the winning quote's vendor for each line. Re-select winners on the procurement plan to re-group.
- "Currency mismatch in a single PO." Each line carries its own currency from the winning quote. Mixed-currency POs are allowed but flagged in the UI; convert at receipt time if needed.
Related docs
- Inventory Ledger - PO delivery auto-credits the parts pool
- Manufacturing Suite - variants, lots, BOM lines that drive the shortfall plan
- Vendors - the vendor directory used in quotes
- Roles and Permissions - who can quote, select winners, and mark delivered