Files
erp/.claude/skills/dolibarr-payments-state/SKILL.md
Gabriel Radureau e7abfd5e22 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>
2026-05-28 18:52:48 +02:00

9.8 KiB
Raw Blame History

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: that one validates that a given invoice was emitted correctly; this one validates the money landed.

Depends on the dolibarr 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

Workflow 1 — Per-invoice payment state (reconciliation)

./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):

  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)

./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):

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

./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):

# 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/ holds the live outputs of each script as of the V1 baseline (2026-05-28). To detect drift:

./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.