# vendor-invoice-processing

## Overview

Captures vendor invoices as Account Payable documents and matches them to purchase orders and receipts. A PO is placed and goods are received; when the vendor's invoice arrives, the Purchaser / AP operator captures it as an `AccountPayableDocument` in DRAFT status — either **from the PO** (lines pre-filled from the order and matched) or as an **"Other" invoice** for non-PO charges such as freight, fees, adjustments, and spot buys. The DRAFT invoice is then registered. Registration runs **3-way matching** (ordered vs received vs invoiced) on PO-sourced lines and places SYSTEM `AccountPayableDocumentHold` rows on any variance; **registration still succeeds even when holds are placed**. An operator reviews and releases holds. Registering an invoice against a PO also advances the linked PO's `billingStatus`.

This template exposes **create + register + release-hold** only. Posting to the general ledger (the native `post` transition) is **out of scope** — financial-accounting is wired for the native direct-posting command, but no post action is exposed. Documents are created as `documentType` INVOICE only (the native `CREDIT_MEMO` type is not created here).

## Actors Involved

- [Purchaser](../../actor/purchaser.md) — captures, registers, and reviews vendor invoices (acting as the AP operator)

See [action-matrix.md](./action-matrix.md) for models involved and the action visibility matrix.

## Flow Diagram

```mermaid
sequenceDiagram
    participant P as Purchaser
    participant S as System

    Note over S: A PO is placed (purchase-order-lifecycle) and goods are received (inbound-shipment-processing) before the vendor invoice arrives

    alt PO invoice — matched to a PO
        P->>S: Create invoice from an ORDERED PO (lines pre-filled)
        S-->>P: Invoice in DRAFT status (PURCHASE_ORDER-sourced lines)
    else Other invoice — no PO
        P->>S: Create "Other" invoice (supplier + manual amount-only lines)
        S-->>P: Invoice in DRAFT status (unmatched lines)
    end

    P->>S: Register invoice
    S->>S: Run 3-way matching on PO-sourced lines (ordered vs received vs invoiced)
    alt Variance detected
        S->>S: Raise SYSTEM AccountPayableDocumentHold rows
    end
    S-->>P: Invoice status → REGISTERED (succeeds even with holds)
    S->>S: Recalculate linked PurchaseOrder billingStatus

    alt Holds present
        P->>S: Review holds, then release hold (optional reason)
        S-->>P: Hold released — posting no longer blocked by it
    end

    Note over P,S: Posting to the general ledger (post) is out of scope for this template
```

## Stories

- [Create Vendor Invoice](./story/purchaser--create-vendor-invoice.md)
- [Register Vendor Invoice](./story/purchaser--register-vendor-invoice.md)
- [Release Invoice Hold](./story/purchaser--release-invoice-hold.md)
