#!/usr/bin/env bash # Audit every visible Arcodange thirdparty for completeness. # # Usage: # audit-all-thirdparties.sh [--clients-only] [--suppliers-only] # # Iterates /thirdparties, runs the per-id audit logic inline (one HTTP call # per thirdparty), prints a compact table: id, name, country, role, # mandatory-fail count, optional-unset count, top missing fields. Exits 0 # only if every visible thirdparty has zero mandatory failures. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DOL_CURL="${SCRIPT_DIR}/../../dolibarr/scripts/dol-curl.sh" FILTER="all" while [[ $# -gt 0 ]]; do case "$1" in --clients-only) FILTER="client"; shift ;; --suppliers-only) FILTER="supplier"; shift ;; -h|--help) sed -n '2,10p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) echo "audit-all-thirdparties.sh: unknown arg: $1" >&2; exit 2 ;; esac done WORK="$(mktemp -d -t dolaud.XXXXXX)" trap 'rm -rf "${WORK}"' EXIT "${DOL_CURL}" '/thirdparties?limit=500' > "${WORK}/list.json" IDS=$(python3 -c " import json,sys print(' '.join(str(t['id']) for t in json.load(open(sys.argv[1])) if t.get('id'))) " "${WORK}/list.json") mkdir -p "${WORK}/tp" for id in ${IDS}; do "${DOL_CURL}" "/thirdparties/${id}" > "${WORK}/tp/${id}.json"; done python3 - "${WORK}" "${FILTER}" <<'PY' import json, sys, os work, filt = sys.argv[1], sys.argv[2] EU = set("AT BE BG HR CY CZ DK EE FI FR DE GR HU IE IT LV LT LU MT NL PL PT RO SK SI ES SE".split()) def audit(d): cnty = d.get("country_code") or "" is_client = str(d.get("client") or "0") in ("1","2","3") is_supplier = str(d.get("fournisseur") or "0") == "1" # Build the same rules as audit-thirdparty.sh (keep in sync) mandatory_missing = [] for label, val, mandatory in [ ("name", d.get("name"), True), ("address", d.get("address"), True), ("zip", d.get("zip"), True), ("town", d.get("town"), True), ("country", d.get("country_code"), True), ]: if mandatory and not (val not in (None, "", "0")): mandatory_missing.append(label) if cnty == "FR": for label, val in (("SIREN", d.get("idprof1")), ("SIRET", d.get("idprof2"))): if not val: mandatory_missing.append(label) if is_supplier and not d.get("tva_intra"): mandatory_missing.append("tva_intra") elif cnty in EU and cnty: if not d.get("tva_intra"): mandatory_missing.append("tva_intra") elif cnty: if not d.get("idprof1"): mandatory_missing.append("tax_id") role_bits = [] if is_client: role_bits.append("client") if is_supplier: role_bits.append("supplier") role = "/".join(role_bits) or "-" return cnty, role, mandatory_missing rows = [] for fn in sorted(os.listdir(os.path.join(work, "tp")), key=lambda f: int(f[:-len(".json")])): try: d = json.load(open(os.path.join(work, "tp", fn))) except json.JSONDecodeError: continue cnty, role, missing = audit(d) if filt == "client" and "client" not in role: continue if filt == "supplier" and "supplier" not in role: continue rows.append((d.get("id"), d.get("name") or d.get("ref"), cnty, role, missing)) print(f"{'id':>3} {'name':<35} {'cnty':<4} {'role':<16} {'missing'}") print("-" * 110) fails = 0 for iid, name, cnty, role, missing in rows: miss = ", ".join(missing) if missing else "(complete)" print(f"{iid:>3} {(name or '-')[:35]:<35} {cnty:<4} {role:<16} {miss}") if missing: fails += 1 print("-" * 110) print(f"# {len(rows)} thirdparties audited, {fails} with mandatory gaps") sys.exit(0 if fails == 0 else 1) PY