At a Glance
Persona: Purchaser / Procurement Officer · Module: purchase-request · Workflow stages: approved → completed (Convert to PO) · Key permissions: vendor allocation, pricelist refresh, set convert qty, Convert to PO, bounce-back to Requestor
What this persona does: Takes approved PRs, validates vendor and pricing, groups by vendor + currency, and converts lines into one or more POs.
The Purchaser (also titled Procurement Officer) is the bridge persona between the upstream PR side and the downstream PO side of the procure-to-pay chain. They do not approve PR content — by the time a PR reaches their queue it has already cleared the entire approver chain and pr_status = approved (PR_POST_005). Their job is to take what is already approved, validate the vendor allocation per line, look up the current vendor pricelist to verify price and deviation, group lines from different PRs that share vendor + currency so they can be issued as a single PO, and run the Convert-to-PO action. The link from PR line to PO line is recorded on the bridge table tb_purchase_order_detail_tb_purchase_request_detail (01-data-model.md Section 2) — a many-to-many that supports both consolidation (multiple PR lines → one PO line) and partial conversion (one PR line → multiple PO lines across vendors / delivery dates). When a vendor or spec issue surfaces, the Purchaser can route the PR back to the Requestor via the standard PR send-back mechanism rather than completing the conversion. The Purchaser operates under enum_stage_role = purchase (PR_AUTH_008).
The Purchaser sees PRs only after the approve chain is cleared. The two relevant document states are approved (active conversion candidates) and completed (historical, read-only). Edit rights are scoped to vendor allocation, pricelist refresh, and the per-line convert quantity — never PR content.
| Action | approved (open or partially bridged) | completed (fully bridged) |
|---|---|---|
| View PR | ✅ | ✅ (read-only) |
Allocate / change vendor on a line (vendor_id) |
✅ | ❌ |
Refresh pricelist_price to current |
✅ | ❌ |
| Set per-line convert quantity (full or partial) | ✅ | ❌ |
| Run Convert to PO (writes bridge rows) | ✅ | ❌ |
Bounce-back to Requestor (send-back from purchase stage) |
✅ | ❌ |
| Add Comment | ✅ | ✅ |
| Edit header / lines (qty, price, tax, FOC) | ❌ | ❌ |
Adjust approved_qty |
❌ (Approver's right; PR_VAL_013) |
❌ |
| Reject / Approve / Split-Reject | ❌ | ❌ |
| Delete / Void PR | ❌ (sysadmin only — PR_AUTH_007) |
❌ |
ℹ️ PR → PO snapshot: when the Purchaser runs Convert to PO, the PO snapshots a fresh
exchange_rateand current pricelist context onto each PO line; the PR retains its original snapshot perPR_CALC_006. PR-side and PO-side base totals may differ — this is by design.
Entry point: Sidebar → Purchase Request module → Approved PRs queue (filtered to pr_status = approved and not yet fully bridged to a PO). Alternatively: Procurement workspace → Convert to PO workbench, which presents the same approved-line pool grouped by vendor + currency. In-app and email notifications "Purchase Request [PR-ID] Ready for PO Conversion" deep-link straight to the PR detail page.
Primary flow (happy path):
pr_no, requestor, department, line count, base_total_amount, vendor (if a single vendor covers all lines) or "multi-vendor", currency, and the time since the PR landed in approved. The number of unbridged lines vs total lines is visible per row so partially converted PRs surface clearly.pr_date, required delivery date, currency, exchange_rate, justification, attachments) is non-editable; only vendor allocation, pricelist selection, and the per-line conversion checkbox are interactive.vendor_id / vendor_name. If the Requestor or system auto-allocated a preferred vendor, the Purchaser validates it against current vendor-master data (active status, payment terms, credit limit, blacklist flags) pulled live alongside the vendor-pricelist for current price and deviation. If a line lacks a vendor allocation, the Purchaser picks one from the Allocate Vendor dialog — the dialog ranks candidate vendors by pricelist match against the line's product, location, and required date, and shows their current price, lead time, and historical performance.pricelist_price against the current active pricelist row (resolved by product_id, vendor, location, and effective date). The deviation indicator highlights lines where the current price has moved beyond a configurable tolerance (e.g. ±5%). On a deviation the Purchaser can (a) accept the snapshotted price and proceed, (b) refresh to the current pricelist price before conversion, or (c) raise a concern that routes the PR back to the Requestor for re-justification.approved_base_qty minus already-bridged quantity from prior partial conversions). The Purchaser may convert less than the open quantity, leaving the remainder available for a future PO — the bridge table records the actual converted quantity per PO-PR-line link.(vendor_id, currency_id). Each group becomes a draft PO; lines that share both vendor and currency consolidate into the same PO regardless of which PR they originated from. Each group preview shows: vendor name and code, currency, line count, subtotal, total tax, total discount, and grand total in both transaction and base currency.PR_AUTH_008 and the configured PO module policy, and add a PO-level note. Lines that fail vendor or pricelist validation are flagged in red and excluded from the conversion until resolved.tb_purchase_order per group, inserts the matching tb_purchase_order_detail rows with their snapshotted product / pricing / qty / UoM context, snapshots the FX rate at conversion time onto each PO line, and writes one row per (PO line, PR line) pair into the bridge tb_purchase_order_detail_tb_purchase_request_detail recording the converted quantity. Per PR_POST_007, if every line on a source PR is now fully bridged (sum of bridge-linked PO quantities equals approved_base_qty) or explicitly cancelled, the PR's pr_status flips from approved to completed; lines with remaining open quantity leave the PR in approved for future conversion.type = system audit comments on each source PR (PR_POST_008), sends PO notifications to the named vendor contacts (where vendor portal integration is enabled), and notifies the Requestor that their PR is now linked to a PO.pricelist_price outside the ±X% band): the Purchaser sees the deviation flag in Step 4 and chooses one of three paths. (a) Accept snapshot — proceed with the PR's frozen pricelist_price; the PO inherits the same price. (b) Refresh to current — pull the current tb_pricelist_detail price onto the PO line; the PR's snapshot is unchanged, but the PO records the new price. (c) Raise concern / send back — abandon conversion for that line and route the PR back to the Requestor by triggering the standard send-back path (the PR's workflow_current_stage re-opens to the Requestor's create stage, pr_status returns to draft, soft budget commitment is released until re-submission per PR_POST_003). The bounce-back reason is captured in tb_purchase_request_comment for audit.vendor_id IS NULL): the line cannot be converted as-is. The Purchaser opens the Allocate Vendor dialog, picks a vendor (ranked by pricelist match, lead time, and historical performance), and the line's vendor_id, vendor_name, pricelist_detail_id, pricelist_no, pricelist_unit, pricelist_price, and pricelist_type snapshots are updated on the PR detail row. The PR remains in approved; no approver re-approval is needed because vendor allocation is a Purchaser right under PR_AUTH_008.approved with the unbridged lines visible. The Purchaser (or a teammate) can run a second conversion round later — and a third, as long as any line has open quantity. pr_status flips to completed only when the last open quantity is bridged or cancelled (PR_POST_007).draft with the clarification reason logged. The Requestor revises the line (description, qty, delivery date, or attachments) and re-submits through the full approval chain. The Purchaser picks the PR up again once it lands back in approved.THB and one in USD): the workbench refuses to merge them into a single draft PO group — consolidation requires both vendor_id and currency_id to match. The Purchaser sees two separate draft POs for the same vendor, one per currency.35.50000, today 36.20000): the PR's exchange_rate is immutable per PR_CALC_006 — re-approving does not re-fetch the rate. The PO, however, snapshots a fresh exchange_rate at conversion time so its base-currency totals reflect the rate at the moment of vendor commitment. The PR-side base_total_amount and the PO-side total in base currency may therefore differ; this is expected and documented in the PR detail for traceability.PR_POST_007 flips pr_status from approved to completed immediately; the soft budget commitment converts to a hard commitment on the new PO; the PR drops out of the Approved PRs queue and is preserved read-only for audit.The Purchaser's involvement on a given PR ends at one of three documented points:
pr_status flips from approved to completed (PR_POST_007); the soft budget commitment hardens into a PO commitment; handoff is to the PO module (purchase-order) for vendor commitment, tracking to receipt, and matching to GRN (good-receive-note). The Requestor sees the linked PO(s) on the PR detail page for traceability.pr_status stays approved; the bridge table records exactly which PR-line → PO-line linkages were created and with what quantity. The PR remains in the Approved PRs queue with its unbridged-line count visible, awaiting a future conversion round. Soft commitment for the still-open portion persists.pr_status returns to draft (PR_POST_003), workflow_current_stage reopens to the Requestor's create stage, soft budget commitment is released, and handoff is to the Requestor at 03-user-flow-requestor.md Section 2 step 2. The Requestor revises and resubmits; the PR re-enters the approver chain and eventually returns to the Purchaser's queue.Document state across these transitions is recorded by enum_purchase_request_doc_status = { draft, in_progress, voided, approved, completed }. The Purchaser only sees PRs in approved (active conversion candidates) or completed (historical, read-only). Voiding (pr_status → voided) is reserved for Finance / system-admin per PR_AUTH_007 and is not part of the standard Purchaser flow.
tb_purchase_order_detail_tb_purchase_request_detail (many-to-many PR↔PO line linkage supporting consolidation and partial conversion)PR_AUTH_008 (enum_stage_role = purchase owns vendor allocation and PO conversion)PR_POST_005 (final approve → approved), PR_POST_007 (convert to PO → bridge writes + completed)../carmen/docs/purchase-request-management/PR-User-Experience.md — primary source for the PO-conversion UX, Allocate Vendor dialog, and Convert-to-PO workbench../carmen/docs/purchase-request-management/PR-Overview.md — module overview, Purchaser / Procurement Officer role definition, and integration with the PO module../carmen/docs/purchase-request-management/purchase-request-module-prd.md — product requirements driving the consolidation grouping (vendor + currency) and partial-conversion behaviourpr_status flips to approved