Skip to main content
Quanta Meridian logo
Reporting Foundations

Purchase Order, Receipt and Invoice Reconciliation

A three-way reconciliation checks whether the purchase order, warehouse receipt and supplier invoice agree before an invoice is cleared for payment.

Project previewOpen full image

Before an invoice is paid

Should this supplier invoice be paid?

A buyer confirms what was ordered. The warehouse records what arrived. Accounts Payable records what the supplier billed. This build compares those events for every purchase order item, clears supported cases and holds the rest for the team that can resolve them.

251,734 purchase items=217,055 supported+34,679 held

The equation comes from the complete BPI Challenge 2019 build. Each item has one final class. Consignment items are kept outside the invoice decision rather than forced through a rule that does not apply. The retained reconciliation residual is 0 purchase items.

Purchase items in the event log251,734
Can be paid or continued

The purchase item has the required order, receipt and invoice evidence for its rule.

202,557
Outside the normal invoice decision

Consignment items remain visible but do not enter the standard supplier-invoice release.

14,498
Held before payment

A missing document, reversal or value difference keeps the item with a named team.

34,679

217,055 items are supported overall; 34,679 remain held before payment.

Primary retained evidence

The release equation, exception rows and trace come from the rebuilt outputs.

This evidence view is rendered from the retained DuckDB exports after the complete event log has been classified. It is not an Accounts Payable product screenshot; the executable matching SQL and source limits remain inspectable below.

Retained DuckDB output · complete BPI Challenge 2019 build

251,734 purchase items reconcile to 217,055 supported and 34,679 held, with a zero-item residual. The dedicated mobile image keeps two complete exception rows readable.

Invoices that still need a decision

The difference stays beside the team that can investigate it.

The queue below is exported from DuckDB. It shows one retained item from several unresolved classes, including a missing invoice, a missing receipt, a reversal and a recorded value difference.

Purchase itemReasonPurchase valueReceipt valueInvoice valueAge at event-log closeResponsible teamDecision
4507000280_00010Purchase item was cancelled or deleted39700702 daysBuyerpayment hold
4507000473_00001Invoice is missing9276,6750702 daysAccounts Payablepayment hold
4507075965_00020A receipt or invoice was cancelled2650265686 daysFinance reviewerpayment hold
4507000855_00080Recorded values differ8817788672 daysBuyerpayment hold
4507004049_00030Warehouse receipt is missing92092658 daysWarehouse receivingpayment hold

Values are the publisher's translated monetary fields. They preserve comparisons but do not represent disclosed currency amounts.

Exception reason Pareto

Most held items are missing an invoice or need a buyer decision.

  1. Invoice is missingAccounts Payable
    17,751
  2. Purchase item was cancelled or deletedBuyer
    8,417
  3. A receipt or invoice was cancelledFinance reviewer
    6,659
  4. Recorded values differBuyer
    1,556
  5. Warehouse receipt is missingWarehouse receiving
    296

How the decision is made

The purchase, receipt and invoice meet before payment.

The BPI item record states whether a goods receipt is required. Two-way items compare the purchase item and supplier invoice. Three-way items also require a warehouse receipt. Ordered rules then deal with timing, repeated events, reversals and missing records.

Purchase order, goods receipt and supplier invoice matchingA purchase order, warehouse goods receipt and supplier invoice converge on ordered matching rules. Supported items continue to payment. Missing, cancelled or different records branch to the responsible team with their event history retained.BUYERPURCHASE ORDER ITEMWAREHOUSEGOODS RECEIPTACCOUNTS PAYABLESUPPLIER INVOICESHOULD THISINVOICE BE PAID?ORDER, RECEIPT AND BILL PRESENT?VALUES WITHIN RULE?BLOCK, REVERSAL OR TIMING NOTE?251,734 ITEMS CLASSIFIED ONCEPAY OR CONTINUERequired records support the releaseDO NOT PAY YETBuyer, warehouse, AP or finance review
  1. 01
    The buyer raises a purchase item

    The purchase document, supplier and required receipt rule remain attached.

  2. 02
    The warehouse records what arrived

    Receipt, cancellation and repeated receipt events stay in recorded order.

  3. 03
    Accounts Payable records the invoice

    The build checks whether the required records and translated values agree.

  4. 04
    The item is cleared or held

    A held item keeps its reason, responsible team, age and complete event history.

