1---2name: reflect-3-attempt-02-483description: ProcureOps Task Solver — Reusable SOP4---5# ProcureOps Task Solver — Reusable SOP67## Environment89- Use the remote API base URL provided by the task runner (env var or `environment_access.md`). Never hardcode `localhost` or `127.0.0.1`.10- Public endpoints: `/programs`, `/suppliers`, `/items`, `/contracts`, `/purchase_orders`, `/purchase_requisitions`, `/receipts`, `/ap/invoices`, `/ap/payments`, `/approval_events`, `/budget_snapshots`, `/vendor_risk_events`.11- API responses are unpaginated: `{"count": N, "results": [...]}` returns all records in one call.1213## Source Precedence14151. **API is the source of truth** for all operational records. Task memos name targets but API data overrides them.162. Local payloads (`input/payloads/`) provide business controls (tax rates, approval rules, chargeback registers) and answer templates. Use them for structure and business rules, not for record data.1718## Output Schema Rules1920- **USD amounts**: always round to 2 decimal places (cents).21- **Ratios**: 4 decimal places (e.g., `0.9000` not `0.9`).22- **Percentages**: 1 decimal place (e.g., `10.0` not `10`).23- **List fields**: sort ascending by ID unless the template explicitly says "set; evaluator sorts values". When the evaluator sorts, any order is accepted but keep IDs unique.24- **ID lists**: all IDs should be strings, not numbers.25- **task_id**: match exactly what the template specifies (e.g., `"train_002"`, `"task_group_006_train_001"`).26- **Dates**: `YYYY-MM-DD` string format.27- **Booleans**: JSON `true`/`false`, not strings.2829## Date Filtering Conventions3031- **"as of" a date**: include records with dates ≤ the as_of_date. Receipts dated after the as_of_date are excluded, even if they share the same PO.32- **"through" a date**: inclusive of the boundary date. "Through 2026-06-30" includes June 30.33- **Invoice dates**: an invoice dated on the as_of_date is included.3435## Business Rules3637### Budget & Contract38- **Budget headroom** = `budget_cap - committed_amount` from the budget snapshot. Do NOT subtract `pending_invoice_amount`.39- **Contract noncancelled subtotal**: sum `subtotal` of all non-cancelled POs referencing that contract. Exclude POs with status `"cancelled"`.40- **Contract headroom** = `ceiling_amount - noncancelled_subtotal`. Then subtract the requested change subtotal for headroom after change.41- **Contract rate**: unit price × tax rate. `requested_tax = requested_subtotal * tax_rate_pct / 100`. `requested_total = requested_subtotal + requested_tax`. No freight unless the memo provides it.42- **Max quantity with budget**: `floor(remaining_budget / (unit_price * (1 + tax_rate)))`. Verify: round down to integer.4344### Receipts & Reconciliation45- **Received goods value** = `received_qty × po_unit_price`.46- **Unreceived goods value** = `(ordered_qty - received_qty) × po_unit_price`.47- **short_qty_vs_po** = `ordered_qty - received_qty`.48- **unreceived_billed_qty** = `billed_qty - received_qty`.49- **receipt_completion_ratio** = `received_qty / ordered_qty` (4 decimal places).50- **quantity_variance** = `billed_qty - received_qty`.51- **quantity_variance_pct** = `(variance / PO_ordered_qty) × 100` (1 decimal place). When no receipt exists, received = 0 and variance = billed, variance_pct = 100.0.5253### Three-Way Match54- PO, receipt, and invoice all exist AND quantities match → `APPROVED_THREE_WAY_MATCH`.55- Missing receipt → `NO_RECEIPT`.56- Quantity mismatch → `QTY_VARIANCE`.57- Invoice has a scheduled payment through the cutoff → `SCHEDULED_PAYMENT_FOUND`.5859### Approval Events60- Find the **latest** approval event (by date) for the target requisition.61- Only actions listed in business controls' `approval_good_actions` count as approved. Typically only `"approved"` counts; `"submitted"`, `"returned"`, `"escalated"` do not.62- Never fabricate approval event data. Use exact API values.6364### Supplier Risk65- `"watch"` risk rating is **context only** — it does not block approval unless an open **severe** (high severity) event exists.66- Non-severe open events still count toward `open_supplier_risk` blocker code and appear in `risk_event_ids`.67- For invoice exception codes: include `SUPPLIER_WATCH_RISK` when the supplier has a `"watch"` rating, regardless of open events.6869### Blockers70- Include **all** applicable codes from the allowed set. Do not include `"none"` when real blockers exist.71- `missing_contract`: no contract exists for the SKU-supplier-program combination.72- `supplier_watch`: supplier `risk_rating` is `"watch"` and task rules treat it as a blocker.73- `open_supplier_risk`: any open risk event for the supplier as of the as_of_date.74- `ap_hold`: any invoice for the line is in `on_hold` or `pending_receipt` status.75- `pending_receipt`: PO is not fully received (status is `open`, `partial_receipt`, or `confirmed` with no receipt).76- `late_due_date`: PO `due_date` is before the as_of_date.7778### Overall Readiness79- Reflect the **worst** line status. If any line is `"not_ready"`, the overall is `"not_ready"`.80- Only use `"ready"` when all lines are `"ready"`.8182### Committee / Escalation83- `next_owner` should be `"program_owner"` when issues span multiple departments (contract, AP, risk).84- `send_to_committee` is `"yes"` when any line is not `"nominate"`.8586### Vendor Balances (AP Close)87- Opening balance for a close slice is given by the memo (often `0.00`).88- `scheduled_payments` = sum of payments for the **target invoices only**, scheduled on or before the cutoff date.89- `close_balance` = `opening_balance + invoice_total - scheduled_payments`.90- Status: `FULLY_SCHEDULED` when close_balance = 0, `OPEN_HELD` when all invoices are held, `OPEN_APPROVED` when all are releasable.9192### Chargebacks (AP Release)93- `approved_chargeback_amount` = chargeback `basis_quantity × unit_cost` for chargebacks with status `"approved"`.94- `pending_chargeback_amount` = same formula for `"pending_quality_review"` chargebacks.95- `net_release_amount` = `invoice_total - approved_chargeback - pending_chargeback`. For held invoices, net_release = 0.96- Receipt exclusion: list receipts for the same PO that are not in the target receipt scope under `excluded_same_po_receipt_ids`.9798### Contract Price Match99- Compare `po_unit_price`, `contract_unit_price`, and `invoice_unit_price`. All three must be equal for `contract_price_match: true`.100101## Arithmetic Checks102103- Budget headroom ≥ 0 before change → budget_ok.104- Contract headroom ≥ 0 after change → ceiling_ok.105- Verify: received_goods + unreceived_goods = ordered_qty × po_unit_price.106- Verify: billed_qty × invoice_unit_price = invoice_subtotal.107- Verify: close_balance = opening + invoice_total - scheduled_payments (per vendor).108- When max_quantity calculation produces a fractional result, floor it. Verify by plugging back: `floor_q × unit_price × (1 + tax_rate) ≤ remaining_budget` and `(floor_q + 1) × unit_price × (1 + tax_rate) > remaining_budget`.109110## Common Pitfalls111112- **Do not add freight to budget exposure** unless the change memo explicitly provides freight.113- **"Submitted" is not "approved"** for approval checks unless business controls say otherwise.114- **Do not subtract pending_invoice_amount from budget headroom** — use committed_amount.115- **Receipt dates** filter as_of_date; future-dated receipts are excluded even for the same PO.116- **Exclude cancelled POs** from contract usage and supporting IDs.117- **Lists are ID sets**: no duplicates, sorting matters unless template says "evaluator sorts".118- **Never fabricate API data**. If the API says action is `"submitted"`, write `"submitted"`, not `"approved"`.119120## Data Integrity121122- Pull all API records before constructing answers. Use the full response — the API returns everything in one call.123- Cross-reference: every invoice's receipt_id should point to a real receipt; if it's `null`, that's intentional.124- Chargeback registers in local payloads reference API records — verify the PO, receipt, and invoice IDs match.125- When a task says "use available shared IDs" or notes that certain identifiers are not in the shared environment, trust the provided mapping.