WIP: fix(profile): cotisations TNS en 641 et non 646 — échéancier URSSAF 2026 réel #86
@@ -6,32 +6,58 @@ fois, elle doit en coûter deux minutes ensuite.
|
|||||||
|
|
||||||
## Pourquoi ce n'est pas une facture fournisseur
|
## Pourquoi ce n'est pas une facture fournisseur
|
||||||
|
|
||||||
L'URSSAF n'est pas un fournisseur. Sa cotisation va au compte **646**
|
L'URSSAF n'est pas un fournisseur. L'inscrire en facture fournisseur pollue le
|
||||||
(cotisations personnelles du dirigeant), pas au compte fournisseur — l'inscrire
|
grand livre auxiliaire, les balances âgées et les états de dettes fournisseurs.
|
||||||
en facture fournisseur pollue le grand livre auxiliaire, les balances âgées et
|
C'est une **charge sociale**, saisie comme telle.
|
||||||
les états de dettes fournisseurs.
|
|
||||||
|
|
||||||
**645 contre 646**, la distinction qui décide de tout :
|
## Quel compte — et pourquoi ce n'est pas 646
|
||||||
|
|
||||||
| Compte | Pour qui |
|
> [!IMPORTANT]
|
||||||
| --- | --- |
|
> **Arcodange est une SARL à l'IS. Le compte est 641, pas 646.**
|
||||||
| 645 | cotisations **patronales sur salaires** — suppose des salariés |
|
> Le **646** (« cotisations sociales de l'exploitant ») est réservé à
|
||||||
| **646** | cotisations **personnelles du dirigeant TNS** |
|
> l'**entreprise individuelle et aux sociétés à l'IR**. Il ne s'applique pas à
|
||||||
|
> une société. Quand la société règle les cotisations personnelles de son gérant
|
||||||
|
> majoritaire, c'est un **complément de rémunération** : compte **641**, dans un
|
||||||
|
> sous-compte dédié (`641150` « Sécurité sociale des indépendants » par exemple),
|
||||||
|
> et c'est **déductible** du résultat de la société.
|
||||||
|
|
||||||
Arcodange n'a aucun salarié et Gabriel est gérant associé unique d'une SARLU,
|
| Compte | Pour qui | Arcodange |
|
||||||
donc **TNS** : tout va en 646. Le compte 645 doit rester vide.
|
| --- | --- | --- |
|
||||||
|
| **641** (sous-compte dédié) | rémunération + cotisations du **gérant majoritaire TNS** | ← **celui-ci** |
|
||||||
|
| 646 | cotisations de l'**exploitant individuel** / société à l'IR | sans objet |
|
||||||
|
| 645 | cotisations **sur salaires** | vide — aucun salarié |
|
||||||
|
| 631 / 633 | contributions **de l'employeur** (formation, apprentissage) | vide — **Gabriel n'est pas employeur** |
|
||||||
|
|
||||||
Dans Dolibarr, cela se pilote par le **type de charge**, jamais par une saisie
|
Contrepartie **431** (Sécurité sociale), soldée par **512** au paiement.
|
||||||
manuelle du compte :
|
Régularisation à la clôture : 641 contre **4286** (autres charges à payer).
|
||||||
|
|
||||||
- `Securite sociale (URSSAF / MSA)` → régime salarié → 645
|
L'appel URSSAF se comptabilise **globalement** dans ce sous-compte 641 : pas de
|
||||||
- **`Securite sociale des indépendants (URSSAF)`** → TNS → 646 ← **celui-ci**
|
ventilation entre cotisations, CFP et CSG/CRDS. En particulier, la contribution
|
||||||
|
à la formation professionnelle d'un TNS **n'est pas** la participation employeur
|
||||||
|
du compte 6333 — Arcodange n'emploie personne ; c'est une contribution
|
||||||
|
personnelle, elle suit les cotisations.
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> Le code comptable de chaque type vit dans **Configuration → Dictionnaires →
|
> **Le piège CSG.** L'appel URSSAF porte une mention « montant de CSG déductible
|
||||||
> Types de charges sociales**. Vérifier une fois que la ligne « indépendants »
|
> fiscalement : N € ». Elle vise l'**impôt sur le revenu personnel du gérant**
|
||||||
> porte bien 646 : si elle porte autre chose, le bon type enverra quand même
|
> (art. 62 CGI), **pas l'IS de la société**. Pour la SARL, la CSG/CRDS est
|
||||||
> l'écriture au mauvais compte. Non vérifié à ce jour.
|
> **intégralement déductible** : aucune réintégration extra-comptable. Ne pas
|
||||||
|
> transposer le raisonnement de l'entreprise individuelle, où la CSG non
|
||||||
|
> déductible se reclasse en compte de l'exploitant.
|
||||||
|
|
||||||
|
### Ce que Dolibarr ne fait pas
|
||||||
|
|
||||||
|
Le type de charge **ne pilote aucune écriture**. Vérifié le 2026-08-13 dans
|
||||||
|
**Configuration → Dictionnaires → Types de charges sociales ou fiscales**
|
||||||
|
(`/admin/dict.php?id=7`) : la colonne **« Code comptable » est vide pour tous
|
||||||
|
les types**, `TAXSSI` compris. Le module comptabilité n'est pas déployé —
|
||||||
|
`/accountancy/*` répond 404.
|
||||||
|
|
||||||
|
Conséquence pratique : **le choix du compte ne se joue pas dans l'ERP**. Dolibarr
|
||||||
|
porte les faits (montant, échéance, justificatif) ; l'imputation vit dans le
|
||||||
|
grand livre de l'expert-comptable. Choisir le type
|
||||||
|
`Securite sociale des indépendants (URSSAF)` pour la lisibilité, sans croire
|
||||||
|
qu'il décide de quoi que ce soit.
|
||||||
|
|
||||||
## La commande
|
## La commande
|
||||||
|
|
||||||
@@ -67,6 +93,19 @@ a réellement eu lieu — jamais par anticipation.
|
|||||||
- **Garde d'hôte** : `guard.ts` refuse toute cible qui n'est pas la sandbox,
|
- **Garde d'hôte** : `guard.ts` refuse toute cible qui n'est pas la sandbox,
|
||||||
sauf double opt-in production.
|
sauf double opt-in production.
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
> **Une charge sociale est IMMUABLE sur ce déploiement. La date doit être juste
|
||||||
|
> du premier coup.** Toute soumission du formulaire d'édition échoue —
|
||||||
|
> y compris en ne touchant que le montant :
|
||||||
|
> `ERROR 42601: multiple assignments to same column "fk_user_modif"`.
|
||||||
|
> `ChargeSociales::update()` affecte deux fois la même colonne dans son `UPDATE` ;
|
||||||
|
> MySQL l'accepte, **PostgreSQL le rejette**. Vérifié le 2026-08-13 en sandbox sur
|
||||||
|
> la date et sur le montant. Le défaut est propre à cet objet — la mise à jour
|
||||||
|
> d'un tiers via REST fonctionne. `test/updateSocialCharge.ts` conserve le cas de
|
||||||
|
> reproduction et diagnostique l'erreur.
|
||||||
|
>
|
||||||
|
> Relire la date **avant** de soumettre : `--dry-run` l'affiche.
|
||||||
|
|
||||||
## Les quatre pièges, tous rencontrés
|
## Les quatre pièges, tous rencontrés
|
||||||
|
|
||||||
1. **La date est un piège à double fond.** Le champ visible `ech` est décoratif :
|
1. **La date est un piège à double fond.** Le champ visible `ech` est décoratif :
|
||||||
@@ -97,8 +136,32 @@ gate. Acceptable pour une opération à trois champs ; à ne pas généraliser.
|
|||||||
## Après l'enregistrement
|
## Après l'enregistrement
|
||||||
|
|
||||||
- Rapprocher le prélèvement bancaire quand il apparaît (Qonto pour Arcodange).
|
- Rapprocher le prélèvement bancaire quand il apparaît (Qonto pour Arcodange).
|
||||||
|
- **Attacher le justificatif à la charge.** L'appel de cotisations est la pièce
|
||||||
|
qui la justifie ; sans lui la charge n'est qu'une affirmation.
|
||||||
|
```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 @- <<JSON
|
||||||
|
{"filename":"URSSAF-appel-cotisations-2026.pdf","modulepart":"tax",
|
||||||
|
"subdir":"<ID DE LA CHARGE>","filecontent":"<BASE64>","fileencoding":"base64",
|
||||||
|
"overwriteifexists":1}
|
||||||
|
JSON
|
||||||
|
```
|
||||||
|
**`subdir` doit être l'identifiant nu de la charge** (`2`), rien d'autre.
|
||||||
|
L'API accepte silencieusement n'importe quel chemin (`sociales/2`, `tax/2`…)
|
||||||
|
et y dépose un fichier que l'onglet Documents ne montrera jamais. Vérifier sur
|
||||||
|
`/compta/sociales/document.php?id=<ID>` : « Nombre de fichiers liés » doit
|
||||||
|
passer à 1. `modulepart=tax` avec `ref` renvoie 500, c'est normal.
|
||||||
- Le calendrier `fleet/profile/calendar.yaml` porte les échéances URSSAF 2026 :
|
- Le calendrier `fleet/profile/calendar.yaml` porte les échéances URSSAF 2026 :
|
||||||
493,00 (22/05) + 1 215,00 (05/08) + 1 333,00 (05/11) = **3 041,00 €**.
|
493,00 (05/05) + 1 215,00 (05/08) + 1 333,00 (05/11) = **3 041,00 €**.
|
||||||
|
- **Échéance ≠ prélèvement.** L'appel donne des dates d'échéance au 5 du mois ;
|
||||||
|
le débit bancaire tombe plus tard (22/05 pour l'échéance du 05/05). Enregistrer
|
||||||
|
la charge à la **date d'échéance** — c'est elle qui fait foi et qui détermine
|
||||||
|
un éventuel retard.
|
||||||
|
- **Les montants sont provisoires.** Tant que l'activité est en début d'activité,
|
||||||
|
ils sont calculés sur une base forfaitaire et **régularisés** après déclaration
|
||||||
|
des revenus. L'assiette est la **rémunération du gérant**, jamais le chiffre
|
||||||
|
d'affaires — ne pas anticiper de régularisation à partir du CA encaissé.
|
||||||
- L'échéancier officiel n'est disponible **que** dans l'espace urssaf.fr : les
|
- L'échéancier officiel n'est disponible **que** dans l'espace urssaf.fr : les
|
||||||
notifications par mail ne contiennent aucun montant, et le transfert Gmail →
|
notifications par mail ne contiennent aucun montant, et le transfert Gmail →
|
||||||
Zoho remplace même leur contenu par un texte générique. Récupérer le PDF à la
|
Zoho remplace même leur contenu par un texte générique. Récupérer le PDF à la
|
||||||
|
|||||||
@@ -168,8 +168,8 @@ entries:
|
|||||||
due: "2026-08-05"
|
due: "2026-08-05"
|
||||||
authority: "URSSAF Île-de-France"
|
authority: "URSSAF Île-de-France"
|
||||||
amount_eur: 1215.00
|
amount_eur: 1215.00
|
||||||
source: "échéancier de cotisations 2026 communiqué par l'opérateur le 2026-08-13"
|
source: "appel de cotisations 2026 URSSAF Île-de-France du 09/07/2026, n° TI 117 1583346778 4 (PDF attaché à la charge en production)"
|
||||||
notes: "Réglée par l'opérateur le 13/08/2026 (SEPA), avec 8 jours de retard sur l'échéance. Non encore visible sur Qonto au 13/08 — un SEPA met 1 à 2 jours ouvrés. À rapprocher du compte 646 (cotisations personnelles du dirigeant TNS) — PAS 645, qui vise les cotisations patronales sur salaires et doit rester vide : Arcodange n'a aucun salarié."
|
notes: "Réglée par l'opérateur le 13/08/2026 (SEPA), avec 8 jours de retard sur l'échéance. Non encore visible sur Qonto au 13/08 — un SEPA met 1 à 2 jours ouvrés. Imputation : compte 641 (sous-compte dédié), PAS 646 qui vise l'exploitant individuel et les sociétés à l'IR — Arcodange est une SARL à l'IS, la prise en charge des cotisations du gérant majoritaire est un complément de rémunération déductible. 645 et 631/633 restent vides : aucun salarié, l'opérateur n'est pas employeur."
|
||||||
|
|
||||||
- id: "urssaf-2026-t3"
|
- id: "urssaf-2026-t3"
|
||||||
title: "URSSAF — 3e et dernière échéance 2026 (1 333 EUR)"
|
title: "URSSAF — 3e et dernière échéance 2026 (1 333 EUR)"
|
||||||
@@ -178,15 +178,27 @@ entries:
|
|||||||
due: "2026-11-05"
|
due: "2026-11-05"
|
||||||
authority: "URSSAF Île-de-France"
|
authority: "URSSAF Île-de-France"
|
||||||
amount_eur: 1333.00
|
amount_eur: 1333.00
|
||||||
source: "échéancier de cotisations 2026 ; prélèvement SEPA validé par l'opérateur le 2026-08-13"
|
source: "appel de cotisations 2026 URSSAF Île-de-France du 09/07/2026, n° TI 117 1583346778 4 (PDF attaché à la charge en production)"
|
||||||
notes: "Prélèvement automatique déjà autorisé. Provisionner sur Qonto : c'est le compte prélevé (cf. l'échéance du 22/05)."
|
notes: "Prélèvement automatique déjà autorisé. Provisionner sur Qonto : c'est le compte prélevé (cf. l'échéance du 05/05, débitée le 22/05). Inclut 120 EUR de contribution à la formation professionnelle — contribution personnelle du TNS, pas la participation employeur du compte 6333 : l'opérateur n'est pas employeur."
|
||||||
|
|
||||||
# Total 2026 : 493,00 (22/05, prélevé) + 1 215,00 (05/08) + 1 333,00 (05/11) = 3 041,00 EUR.
|
- id: "urssaf-2026-regularisation"
|
||||||
|
title: "URSSAF — régularisation des cotisations 2026 (montant inconnu)"
|
||||||
|
category: "social"
|
||||||
|
status: "pending-definition"
|
||||||
|
authority: "URSSAF Île-de-France"
|
||||||
|
source: "appel de cotisations 2026 du 09/07/2026 : « calculées de façon provisoire sur la base forfaitaire applicable aux assurés en début d'activité […] régularisé dès que vous aurez effectué la déclaration de vos revenus 2026 »"
|
||||||
|
notes: "Les 3 041 EUR appelés en 2026 sont PROVISOIRES, assis sur un forfait début d'activité de 8 856 EUR ; ils seront régularisés après la déclaration des revenus 2026 (mi-2027), à la hausse ou à la baisse. PIÈGE : l'assiette est la RÉMUNÉRATION DU GÉRANT, jamais le chiffre d'affaires encaissé — ne pas dimensionner la provision sur le CA. Aucune rémunération n'a été versée en 2026 (vérifié au grand livre bancaire au 13/08), ce qui oriente vers une régularisation à la baisse ; mais la prise en charge des cotisations par la société est elle-même un complément de rémunération, donc l'assiette n'est pas nulle. À arbitrer avec l'expert-comptable, avec la décision de verser ou non une rémunération avant le 31/12."
|
||||||
|
|
||||||
|
# Total 2026 : 493,00 (05/05, débité le 22/05) + 1 215,00 (05/08) + 1 333,00 (05/11)
|
||||||
|
# = 3 041,00 EUR, dont 2 062 de cotisations (après 449 d'exonération ACRE),
|
||||||
|
# 120 de formation professionnelle et 859 de CSG/CRDS.
|
||||||
|
# Les dates ci-dessus sont les dates d'ÉCHÉANCE portées par l'appel officiel (le 5 du
|
||||||
|
# mois), pas les dates de débit bancaire, qui tombent plus tard.
|
||||||
# Cette ligne remplace l'ancienne entrée « urssaf-echeancier / pending-definition » :
|
# Cette ligne remplace l'ancienne entrée « urssaf-echeancier / pending-definition » :
|
||||||
# la cadence n'était pas trimestrielle mais un échéancier à trois appels irréguliers,
|
# la cadence n'était pas trimestrielle mais un échéancier à trois appels irréguliers,
|
||||||
# et l'hypothèse PRD « URSSAF dormant tant qu'il n'y a pas de salaire » était fausse —
|
# et l'hypothèse PRD « URSSAF dormant tant qu'il n'y a pas de salaire » était fausse —
|
||||||
# le gérant cotise. Le point erp#57 est clos sur la partie cadence ; reste à qualifier
|
# le gérant cotise. Le point erp#57 est clos sur la partie cadence ; la nature des
|
||||||
# la nature exacte des cotisations avec l'expert-comptable si besoin.
|
# cotisations est qualifiée par adc-009.
|
||||||
|
|
||||||
# --- Contract-driven (KissMetrics) ----------------------------------------
|
# --- Contract-driven (KissMetrics) ----------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
---
|
||||||
|
id: adc-009
|
||||||
|
title: "Cotisations TNS du gérant en compte 641, pas 646 — CSG/CRDS intégralement déductible à l'IS"
|
||||||
|
status: Proposed
|
||||||
|
decided: null
|
||||||
|
effective_from: 2026-01-01
|
||||||
|
effective_until: null
|
||||||
|
supersedes: null
|
||||||
|
superseded_by: null
|
||||||
|
---
|
||||||
|
|
||||||
|
# adc-009 — Imputation des cotisations sociales personnelles du gérant
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
L'appel de cotisations URSSAF 2026 (09/07/2026, n° TI 117 1583346778 4) porte
|
||||||
|
**3 041 €** au titre des cotisations personnelles du gérant : 2 062 € de
|
||||||
|
cotisations obligatoires après 449 € d'exonération ACRE, 120 € de contribution à
|
||||||
|
la formation professionnelle, 859 € de CSG/CRDS. Il mentionne un « montant de CSG
|
||||||
|
déductible fiscalement » de 602 €.
|
||||||
|
|
||||||
|
Les trois échéances ont été enregistrées en production comme charges sociales
|
||||||
|
(ids 1, 2, 3). Restait à qualifier leur imputation comptable — question laissée
|
||||||
|
explicitement ouverte par `RUNBOOK_charges_sociales.md`, qui affirmait le
|
||||||
|
compte **646**.
|
||||||
|
|
||||||
|
Arcodange est une **SARL unipersonnelle à l'IS**. Gabriel Radureau en est le
|
||||||
|
gérant associé unique, donc **TNS**. La société **n'a aucun salarié** et
|
||||||
|
l'opérateur **n'est pas employeur**.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
Les cotisations personnelles du gérant réglées par la société s'imputent au
|
||||||
|
compte **641**, dans un sous-compte dédié (par exemple `641150` « Sécurité
|
||||||
|
sociale des indépendants »), en contrepartie du compte **431**, soldé par le
|
||||||
|
**512** au paiement. La régularisation constatée à la clôture passe par le
|
||||||
|
compte **4286** (autres charges à payer).
|
||||||
|
|
||||||
|
L'appel se comptabilise **globalement** : aucune ventilation entre cotisations,
|
||||||
|
contribution formation professionnelle et CSG/CRDS.
|
||||||
|
|
||||||
|
La **CSG/CRDS est intégralement déductible** du résultat de la société. Aucune
|
||||||
|
réintégration extra-comptable n'est pratiquée.
|
||||||
|
|
||||||
|
Les comptes **645** (cotisations sur salaires) et **631 / 633** (contributions de
|
||||||
|
l'employeur) restent **vides**.
|
||||||
|
|
||||||
|
## Base légale & doctrine
|
||||||
|
|
||||||
|
Le compte **646** est défini comme « cotisations sociales de l'exploitant » : il
|
||||||
|
vise l'entreprise individuelle et les sociétés soumises à l'IR. Il ne s'applique
|
||||||
|
pas à une société à l'IS.
|
||||||
|
|
||||||
|
Lorsque la société prend en charge les cotisations obligatoires de son gérant
|
||||||
|
majoritaire, cette prise en charge s'analyse comme un **complément de
|
||||||
|
rémunération** — d'où l'imputation en 641 aux côtés de la rémunération, et sa
|
||||||
|
déductibilité du résultat social. Corrélativement, la rémunération du gérant
|
||||||
|
majoritaire relève de l'**article 62 du CGI** pour son imposition personnelle.
|
||||||
|
|
||||||
|
C'est ce dernier point qui explique le piège de la CSG : la mention « CSG
|
||||||
|
déductible fiscalement : 602 € » portée par l'appel URSSAF concerne l'**impôt sur
|
||||||
|
le revenu du gérant**, pas l'IS de la société. Le mécanisme de réintégration de
|
||||||
|
la CSG non déductible appartient au régime de l'entreprise individuelle, où la
|
||||||
|
quote-part non déductible se reclasse en compte de l'exploitant. Il n'a pas de
|
||||||
|
transposition à l'IS.
|
||||||
|
|
||||||
|
La contribution à la formation professionnelle d'un TNS est une contribution
|
||||||
|
**personnelle**, recouvrée par l'URSSAF avec les cotisations. Elle n'est pas la
|
||||||
|
participation de l'employeur à la formation professionnelle continue du compte
|
||||||
|
**6333**, qui suppose des salaires — Arcodange n'en verse aucun.
|
||||||
|
|
||||||
|
## Alternatives rejected
|
||||||
|
|
||||||
|
- **Compte 646** — première proposition, portée par le runbook. Rejetée : réservée
|
||||||
|
à l'exploitant individuel et aux sociétés à l'IR.
|
||||||
|
- **Compte 658 ou 455, charge non déductible, réintégration de 2 439 € au titre
|
||||||
|
d'un acte anormal de gestion** — position soutenue par `mistral-large-2512`
|
||||||
|
lors du challenge contradictoire. Rejetée : la prise en charge des cotisations
|
||||||
|
obligatoires du gérant est un complément de rémunération déductible, pas une
|
||||||
|
libéralité. Le challenger étayait cette position sur des références
|
||||||
|
invérifiables et sur des libellés de comptes erronés (cf. QA).
|
||||||
|
- **Ventilation de la CSG/CRDS entre 635 et 637 selon sa déductibilité** — même
|
||||||
|
origine. Rejetée deux fois : la déductibilité ne détermine pas le compte, et la
|
||||||
|
CSG est ici intégralement déductible.
|
||||||
|
- **Compte 6333 pour la contribution formation** — rejetée : compte de
|
||||||
|
participation **employeur**, assis sur les salaires. Sans objet ici.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- **L'ERP ne tranche pas cette question et n'a pas à la trancher.** Le
|
||||||
|
dictionnaire *Types de charges sociales ou fiscales* (`/admin/dict.php?id=7`) a
|
||||||
|
sa colonne « Code comptable » **vide pour tous les types**, `TAXSSI` compris —
|
||||||
|
vérifié au niveau cellule le 13/08/2026. Le module comptabilité n'est pas
|
||||||
|
déployé (`/accountancy/*` répond 404). Dolibarr porte les faits — montant,
|
||||||
|
échéance, justificatif — et l'imputation vit dans le grand livre de
|
||||||
|
l'expert-comptable. Le type de charge n'est qu'un libellé.
|
||||||
|
- `RUNBOOK_charges_sociales.md` est corrigé : il affirmait 646 et prétendait que
|
||||||
|
le type de charge pilotait le compte. Les deux étaient faux.
|
||||||
|
- **L'assiette des cotisations est la rémunération du gérant, jamais le chiffre
|
||||||
|
d'affaires.** Toute anticipation de régularisation bâtie sur le CA encaissé est
|
||||||
|
sans fondement. Entrée `urssaf-2026-regularisation` au calendrier.
|
||||||
|
- Question laissée ouverte, qui conditionne le passage de cette décision en
|
||||||
|
*Accepted* : aucune rémunération n'ayant été versée en 2026, la prise en charge
|
||||||
|
des cotisations constitue-t-elle à elle seule l'assiette ? Et faut-il verser une
|
||||||
|
rémunération avant le 31/12 ? Arbitrage expert-comptable.
|
||||||
|
|
||||||
|
## QA & validation
|
||||||
|
|
||||||
|
- Imputation vérifiée contre **deux sources indépendantes et concordantes**
|
||||||
|
(compta-facile, compta-online), toutes deux explicites sur le fait que le 646
|
||||||
|
ne s'applique pas aux sociétés.
|
||||||
|
- **Le challenge contradictoire a été lui-même vérifié, et pris en défaut.**
|
||||||
|
`mistral-large-2512` donnait le compte 6333 pour « versements libératoires
|
||||||
|
taxe d'apprentissage » (c'est le 6335) et le 6354 pour « impôts sur
|
||||||
|
rémunérations » (c'est « droits d'enregistrement et de timbre »), et citait des
|
||||||
|
décisions de justice invérifiables. Son diagnostic « 646 est faux » était juste,
|
||||||
|
sa correction ne l'était pas. **Un verdict de challenger ne se reporte pas sans
|
||||||
|
contrôle** — c'est la leçon opératoire de cette décision.
|
||||||
|
- Contrôle arithmétique de l'appel : 2 062 + 120 + 859 = 3 041 ✓ ;
|
||||||
|
échéancier 0 + 493 + 1 215 + 1 333 = 3 041 ✓.
|
||||||
|
- Justificatif attaché aux trois charges de production, vérifié sur
|
||||||
|
`/compta/sociales/document.php?id=1|2|3`.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- Appel de cotisations 2026, URSSAF Île-de-France, 09/07/2026, n° TI 117
|
||||||
|
1583346778 4 — attaché aux charges 1, 2 et 3 en production.
|
||||||
|
- Échéancier et régularisation : `fleet/profile/calendar.yaml`,
|
||||||
|
entrées `urssaf-2026-t2`, `urssaf-2026-t3`, `urssaf-2026-regularisation`.
|
||||||
|
- Mode opératoire : `.claude/skills/dolibarr-sandbox-write/RUNBOOK_charges_sociales.md`.
|
||||||
|
- Exercice comptable : `fleet/profile/fiscal.yaml`.
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
Correct the dates of an existing social charge through the Dolibarr UI.
|
||||||
|
|
||||||
|
!! BLOQUÉ PAR UN BUG AMONT — CE SCRIPT NE PEUT PAS ABOUTIR AUJOURD'HUI. !!
|
||||||
|
|
||||||
|
Sur ce déploiement (Dolibarr 22.0.4 + PostgreSQL), AUCUNE charge sociale n'est
|
||||||
|
modifiable : toute soumission du formulaire d'édition, même en ne touchant que
|
||||||
|
le montant, échoue sur
|
||||||
|
|
||||||
|
ERROR 42601: multiple assignments to same column "fk_user_modif"
|
||||||
|
|
||||||
|
ChargeSociales::update() construit un UPDATE qui affecte deux fois la même
|
||||||
|
colonne. MySQL l'accepte, PostgreSQL le rejette. Vérifié le 2026-08-13 en
|
||||||
|
sandbox sur la date ET sur le montant ; la mise à jour d'un tiers via REST
|
||||||
|
fonctionne, donc le défaut est propre à cet objet, pas systémique.
|
||||||
|
|
||||||
|
CONSÉQUENCE OPÉRATOIRE : une charge sociale est de fait IMMUABLE. Sa date doit
|
||||||
|
être juste à la création — voir RUNBOOK_charges_sociales.md, « échéance ≠
|
||||||
|
prélèvement ». Ce script est conservé comme cas de reproduction : il
|
||||||
|
diagnostique l'erreur au lieu de la subir, et redeviendra utile dès que le bug
|
||||||
|
amont sera corrigé.
|
||||||
|
|
||||||
|
WHY THIS EXISTS: recordSocialCharge.ts only creates. When a charge was booked
|
||||||
|
on the wrong date the record must be corrected in place — deleting and
|
||||||
|
recreating is not an option, since no agent scope grants DELETE and a ledger
|
||||||
|
is append-only by doctrine.
|
||||||
|
|
||||||
|
THE CORRECTION THIS WAS WRITTEN FOR: the URSSAF échéancier gives DUE dates on
|
||||||
|
the 5th of the month. The bank debit lands later (22/05 for the 05/05 due
|
||||||
|
date). The first échéance had been recorded at its debit date, which makes a
|
||||||
|
17-day late payment look punctual and puts the charge in the wrong month.
|
||||||
|
|
||||||
|
Same double-bottom date trap as the create form: the visible `ech` / `period`
|
||||||
|
inputs are decorative, the backend reads ONLY the hidden day/month/year
|
||||||
|
triplets fed by the jQuery datepicker. See RUNBOOK_charges_sociales.md.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
deno run -A test/updateSocialCharge.ts --id 1 --due 2026-05-05 \
|
||||||
|
--period 2026-05-05 [--dry-run]
|
||||||
|
*/
|
||||||
|
import "load_dotenv";
|
||||||
|
import { chromium } from "playwright";
|
||||||
|
import login from "./scripts/login.ts";
|
||||||
|
import { assertSandbox } from "./scripts/guard.ts";
|
||||||
|
|
||||||
|
const argv = Deno.args;
|
||||||
|
const pick = (f: string, d = "") => (argv.includes(f) ? argv[argv.indexOf(f) + 1] : d);
|
||||||
|
|
||||||
|
const id = pick("--id");
|
||||||
|
const due = pick("--due"); // yyyy-mm-dd
|
||||||
|
const period = pick("--period"); // yyyy-mm-dd
|
||||||
|
const dryRun = argv.includes("--dry-run");
|
||||||
|
|
||||||
|
if (!id || !due) {
|
||||||
|
console.error("--id and --due (yyyy-mm-dd) are required");
|
||||||
|
Deno.exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dolibarrAddress = assertSandbox();
|
||||||
|
const fr = (iso: string) => {
|
||||||
|
const [y, m, d] = iso.split("-");
|
||||||
|
return `${d}/${m}/${y}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(`target : ${dolibarrAddress}`);
|
||||||
|
console.log(`charge ${id} : échéance → ${fr(due)}${period ? `, période → ${fr(period)}` : ""}`);
|
||||||
|
if (dryRun) {
|
||||||
|
console.log("\n--dry-run : rien n'est soumis.");
|
||||||
|
Deno.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const browser = await chromium.launch({ headless: true });
|
||||||
|
const context = await browser.newContext({ locale: "fr-FR" });
|
||||||
|
const page = await context.newPage();
|
||||||
|
|
||||||
|
async function setDolibarrDate(name: string, iso: string): Promise<void> {
|
||||||
|
const [y, m, d] = iso.split("-");
|
||||||
|
await page.fill(`input[name="${name}"]`, fr(iso)).catch(() => {});
|
||||||
|
await page.evaluate(
|
||||||
|
({ n, dd, mm, yy }: { n: string; dd: string; mm: string; yy: string }) => {
|
||||||
|
const doc = (globalThis as unknown as {
|
||||||
|
document: { querySelector(s: string): { value: string } | null };
|
||||||
|
}).document;
|
||||||
|
const set = (suffix: string, v: string) => {
|
||||||
|
const el = doc.querySelector(`input[name="${n}${suffix}"]`);
|
||||||
|
if (el) el.value = v;
|
||||||
|
};
|
||||||
|
set("day", String(Number(dd)));
|
||||||
|
set("month", String(Number(mm)));
|
||||||
|
set("year", yy);
|
||||||
|
},
|
||||||
|
{ n: name, dd: d, mm: m, yy: y },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read the dates back off the card — the only trustworthy confirmation. */
|
||||||
|
async function readDates(): Promise<string> {
|
||||||
|
await page.goto(`${dolibarrAddress}/compta/sociales/card.php?id=${id}`);
|
||||||
|
return (await page.locator("div.fichecenter, table").first().innerText())
|
||||||
|
.replace(/\s+/g, " ").trim().slice(0, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await login.doAdminLogin({
|
||||||
|
page,
|
||||||
|
dolibarrAddress,
|
||||||
|
adminCredentials: {
|
||||||
|
username: Deno.env.get("DOLI_ADMIN_LOGIN") || "undefined",
|
||||||
|
password: Deno.env.get("DOLI_ADMIN_PASSWORD") || "undefined",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`avant : ${await readDates()}`);
|
||||||
|
|
||||||
|
await page.goto(`${dolibarrAddress}/compta/sociales/card.php?id=${id}&action=edit`);
|
||||||
|
await setDolibarrDate("ech", due);
|
||||||
|
if (period) await setDolibarrDate("period", period);
|
||||||
|
await page.locator('input[name="save"], input[type="submit"][value="Enregistrer"]').first().click();
|
||||||
|
await page.waitForLoadState("networkidle");
|
||||||
|
|
||||||
|
// Diagnose the known upstream failure rather than reporting a bare mismatch:
|
||||||
|
// "la date n'a pas changé" sends the reader hunting through the date fields,
|
||||||
|
// which are not the problem.
|
||||||
|
const submitted = (await page.locator("body").innerText()).replace(/\s+/g, " ");
|
||||||
|
const dup = submitted.match(/multiple assignments to same column '?"?(\w+)/);
|
||||||
|
if (dup) {
|
||||||
|
console.error(
|
||||||
|
`\nBLOQUÉ PAR LE BUG AMONT — UPDATE invalide sur la colonne « ${dup[1]} ».\n` +
|
||||||
|
`ChargeSociales::update() l'affecte deux fois ; PostgreSQL rejette (42601).\n` +
|
||||||
|
`Une charge sociale est immuable sur ce déploiement : la recréer avec la\n` +
|
||||||
|
`bonne date, ou corriger en base, sont les seules voies.`,
|
||||||
|
);
|
||||||
|
Deno.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const after = await readDates();
|
||||||
|
console.log(`après : ${after}`);
|
||||||
|
if (!after.includes(fr(due))) {
|
||||||
|
console.error(`\nÉCHEC — la carte ne porte pas ${fr(due)}.`);
|
||||||
|
Deno.exit(1);
|
||||||
|
}
|
||||||
|
console.log(`\ncorrigée et vérifiée : échéance ${fr(due)}`);
|
||||||
|
} finally {
|
||||||
|
await context.close();
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user