03 — Integration

SAP AP is a member of the Work & Supply network (message protocol v1) with the network domain finance. Its contract is schema/sap_ap.integration.dsl (authoring spec docs/implementation/integration_authoring_spec.md), generated with python -m codegen.cli integration sap_ap --network work_supply; the handlers are in integration/handlers.py. The whole network is in networks/work_supply/NETWORK_MAP.md.

What it owns

Network entity Model Business reference
finance.purchase_commitment PurchaseCommitment commitment_number (PC-…)
finance.supplier_invoice SupplierInvoice supplier_invoice_number (the supplier's)
finance.supplier_invoice_line SupplierInvoiceLine —
finance.invoice_match InvoiceMatch match_number (IM-{sequence:05})
finance.supplier_credit_memo SupplierCreditMemo credit_memo_number (the supplier's)
finance.ap_transaction ApTransaction ap_document_number (51{sequence:08})
finance.payment_status PaymentStatus —

Messages (all implemented)

Kind Message What
publishes finance.purchase_commitment_posted the order's commitment and SAP PO number (Purchasing records it)
publishes finance.invoice_received an invoice registered (with its duplicate-check result)
publishes finance.invoice_match_completed / invoice_match_exception a match result
publishes finance.ap_posted an AP document posted (transaction_type: invoice_liability, payment, credit_memo)
publishes finance.payment_status_changed due / scheduled / paid / held
publishes finance.work_cost_posted / finance.work_posting_held a closed order's cost posted to its cost centre / held because the asset has no coding
publishes finance.supplier_credit_memo_posted a credit memo posted
consumes asset.asset_reference_changed keeps the readable asset number on AssetCoding current
consumes purchasing.order_placed post the commitment (once per order)
consumes work.work_closed job cost: move the order's cost from work in progress (180000) to its asset's cost centre and ledger account (AssetCoding in force on the finish date), one line per cost type; with no coding the posting is held for finance. The first close of an order is one posting; when it closes again (after a reopen) the cost now, by type, less everything already posted is posted as an amendment, and nothing is posted if there is no difference
consumes inventory.receipt_rejected / receipt_quarantined matched but unposted matches of the order back to exception
consumes work.late_cost_recorded a cost reached an order after it closed: a supplementary posting on the same order, dated the day it is recorded, to the asset's cost centre (held when the asset has no coding)
answers finance.work_posting_status every posting of a work order (the order, supplements, amendments) and what they add up to
accepts finance.repost_held_work try the held work postings again (after an asset has been coded)
accepts finance.post_purchase_commitment post a commitment explicitly
accepts finance.register_supplier_invoice an invoice with its lines (duplicate check)
accepts finance.run_invoice_match match against the order and its accepted receipts
accepts finance.post_ap_liability refused unless matched (and approved where required) and not posted
accepts finance.update_payment_status paid refused without a posted liability
accepts finance.register_supplier_credit_memo posted at once; a duplicate number is refused
answers finance.invoice_status, invoice_match_status, ap_status, credit_memo_status, external_document_mapping read-only

Match evidence: direct queries, not copies

At match time SAP AP asks the owners directly (read-only, service token, not recorded): purchasing.purchase_order_status for the order lines with quantities and prices, and inventory.purchase_order_receipts (added for this) for every receipt of the order with received and accepted quantities. If either application cannot be reached the match is refused (source_unavailable) rather than run on stale data.

Who refers to it

Purchasing stores the SAP PO number on the order (external_erp_reference) from finance.purchase_commitment_posted. Nothing else consumes finance events yet; a later stage can show invoice / payment status on the order and feed warranty recoveries into credit memos.

Differences from the pack

The pack's commitment and payment events named Purchasing's order and the invoice; here they name SAP AP's own entities (finance.purchase_commitment, finance.payment_status), because an event's entity must belong to its publisher. Match policies are data rows, not contract blocks; the pack's invariants are enforced by the handlers and listed in sap_ap.integration.yaml. See the contract's header for the full list.