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

192 lines
11 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-invoice-audit
description: Audit Arcodange invoices and the KissMetrics thirdparty record against contractual and French legal expectations. Three workflows — (1) list KissMetrics invoices with payment state and flag credit notes (AVC refs or negative HT); (2) audit one invoice end-to-end — JSON side (socid / dates / HT / TVA reverse charge / paye flag) AND PDF side (structural presence of mandatory mentions: forme juridique, SIRET, numéro TVA intracom, RCS Évry, NAF-APE, capital social, TVA 259-1° CGI, L.441-10 penalties at BCE+10 or 12,15 %, 40 € indemnité forfaitaire, L.123-22 / R.123-237); (3) audit the KissMetrics thirdparty record for address completeness and EIN presence (today idprof1..6 are empty — known gap to surface). Use when the user asks "is the M1 invoice emitted", "is invoice X paid", "vérifier les mentions obligatoires", "audit mentions légales", "état des paiements KissMetrics", "vérifier la fiche KissMetrics", or any cohort-review billing check on the Arcodange Dolibarr. Depends on the `dolibarr` skill for connection + permissions. SKIP for non-Arcodange ERPs, for non-KissMetrics clients (future skill), for write/correction tasks (the API is read-only — use the Dolibarr UI), and for Helm / Ansible deployment work.
requires:
bins: ["curl", "jq", "python3", "pdftotext"]
auth: true
---
# dolibarr-invoice-audit — KissMetrics billing audit
**CLI shortcuts:** `bin/arcodange invoice list` · `bin/arcodange invoice audit <id>`
This skill answers the questions the Arcodange × KissMetrics cohort review keeps asking:
- Has the M-N invoice been emitted? Is it paid?
- Does the PDF carry the mandatory French legal mentions?
- Is the KissMetrics thirdparty record complete enough (EIN, full address)?
It depends on the [dolibarr](../dolibarr/SKILL.md) base skill for the connection, the `.env` credentials, and the `voir_tous` permission setup. **If `list-km-invoices.sh` returns nothing, your first stop is the permission gotcha in the base skill — not this one.**
## Prerequisites
- [`dolibarr/.env`](../dolibarr/.env) populated with a valid `DOLIBARR_API_KEY`, mode 600.
- `ai_agent` in Dolibarr has the four `voir_tous` flags ticked (see [dolibarr/README.md](../dolibarr/README.md) step 2).
- `pdftotext` installed locally: `brew install poppler`.
All scripts source the base skill's `.env` via the relative path `../../dolibarr/scripts/dol-curl.sh`. Run them from anywhere.
## Workflow 1 — List KissMetrics invoices
```bash
./scripts/list-km-invoices.sh # all KM invoices, newest first
./scripts/list-km-invoices.sh --since 2026-04-01 # filter by invoice date
```
Output (live as of 2026-05-28, captured at [examples/list-km-invoices.txt](examples/list-km-invoices.txt)):
```
id ref date HT TVA TTC paid AVC pdf
----------------------------------------------------------------------------------------------------------------
12 FAC002-CL0001002 2026-02-24 5100.00 0.00 5100.00 yes facture/FAC002-CL0001002/FAC002-CL0001002.pdf
13 FAC003-CL0001003 2026-02-24 2550.00 0.00 2550.00 yes facture/FAC003-CL0001003/FAC003-CL0001003.pdf
2 FAC001-CL00001 2026-01-30 510.00 0.00 510.00 yes facture/FAC001-CL00001/FAC001-CL00001.pdf
11 FAC001-CL0001001 2026-01-30 510.00 0.00 510.00 yes facture/FAC001-CL0001001/FAC001-CL0001001.pdf
10 AVC001-CL0001001 2026-01-30 -510.00 0.00 -510.00 yes AVOIR facture/AVC001-CL0001001/AVC001-CL0001001.pdf
```
Read the columns:
- **paid** — Dolibarr's `paye=1` flag. `yes` means fully paid (not just "validated").
- **AVC** — `AVOIR` is shown when the ref starts with `AVC` *or* the HT is negative. The two should match; a discrepancy is a Dolibarr data issue.
- **pdf** — `last_main_doc`. Pass to `audit-invoice.sh` indirectly via the invoice id.
KissMetrics is the thirdparty with `socid=1` in this Dolibarr. If that ever changes, update `KM_SOCID` in the script. The TOTAL line sums HT/TTC across all visible rows (including AVOIRs, which subtract — handy for net revenue checks).
## Workflow 2 — Audit one invoice (JSON facts + PDF mandatory mentions)
```bash
./scripts/audit-invoice.sh 12 # FAC002-CL0001002 (current M1 candidate)
echo "exit: $?" # 0 if every mention check passes, 1 otherwise
```
The script does two passes against `/invoices/{id}` and the attached PDF.
### JSON side
Prints the structured facts the cohort review needs to spot-check against the contract:
```
Thirdparty : KissMetrics (socid=1)
Invoice date : 2026-02-24
Due date : 2026-03-31 (cond_reglement_code=10DENDMONTH)
Total HT : 5100.00000000
Total TVA : 0.00000000 (TVA=0 → reverse-charge expected; the 259-1° CGI mention MUST be on the PDF)
Total TTC : 5100.00000000
Payment state : PAID
PDF : facture/FAC002-CL0001002/FAC002-CL0001002.pdf
```
Cross-check against the cohort spec:
- `socid` matches `KissMetrics` (id=1)
- `date` is in the expected billing month
- `total_ht` matches the contract line (10 days × 510 €/d = 5 100 € for FAC002, etc.)
- `total_tva == 0` confirms the reverse-charge posture — the 259-1° CGI mention is then **mandatory** on the PDF
- `paye == 1` if the invoice should be paid by now
- `cond_reglement_code` tells you the payment-term shape (`10DENDMONTH` = "10 jours fin de mois")
### PDF side — mandatory-mention audit
Downloads the PDF via `/documents/download`, base64-decodes, runs `pdftotext -layout`, then greps for **structural presence** of each mandatory mention. We deliberately do NOT match against the placeholder values in `static/config/company.json` — that file is a template; the real legal identifiers (SIRET `99965745500013`, TVA `FR00999657455`, forme **SARL**) live in Dolibarr's own setup and are what gets rendered into the PDF.
The checklist:
| Mention | Why it must be there |
|--------------------------------------|----------------------------------------------|
| Forme juridique (SARL / SAS / EURL / SA / SCI / SASU) | L.123-12 du Code de commerce (forme + capital) |
| SIRET (14 digits) | Décret 2003-1196 |
| Numéro TVA intracom (FR + 11) | Article 242 nonies A annexe II du CGI |
| RCS / R.C.S. Évry | L.123-12 (identification au registre) |
| NAF-APE code | Décret 2003-1196 |
| Capital social | L.123-12 du Code de commerce |
| TVA 259-1° CGI (reverse charge) | Article 259-1° CGI for services to non-EU B2B |
| L.441-10 — BCE+10 or 12,15 % | Code de commerce L.441-10 (late-payment penalties) |
| 40 € indemnité forfaitaire | Décret 2012-1115 (recouvrement) |
| L.123-22 / R.123-237 | Identification supplementaire des actes commerciaux |
Live result on invoice 12 (captured at [examples/audit-invoice-12.txt](examples/audit-invoice-12.txt) — exit code 1):
```
[OK] Forme juridique (SARL/SAS/EURL/SA/SCI/SASU)
[OK] SIRET (14 digits)
[OK] Numéro TVA intracom (FR + 11 chars)
[OK] RCS / R.C.S. Évry
[OK] NAF-APE code
[XX] Capital social
[OK] TVA 259-1° CGI / autoliquidation
[XX] L.441-10 — BCE+10 or 12,15 %
[XX] 40 € indemnité forfaitaire
[XX] L.123-22 / R.123-237
Real identifiers extracted from the PDF (informational):
SARL
SIRET: 99965745500013
TVA: FR00999657455
APE: 6201Z
6 pass / 4 fail
```
This is a **real cohort-review finding**: the four `[XX]` lines are mandatory mentions absent from the live Dolibarr PDF template. To fix them, edit the Dolibarr invoice template (Setup → PDF model → Edit) and re-issue an avoir + new invoice. The skill itself doesn't touch the template — it just measures.
Also note: `static/config/company.json` claims forme juridique = SAS but the real Dolibarr says **SARL**. The PDF is the source of truth; the `static/config/company.json` file appears to hold placeholders.
## Workflow 3 — Audit the KissMetrics thirdparty record
```bash
./scripts/audit-km-thirdparty.sh
echo "exit: $?" # 0 if complete, 1 otherwise
```
Live result (captured at [examples/audit-km-thirdparty.txt](examples/audit-km-thirdparty.txt) — exit code 1):
```
[OK] name = 'KissMetrics'
[OK] client flag = 'yes'
[OK] country_code = 'US'
[OK] state_id = '1167'
[OK] address = '2850 34th Street North, 307'
[OK] zip = '33713'
[OK] town = 'St. Petersburg'
[OK] email = 'evan@kissmetrics.io'
[XX] phone = None
[XX] url = None
idprof1..idprof6 (EIN slot for non-EU customers):
idprof1 = '' ... idprof6 = ''
[XX] EIN present (any idprof populated)
```
Open follow-ups for the cohort review:
- **EIN missing** — all `idprof1..6` empty. KissMetrics is a US entity; the EIN should land in `idprof1` or `idprof2` per Dolibarr convention. Either fill it in the Dolibarr UI or document why it's intentionally absent.
- **Phone / URL missing** — minor; not legally required for B2B invoicing but useful for the customer file.
## Captured baselines
[`examples/`](examples/) holds the live outputs of each script as of the V1 baseline (2026-05-28). To detect drift, re-run a script and `diff` against the captured file:
```bash
./scripts/audit-invoice.sh 12 > /tmp/new.txt 2>&1
diff examples/audit-invoice-12.txt /tmp/new.txt && echo "unchanged"
```
When you intentionally update the audit (new mention, fixed regex, etc.), re-capture the baselines as part of the same change.
## Adding a new mandatory mention
In [`scripts/audit-invoice.sh`](scripts/audit-invoice.sh) find the block under `# Mandatory-mention audit — structural presence on the PDF:` and add:
```bash
check "Your new mention label" "your-extended-regex-pattern"
```
Use `[[:space:]]`, `[Cc]apital`-style character classes, and prefer matching presence of the law reference (`L\\.?441-10`) over matching the verbatim French text — the wording in the PDF template can drift.
If the new check should source a value from somewhere (e.g. company data), pull it via `jq` from a stable file (don't re-parse `static/config/company.json` — its values are placeholders). For Dolibarr-derived expectations, fetch them via `dol-curl.sh` at script start.
## Out of scope
- **Writes / corrections.** The API key is read-only. To fix a missing mention or a wrong identifier, edit the Dolibarr invoice template / company setup in the UI and re-issue.
- **Audits for clients other than KissMetrics.** The scripts hard-code `KM_SOCID=1`. A future `dolibarr-invoice-audit-<client>` (or a parametrized rewrite) will handle other thirdparties.
- **Recurring-template inspection** (the `Kiss Metrics Invoice` template that backs FAC002 / FAC003). Different endpoint shape (`/invoices/templates`), V2 work.
- **Payment-state cross-reference with bank statements.** Future skill (likely `dolibarr-payments-state`).