# Runbook — quel instrument pour quelle dette Public : un agent, quel que soit son modèle, ou l'opérateur. **Lire ceci AVANT d'enregistrer quoi que ce soit.** Le choix de l'instrument décide de tout ce qui suit : le compte comptable, les rapports où l'écriture apparaîtra, et jusqu'à la voie technique disponible. Une opération parfaitement exécutée avec le mauvais instrument reste une erreur, et elle est plus coûteuse à défaire qu'à éviter. ## La question qui tranche > **À qui la société doit-elle cet argent ?** | Le créancier est… | Instrument | Écran Dolibarr | | --- | --- | --- | | un **fournisseur réel** (prestataire, éditeur, greffe, La Poste…) | **facture fournisseur** | Facturation → Factures fournisseur | | un **organisme social ou fiscal** (URSSAF, CFE, TVA…) | **charge sociale ou fiscale** | Comptabilité → Charges sociales/fiscales | | **l'associé lui-même**, ou personne (régularisation interne) | **paiement divers** | Banques → Paiements divers | ### Le piège, et il a été payé deux fois **Ni l'URSSAF ni le gérant ne sont des fournisseurs.** Leur ouvrir une fiche fournisseur les fait apparaître au grand livre auxiliaire, dans les balances âgées et dans les états de dettes fournisseurs — des états censés ne montrer que le poste fournisseurs. L'erreur est invisible à la saisie et se découvre à la clôture. Le contrôle qui la révèle est gratuit : **regarder l'existant**. Les dettes déjà portées au compte courant d'associé sont toutes des factures de fournisseurs réels payées personnellement par le gérant — le tiers y est le fournisseur, jamais le gérant. Un modèle qui contredit celui déjà en place est presque toujours le mauvais. ## Une charge sociale est TOTALEMENT figée — écrire juste du premier coup > [!CAUTION] > Sur ce déploiement (Dolibarr 22.0.4 + PostgreSQL), **aucune écriture sur une > charge sociale n'aboutit** : ni la date, ni le montant, **ni même la note > publique**. Toutes échouent sur > `ERROR 42601: multiple assignments to same column "fk_user_modif"` — > `ChargeSociales::update()` affecte deux fois la même colonne, ce que MySQL > tolère et PostgreSQL rejette. Suivi : [erp#87](https://gitea.arcodange.lab/arcodange-org/erp/issues/87). **La règle générale — « si c'est déjà en production et sans incidence sur l'exercice, annoter l'objet suffit » — reste juste, mais son canal habituel est fermé ici.** Le champ note passe par le même `UPDATE`. Ce qui fonctionne, parce que c'est un autre chemin : **attacher un document**. Le téléversement n'est pas un `UPDATE` sur l'objet. ```bash curl -s -X POST https://erp.arcodange.lab/api/index.php/documents/upload \ -H "DOLAPIKEY: $(cat test/.ai_agent_prod_prod_write.key)" \ -H 'Content-Type: application/json' -d @- <-.md","modulepart":"tax","subdir":"", "filecontent":"","fileencoding":"base64","overwriteifexists":1} JSON ``` Vérifier sur `/compta/sociales/document.php?id=` que le compteur a bougé. Première application : la charge n°1 (URSSAF 1re échéance) porte le 22/05, date du *prélèvement*, quand l'échéance officielle est le 05/05 — l'écart, resté dans le même mois et le même exercice, est porté par une note attachée plutôt que forcé dans la donnée. `test/annotateObject.ts` écrit la note publique d'un objet **et refuse explicitement** quand le bug la bloque, au lieu de croire une page qui ré-affiche le formulaire. Ce faux positif a bien failli passer : la page de retour contient le texte soumis, donc un contrôle naïf « le texte est là » réussit sur un enregistrement qui n'a jamais eu lieu. **Relire l'objet, jamais la page de retour.** Le script reste utile sur les objets non affectés par erp#87. ## Le compte courant d'associé : deux usages à ne pas confondre Le compte bancaire **`CCA1` (id 3)** porte le numéro comptable **45511** et son propre journal comptable. Il sert dans deux cas *différents* : **1. Le gérant a avancé une dépense** — un fournisseur réel a facturé, le gérant a payé de sa poche. → facture fournisseur au nom du **fournisseur**, puis règlement sur le compte 3. C'est `adc-005`. **2. La société doit quelque chose au gérant lui-même** — indemnité d'occupation, remboursement forfaitaire. → **paiement divers** sur le compte 3, sans aucun tiers. ```bash cd test DOLIBARR_ADDRESS=https://erp-sandbox.arcodange.lab \ deno run -A recordVariousPayment.ts \ --label "Indemnité d'occupation — mars 2026" \ --amount 220.00 --date 2026-03-31 ``` Production — double opt-in explicite, comme toute écriture de production : ```bash DOLIBARR_ADDRESS=https://erp.arcodange.lab \ ARCO_ALLOW_PRODUCTION=erp.arcodange.lab \ ARCO_PROD_CONFIRM=I-UNDERSTAND-THIS-WRITES-PROD \ deno run -A recordVariousPayment.ts --label "…" --amount … --date … ``` Défauts : `--account 3` (compte courant), `--code 613` (Locations), `--sens 0` (débit). `--dry-run` affiche sans écrire. L'écriture produite : ``` débit 613000 Locations (la charge) crédit 45511 G. RADUREAU, compte courant (la dette envers l'associé) ``` ## Le plan comptable est chargé — nuance à connaître **358 comptes sont disponibles** dans le sélecteur des paiements divers, dont un `455110` déjà dédié au compte courant du gérant. Ne pas confondre trois choses : - le **plan comptable** est chargé et utilisable depuis ce formulaire ; - l'**API REST comptable** n'est pas exposée (`/accountancy/*` → 404) ; - le **dictionnaire des types de charges sociales** ne porte aucun code comptable (colonne vide pour tous les types, `TAXSSI` compris). Conclusion pratique : sur un paiement divers, le compte se choisit et **est enregistré**. Sur une charge sociale, le type n'est qu'un libellé et l'imputation vit dans le grand livre de l'expert-comptable. ## Ce que le pipeline gated ne peut pas porter `fleet/harness/promote/` parle REST. Or **ni les charges sociales ni les paiements divers n'ont d'API** : `/taxes`, `/socialcontributions`, `/chargesociales`, `/variouspayments` répondent tous « API not found ». Le choix de l'instrument décide donc de la voie disponible. Facture fournisseur → pipeline gated complet, avec juge et artefact de gate. Charge sociale ou paiement divers → script UI, qui garde la discipline (répétition sandbox, relecture par la liste, opt-in production) **sans** juge indépendant ni gate. Ne pas choisir l'instrument pour la commodité de la voie : c'est la nature de la dette qui décide, et la voie s'ajuste. ## Les pièges, tous rencontrés 1. **Les dates sont un piège à double fond.** Le champ visible est décoratif : le backend ne lit que les champs **cachés** `{nom}day` / `{nom}month` / `{nom}year`. Remplir le champ texte seul soumet une date vide. Vaut pour `datep`, `datev`, `ech`, `period`. 2. **Vérifier par la LISTE, jamais par l'URL.** Dolibarr renvoie des pages sans identifiant : conclure d'après l'URL fait déclarer un échec sur une création réussie — c'est ainsi que quatre doublons sont apparus en sandbox. 3. **Comparer le libellé ENTIER, jamais un préfixe.** Une version comparait les 24 premiers caractères ; « Indemnité d'occupation — » en fait exactement 24, si bien que mars reconnaissait février et se déclarait déjà enregistré — six mois silencieusement sautés. Un préfixe ne distingue que ce qui diffère avant lui. *(`recordSocialCharge.ts` porte encore ce défaut, latent : ses libellés diffèrent avant le 24ᵉ caractère, aujourd'hui seulement.)* 4. **Les milliers s'affichent avec une espace insécable** : `1215.00` devient « 1 215,00 ». Comparer sans les espaces, sinon l'idempotence saute au-delà de 999 €. 5. **En zsh, `set -- $var` ne découpe pas les mots** (contrairement à bash) : une boucle de saisie a produit des dates `2026--`. Écrire les appels explicitement, ou utiliser un tableau. ## Après l'enregistrement - Rapprocher le mouvement bancaire réel quand il a lieu — un paiement divers sur le compte courant ne déplace **aucune trésorerie**, il constate une dette. - Attacher le justificatif à l'objet concerné : voir `RUNBOOK_ged.md`.