Files
Gabriel Radureau 1c0ba8ea75 add bin/arcodange CLI and dolibarr-tva-summary skill
Two changes that go together: now operators can run every read-only
workflow without going through Claude. The skills (SKILL.md files)
remain the source of behaviour documentation and Claude triggers;
bin/arcodange is the human-facing entry point.

bin/arcodange:
- Bash dispatcher at the project root. Subcommands per domain:
  tva {collect, collect-detail, deductible, deductible-detail, summary},
  invoice {list, audit}, thirdparty {audit, audit-all},
  payments {state, timeline, by-month},
  templates {list, inspect},
  snapshot, whoami, ping, curl, help.
- Locates the project root via `git rev-parse` so it works from any
  CWD (including from a worktree).
- Per-subcommand `help` text. Unknown commands exit 2 with a hint.
- Reuses the existing per-skill scripts under .claude/skills/<name>/
  scripts/ via `exec` (zero behaviour drift, full credit to the
  existing tested code).

dolibarr-tva-summary:
- Composes dolibarr-tva-reconciliation (TVA collectée customer-side)
  and dolibarr-tva-deductible (TVA déductible supplier-side) into a
  single CA3-ready monthly summary with per-month net verdict
  (TVA à reverser / crédit de TVA / équilibre) and a cumulative line.
- Live baseline: Arcodange en crédit de TVA de 223.22 € cumulé
  (0 € collectée 259-1° CGI vs 223.22 € déductible).
- Exposed as `arcodange tva summary [--year|--since|--until]`.

Each existing skill's SKILL.md gets a one-line "CLI shortcut" near
the top so the human path is discoverable from any skill page.
The project root README.md gets a CLI section as the primary
operator entry point.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 11:30:18 +02:00

9.9 KiB
Raw Permalink 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

CLI shortcuts: bin/arcodange payments state · bin/arcodange payments timeline · bin/arcodange payments by-month

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.