First two of an expected family of dolibarr-* skills: - dolibarr/: platform reference — DOLAPIKEY auth, the voir_tous ACL trap, endpoint catalogue, the dol-curl.sh wrapper, .env credentials layout (gitignored, mode 600). Every future workflow skill depends on this one. - dolibarr-invoice-audit/: first workflow — list KissMetrics invoices, audit one invoice end-to-end (JSON facts + PDF mandatory-mention checklist against the French legal corpus), audit the KissMetrics thirdparty record. Live captures in examples/ include real audit findings to surface to the Arcodange × KissMetrics cohort review: PDFs are missing capital social, L.441-10 penalties, 40 € indemnity, L.123-22 / R.123-237; KissMetrics thirdparty has no EIN (idprof1..6 all empty); static/config/company.json holds placeholder values and a wrong forme juridique (claims SAS, the real Dolibarr is SARL). .gitignore hardened with *.credentials, secrets/, *.key, and an explicit .claude/skills/**/.env pattern. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 KiB
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
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 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/.envpopulated with a validDOLIBARR_API_KEY, mode 600.ai_agentin Dolibarr has the fourvoir_tousflags ticked (see dolibarr/README.md step 2).pdftotextinstalled 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
./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):
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=1flag.yesmeans fully paid (not just "validated"). - AVC —
AVOIRis shown when the ref starts withAVCor the HT is negative. The two should match; a discrepancy is a Dolibarr data issue. - pdf —
last_main_doc. Pass toaudit-invoice.shindirectly 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)
./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:
socidmatchesKissMetrics(id=1)dateis in the expected billing monthtotal_htmatches the contract line (10 days × 510 €/d = 5 100 € for FAC002, etc.)total_tva == 0confirms the reverse-charge posture — the 259-1° CGI mention is then mandatory on the PDFpaye == 1if the invoice should be paid by nowcond_reglement_codetells 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 — 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
./scripts/audit-km-thirdparty.sh
echo "exit: $?" # 0 if complete, 1 otherwise
Live result (captured at 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..6empty. KissMetrics is a US entity; the EIN should land inidprof1oridprof2per 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/ 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:
./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 find the block under # Mandatory-mention audit — structural presence on the PDF: and add:
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 futuredolibarr-invoice-audit-<client>(or a parametrized rewrite) will handle other thirdparties. - Recurring-template inspection (the
Kiss Metrics Invoicetemplate that backs FAC002 / FAC003). Different endpoint shape (/invoices/templates), V2 work. - Payment-state cross-reference with bank statements. Future skill (likely
dolibarr-payments-state).