Files
erp/bin/arcodange
Gabriel Radureau bd90266372 add arcodange-bank-reco — Qonto + Wise reconciliation against Dolibarr
V6 — the first cross-system skill (under arcodange-* not dolibarr-*).
Closes the loop between what Dolibarr says (ERP-internal) and what the
bank actually saw.

What ships:
- arcodange-bank-reco/scripts/bank-curl.sh        unified read-only wrapper for Qonto + Wise
- arcodange-bank-reco/scripts/bank-probe.sh       auth + discovery (org slug, profile id, balances)
- arcodange-bank-reco/scripts/qonto-transactions  Qonto txn lister with pagination + filters
- arcodange-bank-reco/scripts/wise-transactions   Wise activity lister with --enrich for wire refs
- arcodange-bank-reco/scripts/bank-match.sh       3-bucket reconciliation (matched/bank-only/dol-only)
                                                  with internal Wise↔Qonto consolidation detection
- arcodange-bank-reco/scripts/bank-balance.sh     live balances + Dolibarr cumulative-by-fk_account

The headline bank-curl.sh is SCA-aware (Wise RSA dance) even though we
don't end up using it: the EU statement endpoint is region-blocked
("Funding transfers and retrieving balance statements via API are not
supported except for accounts based in the US, Canada, Australia, New
Zealand, Singapore, and Malaysia" per Wise docs). The wrapper supports
SCA so when/if Wise opens it, we're ready.

The pivot that unblocked Wise incoming: /v1/profiles/{pid}/activities
(documented at https://docs.wise.com/api-reference/activity/activitylist.md)
returns ALL movements in a unified HTML-tagged feed, no SCA required.
Parsing strips the HTML and recovers structured amount/sign/currency.

CLI integration:
- bin/arcodange bank {probe,qonto-transactions,wise-transactions,match,balance,curl}
- dolibarr/SKILL.md catalogue + Pointers updated
- dolibarr/README.md env schema extended with QONTO_*, WISE_*

Live baseline findings to raise with the cohort review (captured in
examples/bank-match-2026-01-to-05.txt):
- Wise 2026-05-29 +2147 EUR Kissmetrics NOT YET in Dolibarr
- Qonto bank-only: MISTRAL.AI 172.68, CLAUDE.AI 180, URSSAF 493, FOUREZ +1000
- 6 movements matched cleanly across Jan-May 2026
- Wise→Qonto 5000 EUR consolidation on 2026-03-13 auto-detected as internal
- Live balance: Qonto 4191.54 + Wise 5308.25 = 9499.79 EUR

V7 candidates noted in SKILL.md out-of-scope: reference-based matching
via the Wise --enrich wire refs (FOR INVOICE FAC***), multi-row Dolibarr
sub-payment aggregation, smarter avoir cycle handling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 13:57:21 +02:00

268 lines
11 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# arcodange — read-only operational CLI for the Arcodange Dolibarr ERP.
#
# Usage: arcodange <command> [subcommand] [args]
#
# Run `arcodange help` for the full command list.
#
# This is a thin dispatcher: every subcommand delegates to a script under
# .claude/skills/<skill>/scripts/. The skills (markdown SKILL.md files)
# remain the source of behaviour documentation; this CLI is the human-
# friendly entry point so you don't have to spell out 5-component paths.
set -euo pipefail
# --- Locate the project root ----------------------------------------------
# Strategy:
# 1. git rev-parse --show-toplevel (works when CWD is inside the repo).
# 2. Walk up from this script's directory to find a sibling .claude/skills.
# Either approach handles being run from a worktree without surprises.
if SROOT=$(git rev-parse --show-toplevel 2>/dev/null) && [[ -d "${SROOT}/.claude/skills" ]]; then
:
else
SROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
if [[ ! -d "${SROOT}/.claude/skills" ]]; then
echo "arcodange: cannot find project root (no .claude/skills/ found)" >&2
exit 2
fi
fi
SKILLS="${SROOT}/.claude/skills"
DOLC="${SKILLS}/dolibarr/scripts/dol-curl.sh"
# --- Help text -----------------------------------------------------------
usage() {
cat <<'EOF'
arcodange — read-only Arcodange Dolibarr CLI.
USAGE
arcodange <command> [subcommand] [args...]
COMMANDS
tva French TVA monthly preparation
collect [--year|--since|--until] TVA collectée by month × rate (CA3 A1/A4/E2)
collect-detail [--year|--since|--until] Per-line audit, customer side
deductible [--year|--since|--until] TVA déductible by month × rate (CA3 19/20/17+24)
deductible-detail [--year|--since|--until] Per-line audit, supplier side
summary [--year|--since|--until] Composite CA3-ready monthly summary
invoice Customer invoices (KissMetrics)
list [--since YYYY-MM-DD] Table of KM invoices with payment state
audit <invoice-id> JSON facts + PDF mandatory-mention audit
thirdparty Clients + suppliers completeness
audit <socid> Country-aware audit for one thirdparty
audit-all [--clients-only|--suppliers-only] Audit every visible thirdparty
payments Cash receipts (KissMetrics-side)
state [--since YYYY-MM-DD] Per-invoice TTC vs payments reconciliation
timeline [--year|--since|--until] Payment timeline with cumulative balance
by-month [--year|--all-clients] Monthly aggregation
templates Recurring invoice templates
list [--max-id N] Enumerate templates (probes ids)
inspect <template-id> Full template audit with health checks
snapshot [--out FILE|--print-only] Bundle full read-only state into one JSON
bank Bank-side data (Qonto + Wise) + Dolibarr reconciliation
probe Auth + discovery (org slug, profile id, balance ids)
qonto-transactions [--month|--since|--until] Qonto transactions table (incoming + outgoing)
wise-transactions [--month|--since|--until|--type|--enrich] Wise activities (incoming + outgoing)
match [--month|--since|--until|--window-days N] Match bank ↔ Dolibarr (3 buckets)
balance Live balances + Dolibarr cross-check per fk_account
curl <qonto|wise> <path> Raw read-only curl through bank-curl.sh
whoami GET /users/info — confirm auth
ping GET /status — liveness + Dolibarr version
curl <path> Raw read-only curl through dol-curl.sh
help [command] Show this help (or subcommand help)
CREDENTIALS
Reads .claude/skills/dolibarr/.env (mode 600, gitignored). See
.claude/skills/dolibarr/README.md for one-time setup.
EXAMPLES
arcodange ping
arcodange whoami
arcodange invoice list
arcodange invoice audit 12
arcodange tva summary --year 2026
arcodange thirdparty audit-all
arcodange snapshot --out /tmp/erp.json
EOF
}
# --- Dispatch ------------------------------------------------------------
cmd="${1:-help}"
shift || true
case "${cmd}" in
tva)
sub="${1:-help}"; shift || true
case "${sub}" in
collect) exec "${SKILLS}/dolibarr-tva-reconciliation/scripts/tva-by-month.sh" "$@" ;;
collect-detail) exec "${SKILLS}/dolibarr-tva-reconciliation/scripts/tva-line-detail.sh" "$@" ;;
deductible) exec "${SKILLS}/dolibarr-tva-deductible/scripts/deductible-by-month.sh" "$@" ;;
deductible-detail) exec "${SKILLS}/dolibarr-tva-deductible/scripts/deductible-line-detail.sh" "$@" ;;
summary) exec "${SKILLS}/dolibarr-tva-summary/scripts/tva-summary.sh" "$@" ;;
help|-h|--help)
cat <<'EOF'
arcodange tva — French TVA monthly preparation.
collect TVA collectée by month × rate (CA3 A1/A4/E2)
collect-detail Per-line audit, customer side
deductible TVA déductible by month × rate (CA3 19/20/17+24)
deductible-detail Per-line audit, supplier side
summary CA3-ready monthly net summary (collectée déductible)
All accept --year YYYY, --since YYYY-MM-DD, --until YYYY-MM-DD.
EOF
;;
*) echo "arcodange tva: unknown subcommand '${sub}' (try 'arcodange tva help')" >&2; exit 2 ;;
esac
;;
invoice)
sub="${1:-help}"; shift || true
case "${sub}" in
list) exec "${SKILLS}/dolibarr-invoice-audit/scripts/list-km-invoices.sh" "$@" ;;
audit) exec "${SKILLS}/dolibarr-invoice-audit/scripts/audit-invoice.sh" "$@" ;;
help|-h|--help)
cat <<'EOF'
arcodange invoice — customer (KissMetrics) invoice operations.
list [--since YYYY-MM-DD] Table of KM invoices with payment state
audit <invoice-id> JSON facts + PDF mandatory-mention audit
EOF
;;
*) echo "arcodange invoice: unknown subcommand '${sub}' (try 'arcodange invoice help')" >&2; exit 2 ;;
esac
;;
thirdparty)
sub="${1:-help}"; shift || true
case "${sub}" in
audit) exec "${SKILLS}/dolibarr-thirdparty-completeness/scripts/audit-thirdparty.sh" "$@" ;;
audit-all) exec "${SKILLS}/dolibarr-thirdparty-completeness/scripts/audit-all-thirdparties.sh" "$@" ;;
help|-h|--help)
cat <<'EOF'
arcodange thirdparty — clients + suppliers completeness.
audit <socid> Country-aware audit for one thirdparty
audit-all [--clients-only|--suppliers-only] Audit every visible thirdparty
EOF
;;
*) echo "arcodange thirdparty: unknown subcommand '${sub}'" >&2; exit 2 ;;
esac
;;
payments)
sub="${1:-help}"; shift || true
case "${sub}" in
state) exec "${SKILLS}/dolibarr-payments-state/scripts/km-payment-state.sh" "$@" ;;
timeline) exec "${SKILLS}/dolibarr-payments-state/scripts/km-payment-timeline.sh" "$@" ;;
by-month) exec "${SKILLS}/dolibarr-payments-state/scripts/payments-by-month.sh" "$@" ;;
help|-h|--help)
cat <<'EOF'
arcodange payments — KissMetrics cash-receipt tracking.
state [--since YYYY-MM-DD] Per-invoice TTC vs payments reconciliation
timeline [--year|--since|--until] Payment timeline with cumulative balance
by-month [--year|--all-clients] Monthly aggregation
EOF
;;
*) echo "arcodange payments: unknown subcommand '${sub}'" >&2; exit 2 ;;
esac
;;
templates)
sub="${1:-help}"; shift || true
case "${sub}" in
list) exec "${SKILLS}/dolibarr-recurring-templates/scripts/list-templates.sh" "$@" ;;
inspect) exec "${SKILLS}/dolibarr-recurring-templates/scripts/inspect-template.sh" "$@" ;;
help|-h|--help)
cat <<'EOF'
arcodange templates — recurring invoice templates.
list [--max-id N] Enumerate templates (probes ids)
inspect <template-id> Full audit with health checks
EOF
;;
*) echo "arcodange templates: unknown subcommand '${sub}'" >&2; exit 2 ;;
esac
;;
snapshot)
exec "${SKILLS}/dolibarr-data-snapshot/scripts/snapshot.sh" "$@"
;;
bank)
sub="${1:-help}"; shift || true
case "${sub}" in
probe) exec "${SKILLS}/arcodange-bank-reco/scripts/bank-probe.sh" "$@" ;;
qonto-transactions) exec "${SKILLS}/arcodange-bank-reco/scripts/qonto-transactions.sh" "$@" ;;
wise-transactions) exec "${SKILLS}/arcodange-bank-reco/scripts/wise-transactions.sh" "$@" ;;
match) exec "${SKILLS}/arcodange-bank-reco/scripts/bank-match.sh" "$@" ;;
balance) exec "${SKILLS}/arcodange-bank-reco/scripts/bank-balance.sh" "$@" ;;
curl)
if [[ $# -lt 2 ]]; then
echo "arcodange bank curl: usage: bank curl <qonto|wise> <path>" >&2; exit 2
fi
exec "${SKILLS}/arcodange-bank-reco/scripts/bank-curl.sh" "$@"
;;
help|-h|--help)
cat <<'EOF'
arcodange bank — bank-side data (Qonto + Wise) and Dolibarr reconciliation.
probe Auth + discovery (org slug, profile id, balance ids)
qonto-transactions [--month|--since|--until] Qonto transactions table
wise-transactions [--month|--since|--until|--type|--enrich] Wise activities (incoming + outgoing)
match [--month|--since|--until|--window-days N] Match bank ↔ Dolibarr (3 buckets)
balance Live balances + Dolibarr cross-check per fk_account
curl <qonto|wise> <path> Raw read-only curl through bank-curl.sh
Requires QONTO_LOGIN, QONTO_SECRET_KEY, QONTO_ORG_SLUG, WISE_API_TOKEN,
WISE_PROFILE_ID in .env. See arcodange-bank-reco/SKILL.md for setup.
EOF
;;
*) echo "arcodange bank: unknown subcommand '${sub}' (try 'arcodange bank help')" >&2; exit 2 ;;
esac
;;
whoami)
exec "${DOLC}" /users/info
;;
ping)
exec "${DOLC}" /status
;;
curl)
if [[ $# -lt 1 ]]; then
echo "arcodange curl: missing path. Example: arcodange curl /invoices/12" >&2
exit 2
fi
exec "${DOLC}" "$@"
;;
help|-h|--help|"")
if [[ $# -gt 0 ]]; then
exec "$0" "$1" help
fi
usage
;;
*)
echo "arcodange: unknown command '${cmd}'" >&2
echo " Try 'arcodange help' for the list." >&2
exit 2
;;
esac