Files
erp/.claude/skills/dolibarr-invoice-audit/SKILL.md
Gabriel Radureau bbfa50c3eb add dolibarr api skills for read-only inspection
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>
2026-05-28 18:43:39 +02:00

11 KiB
Raw Blame History

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

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

./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=1 flag. yes means fully paid (not just "validated").
  • AVCAVOIR is shown when the ref starts with AVC or the HT is negative. The two should match; a discrepancy is a Dolibarr data issue.
  • pdflast_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)

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