feat(bank-match): exact tx-id match pass (consumes payment transaction_id)
The consumer side of erp#26/#27: now that a règlement stores its originating bank transaction id (transaction_id -> llx_bank.num_chq), bank-match uses it. New PASS 0 (exact), highest priority, before wire-ref and amt+date: - carry each feed movement's own id (Qonto transaction id; Wise activity + transfer resource id) as feed_ids, and each Dolibarr payment's num. - match when a payment's num equals a feed id. Tagged [tx-id]. - DATE-WINDOW-INDEPENDENT — the id is proof, so it pairs movements whose bank settlement and Dolibarr saisie are weeks apart (which amt+date would miss). Pass 0 runs before the ref index is built, so its matches are excluded from the later passes (no double-match). Fixture-proven: a payment dated 15d off the bank movement (outside the ±7d window) matches via [tx-id] when num carries the Qonto id, and correctly does NOT match when num is empty. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -175,7 +175,7 @@ V7 adds three improvements that reshape the output buckets:
|
||||
|
||||
| Bucket | Meaning | Counts toward exit-1? |
|
||||
|---|---|---|
|
||||
| **MATCHED** | Bank ↔ Dolibarr paired. Annotated with match kind: `[wire-ref]` (strong, via `--enrich`) or `[amt+date]` (loose). | No |
|
||||
| **MATCHED** | Bank ↔ Dolibarr paired. Match kind: `[tx-id]` (exact — the payment's `transaction_id` equals the feed tx id; date-independent), `[wire-ref]` (strong, via `--enrich`), or `[amt+date]` (loose). | No |
|
||||
| **INTERNAL** | Wise↔Qonto consolidations (5000€ moved between Arcodange's own accounts). | No |
|
||||
| **AVOIR-NETTED** | Dolibarr AVC + FAC cancellation cycles paired and excluded (the bank only saw the net). | No |
|
||||
| **BANK-ONLY — known patterns** | Bank movement with a `known-patterns.json` annotation. Intentional gap. | No |
|
||||
@@ -185,6 +185,18 @@ V7 adds three improvements that reshape the output buckets:
|
||||
|
||||
Exit code 0 iff the two "real gap" buckets are empty.
|
||||
|
||||
### Matching priority — exact tx-id first
|
||||
|
||||
Matching runs in three passes, highest confidence first:
|
||||
|
||||
1. **`[tx-id]` (exact)** — a Dolibarr payment whose stored `num` (`llx_bank.num_chq`,
|
||||
set from the règlement's `transaction_id`, see `dolibarr-sandbox-write`) equals the
|
||||
feed transaction's own id. **Date-window-independent** — the id is proof, so it
|
||||
matches even when bank settlement and Dolibarr saisie are weeks apart. Record
|
||||
payments with their `transaction_id` and reconciliation becomes deterministic.
|
||||
2. **`[wire-ref]` (strong)** — via `--enrich`, below.
|
||||
3. **`[amt+date]` (loose)** — the fallback heuristic.
|
||||
|
||||
### `--enrich` — wire-reference strong matching
|
||||
|
||||
`bank-match.sh --enrich` fetches `/v1/transfers/{id}` for each Wise TRANSFER and reads the `reference` field (the wire memo from the sender, e.g. `FROM KISSMETRICS HOLDINGS INC FOR INVOICE FAC002CL0001002/ VENDOR:DEV`). When the reference contains a `FAC\d+(CL\d+)?` pattern matching a Dolibarr customer invoice, that pairing takes precedence over the loose date+amount match. Only the strong-matched ones get `[wire-ref]`; the rest fall through to `[amt+date]`. Cost: 1 extra HTTP call per Wise transfer.
|
||||
|
||||
Reference in New Issue
Block a user