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

145 lines
9.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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](../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.