Four routes that must not be conflated

Quantity, value, timing and missing records lead to different decisions.

A credible three-way control has to say which comparison failed, whether the retained source can test it and who owns the next action. These routes use only fields and counts present in the retained event-log build.

  1. 01

    Quantity

    Not recordedThe event log does not expose ordered, received or invoiced physical quantities. A production quantity rule would need those fields before payment release.
    Decision
    Cannot test from this source
    Next team
    Additional purchasing extract required
  2. 02

    Price / recorded value

    1,556 itemsUnit prices are not exposed. The retained rule compares the translated purchase, receipt and invoice values and sends differences to the buyer.
    Decision
    Payment hold
    Next team
    Buyer
  3. 03

    Timing

    109,197 itemsAn invoice recorded before its required receipt waits for the warehouse event; once values agree, the block can be removed with the event order retained.
    Decision
    Cleared with timing note
    Next team
    Accounts Payable
  4. 04

    Missing record

    18,047 itemsA missing invoice stays with Accounts Payable. A three-way item without a receipt stays with the warehouse until the missing record is supplied or explained.
    Decision
    Payment hold
    Next team
    Accounts Payable or warehouse

What the comparison found

Exact, grouped, timing and exception paths are all retained.

The full event log naturally exercises twelve of the fourteen configured classes. Small-value tolerance and partial-open behaviour are tested with explicit SQL fixtures because those two edge cases are not present in the public event log.

  1. 01
    Warehouse receipt is missing

    A three-way item stays on hold until warehouse receiving records what arrived or corrects the purchase record.

    Purchase items
    296
    Payment state
    payment hold
    Next team
    Warehouse receiving
  2. 02
    A receipt or invoice was cancelled

    A finance reviewer checks the reversal history before the item can be cleared.

    Purchase items
    6,659
    Payment state
    payment hold
    Next team
    Finance reviewer
  3. 03
    Invoice arrived before receipt

    The invoice waited until the warehouse receipt was recorded, then Accounts Payable cleared it with the timing history retained.

    Purchase items
    109,197
    Payment state
    cleared with timing note
    Next team
    Accounts Payable
  4. 04
    Several receipt events

    More than one goods receipt belongs to the purchase item. The events are reviewed together before the invoice is cleared.

    Purchase items
    1,076
    Payment state
    cleared after grouped review
    Next team
    Warehouse receiving
  5. 05
    Purchase, receipt and invoice agree

    The required documents are present and their recorded translated values agree.

    Purchase items
    89,301
    Payment state
    cleared by rule
    Next team
    Accounts Payable
  6. 06
    Recorded values differ

    The buyer reviews the purchase record and supplier bill because the translated values do not agree within the configured rule.

    Purchase items
    1,556
    Payment state
    payment hold
    Next team
    Buyer

Executable matching artefact

The payment state is assigned by ordered SQL, not by the website.

The retained SQL classifies each purchase item once, joins it to the named rule and assigns the payment state and responsible team. It runs against the retained DuckDB database during the verifier; this excerpt is the executable file.

