diff --git a/.claude/skills/dolibarr-invoice-audit/SKILL.md b/.claude/skills/dolibarr-invoice-audit/SKILL.md new file mode 100644 index 0000000..7b3d7a6 --- /dev/null +++ b/.claude/skills/dolibarr-invoice-audit/SKILL.md @@ -0,0 +1,189 @@ +--- +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](../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-` (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`). diff --git a/.claude/skills/dolibarr-invoice-audit/examples/audit-invoice-12.txt b/.claude/skills/dolibarr-invoice-audit/examples/audit-invoice-12.txt new file mode 100644 index 0000000..f72db72 --- /dev/null +++ b/.claude/skills/dolibarr-invoice-audit/examples/audit-invoice-12.txt @@ -0,0 +1,31 @@ +================================================================================ + Invoice 12 — FAC002-CL0001002 +================================================================================ + 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 + + Mandatory-mention audit — structural presence on the PDF: + [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 (looked for: [Cc]apital) + [OK] TVA 259-1° CGI / autoliquidation + [XX] L.441-10 — BCE+10 or 12,15 % (looked for: (L\.?441-10|BCE[[:space:]]*\+[[:space:]]*10|12[.,]15[[:space:]]*%)) + [XX] 40 € indemnité forfaitaire (looked for: (40[[:space:]]*€|indemnit[eé] forfaitaire|D[eé]cret 2012-1115)) + [XX] L.123-22 / R.123-237 (looked for: (L\.?123-22|R\.?123-237)) + + Real identifiers extracted from the PDF (informational): + SARL + SIRET: 99965745500013 + TVA: FR00999657455 + APE: 6201Z + + 6 pass / 4 fail diff --git a/.claude/skills/dolibarr-invoice-audit/examples/audit-km-thirdparty.txt b/.claude/skills/dolibarr-invoice-audit/examples/audit-km-thirdparty.txt new file mode 100644 index 0000000..44110f3 --- /dev/null +++ b/.claude/skills/dolibarr-invoice-audit/examples/audit-km-thirdparty.txt @@ -0,0 +1,26 @@ +================================================================================ + KissMetrics thirdparty audit — socid=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 = '' + idprof2 = '' + idprof3 = '' + idprof4 = '' + idprof5 = '' + idprof6 = '' + [XX] EIN present (any idprof populated) + + array_options (Dolibarr extrafields): (none) + + 8 pass / 3 fail diff --git a/.claude/skills/dolibarr-invoice-audit/examples/list-km-invoices.txt b/.claude/skills/dolibarr-invoice-audit/examples/list-km-invoices.txt new file mode 100644 index 0000000..0278c7a --- /dev/null +++ b/.claude/skills/dolibarr-invoice-audit/examples/list-km-invoices.txt @@ -0,0 +1,10 @@ + 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 +---------------------------------------------------------------------------------------------------------------- + TOTAL 8160.00 8160.00 +# 5 invoice(s) shown, socid=1 diff --git a/.claude/skills/dolibarr-invoice-audit/scripts/audit-invoice.sh b/.claude/skills/dolibarr-invoice-audit/scripts/audit-invoice.sh new file mode 100755 index 0000000..2ba5d06 --- /dev/null +++ b/.claude/skills/dolibarr-invoice-audit/scripts/audit-invoice.sh @@ -0,0 +1,152 @@ +#!/usr/bin/env bash +# Audit one Arcodange invoice end-to-end. +# +# Usage: +# audit-invoice.sh +# +# JSON side: pulls /invoices/{id} + /thirdparties/{socid}, prints facts +# (ref, dates, HT, TVA, TTC, paye flag, mode_reglement, cond_reglement). +# +# PDF side: pulls /documents/download, base64-decodes, runs pdftotext, +# then checks STRUCTURAL PRESENCE of mandatory French invoice mentions. +# We do NOT match against static/config/company.json — that file holds +# placeholder values today; Dolibarr renders the real legal data from +# its own setup. So we check shape, not exact strings. +# +# Mandatory-mention checklist (codified for SARL / SAS / EURL Arcodange): +# - Forme juridique (any of SARL / SAS / EURL / SA / SCI / SASU) +# - SIRET (14-digit number, optionally space-separated) +# - TVA intracom (FR + 2 chars + 9 digits) +# - RCS Évry / RCS Evry / R.C.S. Évry +# - NAF-APE code (NNNNL pattern) +# - Capital social ("capital" anywhere) +# - TVA 259-1° CGI (autoliquidation for non-EU prestations de services) +# - L.441-10 — late-payment penalties (BCE+10 or 12,15 %) +# - 40 € indemnité forfaitaire (Décret 2012-1115) +# - L.123-22 / R.123-237 identification mentions +# +# Exits 0 if every check passes, 1 otherwise. +# +# Requires: curl, python3, jq, pdftotext (brew install poppler). + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DOL_CURL="${SCRIPT_DIR}/../../dolibarr/scripts/dol-curl.sh" + +if [[ $# -lt 1 ]]; then + echo "audit-invoice.sh: missing invoice id. Usage: audit-invoice.sh " >&2 + exit 2 +fi +INVOICE_ID="$1" + +command -v pdftotext >/dev/null || { echo "audit-invoice.sh: pdftotext not found (brew install poppler)" >&2; exit 2; } +command -v jq >/dev/null || { echo "audit-invoice.sh: jq not found" >&2; exit 2; } + +# --- JSON side ------------------------------------------------------------- +INV_JSON="$("${DOL_CURL}" "/invoices/${INVOICE_ID}")" +SOCID=$( echo "${INV_JSON}" | jq -r .socid) +REF=$( echo "${INV_JSON}" | jq -r .ref) +DATE_TS=$(echo "${INV_JSON}" | jq -r '.date // 0 | tonumber') +DUE_TS=$( echo "${INV_JSON}" | jq -r '.date_lim_reglement // 0 | tonumber') +HT=$( echo "${INV_JSON}" | jq -r .total_ht) +TVA=$( echo "${INV_JSON}" | jq -r .total_tva) +TTC=$( echo "${INV_JSON}" | jq -r .total_ttc) +PAYE=$( echo "${INV_JSON}" | jq -r .paye) +COND=$( echo "${INV_JSON}" | jq -r '.cond_reglement_code // "-"') +PDF_PATH=$(echo "${INV_JSON}" | jq -r .last_main_doc) + +DATE_HUMAN=$(python3 -c "import datetime,sys; ts=int(sys.argv[1]); print(datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d') if ts else '-')" "${DATE_TS}") +DUE_HUMAN=$( python3 -c "import datetime,sys; ts=int(sys.argv[1]); print(datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d') if ts else '-')" "${DUE_TS}") + +TP_JSON="$("${DOL_CURL}" "/thirdparties/${SOCID}")" +TP_NAME=$(echo "${TP_JSON}" | jq -r '.name // .ref') + +PAYE_HUMAN=$( [[ "${PAYE}" == "1" ]] && echo "PAID" || echo "UNPAID" ) + +# Heuristic: TVA == 0 -> likely reverse-charge (KM is in the US, 259-1° CGI). +TVA_NOTE="" +if [[ "${TVA}" == "0" || "${TVA}" == "0.00000000" || "${TVA}" == "0.00" ]]; then + TVA_NOTE="(TVA=0 → reverse-charge expected; the 259-1° CGI mention MUST be on the PDF)" +fi + +cat <&2 + exit 1 +fi + +PDF_TMP="$(mktemp -t dolaudit.XXXXXX.pdf)" +TXT_TMP="$(mktemp -t dolaudit.XXXXXX.txt)" +trap 'rm -f "${PDF_TMP}" "${TXT_TMP}"' EXIT +echo "${PDF_B64}" | base64 -d > "${PDF_TMP}" +pdftotext -layout "${PDF_TMP}" "${TXT_TMP}" + +pass_count=0 +fail_count=0 +check() { + # check "label" "extended-regex-pattern" + local label="$1" pat="$2" + if grep -E -q -- "${pat}" "${TXT_TMP}"; then + printf ' [OK] %s\n' "${label}" + pass_count=$((pass_count+1)) + else + printf ' [XX] %s (looked for: %s)\n' "${label}" "${pat}" + fail_count=$((fail_count+1)) + fi +} + +echo +echo " Mandatory-mention audit — structural presence on the PDF:" +check "Forme juridique (SARL/SAS/EURL/SA/SCI/SASU)" "(SARL|SAS|EURL|SCI|SASU|SA[^[:alpha:]])" +check "SIRET (14 digits)" "SIRET[[:space:]:]*[0-9]{14}" +check "Numéro TVA intracom (FR + 11 chars)" "(TVA|TVA intra)[[:space:]:]*FR[0-9A-Z]{11}" +check "RCS / R.C.S. Évry" "(R\\.?C\\.?S\\.?|RCS).*[EÉ]vry" +check "NAF-APE code" "(NAF|APE)[[:space:]:-]*[0-9]{4}[A-Z]" +check "Capital social" "[Cc]apital" +check "TVA 259-1° CGI / autoliquidation" "(259-?1|autoliquidation|reverse[- ]charge)" +check "L.441-10 — BCE+10 or 12,15 %" "(L\\.?441-10|BCE[[:space:]]*\\+[[:space:]]*10|12[.,]15[[:space:]]*%)" +check "40 € indemnité forfaitaire" "(40[[:space:]]*€|indemnit[eé] forfaitaire|D[eé]cret 2012-1115)" +check "L.123-22 / R.123-237" "(L\\.?123-22|R\\.?123-237)" + +# Surface the real legal identifiers extracted from the PDF — useful for +# cross-checking against the cohort review without re-running pdftotext. +echo +echo " Real identifiers extracted from the PDF (informational):" +SIRET_FOUND=$( grep -E -o "SIRET[[:space:]:]*[0-9]{14}" "${TXT_TMP}" | head -1 || true) +TVA_FOUND=$( grep -E -o "(TVA|TVA intra)[[:space:]:]*FR[0-9A-Z]{11}" "${TXT_TMP}" | head -1 || true) +APE_FOUND=$( grep -E -o "(NAF|APE)[[:space:]:-]*[0-9]{4}[A-Z]" "${TXT_TMP}" | head -1 || true) +FORM_FOUND=$( grep -E -o "(SARL|SAS|EURL|SCI|SASU|Soci[eé]t[eé] [^[:cntrl:]]{0,40})" "${TXT_TMP}" | head -1 || true) +echo " ${FORM_FOUND:-(forme juridique not found)}" +echo " ${SIRET_FOUND:-(SIRET not found)}" +echo " ${TVA_FOUND:-(TVA intracom not found)}" +echo " ${APE_FOUND:-(NAF-APE not found)}" + +echo +echo " ${pass_count} pass / ${fail_count} fail" +[[ ${fail_count} -eq 0 ]] diff --git a/.claude/skills/dolibarr-invoice-audit/scripts/audit-km-thirdparty.sh b/.claude/skills/dolibarr-invoice-audit/scripts/audit-km-thirdparty.sh new file mode 100755 index 0000000..ce743ff --- /dev/null +++ b/.claude/skills/dolibarr-invoice-audit/scripts/audit-km-thirdparty.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# Audit the KissMetrics thirdparty record (socid=1) for completeness. +# +# Usage: +# audit-km-thirdparty.sh +# +# Checks the contact fields and the idprof1..idprof6 slots where the US EIN +# should live for a non-EU customer. Today EIN is missing — this script's +# exit-1 IS the finding to surface to the cohort review. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DOL_CURL="${SCRIPT_DIR}/../../dolibarr/scripts/dol-curl.sh" +KM_SOCID=1 + +TMP_JSON="$(mktemp -t doltp.XXXXXX.json)" +trap 'rm -f "${TMP_JSON}"' EXIT + +"${DOL_CURL}" "/thirdparties/${KM_SOCID}" > "${TMP_JSON}" + +python3 - "${TMP_JSON}" <<'PY' +import json, sys +with open(sys.argv[1]) as f: + d = json.load(f) + +print("=" * 80) +print(f" KissMetrics thirdparty audit — socid={d.get('id')}") +print("=" * 80) + +required = [ + ("name", d.get("name")), + ("client flag", "yes" if str(d.get("client")) == "1" else None), + ("country_code", d.get("country_code")), + ("state_id", d.get("state_id")), + ("address", d.get("address")), + ("zip", d.get("zip")), + ("town", d.get("town")), + ("email", d.get("email")), + ("phone", d.get("phone")), + ("url", d.get("url")), +] +idprofs = [(f"idprof{i}", d.get(f"idprof{i}")) for i in range(1, 7)] +ein_present = any(v not in (None, "", "0") for _, v in idprofs) + +passes = fails = 0 +def check(label, value): + global passes, fails + ok = value not in (None, "", "0") + print(f" [{'OK' if ok else 'XX'}] {label:<18} = {value!r}") + if ok: passes += 1 + else: fails += 1 + +for label, value in required: + check(label, value) + +print() +print(" idprof1..idprof6 (EIN slot for non-EU customers):") +for label, value in idprofs: + print(f" {label:<10} = {value!r}") +print(f" [{'OK' if ein_present else 'XX'}] EIN present (any idprof populated)") +if ein_present: passes += 1 +else: fails += 1 + +ao = d.get("array_options") or {} +print() +print(f" array_options (Dolibarr extrafields): {ao if ao else '(none)'}") + +print() +print(f" {passes} pass / {fails} fail") +sys.exit(0 if fails == 0 else 1) +PY diff --git a/.claude/skills/dolibarr-invoice-audit/scripts/list-km-invoices.sh b/.claude/skills/dolibarr-invoice-audit/scripts/list-km-invoices.sh new file mode 100755 index 0000000..e90b84a --- /dev/null +++ b/.claude/skills/dolibarr-invoice-audit/scripts/list-km-invoices.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# List Arcodange → KissMetrics invoices with payment state. +# +# Usage: +# list-km-invoices.sh [--since YYYY-MM-DD] +# +# KissMetrics is the thirdparty with socid=1 in this Dolibarr. If that ever +# changes, update KM_SOCID below or detect it dynamically. +# +# Credit notes (AVOIRs) are flagged: ref starting with "AVC" or negative HT. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DOL_CURL="${SCRIPT_DIR}/../../dolibarr/scripts/dol-curl.sh" + +KM_SOCID=1 +SINCE="" +while [[ $# -gt 0 ]]; do + case "$1" in + --since) SINCE="$2"; shift 2 ;; + -h|--help) + sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//' + exit 0 + ;; + *) echo "list-km-invoices.sh: unknown arg: $1" >&2; exit 2 ;; + esac +done + +SINCE_EPOCH=0 +if [[ -n "${SINCE}" ]]; then + if SINCE_EPOCH=$(date -j -f "%Y-%m-%d" "${SINCE}" "+%s" 2>/dev/null); then : + else SINCE_EPOCH=$(date -d "${SINCE}" "+%s"); fi +fi + +TMP_JSON="$(mktemp -t dollist.XXXXXX.json)" +trap 'rm -f "${TMP_JSON}"' EXIT + +"${DOL_CURL}" '/invoices?limit=100&sortfield=t.datef&sortorder=DESC' > "${TMP_JSON}" + +python3 - "${TMP_JSON}" "${KM_SOCID}" "${SINCE_EPOCH}" <<'PY' +import json, sys, datetime +with open(sys.argv[1]) as f: + rows = json.load(f) +km_socid = sys.argv[2] +since_ts = int(sys.argv[3]) + +km = [r for r in rows if str(r.get("socid")) == km_socid] +km.sort(key=lambda r: int(r.get("date") or 0), reverse=True) + +print(f"{'id':>4} {'ref':<24} {'date':<10} {'HT':>10} {'TVA':>8} {'TTC':>10} {'paid':<5} {'AVC':<5} pdf") +print("-" * 112) +total_ht = total_ttc = 0.0 +shown = 0 +for r in km: + ts = int(r.get("date") or 0) + if since_ts and ts < since_ts: + continue + shown += 1 + dt = datetime.datetime.fromtimestamp(ts).strftime("%Y-%m-%d") if ts else "-" + ht = float(r.get("total_ht") or 0) + tva = float(r.get("total_tva") or 0) + ttc = float(r.get("total_ttc") or 0) + paid = "yes" if str(r.get("paye")) == "1" else "no" + avc = "AVOIR" if (r.get("ref","").startswith("AVC") or ht < 0) else "" + pdf = r.get("last_main_doc") or "-" + print(f"{r['id']:>4} {r['ref']:<24} {dt:<10} {ht:>10.2f} {tva:>8.2f} {ttc:>10.2f} {paid:<5} {avc:<5} {pdf}") + total_ht += ht + total_ttc += ttc +print("-" * 112) +print(f"{'TOTAL':>40} {total_ht:>10.2f} {' ':>8} {total_ttc:>10.2f}") +print(f"# {shown} invoice(s) shown, socid={km_socid}") +PY diff --git a/.claude/skills/dolibarr/README.md b/.claude/skills/dolibarr/README.md new file mode 100644 index 0000000..fb23765 --- /dev/null +++ b/.claude/skills/dolibarr/README.md @@ -0,0 +1,56 @@ +# dolibarr — one-time setup + +Skill body: [SKILL.md](SKILL.md). This README is the human-facing setup checklist. + +## 1. Create `.env` (mode 600, never committed) + +```bash +cat > .claude/skills/dolibarr/.env <<'EOF' +DOLIBARR_URL=https://erp.arcodange.lab +DOLIBARR_API_KEY= +DOLIBARR_USER=ai_agent +DOLIBARR_PASSWORD= +EOF +chmod 600 .claude/skills/dolibarr/.env +``` + +Verify it's gitignored: + +```bash +git check-ignore .claude/skills/dolibarr/.env # should print the path +``` + +## 2. Grant `ai_agent` the four `voir_tous` permission flags + +`ai_agent` is read-only by design. But Dolibarr's per-record ACL silently filters out invoices and thirdparties unless the `voir_tous` (see-all) flags are ticked. Without them, `/invoices` returns `[]` and `/thirdparties` returns 404 — looks like an empty database. + +In the Dolibarr UI (https://erp.arcodange.lab/ → **Setup → Users & Groups → `ai_agent` → Permissions**), tick: + +- [ ] **Tiers** → Lire les tiers +- [ ] **Tiers** → Voir tous les tiers (et pas seulement ceux liés à l'utilisateur courant) +- [ ] **Factures** → Lire les factures +- [ ] **Factures** → Voir toutes les factures (et pas seulement celles liées à l'utilisateur courant) + +Save. Future modules used by `dolibarr-*` sibling skills (Paiements, Produits, …) need the same treatment. + +## 3. Quick-start test + +```bash +./.claude/skills/dolibarr/scripts/dol-curl.sh /users/info | jq -r .login +# → ai_agent +./.claude/skills/dolibarr/scripts/dol-curl.sh /status +# → {"success":{"code":200,"dolibarr_version":"22.0.4",...}} +./.claude/skills/dolibarr/scripts/dol-curl.sh /thirdparties/1 | jq '{ref, country_code, town}' +# → {"ref":"KissMetrics","country_code":"US","town":"St. Petersburg"} +``` + +If the third one returns HTTP 403 `Access not allowed for login ai_agent on this thirdparty`, the `voir_tous` flags from step 2 are missing. + +## 4. Rotating the API key + +If the key leaks: Dolibarr UI → Users → `ai_agent` → API key → **Generate new** → copy the new value into `.env`. No other change needed; every `dolibarr-*` skill picks it up via `dol-curl.sh`. + +## Pointers + +- Full skill body, endpoint catalogue, gotchas: [SKILL.md](SKILL.md). +- First workflow skill that depends on this one: [../dolibarr-invoice-audit/SKILL.md](../dolibarr-invoice-audit/SKILL.md). diff --git a/.claude/skills/dolibarr/SKILL.md b/.claude/skills/dolibarr/SKILL.md new file mode 100644 index 0000000..3ebb670 --- /dev/null +++ b/.claude/skills/dolibarr/SKILL.md @@ -0,0 +1,139 @@ +--- +name: dolibarr +description: Reference + connection layer for the Arcodange Dolibarr ERP REST API at https://erp.arcodange.lab/. Documents authentication via DOLAPIKEY, the read-only `ai_agent` account's permission requirements (the `voir_tous` ACL trap that returns empty arrays or 404s instead of 403s on listing endpoints), the credentials layout at `.claude/skills/dolibarr/.env`, the `scripts/dol-curl.sh` wrapper, the catalogue of useful read endpoints (invoices, thirdparties, documents/download, products, status, users/info), and the common gotchas (mode-as-int, paye-vs-status, empty-vs-404-vs-403, unix-epoch dates). Use when setting up the connection, debugging an API call, looking up an endpoint, decoding a permission error, or as a dependency referenced by any `dolibarr-*` workflow skill. SKIP for Dolibarr admin / Helm chart / Ansible config (covered by `chart/` + `ansible/`), for any ERP other than Arcodange's, and for specific business workflows that have their own `dolibarr-` skill. +requires: + bins: ["curl", "jq", "python3"] + auth: true +--- + +# dolibarr — Arcodange ERP API platform reference + +This is the **base skill** for talking to the Arcodange Dolibarr instance from Claude Code. It documents the connection, the permissions, the endpoint catalogue, and the gotchas. **Each business workflow lives in its own `dolibarr-` sibling skill** that depends on this one — V1 ships `dolibarr-invoice-audit` for the KissMetrics audit; future siblings will follow the same pattern (e.g. `dolibarr-payments-state`, `dolibarr-tva-reconciliation`). + +The API key for `ai_agent` is **read-only by design**. Never attempt writes from any `dolibarr-*` skill — use the Dolibarr UI directly for corrections. + +## Quick start + +From the repo root: + +```bash +./.claude/skills/dolibarr/scripts/dol-curl.sh /users/info | jq -r .login +# → ai_agent +``` + +If you see `ai_agent`, auth works. If not, check `.env` (next section) and `dol-curl.sh`'s error message. + +For a liveness check that needs no auth: + +```bash +curl -s https://erp.arcodange.lab/api/index.php/status | jq . +# → {"success":{"code":200,"dolibarr_version":"22.0.4",...}} +``` + +## Credentials + +Schema of `.claude/skills/dolibarr/.env` (mode **600**, gitignored): + +``` +DOLIBARR_URL=https://erp.arcodange.lab +DOLIBARR_API_KEY= +DOLIBARR_USER=ai_agent +DOLIBARR_PASSWORD= +``` + +The DOLAPIKEY is the only secret needed for API calls. `DOLIBARR_USER`/`DOLIBARR_PASSWORD` are kept here only so the operator has them at hand if they need to log into the Dolibarr UI to fix permissions. + +**Rules**: +- `chmod 600 .env`. Verify with `stat -f %Lp .env` → `600`. +- Never commit. The root `.gitignore` already excludes `.env` at any depth; redundant patterns (`*.credentials`, `.claude/skills/**/.env`) belt-and-braces it. +- Never paste the key into chat. If a key leaks, rotate it from the Dolibarr UI: `Users → ai_agent → API key → Generate new`. +- Every sibling `dolibarr-*` skill sources this file via `../dolibarr/.env`. There is exactly one copy. + +## Permission gotcha — read this first + +Dolibarr enforces TWO layers of access: +1. Per-API-endpoint permissions (does the user's role allow `/invoices`?). +2. Per-record ACL (can this user see THIS invoice/thirdparty?). + +Layer 2 is the trap. When `ai_agent` has the endpoint permission but **not** the `voir_tous` flag, listing endpoints silently filter rows out: + +- `GET /invoices` returns `[]` with HTTP **200** (looks like "no invoices exist"). +- `GET /thirdparties` returns HTTP **404** with `"No third parties found"` (looks like "no thirdparties exist"). +- `GET /thirdparties/{id}` returns HTTP **403** with `"Access not allowed for login ai_agent on this thirdparty"` (this is the only honest error). + +**Diagnostic recipe.** If a listing endpoint returns empty/404 *while you expect data*: + +```bash +./scripts/dol-curl.sh /thirdparties/1 +``` + +If you get a 403 with `Access not allowed`, the ACL is the cause (saved as a reference at [examples/acl_403_thirdparty.json](examples/acl_403_thirdparty.json)). **Do not retry the call blindly.** Fix the permissions, then retest. + +**Fix.** In the Dolibarr UI (https://erp.arcodange.lab/ → Setup → Users & Groups → `ai_agent` → Permissions), tick: + +- **Tiers** → Lire les tiers +- **Tiers** → Voir tous les tiers (et pas seulement ceux liés à l'utilisateur courant) +- **Factures** → Lire les factures +- **Factures** → Voir toutes les factures (et pas seulement celles liées à l'utilisateur courant) + +Add the equivalent flags for any new module a future `dolibarr-*` skill needs (Paiements, Produits, …). The `ai_agent` user has no UI access by default, so `voir_tous` is the right grant — there's no sales-rep relationship to honor. + +## Endpoint catalogue + +Read-only endpoints we've validated against this instance. Live captures are under [examples/](examples/). + +| Endpoint | HTTP | Purpose | Key params / gotchas | Example | +|------------------------------------------------|------|--------------------------------------|------------------------------------------------------------------|---------| +| `GET /status` | 200 | Liveness + Dolibarr version | No auth needed | [status.json](examples/status.json) | +| `GET /users/info` | 200 | Current API user (auth sanity) | Returns `login`, `id`, `rights` tree | [users_info.json](examples/users_info.json) | +| `GET /invoices` | 200 | List invoices | `limit`, `sortfield=t.datef`, `sortorder=DESC`, `status=draft\|unpaid\|paid`, `sqlfilters` | [invoices_list.json](examples/invoices_list.json) | +| `GET /invoices/{id}` | 200 | Invoice detail | `paye=1` is the canonical "paid" flag | [invoice_detail.json](examples/invoice_detail.json) | +| `GET /thirdparties` | 200 | List thirdparties | `mode` MUST be integer (`mode=1` = customers). String fails 400. | (use `/{id}` below) | +| `GET /thirdparties/{id}` | 200 | Thirdparty detail | KissMetrics is `id=1` in this instance | [thirdparty_km.json](examples/thirdparty_km.json) | +| `GET /products` / `/products/{id}` | 200 | Product catalogue | `KM-audit` is `id=1` | — | +| `GET /documents/download` | 200 | Download a stored document as base64 | `modulepart=facture&original_file=/.pdf` (URL-encode slashes). Returns `{filename, content-type, filesize, content}` with `content` base64. | [document_download_meta.json](examples/document_download_meta.json) | + +Not available on this account (intentionally): `/setup/modules` (admin-only), `/invoices/templates` (requires a path arg — different route shape; V2). + +## The `dol-curl.sh` wrapper + +[scripts/dol-curl.sh](scripts/dol-curl.sh) is a thin wrapper used by this skill and every sibling. It: + +- Sources `../.env` (relative to itself), so it works regardless of the caller's CWD. +- Fails loudly if `.env` is missing or `DOLIBARR_URL` / `DOLIBARR_API_KEY` is unset. +- Prepends `DOLAPIKEY` and `Accept: application/json` headers + a 30s timeout. +- Prints the response body to stdout. +- On HTTP ≥ 400, also prints `dol-curl.sh: HTTP on ` to stderr and exits 1 — so `set -e` in caller scripts surfaces the failure. + +```bash +# Examples +./scripts/dol-curl.sh /users/info | jq .login +./scripts/dol-curl.sh '/invoices?limit=5&sortfield=t.datef&sortorder=DESC' | jq '.[].ref' +./scripts/dol-curl.sh /invoices/12 | jq '{ref, paye, total_ht, last_main_doc}' +./scripts/dol-curl.sh '/documents/download?modulepart=facture&original_file=FAC002-CL0001002%2FFAC002-CL0001002.pdf' \ + | jq -r .content | base64 -d > /tmp/inv.pdf +``` + +## Common gotchas + +- **`mode` is an integer.** `?mode=1` works; `?mode=customer` → HTTP 400 `Invalid value specified for mode`. +- **Empty list vs 404 vs 403.** `/invoices` returns `[]` (200) on empty/permission-filtered. `/thirdparties` returns 404 `"No third parties found"`. `/thirdparties/{id}` returns 403 if the ACL hides the row. All three can mean "no permission" — the diagnostic is to hit `/thirdparties/1` directly (see Permission gotcha above). +- **Dates are unix epoch (seconds).** `.date`, `.datef`, `.date_lim_reglement`, `.tms` are integers. + ```bash + python3 -c "import datetime,sys; print(datetime.datetime.fromtimestamp(int(sys.argv[1])))" 1771887600 + # → 2026-02-24 00:00:00 + ``` +- **`paye` is the paid flag, `status` is the workflow state.** `status=2` means "validated", `paye=1` means "fully paid". They're independent — a status-2 invoice can still be unpaid. +- **`last_main_doc` paths** are relative to Dolibarr's document root. For `/documents/download`, pass `modulepart=facture` + URL-encoded `original_file=/` (encode the `/`). +- **`array_options=[]` vs `{}`.** Dolibarr returns `[]` when no extrafields are set and `{}` when there are some. Treat both as "no custom fields" in Python. + +## Pointers + +- Workflow skill for invoice + thirdparty audits: [dolibarr-invoice-audit](../dolibarr-invoice-audit/SKILL.md). +- Future workflow skills follow the `dolibarr-` convention. Each one depends on this skill for connection + permissions + endpoint reference; each one keeps its triggers focused on its specific business workflow. + +## Out of scope + +- **Writes.** The `ai_agent` key is read-only by design. For corrections (edit a thirdparty, void an invoice, fix a mention), use the Dolibarr UI. +- **Admin endpoints.** `/setup/*` is gated to admins or to logins listed in `API_LOGINS_ALLOWED_FOR_GET_MODULES`; not available to `ai_agent`. +- **Helm chart / Ansible / Kubernetes operations.** Covered by `chart/`, `ansible/`, and the project root `README.md`. diff --git a/.claude/skills/dolibarr/examples/acl_403_thirdparty.json b/.claude/skills/dolibarr/examples/acl_403_thirdparty.json new file mode 100644 index 0000000..7a4b8dc --- /dev/null +++ b/.claude/skills/dolibarr/examples/acl_403_thirdparty.json @@ -0,0 +1,25 @@ +{ + "_captured_when": "2026-05-28, before the four voir_tous permission flags were ticked on ai_agent. Kept here as the reference signature of the ACL trap. Re-occurrence means the permissions regressed.", + "_curl": "curl -H 'DOLAPIKEY: ' https://erp.arcodange.lab/api/index.php/thirdparties/1", + "_http_status": 403, + "error": { + "code": 403, + "message": "Forbidden: Access not allowed for login ai_agent on this thirdparty" + }, + "debug": { + "source": "api_thirdparties.class.php:2403 at call stage", + "stages": { + "success": [ + "get", + "route", + "negotiate", + "authenticate", + "validate" + ], + "failure": [ + "call", + "message" + ] + } + } +} diff --git a/.claude/skills/dolibarr/examples/document_download_meta.json b/.claude/skills/dolibarr/examples/document_download_meta.json new file mode 100644 index 0000000..41d0cb3 --- /dev/null +++ b/.claude/skills/dolibarr/examples/document_download_meta.json @@ -0,0 +1,7 @@ +{ + "filename": "FAC002-CL0001002.pdf", + "content-type": "application/pdf", + "filesize": 62345, + "content": "JVBERi0xLjcKJeLjz9MKNiAwIG9iago8PCAvVHlwZSAvUGFnZSAvUGFyZW50IDEgMCBSIC9MYXN0TW9kaWZpZWQgKEQ6MjAyNjAzMTMxNTIxNTcrMDEnMDAn...[truncated for repo; 62345-byte PDF]", + "encoding": "base64" +} diff --git a/.claude/skills/dolibarr/examples/invoice_detail.json b/.claude/skills/dolibarr/examples/invoice_detail.json new file mode 100644 index 0000000..036e004 --- /dev/null +++ b/.claude/skills/dolibarr/examples/invoice_detail.json @@ -0,0 +1,273 @@ +{ + "module": null, + "id": "12", + "entity": "1", + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": [], + "contacts_ids_internal": null, + "linkedObjectsIds": [], + "fk_project": null, + "contact_id": null, + "user": null, + "origin_type": null, + "origin_id": null, + "ref": "FAC002-CL0001002", + "ref_ext": null, + "statut": "2", + "status": "2", + "country_id": null, + "country_code": null, + "state_id": null, + "region_id": null, + "mode_reglement_id": "2", + "cond_reglement_id": "10", + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method_id": null, + "shipping_method": null, + "fk_multicurrency": "0", + "multicurrency_code": "EUR", + "multicurrency_tx": "1.00000000", + "multicurrency_total_ht": "5100.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "5100.00000000", + "last_main_doc": "facture/FAC002-CL0001002/FAC002-CL0001002.pdf", + "fk_account": "2", + "note_public": null, + "note_private": "Généré depuis la facture modèle récurrente Kiss Metrics Invoice", + "total_ht": "5100.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "5100.00000000", + "lines": [ + { + "module": null, + "id": "12", + "entity": null, + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": null, + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "origin_type": null, + "origin_id": null, + "ref": "KM-cloud-devops", + "ref_ext": "", + "statut": null, + "status": null, + "state_id": null, + "region_id": null, + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method": null, + "multicurrency_tx": null, + "multicurrency_total_ht": "5100.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "5100.00000000", + "last_main_doc": null, + "fk_account": null, + "total_ht": "5100.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "5100.00000000", + "lines": null, + "actiontypecode": null, + "civility_code": null, + "date_creation": null, + "date_validation": null, + "date_modification": null, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": null, + "user_valid": null, + "user_validation": null, + "user_validation_id": null, + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": null, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": null, + "warehouse_id": null, + "parent_element": "", + "fk_parent_attribute": "", + "rowid": "12", + "fk_unit": null, + "date_debut_prevue": null, + "date_debut_reel": null, + "date_fin_prevue": null, + "date_fin_reel": null, + "weight": null, + "weight_units": null, + "length": null, + "length_units": null, + "width": null, + "width_units": null, + "height": null, + "height_units": null, + "surface": null, + "surface_units": null, + "volume": null, + "volume_units": null, + "multilangs": null, + "product_type": "1", + "fk_product": "2", + "desc": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "description": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "product_ref": "KM-cloud-devops", + "product_label": "KissMetrics - Cloud Devops - 1 day", + "product_barcode": null, + "product_desc": "", + "fk_product_type": "1", + "qty": "10", + "duree": null, + "remise_percent": "0", + "info_bits": "0", + "special_code": "0", + "subprice": "510.00000000", + "subprice_ttc": null, + "tva_tx": "0.0000", + "multicurrency_subprice": "510.00000000", + "multicurrency_subprice_ttc": null, + "label": null, + "libelle": "KissMetrics - Cloud Devops - 1 day", + "price": null, + "vat_src_code": "", + "localtax1_tx": "0.0000", + "localtax2_tx": "0.0000", + "localtax1_type": "0", + "localtax2_type": "0", + "remise": null, + "revenuestamp": null, + "date_start_fill": null, + "date_end_fill": null, + "buy_price_ht": null, + "buyprice": null, + "pa_ht": "0.00000000", + "marge_tx": "", + "marque_tx": "100", + "fk_user_author": null, + "fk_accounting_account": "7", + "fk_facture": "12", + "fk_parent_line": null, + "fk_remise_except": null, + "rang": "1", + "fk_fournprice": null, + "tva_npr": null, + "batch": "", + "fk_warehouse": "0", + "fk_code_ventilation": 0, + "date_start": 1769986800, + "date_end": 1770937200, + "situation_percent": "100", + "fk_prev_id": null, + "packaging": null + } + ], + "actiontypecode": null, + "name": null, + "lastname": null, + "firstname": null, + "civility_id": null, + "civility_code": null, + "date_creation": 1771929906, + "date_validation": 1771887600, + "date_modification": 1773408117, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": "2", + "user_valid": null, + "user_validation": null, + "user_validation_id": "2", + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": 5100, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": "0", + "warehouse_id": null, + "title": null, + "type": "0", + "subtype": null, + "fk_soc": null, + "socid": "1", + "paye": "1", + "date": 1771887600, + "date_lim_reglement": 1774908000, + "cond_reglement_code": "10DENDMONTH", + "cond_reglement_label": null, + "cond_reglement_doc": "Due in 10 days, end of month", + "mode_reglement_code": "VIR", + "revenuestamp": "0.00000000", + "totaldeposits": null, + "totalcreditnotes": null, + "sumpayed": "5100.00000000", + "sumpayed_multicurrency": null, + "sumdeposit": null, + "sumdeposit_multicurrency": null, + "sumcreditnote": null, + "sumcreditnote_multicurrency": null, + "remaintopay": "0", + "nbofopendirectdebitorcredittransfer": null, + "creditnote_ids": [], + "stripechargedone": null, + "stripechargeerror": null, + "description": null, + "ref_client": null, + "situation_cycle_ref": null, + "close_code": null, + "close_note": null, + "postactionmessages": null, + "fk_incoterms": "0", + "label_incoterms": null, + "location_incoterms": "", + "fk_user_author": "2", + "fk_user_valid": "2", + "datem": 1773408117, + "delivery_date": null, + "ref_customer": null, + "resteapayer": null, + "module_source": null, + "pos_source": null, + "fk_fac_rec_source": "1", + "fk_facture_source": null, + "line": null, + "fac_rec": null, + "date_pointoftax": "", + "situation_counter": null, + "situation_final": "0", + "tab_previous_situation_invoice": [], + "tab_next_situation_invoice": [], + "retained_warranty": "0", + "retained_warranty_date_limit": "", + "availability_id": null, + "date_closing": null, + "source": null, + "remise_percent": null, + "online_payment_url": "https://erp.arcodange.lab/public/payment/newpayment.php?source=invoice&ref=FAC002-CL0001002" +} diff --git a/.claude/skills/dolibarr/examples/invoices_list.json b/.claude/skills/dolibarr/examples/invoices_list.json new file mode 100644 index 0000000..04c8378 --- /dev/null +++ b/.claude/skills/dolibarr/examples/invoices_list.json @@ -0,0 +1,1369 @@ +[ + { + "module": null, + "id": "12", + "entity": "1", + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": [], + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "fk_project": null, + "contact_id": null, + "user": null, + "origin_type": null, + "origin_id": null, + "ref": "FAC002-CL0001002", + "ref_ext": null, + "statut": "2", + "status": "2", + "country_id": null, + "country_code": null, + "state_id": null, + "region_id": null, + "mode_reglement_id": "2", + "cond_reglement_id": "10", + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method_id": null, + "shipping_method": null, + "fk_multicurrency": "0", + "multicurrency_code": "EUR", + "multicurrency_tx": "1.00000000", + "multicurrency_total_ht": "5100.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "5100.00000000", + "last_main_doc": "facture/FAC002-CL0001002/FAC002-CL0001002.pdf", + "fk_account": "2", + "note_public": null, + "note_private": "Généré depuis la facture modèle récurrente Kiss Metrics Invoice", + "total_ht": "5100.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "5100.00000000", + "lines": [ + { + "module": null, + "id": "12", + "entity": null, + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": null, + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "origin_type": null, + "origin_id": null, + "ref": "KM-cloud-devops", + "ref_ext": "", + "statut": null, + "status": null, + "state_id": null, + "region_id": null, + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method": null, + "multicurrency_tx": null, + "multicurrency_total_ht": "5100.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "5100.00000000", + "last_main_doc": null, + "fk_account": null, + "total_ht": "5100.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "5100.00000000", + "lines": null, + "actiontypecode": null, + "civility_code": null, + "date_creation": null, + "date_validation": null, + "date_modification": null, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": null, + "user_valid": null, + "user_validation": null, + "user_validation_id": null, + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": null, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": null, + "warehouse_id": null, + "parent_element": "", + "fk_parent_attribute": "", + "rowid": "12", + "fk_unit": null, + "date_debut_prevue": null, + "date_debut_reel": null, + "date_fin_prevue": null, + "date_fin_reel": null, + "weight": null, + "weight_units": null, + "length": null, + "length_units": null, + "width": null, + "width_units": null, + "height": null, + "height_units": null, + "surface": null, + "surface_units": null, + "volume": null, + "volume_units": null, + "multilangs": null, + "product_type": "1", + "fk_product": "2", + "desc": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "description": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "product_ref": "KM-cloud-devops", + "product_label": "KissMetrics - Cloud Devops - 1 day", + "product_barcode": null, + "product_desc": "", + "fk_product_type": "1", + "qty": "10", + "duree": null, + "remise_percent": "0", + "info_bits": "0", + "special_code": "0", + "subprice": "510.00000000", + "subprice_ttc": null, + "tva_tx": "0.0000", + "multicurrency_subprice": "510.00000000", + "multicurrency_subprice_ttc": null, + "label": null, + "libelle": "KissMetrics - Cloud Devops - 1 day", + "price": null, + "vat_src_code": "", + "localtax1_tx": "0.0000", + "localtax2_tx": "0.0000", + "localtax1_type": "0", + "localtax2_type": "0", + "remise": null, + "revenuestamp": null, + "date_start_fill": null, + "date_end_fill": null, + "buy_price_ht": null, + "buyprice": null, + "pa_ht": "0.00000000", + "marge_tx": "", + "marque_tx": "100", + "fk_user_author": null, + "fk_accounting_account": "7", + "fk_facture": "12", + "fk_parent_line": null, + "fk_remise_except": null, + "rang": "1", + "fk_fournprice": null, + "tva_npr": null, + "batch": "", + "fk_warehouse": "0", + "fk_code_ventilation": 0, + "date_start": 1769986800, + "date_end": 1770937200, + "situation_percent": "100", + "fk_prev_id": null, + "packaging": null + } + ], + "actiontypecode": null, + "name": null, + "lastname": null, + "firstname": null, + "civility_id": null, + "civility_code": null, + "date_creation": 1771929906, + "date_validation": 1771887600, + "date_modification": 1773408117, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": "2", + "user_valid": null, + "user_validation": null, + "user_validation_id": "2", + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": 5100, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": "0", + "warehouse_id": null, + "title": null, + "type": "0", + "subtype": null, + "fk_soc": null, + "socid": "1", + "paye": "1", + "date": 1771887600, + "date_lim_reglement": 1774908000, + "cond_reglement_code": "10DENDMONTH", + "cond_reglement_label": null, + "cond_reglement_doc": "Due in 10 days, end of month", + "mode_reglement_code": "VIR", + "revenuestamp": "0.00000000", + "totaldeposits": null, + "totalcreditnotes": null, + "sumpayed": "5100.00000000", + "sumpayed_multicurrency": null, + "sumdeposit": null, + "sumdeposit_multicurrency": null, + "sumcreditnote": null, + "sumcreditnote_multicurrency": null, + "remaintopay": "0", + "nbofopendirectdebitorcredittransfer": null, + "creditnote_ids": [], + "stripechargedone": null, + "stripechargeerror": null, + "description": null, + "ref_client": null, + "situation_cycle_ref": null, + "close_code": null, + "close_note": null, + "postactionmessages": null, + "fk_incoterms": "0", + "label_incoterms": null, + "location_incoterms": "", + "fk_user_author": "2", + "fk_user_valid": "2", + "datem": 1773408117, + "delivery_date": null, + "ref_customer": null, + "resteapayer": null, + "module_source": null, + "pos_source": null, + "fk_fac_rec_source": "1", + "fk_facture_source": null, + "line": null, + "fac_rec": null, + "date_pointoftax": "", + "situation_counter": null, + "situation_final": "0", + "tab_previous_situation_invoice": [], + "tab_next_situation_invoice": [], + "retained_warranty": "0", + "retained_warranty_date_limit": "", + "availability_id": null, + "date_closing": null, + "source": null, + "remise_percent": null, + "online_payment_url": "https://erp.arcodange.lab/public/payment/newpayment.php?source=invoice&ref=FAC002-CL0001002" + }, + { + "module": null, + "id": "13", + "entity": "1", + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": [], + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "fk_project": null, + "contact_id": null, + "user": null, + "origin_type": null, + "origin_id": null, + "ref": "FAC003-CL0001003", + "ref_ext": null, + "statut": "2", + "status": "2", + "country_id": null, + "country_code": null, + "state_id": null, + "region_id": null, + "mode_reglement_id": "2", + "cond_reglement_id": "3", + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method_id": null, + "shipping_method": null, + "fk_multicurrency": "0", + "multicurrency_code": "EUR", + "multicurrency_tx": "1.00000000", + "multicurrency_total_ht": "2550.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "2550.00000000", + "last_main_doc": "facture/FAC003-CL0001003/FAC003-CL0001003.pdf", + "fk_account": "2", + "note_public": "Faveur au client de partager la facture du mois et de demander paiement de la seconde partie au mois suivant.", + "note_private": "Généré depuis la facture modèle récurrente Kiss Metrics Invoice", + "total_ht": "2550.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "2550.00000000", + "lines": [ + { + "module": null, + "id": "13", + "entity": null, + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": null, + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "origin_type": null, + "origin_id": null, + "ref": "KM-cloud-devops", + "ref_ext": "", + "statut": null, + "status": null, + "state_id": null, + "region_id": null, + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method": null, + "multicurrency_tx": null, + "multicurrency_total_ht": "2550.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "2550.00000000", + "last_main_doc": null, + "fk_account": null, + "total_ht": "2550.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "2550.00000000", + "lines": null, + "actiontypecode": null, + "civility_code": null, + "date_creation": null, + "date_validation": null, + "date_modification": null, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": null, + "user_valid": null, + "user_validation": null, + "user_validation_id": null, + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": null, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": null, + "warehouse_id": null, + "parent_element": "", + "fk_parent_attribute": "", + "rowid": "13", + "fk_unit": null, + "date_debut_prevue": null, + "date_debut_reel": null, + "date_fin_prevue": null, + "date_fin_reel": null, + "weight": null, + "weight_units": null, + "length": null, + "length_units": null, + "width": null, + "width_units": null, + "height": null, + "height_units": null, + "surface": null, + "surface_units": null, + "volume": null, + "volume_units": null, + "multilangs": null, + "product_type": "1", + "fk_product": "2", + "desc": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "description": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "product_ref": "KM-cloud-devops", + "product_label": "KissMetrics - Cloud Devops - 1 day", + "product_barcode": null, + "product_desc": "", + "fk_product_type": "1", + "qty": "5", + "duree": null, + "remise_percent": "0", + "info_bits": "0", + "special_code": "0", + "subprice": "510.00000000", + "subprice_ttc": null, + "tva_tx": "0.0000", + "multicurrency_subprice": "510.00000000", + "multicurrency_subprice_ttc": null, + "label": null, + "libelle": "KissMetrics - Cloud Devops - 1 day", + "price": null, + "vat_src_code": "", + "localtax1_tx": "0.0000", + "localtax2_tx": "0.0000", + "localtax1_type": "0", + "localtax2_type": "0", + "remise": null, + "revenuestamp": null, + "date_start_fill": null, + "date_end_fill": null, + "buy_price_ht": null, + "buyprice": null, + "pa_ht": "0.00000000", + "marge_tx": "", + "marque_tx": "100", + "fk_user_author": null, + "fk_accounting_account": "7", + "fk_facture": "13", + "fk_parent_line": null, + "fk_remise_except": null, + "rang": "1", + "fk_fournprice": null, + "tva_npr": null, + "batch": "", + "fk_warehouse": "0", + "fk_code_ventilation": 0, + "date_start": 1771196400, + "date_end": 1771542000, + "situation_percent": "100", + "fk_prev_id": null, + "packaging": null + } + ], + "actiontypecode": null, + "name": null, + "lastname": null, + "firstname": null, + "civility_id": null, + "civility_code": null, + "date_creation": 1771930027, + "date_validation": 1771887600, + "date_modification": 1778411727, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": "2", + "user_valid": null, + "user_validation": null, + "user_validation_id": "2", + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": 2550, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": "0", + "warehouse_id": null, + "title": null, + "type": "0", + "subtype": null, + "fk_soc": null, + "socid": "1", + "paye": "1", + "date": 1771887600, + "date_lim_reglement": 1774908000, + "cond_reglement_code": "30DENDMONTH", + "cond_reglement_label": null, + "cond_reglement_doc": "Due in 30 days, end of month", + "mode_reglement_code": "VIR", + "revenuestamp": "0.00000000", + "totaldeposits": null, + "totalcreditnotes": null, + "sumpayed": "2550.00000000", + "sumpayed_multicurrency": null, + "sumdeposit": null, + "sumdeposit_multicurrency": null, + "sumcreditnote": null, + "sumcreditnote_multicurrency": null, + "remaintopay": "0", + "nbofopendirectdebitorcredittransfer": null, + "creditnote_ids": [], + "stripechargedone": null, + "stripechargeerror": null, + "description": null, + "ref_client": null, + "situation_cycle_ref": null, + "close_code": null, + "close_note": null, + "postactionmessages": null, + "fk_incoterms": "0", + "label_incoterms": null, + "location_incoterms": "", + "fk_user_author": "2", + "fk_user_valid": "2", + "datem": 1778411727, + "delivery_date": null, + "ref_customer": null, + "resteapayer": null, + "module_source": null, + "pos_source": null, + "fk_fac_rec_source": "1", + "fk_facture_source": null, + "line": null, + "fac_rec": null, + "date_pointoftax": "", + "situation_counter": null, + "situation_final": "0", + "tab_previous_situation_invoice": [], + "tab_next_situation_invoice": [], + "retained_warranty": "0", + "retained_warranty_date_limit": "", + "availability_id": null, + "date_closing": null, + "source": null, + "remise_percent": null, + "online_payment_url": "https://erp.arcodange.lab/public/payment/newpayment.php?source=invoice&ref=FAC003-CL0001003" + }, + { + "module": null, + "id": "2", + "entity": "1", + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": [], + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "fk_project": null, + "contact_id": null, + "user": null, + "origin_type": null, + "origin_id": null, + "ref": "FAC001-CL00001", + "ref_ext": null, + "statut": "2", + "status": "2", + "country_id": null, + "country_code": null, + "state_id": null, + "region_id": null, + "mode_reglement_id": "2", + "cond_reglement_id": "9", + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method_id": null, + "shipping_method": null, + "fk_multicurrency": "0", + "multicurrency_code": "EUR", + "multicurrency_tx": "1.00000000", + "multicurrency_total_ht": "510.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "510.00000000", + "last_main_doc": "facture/FAC001-CL00001/FAC001-CL00001.pdf", + "fk_account": "2", + "note_public": null, + "note_private": null, + "total_ht": "510.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "510.00000000", + "lines": [ + { + "module": null, + "id": "1", + "entity": null, + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": null, + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "origin_type": null, + "origin_id": null, + "ref": "KM-audit", + "ref_ext": "", + "statut": null, + "status": null, + "state_id": null, + "region_id": null, + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method": null, + "multicurrency_tx": null, + "multicurrency_total_ht": "510.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "510.00000000", + "last_main_doc": null, + "fk_account": null, + "total_ht": "510.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "510.00000000", + "lines": null, + "actiontypecode": null, + "civility_code": null, + "date_creation": null, + "date_validation": null, + "date_modification": null, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": null, + "user_valid": null, + "user_validation": null, + "user_validation_id": null, + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": null, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": null, + "warehouse_id": null, + "parent_element": "", + "fk_parent_attribute": "", + "rowid": "1", + "fk_unit": null, + "date_debut_prevue": null, + "date_debut_reel": null, + "date_fin_prevue": null, + "date_fin_reel": null, + "weight": null, + "weight_units": null, + "length": null, + "length_units": null, + "width": null, + "width_units": null, + "height": null, + "height_units": null, + "surface": null, + "surface_units": null, + "volume": null, + "volume_units": null, + "multilangs": null, + "product_type": "1", + "fk_product": "1", + "desc": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "description": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "product_ref": "KM-audit", + "product_label": "KissMetrics - Cloud Infrastructure Audit - 1 day - Jan26", + "product_barcode": null, + "product_desc": "", + "fk_product_type": "1", + "qty": "1", + "duree": null, + "remise_percent": "0", + "info_bits": "0", + "special_code": "0", + "subprice": "510.00000000", + "subprice_ttc": null, + "tva_tx": "0.0000", + "multicurrency_subprice": "510.00000000", + "multicurrency_subprice_ttc": null, + "label": null, + "libelle": "KissMetrics - Cloud Infrastructure Audit - 1 day - Jan26", + "price": null, + "vat_src_code": "", + "localtax1_tx": "0.0000", + "localtax2_tx": "0.0000", + "localtax1_type": "0", + "localtax2_type": "0", + "remise": null, + "revenuestamp": null, + "date_start_fill": null, + "date_end_fill": null, + "buy_price_ht": null, + "buyprice": null, + "pa_ht": "0.00000000", + "marge_tx": "", + "marque_tx": "100", + "fk_user_author": null, + "fk_accounting_account": "7", + "fk_facture": "2", + "fk_parent_line": null, + "fk_remise_except": null, + "rang": "2", + "fk_fournprice": null, + "tva_npr": null, + "batch": "", + "fk_warehouse": "0", + "fk_code_ventilation": 0, + "date_start": "", + "date_end": "", + "situation_percent": "100", + "fk_prev_id": null, + "packaging": null + } + ], + "actiontypecode": null, + "name": null, + "lastname": null, + "firstname": null, + "civility_id": null, + "civility_code": null, + "date_creation": 1769899167, + "date_validation": 1771801200, + "date_modification": 1771926889, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": "2", + "user_valid": null, + "user_validation": null, + "user_validation_id": "1", + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": 510, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": "0", + "warehouse_id": null, + "title": null, + "type": "0", + "subtype": null, + "fk_soc": null, + "socid": "1", + "paye": "1", + "date": 1769727600, + "date_lim_reglement": 1770591600, + "cond_reglement_code": "10D", + "cond_reglement_label": null, + "cond_reglement_doc": "Due in 10 days", + "mode_reglement_code": "VIR", + "revenuestamp": "0.00000000", + "totaldeposits": null, + "totalcreditnotes": null, + "sumpayed": "510.00000000", + "sumpayed_multicurrency": null, + "sumdeposit": null, + "sumdeposit_multicurrency": null, + "sumcreditnote": null, + "sumcreditnote_multicurrency": null, + "remaintopay": "0", + "nbofopendirectdebitorcredittransfer": null, + "creditnote_ids": [ + "10" + ], + "stripechargedone": null, + "stripechargeerror": null, + "description": null, + "ref_client": null, + "situation_cycle_ref": null, + "close_code": null, + "close_note": null, + "postactionmessages": null, + "fk_incoterms": "0", + "label_incoterms": null, + "location_incoterms": "", + "fk_user_author": "2", + "fk_user_valid": "1", + "datem": 1771926889, + "delivery_date": null, + "ref_customer": null, + "resteapayer": null, + "module_source": null, + "pos_source": null, + "fk_fac_rec_source": null, + "fk_facture_source": null, + "line": null, + "fac_rec": null, + "date_pointoftax": "", + "situation_counter": null, + "situation_final": "0", + "tab_previous_situation_invoice": [], + "tab_next_situation_invoice": [], + "retained_warranty": "0", + "retained_warranty_date_limit": 1770591600, + "availability_id": null, + "date_closing": null, + "source": null, + "remise_percent": null, + "online_payment_url": "https://erp.arcodange.lab/public/payment/newpayment.php?source=invoice&ref=FAC001-CL00001" + }, + { + "module": null, + "id": "11", + "entity": "1", + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": [], + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "fk_project": null, + "contact_id": null, + "user": null, + "origin_type": null, + "origin_id": null, + "ref": "FAC001-CL0001001", + "ref_ext": null, + "statut": "2", + "status": "2", + "country_id": null, + "country_code": null, + "state_id": null, + "region_id": null, + "mode_reglement_id": "2", + "cond_reglement_id": "9", + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method_id": null, + "shipping_method": null, + "fk_multicurrency": "0", + "multicurrency_code": "EUR", + "multicurrency_tx": "1.00000000", + "multicurrency_total_ht": "510.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "510.00000000", + "last_main_doc": "facture/FAC001-CL0001001/FAC001-CL0001001.pdf", + "fk_account": "2", + "note_public": null, + "note_private": null, + "total_ht": "510.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "510.00000000", + "lines": [ + { + "module": null, + "id": "11", + "entity": null, + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": null, + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "origin_type": null, + "origin_id": null, + "ref": "KM-audit", + "ref_ext": "", + "statut": null, + "status": null, + "state_id": null, + "region_id": null, + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method": null, + "multicurrency_tx": null, + "multicurrency_total_ht": "510.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "510.00000000", + "last_main_doc": null, + "fk_account": null, + "total_ht": "510.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "510.00000000", + "lines": null, + "actiontypecode": null, + "civility_code": null, + "date_creation": null, + "date_validation": null, + "date_modification": null, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": null, + "user_valid": null, + "user_validation": null, + "user_validation_id": null, + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": null, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": null, + "warehouse_id": null, + "parent_element": "", + "fk_parent_attribute": "", + "rowid": "11", + "fk_unit": null, + "date_debut_prevue": null, + "date_debut_reel": null, + "date_fin_prevue": null, + "date_fin_reel": null, + "weight": null, + "weight_units": null, + "length": null, + "length_units": null, + "width": null, + "width_units": null, + "height": null, + "height_units": null, + "surface": null, + "surface_units": null, + "volume": null, + "volume_units": null, + "multilangs": null, + "product_type": "1", + "fk_product": "1", + "desc": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "description": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "product_ref": "KM-audit", + "product_label": "KissMetrics - Cloud Infrastructure Audit - 1 day - Jan26", + "product_barcode": null, + "product_desc": "", + "fk_product_type": "1", + "qty": "1", + "duree": null, + "remise_percent": "0", + "info_bits": "0", + "special_code": "0", + "subprice": "510.00000000", + "subprice_ttc": null, + "tva_tx": "0.0000", + "multicurrency_subprice": "510.00000000", + "multicurrency_subprice_ttc": null, + "label": null, + "libelle": "KissMetrics - Cloud Infrastructure Audit - 1 day - Jan26", + "price": null, + "vat_src_code": "", + "localtax1_tx": "0.0000", + "localtax2_tx": "0.0000", + "localtax1_type": "0", + "localtax2_type": "0", + "remise": null, + "revenuestamp": null, + "date_start_fill": null, + "date_end_fill": null, + "buy_price_ht": null, + "buyprice": null, + "pa_ht": "0.00000000", + "marge_tx": "", + "marque_tx": "100", + "fk_user_author": null, + "fk_accounting_account": "7", + "fk_facture": "11", + "fk_parent_line": null, + "fk_remise_except": null, + "rang": "2", + "fk_fournprice": null, + "tva_npr": null, + "batch": "", + "fk_warehouse": "0", + "fk_code_ventilation": 0, + "date_start": 1769727600, + "date_end": 1769727600, + "situation_percent": "100", + "fk_prev_id": null, + "packaging": null + } + ], + "actiontypecode": null, + "name": null, + "lastname": null, + "firstname": null, + "civility_id": null, + "civility_code": null, + "date_creation": 1771929766, + "date_validation": 1771887600, + "date_modification": 1771926889, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": "2", + "user_valid": null, + "user_validation": null, + "user_validation_id": "2", + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": 510, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": "0", + "warehouse_id": null, + "title": null, + "type": "0", + "subtype": null, + "fk_soc": null, + "socid": "1", + "paye": "1", + "date": 1769727600, + "date_lim_reglement": 1770591600, + "cond_reglement_code": "10D", + "cond_reglement_label": null, + "cond_reglement_doc": "Due in 10 days", + "mode_reglement_code": "VIR", + "revenuestamp": "0.00000000", + "totaldeposits": null, + "totalcreditnotes": null, + "sumpayed": "510.00000000", + "sumpayed_multicurrency": null, + "sumdeposit": null, + "sumdeposit_multicurrency": null, + "sumcreditnote": null, + "sumcreditnote_multicurrency": null, + "remaintopay": "0", + "nbofopendirectdebitorcredittransfer": null, + "creditnote_ids": [], + "stripechargedone": null, + "stripechargeerror": null, + "description": null, + "ref_client": null, + "situation_cycle_ref": null, + "close_code": null, + "close_note": null, + "postactionmessages": null, + "fk_incoterms": "0", + "label_incoterms": null, + "location_incoterms": "", + "fk_user_author": "2", + "fk_user_valid": "2", + "datem": 1771926889, + "delivery_date": null, + "ref_customer": null, + "resteapayer": null, + "module_source": null, + "pos_source": null, + "fk_fac_rec_source": null, + "fk_facture_source": null, + "line": null, + "fac_rec": null, + "date_pointoftax": "", + "situation_counter": null, + "situation_final": "0", + "tab_previous_situation_invoice": [], + "tab_next_situation_invoice": [], + "retained_warranty": "0", + "retained_warranty_date_limit": 1770591600, + "availability_id": null, + "date_closing": null, + "source": null, + "remise_percent": null, + "online_payment_url": "https://erp.arcodange.lab/public/payment/newpayment.php?source=invoice&ref=FAC001-CL0001001" + }, + { + "module": null, + "id": "10", + "entity": "1", + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": [], + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "fk_project": null, + "contact_id": null, + "user": null, + "origin_type": null, + "origin_id": null, + "ref": "AVC001-CL0001001", + "ref_ext": null, + "statut": "2", + "status": "2", + "country_id": null, + "country_code": null, + "state_id": null, + "region_id": null, + "mode_reglement_id": "2", + "cond_reglement_id": "0", + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method_id": null, + "shipping_method": null, + "fk_multicurrency": "0", + "multicurrency_code": "EUR", + "multicurrency_tx": "1.00000000", + "multicurrency_total_ht": "-510.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "-510.00000000", + "last_main_doc": "facture/AVC001-CL0001001/AVC001-CL0001001.pdf", + "fk_account": "2", + "note_public": "pour pouvoir re-g\u00e9n\u00e9rer une facture identique,\r\ncorrection de l'identification de la facture suite \u00e0 mauvaise configuration du logiciel comptable.\r\nFacture d\u00e9j\u00e0 pay\u00e9e en r\u00e9alit\u00e9.", + "note_private": null, + "total_ht": "-510.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "-510.00000000", + "lines": [ + { + "module": null, + "id": "10", + "entity": null, + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": null, + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "origin_type": null, + "origin_id": null, + "ref": "KM-audit", + "ref_ext": "", + "statut": null, + "status": null, + "state_id": null, + "region_id": null, + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method": null, + "multicurrency_tx": null, + "multicurrency_total_ht": "-510.00000000", + "multicurrency_total_tva": "0.00000000", + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": "-510.00000000", + "last_main_doc": null, + "fk_account": null, + "total_ht": "-510.00000000", + "total_tva": "0.00000000", + "total_localtax1": "0.00000000", + "total_localtax2": "0.00000000", + "total_ttc": "-510.00000000", + "lines": null, + "actiontypecode": null, + "civility_code": null, + "date_creation": null, + "date_validation": null, + "date_modification": null, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": null, + "user_valid": null, + "user_validation": null, + "user_validation_id": null, + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": null, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": null, + "warehouse_id": null, + "parent_element": "", + "fk_parent_attribute": "", + "rowid": "10", + "fk_unit": null, + "date_debut_prevue": null, + "date_debut_reel": null, + "date_fin_prevue": null, + "date_fin_reel": null, + "weight": null, + "weight_units": null, + "length": null, + "length_units": null, + "width": null, + "width_units": null, + "height": null, + "height_units": null, + "surface": null, + "surface_units": null, + "volume": null, + "volume_units": null, + "multilangs": null, + "product_type": "1", + "fk_product": "1", + "desc": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "description": "TVA non applicable – Article 259-1 du CGI – Prestation de services localisée hors de France (USA)", + "product_ref": "KM-audit", + "product_label": "KissMetrics - Cloud Infrastructure Audit - 1 day - Jan26", + "product_barcode": null, + "product_desc": "", + "fk_product_type": "1", + "qty": "1", + "duree": null, + "remise_percent": "0", + "info_bits": "0", + "special_code": "0", + "subprice": "-510.00000000", + "subprice_ttc": null, + "tva_tx": "0.0000", + "multicurrency_subprice": "-510.00000000", + "multicurrency_subprice_ttc": null, + "label": null, + "libelle": "KissMetrics - Cloud Infrastructure Audit - 1 day - Jan26", + "price": null, + "vat_src_code": "", + "localtax1_tx": "0.0000", + "localtax2_tx": "0.0000", + "localtax1_type": "0", + "localtax2_type": "0", + "remise": null, + "revenuestamp": null, + "date_start_fill": null, + "date_end_fill": null, + "buy_price_ht": null, + "buyprice": null, + "pa_ht": "0.00000000", + "marge_tx": "", + "marque_tx": "100", + "fk_user_author": null, + "fk_accounting_account": "7", + "fk_facture": "10", + "fk_parent_line": null, + "fk_remise_except": null, + "rang": "2", + "fk_fournprice": null, + "tva_npr": null, + "batch": "", + "fk_warehouse": "0", + "fk_code_ventilation": 0, + "date_start": "", + "date_end": "", + "situation_percent": "100", + "fk_prev_id": null, + "packaging": null + } + ], + "actiontypecode": null, + "name": null, + "lastname": null, + "firstname": null, + "civility_id": null, + "civility_code": null, + "date_creation": 1771929553, + "date_validation": 1771887600, + "date_modification": 1771927042, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": "1", + "user_valid": null, + "user_validation": null, + "user_validation_id": "2", + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": -510, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": "0", + "warehouse_id": null, + "title": null, + "type": "2", + "subtype": null, + "fk_soc": null, + "socid": "1", + "paye": "1", + "date": 1769727600, + "date_lim_reglement": 1769727600, + "cond_reglement_code": null, + "cond_reglement_label": null, + "cond_reglement_doc": null, + "mode_reglement_code": "VIR", + "revenuestamp": "0.00000000", + "totaldeposits": null, + "totalcreditnotes": null, + "sumpayed": "-510.00000000", + "sumpayed_multicurrency": null, + "sumdeposit": null, + "sumdeposit_multicurrency": null, + "sumcreditnote": null, + "sumcreditnote_multicurrency": null, + "remaintopay": "0", + "nbofopendirectdebitorcredittransfer": null, + "creditnote_ids": [], + "stripechargedone": null, + "stripechargeerror": null, + "description": null, + "ref_client": null, + "situation_cycle_ref": null, + "close_code": null, + "close_note": null, + "postactionmessages": null, + "fk_incoterms": "0", + "label_incoterms": null, + "location_incoterms": "", + "fk_user_author": "1", + "fk_user_valid": "2", + "datem": 1771927042, + "delivery_date": null, + "ref_customer": null, + "resteapayer": null, + "module_source": null, + "pos_source": null, + "fk_fac_rec_source": null, + "fk_facture_source": "2", + "line": null, + "fac_rec": null, + "date_pointoftax": "", + "situation_counter": null, + "situation_final": "0", + "tab_previous_situation_invoice": [], + "tab_next_situation_invoice": [], + "retained_warranty": "0", + "retained_warranty_date_limit": "", + "availability_id": null, + "date_closing": null, + "source": null, + "remise_percent": null, + "online_payment_url": "https://erp.arcodange.lab/public/payment/newpayment.php?source=invoice&ref=AVC001-CL0001001" + } +] diff --git a/.claude/skills/dolibarr/examples/status.json b/.claude/skills/dolibarr/examples/status.json new file mode 100644 index 0000000..c7cf3b7 --- /dev/null +++ b/.claude/skills/dolibarr/examples/status.json @@ -0,0 +1,7 @@ +{ + "success": { + "code": 200, + "dolibarr_version": "22.0.4", + "access_locked": "0" + } +} diff --git a/.claude/skills/dolibarr/examples/thirdparty_km.json b/.claude/skills/dolibarr/examples/thirdparty_km.json new file mode 100644 index 0000000..2b3491e --- /dev/null +++ b/.claude/skills/dolibarr/examples/thirdparty_km.json @@ -0,0 +1,167 @@ +{ + "module": "societe", + "id": "1", + "entity": "1", + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": null, + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "canvas": null, + "fk_project": null, + "contact_id": null, + "user": null, + "origin_type": null, + "origin_id": null, + "ref": "KissMetrics", + "ref_ext": null, + "statut": null, + "status": "1", + "country_id": "11", + "country_code": "US", + "state_id": "1167", + "region_id": "297", + "barcode_type": null, + "barcode_type_coder": null, + "mode_reglement_id": null, + "cond_reglement_id": null, + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method_id": null, + "shipping_method": null, + "fk_multicurrency": "0", + "multicurrency_code": "", + "multicurrency_tx": null, + "multicurrency_total_ht": null, + "multicurrency_total_tva": null, + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": null, + "last_main_doc": null, + "fk_account": "0", + "note_public": null, + "note_private": null, + "actiontypecode": null, + "name": "KissMetrics", + "lastname": null, + "firstname": null, + "civility_id": null, + "civility_code": null, + "date_creation": 1769898064, + "date_validation": null, + "date_modification": 1771926531, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": "1", + "user_valid": null, + "user_validation": null, + "user_validation_id": null, + "user_closing_id": null, + "user_modification": null, + "user_modification_id": "1", + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": null, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": null, + "warehouse_id": null, + "SupplierCategories": [], + "prefixCustomerIsRequired": null, + "name_alias": "", + "phone": null, + "phone_mobile": null, + "fax": null, + "email": "evan@kissmetrics.io", + "no_email": null, + "skype": null, + "twitter": null, + "facebook": null, + "linkedin": null, + "url": null, + "barcode": null, + "idprof1": "", + "idprof2": "", + "idprof3": "", + "idprof4": "", + "idprof5": "", + "idprof6": "", + "idprof7": null, + "idprof8": null, + "idprof9": null, + "idprof10": null, + "socialobject": null, + "tva_assuj": "0", + "tva_intra": "", + "vat_reverse_charge": 0, + "localtax1_assuj": null, + "localtax1_value": "0.0000", + "localtax2_assuj": null, + "localtax2_value": "0.0000", + "managers": null, + "capital": null, + "typent_id": "3", + "typent_code": "TE_MEDIUM", + "effectif": "1 - 5", + "effectif_id": "1", + "forme_juridique_code": null, + "forme_juridique": "", + "remise_percent": 0, + "remise_supplier_percent": "0", + "mode_reglement_supplier_id": null, + "transport_mode_supplier_id": null, + "fk_prospectlevel": "", + "client": "1", + "prospect": 0, + "fournisseur": "0", + "code_client": "CL0001", + "code_fournisseur": null, + "code_compta_client": "411KISSME", + "accountancy_code_customer_general": null, + "accountancy_code_customer": null, + "code_compta_fournisseur": null, + "accountancy_code_supplier_general": null, + "accountancy_code_supplier": null, + "code_compta_product": null, + "stcomm_id": "0", + "stcomm_picto": null, + "status_prospect_label": "Never contacted", + "price_level": null, + "outstanding_limit": null, + "order_min_amount": null, + "supplier_order_min_amount": null, + "parent": null, + "default_lang": null, + "ip": null, + "webservices_url": null, + "webservices_key": null, + "logo": null, + "logo_small": null, + "logo_mini": null, + "logo_squarred": null, + "logo_squarred_small": null, + "logo_squarred_mini": null, + "accountancy_code_sell": "", + "accountancy_code_buy": "", + "currency_code": null, + "fk_warehouse": null, + "termsofsale": null, + "partnerships": [], + "bank_account": null, + "code_compta": null, + "fk_incoterms": "0", + "label_incoterms": null, + "location_incoterms": null, + "socialnetworks": [], + "address": "2850 34th Street North, 307", + "zip": "33713", + "town": "St. Petersburg", + "absolute_discount": "0", + "absolute_creditnote": "0" +} diff --git a/.claude/skills/dolibarr/examples/users_info.json b/.claude/skills/dolibarr/examples/users_info.json new file mode 100644 index 0000000..f5dea1d --- /dev/null +++ b/.claude/skills/dolibarr/examples/users_info.json @@ -0,0 +1,146 @@ +{ + "module": null, + "id": "3", + "entity": "1", + "import_key": null, + "array_options": [], + "array_languages": null, + "contacts_ids": null, + "contacts_ids_internal": null, + "linkedObjectsIds": null, + "canvas": null, + "fk_project": null, + "contact_id": null, + "user": null, + "origin_type": null, + "origin_id": null, + "ref": "3", + "ref_ext": null, + "statut": "1", + "status": "1", + "country_id": null, + "country_code": "", + "state_id": null, + "region_id": null, + "barcode_type": null, + "barcode_type_coder": null, + "mode_reglement_id": null, + "cond_reglement_id": null, + "demand_reason_id": null, + "transport_mode_id": null, + "shipping_method": null, + "fk_multicurrency": null, + "multicurrency_code": null, + "multicurrency_tx": null, + "multicurrency_total_ht": null, + "multicurrency_total_tva": null, + "multicurrency_total_localtax1": null, + "multicurrency_total_localtax2": null, + "multicurrency_total_ttc": null, + "last_main_doc": null, + "fk_account": null, + "note_public": "", + "note_private": "", + "actiontypecode": null, + "name": null, + "lastname": "AI Agent", + "firstname": "", + "civility_id": null, + "civility_code": "", + "date_creation": null, + "date_validation": null, + "date_modification": null, + "tms": null, + "date_cloture": null, + "user_author": null, + "user_creation": null, + "user_creation_id": null, + "user_valid": null, + "user_validation": null, + "user_validation_id": null, + "user_closing_id": null, + "user_modification": null, + "user_modification_id": null, + "fk_user_creat": null, + "fk_user_modif": null, + "specimen": 0, + "totalpaid": null, + "extraparams": [], + "product": null, + "cond_reglement_supplier_id": null, + "deposit_percent": null, + "retained_warranty_fk_cond_reglement": null, + "warehouse_id": null, + "employee": "1", + "fullname": null, + "gender": null, + "birth": "", + "email": "", + "email_oauth2": null, + "personal_email": "", + "socialnetworks": [], + "job": "AI Agent", + "signature": "Claude AI", + "office_phone": "", + "office_fax": "", + "user_mobile": "", + "personal_mobile": "", + "admin": "0", + "login": "ai_agent", + "pass_crypted": null, + "datec": 1779984197, + "datem": 1779977142, + "socid": null, + "fk_member": null, + "fk_user": null, + "fk_user_expense_validator": null, + "fk_user_holiday_validator": null, + "clicktodial_url": null, + "clicktodial_login": null, + "clicktodial_poste": null, + "datelastpassvalidation": "2026-05-28 18:05:42", + "datelastlogin": "", + "datepreviouslogin": "", + "flagdelsessionsbefore": 1779984337, + "iplastlogin": null, + "ippreviouslogin": null, + "datestartvalidity": "", + "dateendvalidity": "", + "photo": null, + "lang": null, + "rights": { + "user": { + "user": {}, + "self": {}, + "user_advance": {}, + "self_advance": {}, + "group_advance": {} + } + }, + "user_group_list": [], + "conf": {}, + "users": [], + "parentof": null, + "accountancy_code_user_general": "", + "accountancy_code": "", + "thm": null, + "tjm": null, + "salary": null, + "salaryextra": null, + "weeklyhours": null, + "color": "ff7f00", + "dateemployment": "", + "dateemploymentend": "", + "default_c_exp_tax_cat": null, + "ref_employee": "", + "national_registration_number": "", + "default_range": null, + "fk_warehouse": null, + "fk_establishment": null, + "label_establishment": null, + "usergroup_entity": null, + "address": "", + "zip": "", + "town": "", + "url": null +} diff --git a/.claude/skills/dolibarr/scripts/dol-curl.sh b/.claude/skills/dolibarr/scripts/dol-curl.sh new file mode 100755 index 0000000..296962a --- /dev/null +++ b/.claude/skills/dolibarr/scripts/dol-curl.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# Tiny read-only curl wrapper for the Arcodange Dolibarr API. +# +# Usage: +# dol-curl.sh # e.g. dol-curl.sh /invoices?limit=5 +# dol-curl.sh -i # include response headers +# dol-curl.sh -o file.json # write body to file +# +# Reads DOLIBARR_URL and DOLIBARR_API_KEY from the sibling .env file +# (.claude/skills/dolibarr/.env), mode 600, gitignored. +# Exits non-zero on HTTP >=400 and prints the response body on stderr. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ENV_FILE="${SCRIPT_DIR}/../.env" + +if [[ ! -f "${ENV_FILE}" ]]; then + echo "dol-curl.sh: missing ${ENV_FILE}" >&2 + echo " Create it with DOLIBARR_URL and DOLIBARR_API_KEY. See dolibarr/README.md." >&2 + exit 2 +fi + +# shellcheck disable=SC1090 +set -a; source "${ENV_FILE}"; set +a + +: "${DOLIBARR_URL:?dol-curl.sh: DOLIBARR_URL not set in .env}" +: "${DOLIBARR_API_KEY:?dol-curl.sh: DOLIBARR_API_KEY not set in .env}" + +# Last positional arg is the API path; everything before it is passed through to curl. +if [[ $# -lt 1 ]]; then + echo "dol-curl.sh: missing API path. Example: dol-curl.sh /users/info" >&2 + exit 2 +fi + +PASSTHRU=() +while [[ $# -gt 1 ]]; do + PASSTHRU+=("$1") + shift +done +API_PATH="$1" + +# Two-stage call: capture HTTP code + body separately so we can fail clearly +# while still letting the user pipe stdout into jq. +BODY_FILE="$(mktemp -t dolcurl.XXXXXX)" +trap 'rm -f "${BODY_FILE}"' EXIT + +HTTP_CODE=$(curl -sS \ + -H "DOLAPIKEY: ${DOLIBARR_API_KEY}" \ + -H "Accept: application/json" \ + --max-time 30 \ + -o "${BODY_FILE}" \ + -w "%{http_code}" \ + ${PASSTHRU[@]+"${PASSTHRU[@]}"} \ + "${DOLIBARR_URL}/api/index.php${API_PATH}") + +cat "${BODY_FILE}" +if [[ "${HTTP_CODE}" -ge 400 ]]; then + echo "dol-curl.sh: HTTP ${HTTP_CODE} on ${API_PATH}" >&2 + exit 1 +fi diff --git a/.gitignore b/.gitignore index a99b13d..01f1a48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,11 @@ .terraform* .DS_Store .vscode -.env \ No newline at end of file +.env + +# Secrets — defense-in-depth (the .env rule above already matches nested .env files) +*.credentials +secrets/ +*.key +.claude/skills/**/.env +.claude/skills/**/examples/document_*.bin \ No newline at end of file