Invoice ↔ GRN Direct Matching

Problem

A client sends invoices and GRNs (goods received notes / delivery slips) without purchase orders. The current matching system only connects GRNs to invoices indirectly through a shared PO cluster. Without POs, these documents remain unmatched.

Solution

Add #{"invoice" "goods-received-note"} as a directly matchable pair, with appropriate evidence signals, LLM prompts, and UI support.

Cardinality

One invoice typically references multiple GRNs (partial deliveries aggregated into a single invoice). One GRN typically maps to one invoice but many-to-many is possible.

Changes

1. Matchable pair registration

candidates.clj: Add #{"invoice" "goods-received-note"} to matchable-pairs. Candidate retrieval and type filtering derive from this automatically.

view/shared.clj: Add :goods-received-note to invoice's counterpart-types list and :invoice to GRN's list.

2. Evidence signals (evidence.clj)

New signal: gr-reference-exact (+55)

Checks if invoice gr-references intersects with GRN delivery-note-numbers or grn-number. Weight 55 matches po-ref-exact — same class of cross-document reference match.

Requires a get-gr-references extractor (invoice yields gr-references, GRN yields grn-number + delivery-note-numbers) and a set intersection in collect-signals.

Extended signal: date-within-period (+20)

Add a case: when one document has a service-period (invoice) and the other has a receipt-date (GRN), check if the receipt date falls within the service period. Reuses the existing signal name.

Expected scoring for correct matches:

3. LLM prompts (llm_decision.clj)

["invoice" "goods-received-note"]: One invoice can match multiple GRNs. Focus on GR references vs delivery note numbers, product descriptions, quantity aggregation (GRN quantities sum to invoice line items), delivery dates within service period. Many matches expected.

["goods-received-note" "invoice"]: Single GRN typically matches one invoice. Same signals from GRN perspective. Allow many matches.

4. Reconciliation

No changes. The reconciliation system is generic — it loads all cluster documents and compares them via LLM. Invoice↔GRN clusters will automatically get quantity reconciliation (GRN quantity-received aggregated vs invoice line item quantities).

5. No changes needed

Matching signals summary (invoice ↔ GRN)

Signal Weight Source
gr-reference-exact +55 Invoice gr-references ∩ GRN delivery-note-numbers/grn-number
description-overlap +25 Line item description token Jaccard > 15%
quantity-exact +35 Individual quantity matches (not aggregated)
date-within-period +20 GRN receipt-date within invoice service-period
vat-id-match +30 Rarely fires — GRN delivery slips often lack VAT ID
currency-mismatch -30 Safety check
vat-id-mismatch -40 Safety check