30_apply_matching.sqlExecuted in the verified rebuild
CREATE TABLE mart.purchase_item_reconciliation AS
WITH classified AS (
  SELECT
    comparison.*,
    CASE
      WHEN match_requirement = 'CONSIGNMENT'
        THEN 'OUTSIDE_INVOICE_SCOPE'
      WHEN deleted_event_count > 0
        THEN 'CANCELLED_OR_DELETED'
      WHEN invoice_receipt_event_count = 0
        THEN 'MISSING_INVOICE'
      WHEN match_requirement = 'THREE_WAY'
        AND goods_receipt_event_count = 0
        THEN 'MISSING_RECEIPT'
      WHEN reversal_event_count > 0
        THEN 'REVERSAL_REVIEW'
      WHEN invoice_arrived_before_receipt
        AND cleared_after_receipt
        AND purchase_to_invoice_difference <= value_tolerance
        AND receipt_to_invoice_difference <= value_tolerance
        THEN 'TIMING_ITEM_RESOLVED'
      WHEN goods_receipt_event_count > 1
        AND invoice_receipt_event_count > 1
        AND purchase_to_invoice_difference <= value_tolerance
        AND receipt_to_invoice_difference <= value_tolerance
        THEN 'MANY_TO_MANY'
      WHEN goods_receipt_event_count > 1
        AND invoice_receipt_event_count = 1
        AND purchase_to_invoice_difference <= value_tolerance
        AND receipt_to_invoice_difference <= value_tolerance
        THEN 'ONE_TO_MANY_RECEIPTS'
      WHEN goods_receipt_event_count <= 1
        AND invoice_receipt_event_count > 1
        AND purchase_to_invoice_difference <= value_tolerance
        AND receipt_to_invoice_difference <= value_tolerance
        THEN 'ONE_TO_MANY_INVOICES'
      WHEN match_requirement = 'THREE_WAY'
        AND purchase_to_invoice_difference <= 0.01
        AND receipt_to_invoice_difference <= 0.01
        THEN 'EXACT_THREE_WAY'
      WHEN match_requirement = 'TWO_WAY'
        AND purchase_to_invoice_difference <= 0.01
        THEN 'EXACT_TWO_WAY'
      WHEN purchase_to_invoice_difference <= value_tolerance
        AND receipt_to_invoice_difference <= value_tolerance
        THEN 'WITHIN_VALUE_TOLERANCE'
      WHEN recorded_invoice_value < purchase_item_value
        AND invoice_cleared_at IS NULL
        THEN 'PARTIAL_OR_OPEN'
      ELSE 'VALUE_DIFFERENCE'
    END AS match_class
  FROM staging.document_comparison AS comparison
)
SELECT
  classified.*,
  rule.rule_id,
  rule.priority AS rule_priority,
  rule.condition_summary,
  rule.responsible_team,
  rule.decision,
  CASE
    WHEN match_class IN (
      'OUTSIDE_INVOICE_SCOPE',
      'TIMING_ITEM_RESOLVED',
      'ONE_TO_MANY_RECEIPTS',
      'ONE_TO_MANY_INVOICES',
      'MANY_TO_MANY',
      'EXACT_THREE_WAY',
      'EXACT_TWO_WAY',
      'WITHIN_VALUE_TOLERANCE'
    ) THEN 'SUPPORTED'
    ELSE 'UNRESOLVED'
  END AS final_group,
  CASE
    WHEN match_class = 'OUTSIDE_INVOICE_SCOPE' THEN 'OUTSIDE_SCOPE'
    WHEN match_class = 'TIMING_ITEM_RESOLVED' THEN 'CLEARED_WITH_TIMING_NOTE'
    WHEN match_class IN (
      'ONE_TO_MANY_RECEIPTS',
      'ONE_TO_MANY_INVOICES',
      'MANY_TO_MANY'
    ) THEN 'CLEARED_AFTER_GROUPED_REVIEW'
    WHEN match_class IN (
      'EXACT_THREE_WAY',
      'EXACT_TWO_WAY'
    ) THEN 'CLEARED_BY_RULE'
    WHEN match_class = 'WITHIN_VALUE_TOLERANCE' THEN 'CLEARED_WITH_TOLERANCE'
    ELSE 'PAYMENT_HOLD'
  END AS payment_state,
  CASE
    WHEN match_class IN (
      'OUTSIDE_INVOICE_SCOPE',
      'TIMING_ITEM_RESOLVED',
      'ONE_TO_MANY_RECEIPTS',
      'ONE_TO_MANY_INVOICES',
      'MANY_TO_MANY',
      'EXACT_THREE_WAY',
      'EXACT_TWO_WAY',
      'WITHIN_VALUE_TOLERANCE'
    ) THEN 0
    ELSE GREATEST(
      0,
      DATE_DIFF(
        'day',
        CAST(last_event_at AS DATE),
        (
          SELECT MAX(CAST(event_timestamp AS DATE))
          FROM staging.events
          WHERE event_timestamp >= TIMESTAMPTZ '2018-01-01 00:00:00+00'
            AND event_timestamp < TIMESTAMPTZ '2020-01-01 00:00:00+00'
        )
      )
    )

