# Supplier Bill Matching

## Overview

Supplier Bill Matching captures supplier invoices as `PurchaseBill` documents and validates them against the commercial and fulfillment evidence already recorded in purchase. Each bill line optionally references a purchase order line — bills can be created without a PO reference to support spot purchases, expense-type invoices, and scenarios where the invoice arrives before a PO is confirmed. When a PO reference is present and 3-way matching is required, the matching also validates against posted goods receipts that prove quantity has actually been received. The result is a procurement-side decision: is this supplier invoice commercially acceptable, blocked for variance, cancelled before downstream acceptance, or ready for downstream accounts payable?

Matching results are recorded as append-only `ThreeWayMatchEvent` records that capture the explicit relationship between bill lines and receipt lines. This provides a direct audit trail independent of the PO-line-based indirect relationship, and supports scenarios where bills or receipts exist without PO references.

This feature does not post journal entries or execute payment. Its responsibility is to compare what the supplier invoiced with what was ordered and received, detect mismatches, and preserve tax and invoice identity required for legal validity. The minimum bill lifecycle is `DRAFT` → `BLOCKED` or `MATCHED`, with `CANCELLED` available only before the bill is matched.

## Business Purpose

- Prevent overbilling by ensuring supplier invoices align with ordered and received quantities
- Detect price variances between purchase order commitments and supplier invoice lines
- Support both 2-way matching (order to invoice) and 3-way matching (order, receipt, invoice)
- Provide a clear blocked-versus-ready status before bills reach downstream accounts-payable workflows
- Allow draft or blocked bills to be cancelled before a bill is matched
- Carry supplier invoice identity, payment-term snapshot, and due-date schedule into payable processing
- Capture supplier tax identifiers, tax codes, and tax amounts needed by downstream AP validation
- Preserve an auditable link between invoice lines, purchase orders, and receipts through ThreeWayMatchEvent records
- Support PO-unlinked bill lines for invoices without a corresponding purchase order

## Process Flow

```mermaid
flowchart TD
    A[Create Purchase Bill] --> B[Enter supplier invoice reference and lines]
    B --> C[Match bill lines to PO lines]
    C --> D{Matching mode?}
    D -->|2-way| E[Compare invoice to ordered qty and price]
    D -->|3-way| F[Compare invoice to ordered qty, price, and posted receipts]
    E --> G{Within tolerance?}
    F --> G
    G -->|No| H[BLOCKED FOR VARIANCE]
    G -->|Yes| I[MATCHED]
    I --> J[Calculate due schedule from payment term]
    J --> K[Bill matched and due schedule calculated]
    H --> L{Cancel?}
    I --> L
    L -->|Yes| M[CANCELLED]
    L -->|No| J
```

## Scenario Patterns

- **Perfect 3-way match**: The supplier invoice arrives after the goods receipt, and billed quantities and prices match the purchase order exactly, so the bill is marked ready. ThreeWayMatchEvent records capture the bill-line-to-receipt-line correspondence
- **Price variance within tolerance**: The supplier invoice price differs slightly from the ordered price due to exchange rounding or minor surcharge, and the configured tolerance allows the bill through
- **Quantity variance blocked**: The supplier invoices 100 units, but only 80 have been received under a 3-way match policy, so the bill is blocked pending additional receipt or correction
- **2-way matching for non-stock procurement**: A service purchase is matched only against the purchase order because warehouse receipt proof is not required by policy
- **Duplicate invoice prevention**: The same supplier invoice number is entered twice for one company and supplier, and the second attempt is rejected
- **PO-unlinked invoice**: A supplier invoice arrives for a spot purchase without a PO. The bill is created with PO-unlinked lines. PO-unlinked lines are included in bill amount calculation but skip PO-based quantity and price variance checks during matching
- **Partial billing**: The supplier bills only the first shipment of a larger order; the matched quantity is recorded and the order remains open for later bills
- **Pre-match cancellation**: A draft or blocked bill is discovered to contain the wrong supplier invoice reference, so procurement cancels the bill and preserves the original evidence for audit and future correction workflows
- **Credit or correction workflow precursor**: A supplier invoice is overbilled and blocked or cancelled, creating the basis for a future thin `PurchaseCreditNote` or bill-revision workflow without redesigning the `PurchaseBill` state machine
- **Payment-term inheritance**: The bill inherits the order's negotiated payment term so downstream AP sees the correct due dates
- **Tax snapshot capture**: The bill snapshots supplier tax identification, tax code, taxable amount, and tax amount so legal invoice validation survives later supplier-master edits

## Test Cases

- Creating a purchase bill with a valid supplier, company, and at least one bill line should succeed
- Creating a purchase bill with PO-unlinked lines (no purchaseOrderLineId) should succeed
- A PO-linked purchase bill line must reference a valid purchase order line
- Every bill line must record a billed quantity greater than zero
- Duplicate supplier invoice numbers for the same supplier and company should be rejected
- A 2-way matched bill must compare billed quantity and price to the referenced purchase order line
- A 3-way matched bill must not approve a billed quantity greater than the cumulative posted receipt quantity, subject to configured tolerance
- A bill with a price variance above configured tolerance should be marked blocked rather than matched
- A bill matched to a cancelled purchase order should fail
- A matched bill must snapshot the supplier invoice date, external invoice number, ordered price reference, assigned payment term, supplier tax identifier, tax code, taxable amount, and tax amount
- Partial billing must increase the purchase order line billed quantity without forcing the order closed
- A supplier bill must not be considered ready for downstream AP until all required matching checks pass
- A draft or blocked bill may transition to `CANCELLED`
- Cancelling a bill must preserve the original variance evidence and line references for future credit-note or dispute workflows
- Bills must be isolated by company and must not reference purchase orders from another company
- If a bill is blocked for variance, the variance reason and comparison basis should remain visible for review
- Matching logic must preserve whether the bill used 2-way or 3-way matching
- Only authorized procurement or AP users should be able to match, block, or release supplier bills
- A matched bill should expose the due-date schedule calculated from the assigned purchase payment term
- Matching must create ThreeWayMatchEvent records for each bill-line-to-receipt-line correspondence
- PO-unlinked bill lines should be included in bill amount calculation but skip PO-based variance checks
- Editing supplier price rules after bill creation must not change the comparison baseline for an existing matched or blocked bill

## Reference Links

- [Odoo vendor bills and three-way matching](https://www.odoo.com/documentation/19.0/applications/inventory_and_mrp/purchase/manage_deals/manage.html#vendor-bills)
- [Oracle invoice matching overview](https://docs.oracle.com/en/cloud/saas/financials/24c/fappp/invoice-matching.html)
- [SAP supplier invoice and invoice verification documentation](https://help.sap.com/docs/SAP_S4HANA_CLOUD)
