fix(txid): normalize bank tx ids to fit Dolibarr's num_payment varchar(50)
Qonto transaction ids run ~67 chars (<org>-<n>-<n>-transaction-<uuid>) but Dolibarr stores num_payment in varchar(50) (llx_paiement.num_paiement, llx_paiementfourn.num_paiement) — POSTing a payment with the raw id fails HTTP 400 "value too long for type character varying(50)". Parade proven live on the sandbox (2026-07-11): store the UUID suffix (globally unique, ~37 chars). Wise ids (short numerics) are unaffected. Writer side — payment-record.sh strips everything through "transaction-" before POST, announces the normalization on stderr, REFUSES (never truncates) ids still >50 chars after normalization, and emits the normalized num in the output JSON. Reader side — bank-match.sh PASS 0 (exact tx-id, erp#28) now compares BOTH sides in raw AND canonical short form: Qonto feed ids are carried long+short, payment nums are normalized on compare — so nums stored short (the varchar(50) form) and historical long-form nums both keep matching. Wise ids untouched. Proven offline (no credentials, no network, no sandbox/prod writes): - arcodange-bank-reco/tests/run-tests.sh — new bank-match --fixtures offline mode: long feed id ↔ short num, long ↔ long (back-compat), Wise numeric, each Δ+19d outside the ±7d window so only PASS 0 can pair them (exit 0, 3×[tx-id]); plus the empty-num negative (exit 1, 0 matched). - dolibarr-sandbox-write/tests/run-tests.sh — payment-record via a stubbed dol-write.sh (DOL_WRITE hook): long→short in POST body + output JSON, Wise untouched, >50-after-normalization refused BEFORE any POST, citing varchar(50). Both SKILL.md document the canonical short form + the varchar(50) constraint. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
@@ -197,6 +197,19 @@ Matching runs in three passes, highest confidence first:
|
||||
2. **`[wire-ref]` (strong)** — via `--enrich`, below.
|
||||
3. **`[amt+date]` (loose)** — the fallback heuristic.
|
||||
|
||||
**Canonical short form — the varchar(50) constraint.** Qonto feed ids run ~67 chars
|
||||
(`<org>-<n>-<n>-transaction-<uuid>`) but Dolibarr stores `num_payment` in
|
||||
**varchar(50)** columns, so règlements store the **UUID suffix** — the canonical
|
||||
short form `payment-record.sh` normalizes to (strip everything through
|
||||
`transaction-`). PASS 0 therefore compares **both sides in raw AND short form**:
|
||||
a num stored short (the varchar(50) form) or long (historical) matches either way.
|
||||
Wise ids (short numerics, no `transaction-`) are untouched.
|
||||
|
||||
Offline proof: `tests/run-tests.sh` runs `bank-match.sh --fixtures` on
|
||||
`tests/fixtures/` (no credentials, no network, nothing written) — a long Qonto
|
||||
feed id matches one règlement stored short and one stored long, each ~19d outside
|
||||
the ±7d window (so only PASS 0 can pair them), plus the empty-num negative case.
|
||||
|
||||
### `--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