The retained source files are the XES event log, the executable SQL and Python build, the DuckDB reconciliation database and the exported exception, validation and trace files.

One purchase item traced

This invoice waited for the warehouse receipt.

Purchase item 4507000232_00010 carried the same translated value of 564 on the purchase, receipt and invoice events. The invoice was recorded first, so payment stayed blocked until the warehouse event arrived.

Supplier invoice decision
Clear with retained timing note
Responsible team
Accounts Payable
Purchase item value
564
Purchase item4507000232 / 00010

2 Jan 2018

Supplier invoicevendor_0112

3 Jan 2018

Warehouse receiptGoods receipt recorded

4 Jan 2018

Event order

The event history explains the payment hold and release.

The item history is generated from the retained event extract. It is not a narrative added after the page was written.

  1. 01Create Purchase Order Item

    Buyer · 2 Jan 2018

  2. 02Vendor creates invoice

    Accounts Payable · 2 Jan 2018

  3. 03Record Invoice Receipt

    Accounts Payable · 3 Jan 2018

  4. 04Record Goods Receipt

    Warehouse receiving · 4 Jan 2018

  5. 05Remove Payment Block

    Accounts Payable · 4 Jan 2018

  6. 06Clear Invoice

    Accounts Payable · 25 Jan 2018

Accounts Payable removed the block after receipt and cleared the invoice on 25 Jan 2018. The retained decision is “clear with timing note”.

Checks before report release

Twenty-one checks passed on the complete build.

SQL checks the publisher counts, unique keys, classification, responsible teams, summary tie-outs, one purchase item and rule edge cases. A second verifier reads the exported files without querying DuckDB.

VAL-01

Complete purchase-item source retained

PASS
VAL-02

Complete event source retained

PASS
VAL-10

No purchase item is classified twice

PASS
VAL-12

Every unresolved item has a responsible team

PASS
VAL-14

Summary item counts tie to detail

PASS
VAL-19

Out-of-window timestamps are retained as exceptions

PASS

Technical disclosure

The detailed dataset limits stay with the rebuild evidence.

The public page uses the verified counts and keeps the licence, checksum, anomaly list, SQL and independent verifier available for inspection.

Technical detailsOpen the DOI, rebuild command, checks and event-log limits

The build processes all 1,595,923 recorded events for 251,734 purchase order items in BPI Challenge 2019. It retains the publisher DOI, licence, checksum and 320 timestamps outside the main 2018–2019 process window as visible data exceptions.

npm run verify:reconciliation

The command verifies the 728 MB XES file, streams every trace, rebuilds the DuckDB model, exports the decisions and checks those files independently.

Published by 4TU.Centre for Research Data under CC BY 4.0. The DOI resolves to the historical, anonymised BPI Challenge 2019 purchase-to-pay event log.

  • BPI Challenge 2019 is historical anonymised research data and does not describe current organisational performance.
  • The publisher translated monetary values, so displayed values support comparison but are not disclosed currency amounts.
  • The BPI event log does not expose physical ordered, received or invoiced quantities. Quantity matching would require an additional documented extract.
  • The build is not an Accounts Payable product, an audit opinion or proof that a live financial control is effective.

Next step

Review the controls beneath a supplier payment queue.

Start with the files, joins and checks that make the current report difficult to explain or maintain.