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:
@@ -96,9 +96,10 @@ to leave a draft. Emits `{id, ref, ref_supplier, total_ht, total_ttc, statut}`.
|
||||
### 3 · Payment (règlement) — `scripts/payment-record.sh`
|
||||
|
||||
```sh
|
||||
echo '{"invoice_id":19,"mode":"VIR","account_id":1,"transaction_id":"QONTO-TX-1234"}' | scripts/payment-record.sh
|
||||
echo '{"invoice_id":13,"kind":"supplier","mode":"VIR","account_id":1,"amount":96,"transaction_id":"WISE-TX-5678"}' \
|
||||
| scripts/payment-record.sh
|
||||
echo '{"invoice_id":19,"mode":"VIR","account_id":1,"transaction_id":"2159468139"}' | scripts/payment-record.sh
|
||||
echo '{"invoice_id":13,"kind":"supplier","mode":"VIR","account_id":1,"amount":96,
|
||||
"transaction_id":"arcodange-1246-1-transaction-019f14c5-e254-7ac9-9e9f-307ed9-d55f44"}' \
|
||||
| scripts/payment-record.sh # stores num 019f14c5-e254-7ac9-9e9f-307ed9-d55f44
|
||||
```
|
||||
The invoice must be **validated** first. `mode`: `VIR|CB|CHQ|LIQ`. Customer
|
||||
payments settle the full remaining amount and mark the invoice paid; **supplier**
|
||||
@@ -112,9 +113,22 @@ reconciliation matches **by id** rather than by fuzzy amount/date. (`num` is a
|
||||
back-compat alias for the same field.) Recording without it prints a warning — the
|
||||
payment still posts, but it won't auto-reconcile.
|
||||
|
||||
**Canonical short form — the varchar(50) constraint.** Dolibarr stores
|
||||
`num_payment` in **varchar(50)** columns (`llx_paiement.num_paiement`,
|
||||
`llx_paiementfourn.num_paiement`) while Qonto transaction ids run ~67 chars
|
||||
(`<org>-<n>-<n>-transaction-<uuid>`) — POSTing one raw fails with HTTP 400
|
||||
"value too long for type character varying(50)". The script therefore normalizes
|
||||
before POST: everything through `transaction-` is stripped and the **UUID suffix**
|
||||
(globally unique, ~37 chars) is what gets stored. Wise ids (short numerics) pass
|
||||
through unchanged. An id still >50 chars after normalization is **refused** with
|
||||
an explicit error — never truncated silently. `arcodange-bank-reco`'s bank-match
|
||||
normalizes feed ids the same way, so short-form nums keep reconciling by id
|
||||
(historical long-form nums too). Pass the raw feed id; the script does the rest.
|
||||
|
||||
Emits **`{id, bank_transaction_id, transaction_id}`**. `bank_transaction_id` is the
|
||||
Dolibarr bank line (`llx_bank.fk_bank_line`) the payment created — the id the
|
||||
reconciliation (`arcodange-bank-reco`) keys on. Both ends are captured at write time.
|
||||
reconciliation (`arcodange-bank-reco`) keys on. `transaction_id` echoes the
|
||||
**normalized** num actually stored. Both ends are captured at write time.
|
||||
|
||||
### 4 · Credit note (avoir) — `scripts/creditnote-create.sh`
|
||||
|
||||
@@ -180,6 +194,10 @@ sandbox KissMetrics on `--target sandbox` and the prod one on `--target prod`.
|
||||
REST create needs `code_client`/`code_fournisseur = "-1"` to trigger it — the
|
||||
script does this; without it the API errors `ErrorCustomerCodeRequired`.
|
||||
- **Dates** are sent as Unix epochs; pass `date:"YYYY-MM-DD"` or omit for today.
|
||||
- **Qonto tx ids don't fit varchar(50).** `payment-record.sh` strips the
|
||||
`<org>-<n>-<n>-transaction-` prefix and stores the UUID suffix (see workflow 3);
|
||||
ids still >50 chars after that are refused. Offline proof: `tests/run-tests.sh`
|
||||
(stubbed `dol-write.sh` via the `DOL_WRITE` hook — writes nothing anywhere).
|
||||
- **`banque lire`** (rights id 111) is granted → `scripts/bank-accounts.sh` lists
|
||||
accounts (id/label/bank) so a payment can pick its `account_id`. It's in the
|
||||
provisioner's `WRITE_IDS`, so a fresh `provisionSandbox.ts` run includes it.
|
||||
|
||||
Reference in New Issue
Block a user