# PurchaseBill

## Description

PurchaseBill captures a supplier invoice inside the purchase domain until procurement matching is complete. It compares supplier-invoiced quantities, prices, and tax information against purchase-order commitments and, when required, posted goods receipts. The bill is then marked matched, blocked for variance, or cancelled.

Bill lines optionally reference a purchase-order line. PO-unlinked bill lines support scenarios where a supplier invoice arrives without a corresponding purchase order (spot purchases, expense-type invoices). The PO reference can be assigned later before matching. Matching results are recorded as append-only [ThreeWayMatchEvent](./ThreeWayMatchEvent.md) records that capture the explicit relationship between bill lines and receipt lines for audit.

## Domain Model Definitions

### Model type

Stateful

#### State Transitions

```mermaid
stateDiagram-v2
    [*] --> Draft: createPurchaseBill
    Draft --> Draft: updatePurchaseBill
    Draft --> Blocked: matchPurchaseBill
    Draft --> Matched: matchPurchaseBill
    Blocked --> Matched: releasePurchaseBill
    Draft --> Cancelled: cancelPurchaseBill
    Blocked --> Cancelled: cancelPurchaseBill
```

| Operation | From | To | Command |
|-----------|------|----|---------|
| block | DRAFT | BLOCKED | [matchPurchaseBill](../commands/MatchPurchaseBill.md) |
| match | DRAFT | MATCHED | [matchPurchaseBill](../commands/MatchPurchaseBill.md) |
| release | BLOCKED | MATCHED | [releasePurchaseBill](../commands/ReleasePurchaseBill.md) |
| cancel | DRAFT, BLOCKED | CANCELLED | [cancelPurchaseBill](../commands/CancelPurchaseBill.md) |

### Command Definitions

- [createPurchaseBill](../commands/CreatePurchaseBill.md) - Create a draft supplier bill with invoice identity and line references
- [updatePurchaseBill](../commands/UpdatePurchaseBill.md) - Revise a draft bill before procurement matching is finalized
- [matchPurchaseBill](../commands/MatchPurchaseBill.md) - Run 2-way or 3-way matching and set the bill to matched or blocked
- [releasePurchaseBill](../commands/ReleasePurchaseBill.md) - Move a blocked bill to matched after authorized variance resolution
- [cancelPurchaseBill](../commands/CancelPurchaseBill.md) - Cancel a draft or blocked bill

### Query Definitions

- [getPurchaseBill](../queries/GetPurchaseBill.md) - Retrieve a supplier bill with matching results, snapshots, and line references
- [calculatePurchaseBillDueSchedule](../queries/CalculatePurchaseBillDueSchedule.md) - Compute the downstream payable schedule from the bill's payment-term snapshot

### Models

- PurchaseBill
- PurchaseBillLine

### Invariants

- Every purchase bill belongs to exactly one company and one supplier
- Supplier invoice number is unique within one company and supplier combination
- Every bill line records billed quantity greater than zero
- Bill lines optionally reference a purchase-order line; PO-unlinked bill lines are permitted for invoices without a corresponding purchase order
- When a purchase-order-line reference is present, the referenced purchase order must not be cancelled
- `MATCHED` bills preserve the comparison baseline: invoice date, invoice number, ordered price reference, payment-term snapshot, supplier tax identifier, tax code, taxable amount, and tax amount
- A 3-way match cannot mark a bill as matched when billed quantity exceeds cumulative posted receipt quantity beyond tolerance
- PO-unlinked bill lines are included in bill amount calculation but skip PO-based quantity and price variance checks during matching
- Matching results are recorded as append-only ThreeWayMatchEvent records for audit
- `BLOCKED` bills must preserve the variance reason and comparison basis for review
- `CANCELLED` is allowed only from `DRAFT` or `BLOCKED`
- 4-way matching is explicitly out of scope for this module plan; quality evidence can be added as a future extension without redesigning the bill lifecycle
- Credit-note and debit-memo workflows are future extensions that must preserve the original bill evidence rather than rewriting it
- Every purchase bill line belongs to exactly one purchase bill
- Billed quantity must be positive
- Every bill line must carry a unit of measure; PO-linked lines inherit unitId from the purchase-order line when not explicitly provided, PO-unlinked lines must provide unitId explicitly

### Relationships

- **Belongs To BusinessPartner**: Each bill references one supplier [BusinessPartner](../../../business-partner/docs/models/BusinessPartner.md)
- **References PurchaseOrder**: Bill lines optionally reference one or more [PurchaseOrder](./PurchaseOrder.md) lines
- **References GoodsReceipt**: 3-way matching may compare against posted [GoodsReceipt](./GoodsReceipt.md) lines
- **Has Many ThreeWayMatchEvents**: Matching creates append-only [ThreeWayMatchEvent](./ThreeWayMatchEvent.md) records that capture the explicit bill-line-to-receipt-line relationship for audit
- **Snapshots PurchasePaymentTerm**: The bill carries a [PurchasePaymentTerm](./PurchasePaymentTerm.md) snapshot and calculated due schedule
- **Snapshots PartnerIdentification**: The bill stores supplier tax identity from [PartnerIdentification](../../../business-partner/docs/models/PartnerIdentification.md)
- **PurchaseBillLine References PurchaseOrderLine (nullable)**: `purchaseOrderLineId` optionally identifies which order line this bill covers; null for PO-unlinked invoices
