add dolibarr-payments-state skill for cash receipt tracking
V2 in the dolibarr-* family. Three workflows:
- km-payment-state.sh: per-invoice reconciliation (TTC vs sum of
payments) with OK / PARTIAL / UNPAID / OVERPAID classification.
More honest than the `paye` boolean for deferred-cycle agreements.
- km-payment-timeline.sh: all KM payments sorted by date with
cumulative balance — the foundation for cohort-review deferred
9-month-cycle tracking (actual cash receipts vs contractual schedule).
- payments-by-month.sh: monthly aggregation, KM-scoped by default
or --all-clients for accounting basis.
Also updates dolibarr/SKILL.md endpoint catalogue with
/invoices/{id}/payments (note the date-as-string vs unix-epoch quirk)
and /bankaccounts, plus captures the corresponding examples.
V1 baseline of live data: KM is fully reconciled across 5 invoices
(1 avoir + 4 regular), 8160 € total cash receipts spread Feb/Mar/Apr 2026,
all on WISE EURO (BE).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
142
.claude/skills/dolibarr-payments-state/SKILL.md
Normal file
142
.claude/skills/dolibarr-payments-state/SKILL.md
Normal file
@@ -0,0 +1,142 @@
|
||||
---
|
||||
name: dolibarr-payments-state
|
||||
description: Track Arcodange cash receipts and payment-state per invoice via the Dolibarr API. Three workflows — (1) per-invoice payment reconciliation for KissMetrics: total TTC vs sum of payments, with PARTIAL / UNPAID / OK / OVERPAID classification (replaces relying on the `paye=1` flag alone); (2) full payment timeline sorted by date with cumulative balance, suitable for cohort-review deferred-cycle tracking (compare actual cash receipts against the contractual schedule); (3) monthly cash-receipt aggregation, scoped to KissMetrics by default or `--all-clients` for global accounting. Surfaces credit notes (AVOIRs as negative payments) and the bank-account catalogue (QONTO, WISE EURO, G.RADUREAU CCA). Use when the user asks "état des paiements KM", "is invoice X paid", "qui doit combien", "suivi des paiements deferred", "deferred 9-month cycle", "cash receipts par mois", "réconciliation factures vs paiements", or any cohort-review billing-cycle check. Depends on the `dolibarr` skill for connection. SKIP for the legal-mention audit (handled by `dolibarr-invoice-audit`), for write operations (the API is read-only — payments are recorded by the Dolibarr UI), and for full bank-statement reconciliation (which would require parsing bank exports outside Dolibarr — out of scope here, V3 candidate).
|
||||
requires:
|
||||
bins: ["curl", "jq", "python3"]
|
||||
auth: true
|
||||
---
|
||||
|
||||
# dolibarr-payments-state — KissMetrics cash-receipt tracking
|
||||
|
||||
This skill answers "**who owes Arcodange what, and when did they pay?**" against the live Dolibarr. It's the natural follow-up to [dolibarr-invoice-audit](../dolibarr-invoice-audit/SKILL.md): that one validates that a given invoice was emitted correctly; this one validates the money landed.
|
||||
|
||||
Depends on the [dolibarr](../dolibarr/SKILL.md) base skill for the connection, the `.env`, and the `voir_tous` permission flags. The existing **Factures → Voir toutes** flag from V1 is sufficient — payments are nested under invoices (`/invoices/{id}/payments`), and there's no `/payments` list-all endpoint (501 Not Implemented).
|
||||
|
||||
## Why a dedicated skill?
|
||||
|
||||
The `paye` flag on `/invoices/{id}` is a single boolean. The cohort review needs the actual reconciliation: how much was paid, when, by what means, on which bank account. Three things the flag can't tell you:
|
||||
|
||||
1. **Partial payments.** An invoice with one of three deferred installments paid still has `paye=0` but `sum(payments) > 0`.
|
||||
2. **Credit notes.** An AVOIR shows up in the payments list as a negative amount tied to the canceled invoice's pair — the timeline is the easy way to see the chain.
|
||||
3. **Cash-receipt timing.** For deferred-cycle agreements, the **date** a payment hit the bank matters more than whether the invoice is fully paid.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [`dolibarr/.env`](../dolibarr/.env) populated, mode 600.
|
||||
- `ai_agent` permissions from [dolibarr/README.md](../dolibarr/README.md). The existing Factures `voir_tous` covers payments.
|
||||
|
||||
## Workflow 1 — Per-invoice payment state (reconciliation)
|
||||
|
||||
```bash
|
||||
./scripts/km-payment-state.sh # all KM invoices
|
||||
./scripts/km-payment-state.sh --since 2026-02-01 # window
|
||||
echo "exit: $?" # 0 if every invoice reconciles, 1 otherwise
|
||||
```
|
||||
|
||||
Live output (captured at [examples/km-payment-state.txt](examples/km-payment-state.txt)):
|
||||
|
||||
```
|
||||
id ref date HT paid balance state payments
|
||||
----------------------------------------------------------------------------------------------------------------------------------
|
||||
12 FAC002-CL0001002 2026-02-24 5100.00 5100.00 0.00 OK 5100.00@2026-03-12(VIR)
|
||||
13 FAC003-CL0001003 2026-02-24 2550.00 2550.00 0.00 OK 2550.00@2026-04-20(VIR)
|
||||
2 FAC001-CL00001 2026-01-30 510.00 510.00 0.00 OK 510.00@2026-02-05(VIR)
|
||||
11 FAC001-CL0001001 2026-01-30 510.00 510.00 0.00 OK 510.00@2026-02-05(VIR)
|
||||
10 AVC001-CL0001001 2026-01-30 -510.00 -510.00 0.00 OK -510.00@2026-02-05(VIR)
|
||||
----------------------------------------------------------------------------------------------------------------------------------
|
||||
TOTAL 8160.00 8160.00 0.00
|
||||
# 5 invoice(s), 0 not fully reconciled
|
||||
```
|
||||
|
||||
**state column legend:**
|
||||
- `OK` — `|balance| < 0.005` (reconciled to the cent).
|
||||
- `UNPAID` — no payments recorded at all.
|
||||
- `PARTIAL` — payments < TTC.
|
||||
- `OVERPAID` — payments > TTC. Worth investigating (overpayment, duplicate posting, currency drift).
|
||||
|
||||
Reconciles against **TTC** (the contractual payable), not HT, because that's what the customer actually sends. For KM under 259-1° CGI (TVA=0), HT == TTC, so the distinction doesn't matter; for any future French customer with TVA > 0, it would.
|
||||
|
||||
## Workflow 2 — Payment timeline (cohort deferred-cycle tracking)
|
||||
|
||||
```bash
|
||||
./scripts/km-payment-timeline.sh # all-time
|
||||
./scripts/km-payment-timeline.sh --year 2026 # one year
|
||||
./scripts/km-payment-timeline.sh --since 2026-02-01 --until 2026-04-30
|
||||
```
|
||||
|
||||
Live output (captured at [examples/km-payment-timeline.txt](examples/km-payment-timeline.txt)):
|
||||
|
||||
```
|
||||
date invoice amount type ref bank_line running
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
2026-02-05 AVC001-CL0001001 -510.00 VIR REC003-CL00001 bl=7 -510.00
|
||||
2026-02-05 FAC001-CL0001001 510.00 VIR REC002-####002 bl=6 0.00
|
||||
2026-02-05 FAC001-CL00001 510.00 VIR REC001-####001 bl=5 510.00
|
||||
2026-03-12 FAC002-CL0001002 5100.00 VIR REC003-CL00002 bl=19 5610.00
|
||||
2026-04-20 FAC003-CL0001003 2550.00 VIR REC001-CL0001001 bl=24 8160.00
|
||||
--------------------------------------------------------------------------------------------------------------
|
||||
# 5 payment(s), net cash receipts: 8160.00
|
||||
|
||||
# Bank accounts known to this Dolibarr (label / IBAN-leading):
|
||||
# id=1 ref=QON1 label=QONTO country=FR iban=FR761695800001...
|
||||
# id=2 ref=WIS2 label=WISE EURO country=BE iban=BE58967543094979
|
||||
# id=3 ref=CCA1 label=G.RADUREAU Compte Courant Asso country=FR iban=-
|
||||
```
|
||||
|
||||
**bank_line note.** The `fk_bank_line` value on a payment is the row id in the bank-line ledger, not the bank-account id. Dolibarr's API doesn't expose `/bankaccounts/{id}/lines` to `ai_agent` in V1, so we surface the bank-account catalogue at the bottom of the timeline and leave the per-payment lookup as a manual / V3 task. For KissMetrics specifically, the IBAN on the FAC002 PDF (`BE58 9675 4309 4979`) matches **WIS2 (WISE EURO)** — all KM receipts land there.
|
||||
|
||||
**Deferred-cycle interpretation** (cohort review context):
|
||||
- The contract's deferred-payment schedule (9 months for KM) defines an *expected* cash-receipt timeline.
|
||||
- This workflow gives the *actual* one. `diff` between them surfaces overdue cycles or unexpected early payments.
|
||||
|
||||
## Workflow 3 — Monthly cash receipts
|
||||
|
||||
```bash
|
||||
./scripts/payments-by-month.sh # KM only (default)
|
||||
./scripts/payments-by-month.sh --year 2026
|
||||
./scripts/payments-by-month.sh --all-clients # global, for accounting
|
||||
```
|
||||
|
||||
Live output (captured at [examples/payments-by-month.txt](examples/payments-by-month.txt)):
|
||||
|
||||
```
|
||||
# Monthly cash receipts — scope: KissMetrics (socid=1)
|
||||
|
||||
month count amount cumulative
|
||||
--------------------------------------------------
|
||||
2026-02 3 510.00 510.00
|
||||
2026-03 1 5100.00 5610.00
|
||||
2026-04 1 2550.00 8160.00
|
||||
--------------------------------------------------
|
||||
TOTAL 5 8160.00
|
||||
```
|
||||
|
||||
The 2026-02 count of 3 (for a net 510 €) is the AVOIR + reissue cycle around `FAC001-CL00001` — three movements, one net economic event. This is normal and reflects the legal correctness of the credit-note + new-invoice approach Arcodange uses for corrections.
|
||||
|
||||
Use `--all-clients` once Arcodange has more than KM on the books, for monthly accounting / TVA basis (next skill).
|
||||
|
||||
## Captured baselines
|
||||
|
||||
[`examples/`](examples/) holds the live outputs of each script as of the V1 baseline (2026-05-28). To detect drift:
|
||||
|
||||
```bash
|
||||
./scripts/km-payment-state.sh > /tmp/new.txt 2>&1
|
||||
diff examples/km-payment-state.txt /tmp/new.txt && echo "unchanged"
|
||||
```
|
||||
|
||||
When the actual data legitimately changes (new invoice, new payment), re-capture the baselines in the same commit.
|
||||
|
||||
## Adding a new check / column
|
||||
|
||||
The scripts share a common shape: pull invoices → pull per-invoice payments → reconcile in Python (heredoc, argv-passing tmpfile pattern — the pipe + heredoc-stdin collision is real on macOS bash 3.2, see V1 commit history for the trap). Patterns to follow:
|
||||
|
||||
- Sort by **TTC reconciliation**, not `paye` flag (workflow 1 demonstrates this).
|
||||
- The payment `date` is a `YYYY-MM-DD HH:MM:SS` **string**, not a unix epoch — different shape from `/invoices/{id}.date`. Don't `int()` it.
|
||||
- AVOIRs have negative amounts; treat them as first-class. Don't filter them out — that hides the chain.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- **Bank-statement reconciliation.** Matching Dolibarr payments against actual bank exports (Qonto / Wise CSV) is a separate concern; would live in a V3 `arcodange-bank-reco` skill.
|
||||
- **TVA basis calculation per month.** Needs the HT × TVA rate per period — next skill: `dolibarr-tva-reconciliation`.
|
||||
- **Writes.** Recording a payment is done in the Dolibarr UI (or via a script with a write-scoped API key — not in scope here).
|
||||
- **Multi-currency.** Everything is EUR today. If a future contract is USD or other, the cross-multicurrency fields (`multicurrency_total_ttc`) need to be added to the reconciliation.
|
||||
Reference in New Issue
Block a user