Skip to content

fix(25-4-c2): un règlement partiel marque la facture, et l'acceptation rejoue un interblocage (closes #480) - #485

Merged
guycorbaz merged 19 commits into
mainfrom
story/25-4-c2-verrou-acceptation
Sep 30, 2026
Merged

guycorbaz merged 19 commits into
mainfrom
story/25-4-c2-verrou-acceptation

Conversation

@guycorbaz

Copy link
Copy Markdown
Owner

Closes #480.

Le défaut

Une acceptation de rapprochement lit le reste dû d'une facture sur l'instantané de sa transaction (REPEATABLE READ, MariaDB 10.11), puis se protège par un verrou optimiste : UPDATE invoices … WHERE version = ?. Ce verrou ne vaut que si tout écrit qui change le reste dû incrémente version. Un seul écrivain y manquait : le règlement manuel partiel. Une acceptation en cours pouvait donc encaisser une seconde fois une facture qui venait d'être réglée en partie — 1 000.— réglée 1 400.—, compte clients créditeur, sans erreur. Reproduit par test avant correctif.

Ce qui change

  • L'invariant — settle_invoice incrémente version à chaque règlement, partiel compris ; garde rows_affected sur cette ligne et sur l'annulation d'un règlement. Doc-comments qui nomment l'invariant et l'inventaire clos de ses écrivains.
  • Pas de FOR UPDATE à l'acceptation : il lirait version à jour et le reste dû périmé, et désarmerait le verrou au lieu de le renforcer (écrit dans le code).
  • Le rejeu sur interblocage — un 1213 absorbé dans une proposition annule toute la transaction, et c'est le ROLLBACK TO SAVEPOINT suivant qui échoue (1305) : accept_batch le remonte en ReconciliationError::TransactionAborted, et POST /reconciliation/accept rejoue le lot par retry_with (patron de l'annulation). Prédicat local ; is_deadlock_error inchangé.
  • Textes — docs/api-external.md documente enfin POST /reconciliation/accept ; CHANGELOG [0.12.1]. Issue Manuel : la numérotation des factures ne se fait pas dans une transaction SERIALIZABLE #484 ouverte (une affirmation fausse du manuel trouvée en chemin).

Tests

Trois tests de course sans sleep : règlement manuel partiel pendant l'acceptation (verrou de métadonnées LOCK TABLES contacts WRITE — le verrou d'exercice ne permet pas de montage, la recherche d'exercice verrouillant toutes les lignes examinées), deux acceptations depuis deux comptes, interblocage dont l'acceptation est la victime. Mutations : incrément conditionnel rétabli, rejeu neutralisé, reconnaissance du 1305 neutralisée, version = ? relâché — chacune tuée.

Validation et revue

Validation de spec en 2 passes (Sonnet 1 HIGH / 2 MEDIUM → Haiku 0 > LOW). Revue de code en 2 passes (Sonnet ×3 : 1 HIGH / 4 MEDIUM corrigés → Haiku ciblée : 0 > LOW).

Gates locaux, au dernier commit, base remise à zéro

🤖 Generated with Claude Code

guycorbaz and others added 19 commits September 29, 2026 08:35
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… l'orchestrateur (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… arbitrages en attente (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#476) ; périmètre réduit au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… en partie (refs #420)

Le filtre des candidates, le score, le re-score à l'acceptation et le
montant affiché portent sur le reste dû (TTC − avoir − règlements), par
la forme jointe ; le TTC ne suit qu'en mention quand les deux diffèrent.
Manuel et brochure réécrits sur le score réel ; #481 ouverte pour le reste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ues, Playwright départagé (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…le rejeu sur interblocage (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n rejoue un interblocage (refs #480)

Le règlement manuel incrémente invoices.version à chaque règlement, partiel
compris : le verrou optimiste de l'acceptation refuse désormais celle qui
arrive après un règlement concurrent. Un interblocage absorbé dans une
proposition (ROLLBACK TO SAVEPOINT en 1305) remonte en TransactionAborted et
la route rejoue le lot par retry_with. Trois tests de course sans sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…INT, verrou de test détaché (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@guycorbaz
guycorbaz merged commit fdac285 into main Sep 30, 2026
3 checks passed
guycorbaz added a commit that referenced this pull request Sep 30, 2026
…s paramètres (refs #476) (#487)

* docs(25-4-c): story créée — le résiduel au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): arbitrages Q1–Q3 retenus par défaut, rebase sur la b2 (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P1 — 3 HIGH, 2 MED, 1 LOW remédiés (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P2 — 0 finding sans preuve, 2 MED repris par l'orchestrateur (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): références de lignes du verrou recontrôlées (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P3 consignée — 1 CRIT / 3 HIGH, découpage et arbitrages en attente (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): découpée — verrou en 25-4-c2 (#480), arrondi en 25-4-c3 (#476) ; périmètre réduit au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P4 — 1 MED, 1 LOW remédiés (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P5 ciblée — close, 0 > LOW (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): le rapprochement reconnaît le solde d'une facture réglée en partie (refs #420)

Le filtre des candidates, le score, le re-score à l'acceptation et le
montant affiché portent sur le reste dû (TTC − avoir − règlements), par
la forme jointe ; le TTC ne suit qu'en mention quand les deux diffèrent.
Manuel et brochure réécrits sur le score réel ; #481 ouverte pour le reste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): revue de code P1 — CHANGELOG replacé, traductions univoques, Playwright départagé (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): revue de code P2 — close, 0 > LOW ; story done (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): story créée — l'invariant de version au règlement, et le rejeu sur interblocage (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P1 — 1 HIGH, 2 MED, 2 LOW remédiés (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P2 — close, 0 > LOW (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): un règlement partiel marque la facture, et l'acceptation rejoue un interblocage (refs #480)

Le règlement manuel incrémente invoices.version à chaque règlement, partiel
compris : le verrou optimiste de l'acceptation refuse désormais celle qui
arrive après un règlement concurrent. Un interblocage absorbé dans une
proposition (ROLLBACK TO SAVEPOINT en 1305) remonte en TransactionAborted et
la route rejoue le lot par retry_with. Trois tests de course sans sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): revue de code P1 — gardes rows_affected, RELEASE SAVEPOINT, verrou de test détaché (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(25-4-c3): arbitrage de Guy — l'écart d'arrondi passe en écriture ; PR #485 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3): découpée en a1 / a2 / b ; story c3-a1 créée — le réglage du compte d'arrondi (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P1 — 2 MED remédiés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P2 ciblée — close, 0 > LOW (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a1): désigner le compte de différences d'arrondi dans les paramètres (refs #476)

Nouvelle colonne company_invoice_settings.default_rounding_account_id (DDL seul,
non breaking), validée charge ou produit, actif, imputable ; absente d'un PUT
elle est préservée, à null effacée. Section Différences d'arrondi dans
Paramètres > Facturation ; export ; import d'une sauvegarde antérieure prouvé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a1): revue de code P1 — compte d'arrondi validé seulement s'il change, Playwright nettoyé en finally (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
guycorbaz added a commit that referenced this pull request Oct 1, 2026
… livrés, désigné d'office (refs #476) (#489)

* docs(25-4-c): story créée — le résiduel au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): arbitrages Q1–Q3 retenus par défaut, rebase sur la b2 (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P1 — 3 HIGH, 2 MED, 1 LOW remédiés (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P2 — 0 finding sans preuve, 2 MED repris par l'orchestrateur (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): références de lignes du verrou recontrôlées (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P3 consignée — 1 CRIT / 3 HIGH, découpage et arbitrages en attente (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): découpée — verrou en 25-4-c2 (#480), arrondi en 25-4-c3 (#476) ; périmètre réduit au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P4 — 1 MED, 1 LOW remédiés (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P5 ciblée — close, 0 > LOW (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): le rapprochement reconnaît le solde d'une facture réglée en partie (refs #420)

Le filtre des candidates, le score, le re-score à l'acceptation et le
montant affiché portent sur le reste dû (TTC − avoir − règlements), par
la forme jointe ; le TTC ne suit qu'en mention quand les deux diffèrent.
Manuel et brochure réécrits sur le score réel ; #481 ouverte pour le reste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): revue de code P1 — CHANGELOG replacé, traductions univoques, Playwright départagé (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): revue de code P2 — close, 0 > LOW ; story done (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): story créée — l'invariant de version au règlement, et le rejeu sur interblocage (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P1 — 1 HIGH, 2 MED, 2 LOW remédiés (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P2 — close, 0 > LOW (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): un règlement partiel marque la facture, et l'acceptation rejoue un interblocage (refs #480)

Le règlement manuel incrémente invoices.version à chaque règlement, partiel
compris : le verrou optimiste de l'acceptation refuse désormais celle qui
arrive après un règlement concurrent. Un interblocage absorbé dans une
proposition (ROLLBACK TO SAVEPOINT en 1305) remonte en TransactionAborted et
la route rejoue le lot par retry_with. Trois tests de course sans sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): revue de code P1 — gardes rows_affected, RELEASE SAVEPOINT, verrou de test détaché (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(25-4-c3): arbitrage de Guy — l'écart d'arrondi passe en écriture ; PR #485 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3): découpée en a1 / a2 / b ; story c3-a1 créée — le réglage du compte d'arrondi (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P1 — 2 MED remédiés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P2 ciblée — close, 0 > LOW (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a1): désigner le compte de différences d'arrondi dans les paramètres (refs #476)

Nouvelle colonne company_invoice_settings.default_rounding_account_id (DDL seul,
non breaking), validée charge ou produit, actif, imputable ; absente d'un PUT
elle est préservée, à null effacée. Section Différences d'arrondi dans
Paramètres > Facturation ; export ; import d'une sauvegarde antérieure prouvé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a1): revue de code P1 — compte d'arrondi validé seulement s'il change, Playwright nettoyé en finally (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): story créée — le compte de différences d'arrondi dans les plans livrés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P1 — 3 MED, 2 LOW remédiés ; #488 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P2 ciblée — close, 0 > LOW ; dev démarré (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a2): le compte 6940 Différences d'arrondi dans les plans livrés, désigné d'office (refs #476)

Marqueur de plan roundingDifference (pas de rôle, pas de numéro dans le code),
validé au chargement ; les deux insert_with_defaults* désignent le compte marqué
du plan de la société (FOR UPDATE), NULL sans erreur s'il manque. Rien chez les
sociétés existantes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a2): revue de code P1 — marqueur sans rôle, erreur de plan tracée, types liés par l'enum (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): revue de code P2 ciblée — close, 0 finding ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
guycorbaz added a commit that referenced this pull request Oct 5, 2026
…gne (closes #476) (#493)

* docs(25-4-c): story créée — le résiduel au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): arbitrages Q1–Q3 retenus par défaut, rebase sur la b2 (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P1 — 3 HIGH, 2 MED, 1 LOW remédiés (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P2 — 0 finding sans preuve, 2 MED repris par l'orchestrateur (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): références de lignes du verrou recontrôlées (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P3 consignée — 1 CRIT / 3 HIGH, découpage et arbitrages en attente (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): découpée — verrou en 25-4-c2 (#480), arrondi en 25-4-c3 (#476) ; périmètre réduit au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P4 — 1 MED, 1 LOW remédiés (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P5 ciblée — close, 0 > LOW (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): le rapprochement reconnaît le solde d'une facture réglée en partie (refs #420)

Le filtre des candidates, le score, le re-score à l'acceptation et le
montant affiché portent sur le reste dû (TTC − avoir − règlements), par
la forme jointe ; le TTC ne suit qu'en mention quand les deux diffèrent.
Manuel et brochure réécrits sur le score réel ; #481 ouverte pour le reste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): revue de code P1 — CHANGELOG replacé, traductions univoques, Playwright départagé (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): revue de code P2 — close, 0 > LOW ; story done (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): story créée — l'invariant de version au règlement, et le rejeu sur interblocage (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P1 — 1 HIGH, 2 MED, 2 LOW remédiés (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P2 — close, 0 > LOW (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): un règlement partiel marque la facture, et l'acceptation rejoue un interblocage (refs #480)

Le règlement manuel incrémente invoices.version à chaque règlement, partiel
compris : le verrou optimiste de l'acceptation refuse désormais celle qui
arrive après un règlement concurrent. Un interblocage absorbé dans une
proposition (ROLLBACK TO SAVEPOINT en 1305) remonte en TransactionAborted et
la route rejoue le lot par retry_with. Trois tests de course sans sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): revue de code P1 — gardes rows_affected, RELEASE SAVEPOINT, verrou de test détaché (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(25-4-c3): arbitrage de Guy — l'écart d'arrondi passe en écriture ; PR #485 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3): découpée en a1 / a2 / b ; story c3-a1 créée — le réglage du compte d'arrondi (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P1 — 2 MED remédiés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P2 ciblée — close, 0 > LOW (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a1): désigner le compte de différences d'arrondi dans les paramètres (refs #476)

Nouvelle colonne company_invoice_settings.default_rounding_account_id (DDL seul,
non breaking), validée charge ou produit, actif, imputable ; absente d'un PUT
elle est préservée, à null effacée. Section Différences d'arrondi dans
Paramètres > Facturation ; export ; import d'une sauvegarde antérieure prouvé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a1): revue de code P1 — compte d'arrondi validé seulement s'il change, Playwright nettoyé en finally (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): story créée — le compte de différences d'arrondi dans les plans livrés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P1 — 3 MED, 2 LOW remédiés ; #488 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P2 ciblée — close, 0 > LOW ; dev démarré (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a2): le compte 6940 Différences d'arrondi dans les plans livrés, désigné d'office (refs #476)

Marqueur de plan roundingDifference (pas de rôle, pas de numéro dans le code),
validé au chargement ; les deux insert_with_defaults* désignent le compte marqué
du plan de la société (FOR UPDATE), NULL sans erreur s'il manque. Rien chez les
sociétés existantes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a2): revue de code P1 — marqueur sans rôle, erreur de plan tracée, types liés par l'enum (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): revue de code P2 ciblée — close, 0 finding ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): story créée — l'arrondi au centime et l'écart en écriture (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P1 — double borne brut/arrondi, échelle du règlement manuel, sites triés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P2 — échelle normalisée, contrôle client des décimales, reste sous le demi-centime tracé (#490) (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P3 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P3 ciblée — montant reçu tel quel, décimales sur la forme big.js, test d'échelle discriminant, #490 reformulée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P4 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P4 ciblée — 0 finding, boucle close (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-b): solder au centime, l'écart d'arrondi en troisième ligne (refs #476)

Le reste dû peut porter quatre décimales (10.0050) ; QR, rappels et dialogue
réclament 10.01, que le rapprochement ne proposait pas et que le règlement
manuel refusait en trop-perçu. Toute comparaison se fait au centime
(amount_due_to_centime) ; un paiement égal au reste arrondi solde la facture,
réglée au reste brut, l'écart passant sur le compte de différences d'arrondi
(double borne : entre brut et arrondi, trop-perçu). Sans compte utilisable,
refus dédié ROUNDING_ACCOUNT_NOT_CONFIGURED, rien d'écrit. Règlement manuel à
plus de deux décimales refusé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P1 (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-b): revue de code P1 — invariant tracé au rapprochement, compte d'arrondi produit testé (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P2 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): revue de code P2 ciblée — close, aucune correction de production ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
guycorbaz added a commit that referenced this pull request Oct 5, 2026
…loses #494) (#507)

* docs(25-4-c): story créée — le résiduel au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): arbitrages Q1–Q3 retenus par défaut, rebase sur la b2 (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P1 — 3 HIGH, 2 MED, 1 LOW remédiés (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P2 — 0 finding sans preuve, 2 MED repris par l'orchestrateur (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): références de lignes du verrou recontrôlées (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P3 consignée — 1 CRIT / 3 HIGH, découpage et arbitrages en attente (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): découpée — verrou en 25-4-c2 (#480), arrondi en 25-4-c3 (#476) ; périmètre réduit au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P4 — 1 MED, 1 LOW remédiés (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P5 ciblée — close, 0 > LOW (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): le rapprochement reconnaît le solde d'une facture réglée en partie (refs #420)

Le filtre des candidates, le score, le re-score à l'acceptation et le
montant affiché portent sur le reste dû (TTC − avoir − règlements), par
la forme jointe ; le TTC ne suit qu'en mention quand les deux diffèrent.
Manuel et brochure réécrits sur le score réel ; #481 ouverte pour le reste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): revue de code P1 — CHANGELOG replacé, traductions univoques, Playwright départagé (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): revue de code P2 — close, 0 > LOW ; story done (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): story créée — l'invariant de version au règlement, et le rejeu sur interblocage (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P1 — 1 HIGH, 2 MED, 2 LOW remédiés (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P2 — close, 0 > LOW (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): un règlement partiel marque la facture, et l'acceptation rejoue un interblocage (refs #480)

Le règlement manuel incrémente invoices.version à chaque règlement, partiel
compris : le verrou optimiste de l'acceptation refuse désormais celle qui
arrive après un règlement concurrent. Un interblocage absorbé dans une
proposition (ROLLBACK TO SAVEPOINT en 1305) remonte en TransactionAborted et
la route rejoue le lot par retry_with. Trois tests de course sans sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): revue de code P1 — gardes rows_affected, RELEASE SAVEPOINT, verrou de test détaché (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(25-4-c3): arbitrage de Guy — l'écart d'arrondi passe en écriture ; PR #485 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3): découpée en a1 / a2 / b ; story c3-a1 créée — le réglage du compte d'arrondi (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P1 — 2 MED remédiés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P2 ciblée — close, 0 > LOW (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a1): désigner le compte de différences d'arrondi dans les paramètres (refs #476)

Nouvelle colonne company_invoice_settings.default_rounding_account_id (DDL seul,
non breaking), validée charge ou produit, actif, imputable ; absente d'un PUT
elle est préservée, à null effacée. Section Différences d'arrondi dans
Paramètres > Facturation ; export ; import d'une sauvegarde antérieure prouvé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a1): revue de code P1 — compte d'arrondi validé seulement s'il change, Playwright nettoyé en finally (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): story créée — le compte de différences d'arrondi dans les plans livrés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P1 — 3 MED, 2 LOW remédiés ; #488 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P2 ciblée — close, 0 > LOW ; dev démarré (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a2): le compte 6940 Différences d'arrondi dans les plans livrés, désigné d'office (refs #476)

Marqueur de plan roundingDifference (pas de rôle, pas de numéro dans le code),
validé au chargement ; les deux insert_with_defaults* désignent le compte marqué
du plan de la société (FOR UPDATE), NULL sans erreur s'il manque. Rien chez les
sociétés existantes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a2): revue de code P1 — marqueur sans rôle, erreur de plan tracée, types liés par l'enum (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): revue de code P2 ciblée — close, 0 finding ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): story créée — l'arrondi au centime et l'écart en écriture (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P1 — double borne brut/arrondi, échelle du règlement manuel, sites triés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P2 — échelle normalisée, contrôle client des décimales, reste sous le demi-centime tracé (#490) (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P3 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P3 ciblée — montant reçu tel quel, décimales sur la forme big.js, test d'échelle discriminant, #490 reformulée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P4 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P4 ciblée — 0 finding, boucle close (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-b): solder au centime, l'écart d'arrondi en troisième ligne (refs #476)

Le reste dû peut porter quatre décimales (10.0050) ; QR, rappels et dialogue
réclament 10.01, que le rapprochement ne proposait pas et que le règlement
manuel refusait en trop-perçu. Toute comparaison se fait au centime
(amount_due_to_centime) ; un paiement égal au reste arrondi solde la facture,
réglée au reste brut, l'écart passant sur le compte de différences d'arrondi
(double borne : entre brut et arrondi, trop-perçu). Sans compte utilisable,
refus dédié ROUNDING_ACCOUNT_NOT_CONFIGURED, rien d'écrit. Règlement manuel à
plus de deux décimales refusé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P1 (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-b): revue de code P1 — invariant tracé au rapprochement, compte d'arrondi produit testé (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P2 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): revue de code P2 ciblée — close, aucune correction de production ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): story créée — l'arrondi à 5 centimes figé à la validation (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P1 — refus contextualisé, ordre des refus, références corrigées (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P2 — sites de la variante et emplacement du refus écrits (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P3 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P3 ciblée — l'avoir à arrondi nul n'exige aucun compte (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P4 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P4 ciblée — 0 finding, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-a): arrondir à 5 centimes le total des pièces émises, figé à la validation (refs #494)

Le total TTC d'une facture validée est arrondi au multiple de 0.05 (123.44 →
123.45, 234.52 → 234.50) ; l'écart, sans TVA, est figé sur la facture
(invoices.rounding_amount) et écrit en dernière ligne de l'écriture de vente
sur le compte de différences d'arrondi. Toutes les formes du TTC l'intègrent
(reste dû, listes, rapprochement, QR, PDF, e-mail). L'avoir le recopie et
l'annule en miroir. Réglage par société, actif par défaut. Refus à contexte :
le message d'émission ne parle plus de paiement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-a): revue de code P1 — forme jointe du crédit symétrique, manuel admin rectifié, avoir et sauvegarde testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): revue de code P2 ciblée — 0 finding, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): story créée — l'arrondi à 5 centimes, visible et réglable (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P1 — aperçu sur toute réponse brouillon, récapitulatif traduit, doc-comment rectifié (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P2 — type résolu clarifié, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-b): l'arrondi à 5 centimes visible et réglable (refs #494)

Ligne « Arrondi » signée au PDF de la facture, de l'avoir et du rappel, et
sur la fiche (aperçu « estimé » pour un brouillon, calculé par le serveur et
porté par toute réponse qui rend un brouillon, dévalidation comprise). Le
réglage roundTo5Centimes est exposé (GET/PUT, préservé s'il est absent) et
se règle dans Paramètres → Facturation ; les factures émises gardent leur
total. Récapitulatif de la fiche traduit, manuels et CHANGELOG à jour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-b): revue de code P1 — réglage lu sans écriture, arrondi décidé au centime, manuel rectifié, avoir et rappel testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): revue de code P2 ciblée — 0 réel, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4): fixture du test de la fiche (25-6-b) complétée de l'arrondi (refs #494)

La fusion de main apporte invoice-pdf-page.test.ts, dont la fixture
InvoiceResponse ignorait roundingAmount / roundingIsPreview ajoutés par
la c4 : npm run check rougissait (1 erreur), tests et build passaient.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
guycorbaz added a commit that referenced this pull request Oct 5, 2026
…ise (closes #495) (#508)

* docs(25-4-c): story créée — le résiduel au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): arbitrages Q1–Q3 retenus par défaut, rebase sur la b2 (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P1 — 3 HIGH, 2 MED, 1 LOW remédiés (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P2 — 0 finding sans preuve, 2 MED repris par l'orchestrateur (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): références de lignes du verrou recontrôlées (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P3 consignée — 1 CRIT / 3 HIGH, découpage et arbitrages en attente (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): découpée — verrou en 25-4-c2 (#480), arrondi en 25-4-c3 (#476) ; périmètre réduit au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P4 — 1 MED, 1 LOW remédiés (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P5 ciblée — close, 0 > LOW (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): le rapprochement reconnaît le solde d'une facture réglée en partie (refs #420)

Le filtre des candidates, le score, le re-score à l'acceptation et le
montant affiché portent sur le reste dû (TTC − avoir − règlements), par
la forme jointe ; le TTC ne suit qu'en mention quand les deux diffèrent.
Manuel et brochure réécrits sur le score réel ; #481 ouverte pour le reste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): revue de code P1 — CHANGELOG replacé, traductions univoques, Playwright départagé (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): revue de code P2 — close, 0 > LOW ; story done (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): story créée — l'invariant de version au règlement, et le rejeu sur interblocage (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P1 — 1 HIGH, 2 MED, 2 LOW remédiés (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P2 — close, 0 > LOW (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): un règlement partiel marque la facture, et l'acceptation rejoue un interblocage (refs #480)

Le règlement manuel incrémente invoices.version à chaque règlement, partiel
compris : le verrou optimiste de l'acceptation refuse désormais celle qui
arrive après un règlement concurrent. Un interblocage absorbé dans une
proposition (ROLLBACK TO SAVEPOINT en 1305) remonte en TransactionAborted et
la route rejoue le lot par retry_with. Trois tests de course sans sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): revue de code P1 — gardes rows_affected, RELEASE SAVEPOINT, verrou de test détaché (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(25-4-c3): arbitrage de Guy — l'écart d'arrondi passe en écriture ; PR #485 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3): découpée en a1 / a2 / b ; story c3-a1 créée — le réglage du compte d'arrondi (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P1 — 2 MED remédiés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P2 ciblée — close, 0 > LOW (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a1): désigner le compte de différences d'arrondi dans les paramètres (refs #476)

Nouvelle colonne company_invoice_settings.default_rounding_account_id (DDL seul,
non breaking), validée charge ou produit, actif, imputable ; absente d'un PUT
elle est préservée, à null effacée. Section Différences d'arrondi dans
Paramètres > Facturation ; export ; import d'une sauvegarde antérieure prouvé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a1): revue de code P1 — compte d'arrondi validé seulement s'il change, Playwright nettoyé en finally (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): story créée — le compte de différences d'arrondi dans les plans livrés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P1 — 3 MED, 2 LOW remédiés ; #488 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P2 ciblée — close, 0 > LOW ; dev démarré (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a2): le compte 6940 Différences d'arrondi dans les plans livrés, désigné d'office (refs #476)

Marqueur de plan roundingDifference (pas de rôle, pas de numéro dans le code),
validé au chargement ; les deux insert_with_defaults* désignent le compte marqué
du plan de la société (FOR UPDATE), NULL sans erreur s'il manque. Rien chez les
sociétés existantes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a2): revue de code P1 — marqueur sans rôle, erreur de plan tracée, types liés par l'enum (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): revue de code P2 ciblée — close, 0 finding ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): story créée — l'arrondi au centime et l'écart en écriture (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P1 — double borne brut/arrondi, échelle du règlement manuel, sites triés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P2 — échelle normalisée, contrôle client des décimales, reste sous le demi-centime tracé (#490) (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P3 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P3 ciblée — montant reçu tel quel, décimales sur la forme big.js, test d'échelle discriminant, #490 reformulée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P4 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P4 ciblée — 0 finding, boucle close (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-b): solder au centime, l'écart d'arrondi en troisième ligne (refs #476)

Le reste dû peut porter quatre décimales (10.0050) ; QR, rappels et dialogue
réclament 10.01, que le rapprochement ne proposait pas et que le règlement
manuel refusait en trop-perçu. Toute comparaison se fait au centime
(amount_due_to_centime) ; un paiement égal au reste arrondi solde la facture,
réglée au reste brut, l'écart passant sur le compte de différences d'arrondi
(double borne : entre brut et arrondi, trop-perçu). Sans compte utilisable,
refus dédié ROUNDING_ACCOUNT_NOT_CONFIGURED, rien d'écrit. Règlement manuel à
plus de deux décimales refusé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P1 (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-b): revue de code P1 — invariant tracé au rapprochement, compte d'arrondi produit testé (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P2 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): revue de code P2 ciblée — close, aucune correction de production ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): story créée — l'arrondi à 5 centimes figé à la validation (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P1 — refus contextualisé, ordre des refus, références corrigées (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P2 — sites de la variante et emplacement du refus écrits (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P3 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P3 ciblée — l'avoir à arrondi nul n'exige aucun compte (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P4 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P4 ciblée — 0 finding, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-a): arrondir à 5 centimes le total des pièces émises, figé à la validation (refs #494)

Le total TTC d'une facture validée est arrondi au multiple de 0.05 (123.44 →
123.45, 234.52 → 234.50) ; l'écart, sans TVA, est figé sur la facture
(invoices.rounding_amount) et écrit en dernière ligne de l'écriture de vente
sur le compte de différences d'arrondi. Toutes les formes du TTC l'intègrent
(reste dû, listes, rapprochement, QR, PDF, e-mail). L'avoir le recopie et
l'annule en miroir. Réglage par société, actif par défaut. Refus à contexte :
le message d'émission ne parle plus de paiement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-a): revue de code P1 — forme jointe du crédit symétrique, manuel admin rectifié, avoir et sauvegarde testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): revue de code P2 ciblée — 0 finding, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): story créée — l'arrondi à 5 centimes, visible et réglable (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P1 — aperçu sur toute réponse brouillon, récapitulatif traduit, doc-comment rectifié (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P2 — type résolu clarifié, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-b): l'arrondi à 5 centimes visible et réglable (refs #494)

Ligne « Arrondi » signée au PDF de la facture, de l'avoir et du rappel, et
sur la fiche (aperçu « estimé » pour un brouillon, calculé par le serveur et
porté par toute réponse qui rend un brouillon, dévalidation comprise). Le
réglage roundTo5Centimes est exposé (GET/PUT, préservé s'il est absent) et
se règle dans Paramètres → Facturation ; les factures émises gardent leur
total. Récapitulatif de la fiche traduit, manuels et CHANGELOG à jour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-b): revue de code P1 — réglage lu sans écriture, arrondi décidé au centime, manuel rectifié, avoir et rappel testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): revue de code P2 ciblée — 0 réel, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): story créée — un montant minimum configurable sous lequel une facture n'est pas émise (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): validation P1 — sites qui énumèrent les colonnes nommés ; prompt P2 (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): validation P2 ciblée — sites hors dépôt explicités, boucle close (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-e): un montant minimum configurable sous lequel une facture n'est pas émise (refs #495)

Réglage company_invoice_settings.minimum_invoice_amount (NULL = aucun seuil,
le défaut) ; la validation refuse une facture dont le total arrondi est
inférieur (INVOICE_BELOW_MINIMUM, message à deux montants). Avoirs exemptés.
API qui préserve l'absent, section Montant minimum dans Paramètres →
Facturation, manuels et CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): prompt de la revue de code P1 (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-e): revue de code P1 — seuil comparé au centime, plafond, helper d'export réellement appelé (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): prompt de la revue de code P2 ciblée (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): revue de code P2 ciblée — 0 au-dessus de LOW, boucle close ; story done (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4): fixture du test de la fiche (25-6-b) complétée de l'arrondi (refs #494)

La fusion de main apporte invoice-pdf-page.test.ts, dont la fixture
InvoiceResponse ignorait roundingAmount / roundingIsPreview ajoutés par
la c4 : npm run check rougissait (1 erreur), tests et build passaient.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
guycorbaz added a commit that referenced this pull request Oct 5, 2026
…e sur débiteur (refs #384) (#509)

* docs(25-4-c): story créée — le résiduel au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): arbitrages Q1–Q3 retenus par défaut, rebase sur la b2 (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P1 — 3 HIGH, 2 MED, 1 LOW remédiés (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P2 — 0 finding sans preuve, 2 MED repris par l'orchestrateur (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): références de lignes du verrou recontrôlées (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P3 consignée — 1 CRIT / 3 HIGH, découpage et arbitrages en attente (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): découpée — verrou en 25-4-c2 (#480), arrondi en 25-4-c3 (#476) ; périmètre réduit au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P4 — 1 MED, 1 LOW remédiés (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P5 ciblée — close, 0 > LOW (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): le rapprochement reconnaît le solde d'une facture réglée en partie (refs #420)

Le filtre des candidates, le score, le re-score à l'acceptation et le
montant affiché portent sur le reste dû (TTC − avoir − règlements), par
la forme jointe ; le TTC ne suit qu'en mention quand les deux diffèrent.
Manuel et brochure réécrits sur le score réel ; #481 ouverte pour le reste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): revue de code P1 — CHANGELOG replacé, traductions univoques, Playwright départagé (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): revue de code P2 — close, 0 > LOW ; story done (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): story créée — l'invariant de version au règlement, et le rejeu sur interblocage (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P1 — 1 HIGH, 2 MED, 2 LOW remédiés (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P2 — close, 0 > LOW (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): un règlement partiel marque la facture, et l'acceptation rejoue un interblocage (refs #480)

Le règlement manuel incrémente invoices.version à chaque règlement, partiel
compris : le verrou optimiste de l'acceptation refuse désormais celle qui
arrive après un règlement concurrent. Un interblocage absorbé dans une
proposition (ROLLBACK TO SAVEPOINT en 1305) remonte en TransactionAborted et
la route rejoue le lot par retry_with. Trois tests de course sans sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): revue de code P1 — gardes rows_affected, RELEASE SAVEPOINT, verrou de test détaché (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(25-4-c3): arbitrage de Guy — l'écart d'arrondi passe en écriture ; PR #485 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3): découpée en a1 / a2 / b ; story c3-a1 créée — le réglage du compte d'arrondi (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P1 — 2 MED remédiés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P2 ciblée — close, 0 > LOW (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a1): désigner le compte de différences d'arrondi dans les paramètres (refs #476)

Nouvelle colonne company_invoice_settings.default_rounding_account_id (DDL seul,
non breaking), validée charge ou produit, actif, imputable ; absente d'un PUT
elle est préservée, à null effacée. Section Différences d'arrondi dans
Paramètres > Facturation ; export ; import d'une sauvegarde antérieure prouvé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a1): revue de code P1 — compte d'arrondi validé seulement s'il change, Playwright nettoyé en finally (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): story créée — le compte de différences d'arrondi dans les plans livrés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P1 — 3 MED, 2 LOW remédiés ; #488 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P2 ciblée — close, 0 > LOW ; dev démarré (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a2): le compte 6940 Différences d'arrondi dans les plans livrés, désigné d'office (refs #476)

Marqueur de plan roundingDifference (pas de rôle, pas de numéro dans le code),
validé au chargement ; les deux insert_with_defaults* désignent le compte marqué
du plan de la société (FOR UPDATE), NULL sans erreur s'il manque. Rien chez les
sociétés existantes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a2): revue de code P1 — marqueur sans rôle, erreur de plan tracée, types liés par l'enum (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): revue de code P2 ciblée — close, 0 finding ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): story créée — l'arrondi au centime et l'écart en écriture (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P1 — double borne brut/arrondi, échelle du règlement manuel, sites triés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P2 — échelle normalisée, contrôle client des décimales, reste sous le demi-centime tracé (#490) (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P3 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P3 ciblée — montant reçu tel quel, décimales sur la forme big.js, test d'échelle discriminant, #490 reformulée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P4 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P4 ciblée — 0 finding, boucle close (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-b): solder au centime, l'écart d'arrondi en troisième ligne (refs #476)

Le reste dû peut porter quatre décimales (10.0050) ; QR, rappels et dialogue
réclament 10.01, que le rapprochement ne proposait pas et que le règlement
manuel refusait en trop-perçu. Toute comparaison se fait au centime
(amount_due_to_centime) ; un paiement égal au reste arrondi solde la facture,
réglée au reste brut, l'écart passant sur le compte de différences d'arrondi
(double borne : entre brut et arrondi, trop-perçu). Sans compte utilisable,
refus dédié ROUNDING_ACCOUNT_NOT_CONFIGURED, rien d'écrit. Règlement manuel à
plus de deux décimales refusé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P1 (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-b): revue de code P1 — invariant tracé au rapprochement, compte d'arrondi produit testé (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P2 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): revue de code P2 ciblée — close, aucune correction de production ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): story créée — l'arrondi à 5 centimes figé à la validation (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P1 — refus contextualisé, ordre des refus, références corrigées (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P2 — sites de la variante et emplacement du refus écrits (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P3 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P3 ciblée — l'avoir à arrondi nul n'exige aucun compte (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P4 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P4 ciblée — 0 finding, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-a): arrondir à 5 centimes le total des pièces émises, figé à la validation (refs #494)

Le total TTC d'une facture validée est arrondi au multiple de 0.05 (123.44 →
123.45, 234.52 → 234.50) ; l'écart, sans TVA, est figé sur la facture
(invoices.rounding_amount) et écrit en dernière ligne de l'écriture de vente
sur le compte de différences d'arrondi. Toutes les formes du TTC l'intègrent
(reste dû, listes, rapprochement, QR, PDF, e-mail). L'avoir le recopie et
l'annule en miroir. Réglage par société, actif par défaut. Refus à contexte :
le message d'émission ne parle plus de paiement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-a): revue de code P1 — forme jointe du crédit symétrique, manuel admin rectifié, avoir et sauvegarde testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): revue de code P2 ciblée — 0 finding, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): story créée — l'arrondi à 5 centimes, visible et réglable (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P1 — aperçu sur toute réponse brouillon, récapitulatif traduit, doc-comment rectifié (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P2 — type résolu clarifié, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-b): l'arrondi à 5 centimes visible et réglable (refs #494)

Ligne « Arrondi » signée au PDF de la facture, de l'avoir et du rappel, et
sur la fiche (aperçu « estimé » pour un brouillon, calculé par le serveur et
porté par toute réponse qui rend un brouillon, dévalidation comprise). Le
réglage roundTo5Centimes est exposé (GET/PUT, préservé s'il est absent) et
se règle dans Paramètres → Facturation ; les factures émises gardent leur
total. Récapitulatif de la fiche traduit, manuels et CHANGELOG à jour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-b): revue de code P1 — réglage lu sans écriture, arrondi décidé au centime, manuel rectifié, avoir et rappel testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): revue de code P2 ciblée — 0 réel, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): story créée — un montant minimum configurable sous lequel une facture n'est pas émise (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): validation P1 — sites qui énumèrent les colonnes nommés ; prompt P2 (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): validation P2 ciblée — sites hors dépôt explicités, boucle close (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-e): un montant minimum configurable sous lequel une facture n'est pas émise (refs #495)

Réglage company_invoice_settings.minimum_invoice_amount (NULL = aucun seuil,
le défaut) ; la validation refuse une facture dont le total arrondi est
inférieur (INVOICE_BELOW_MINIMUM, message à deux montants). Avoirs exemptés.
API qui préserve l'absent, section Montant minimum dans Paramètres →
Facturation, manuels et CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): prompt de la revue de code P1 (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-e): revue de code P1 — seuil comparé au centime, plafond, helper d'export réellement appelé (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): prompt de la revue de code P2 ciblée (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): revue de code P2 ciblée — 0 au-dessus de LOW, boucle close ; story done (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): story créée — les comptes de solde (escompte, frais bancaires, perte sur débiteur) ; 25-4-d découpée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): validation P1 — test de comptage à créer, double marqueur interdit, messages préservés ; prompt P2 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): validation P2 ciblée — boucle close (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-d1): les comptes de solde — escompte, frais bancaires, perte sur débiteur (refs #384)

Marqueur de plan writeOffNature (discount, bankFees, badDebt), validé par le
même helper que le compte d'arrondi (messages de l'arrondi inchangés), double
marqueur refusé. Plans livrés : 3805 Pertes sur créances ajouté aux trois,
6900 marqué frais bancaires, 3800 marqué escompte (PME, indépendant).

Migration 20261001000003 : trois comptes désignés dans
company_invoice_settings (BIGINT NULL, FK RESTRICT), désignés d'office à la
création d'une société par un helper commun avec l'arrondi. API (absent
préservé, null effacé, validé s'il change), section « Solde du reste » dans
Paramètres → Facturation, quatre locales, manuel admin, CHANGELOG.

Le solde lui-même (écriture, bouton) suit en 25-4-d2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): prompt de la revue de code P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d1): revue P1 — double marqueur nommé avant le type ; manuel admin précisé (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): prompt de la revue de code P2 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): revue de code P2 ciblée — 0 finding, boucle close ; story done (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4): fixture du test de la fiche (25-6-b) complétée de l'arrondi (refs #494)

La fusion de main apporte invoice-pdf-page.test.ts, dont la fixture
InvoiceResponse ignorait roundingAmount / roundingIsPreview ajoutés par
la c4 : npm run check rougissait (1 erreur), tests et build passaient.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
guycorbaz added a commit that referenced this pull request Oct 5, 2026
…384, refs #490) (#510)

* docs(25-4-c): story créée — le résiduel au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): arbitrages Q1–Q3 retenus par défaut, rebase sur la b2 (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P1 — 3 HIGH, 2 MED, 1 LOW remédiés (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P2 — 0 finding sans preuve, 2 MED repris par l'orchestrateur (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): références de lignes du verrou recontrôlées (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P3 consignée — 1 CRIT / 3 HIGH, découpage et arbitrages en attente (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): découpée — verrou en 25-4-c2 (#480), arrondi en 25-4-c3 (#476) ; périmètre réduit au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P4 — 1 MED, 1 LOW remédiés (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P5 ciblée — close, 0 > LOW (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): le rapprochement reconnaît le solde d'une facture réglée en partie (refs #420)

Le filtre des candidates, le score, le re-score à l'acceptation et le
montant affiché portent sur le reste dû (TTC − avoir − règlements), par
la forme jointe ; le TTC ne suit qu'en mention quand les deux diffèrent.
Manuel et brochure réécrits sur le score réel ; #481 ouverte pour le reste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): revue de code P1 — CHANGELOG replacé, traductions univoques, Playwright départagé (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): revue de code P2 — close, 0 > LOW ; story done (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): story créée — l'invariant de version au règlement, et le rejeu sur interblocage (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P1 — 1 HIGH, 2 MED, 2 LOW remédiés (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P2 — close, 0 > LOW (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): un règlement partiel marque la facture, et l'acceptation rejoue un interblocage (refs #480)

Le règlement manuel incrémente invoices.version à chaque règlement, partiel
compris : le verrou optimiste de l'acceptation refuse désormais celle qui
arrive après un règlement concurrent. Un interblocage absorbé dans une
proposition (ROLLBACK TO SAVEPOINT en 1305) remonte en TransactionAborted et
la route rejoue le lot par retry_with. Trois tests de course sans sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): revue de code P1 — gardes rows_affected, RELEASE SAVEPOINT, verrou de test détaché (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(25-4-c3): arbitrage de Guy — l'écart d'arrondi passe en écriture ; PR #485 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3): découpée en a1 / a2 / b ; story c3-a1 créée — le réglage du compte d'arrondi (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P1 — 2 MED remédiés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P2 ciblée — close, 0 > LOW (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a1): désigner le compte de différences d'arrondi dans les paramètres (refs #476)

Nouvelle colonne company_invoice_settings.default_rounding_account_id (DDL seul,
non breaking), validée charge ou produit, actif, imputable ; absente d'un PUT
elle est préservée, à null effacée. Section Différences d'arrondi dans
Paramètres > Facturation ; export ; import d'une sauvegarde antérieure prouvé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a1): revue de code P1 — compte d'arrondi validé seulement s'il change, Playwright nettoyé en finally (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): story créée — le compte de différences d'arrondi dans les plans livrés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P1 — 3 MED, 2 LOW remédiés ; #488 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P2 ciblée — close, 0 > LOW ; dev démarré (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a2): le compte 6940 Différences d'arrondi dans les plans livrés, désigné d'office (refs #476)

Marqueur de plan roundingDifference (pas de rôle, pas de numéro dans le code),
validé au chargement ; les deux insert_with_defaults* désignent le compte marqué
du plan de la société (FOR UPDATE), NULL sans erreur s'il manque. Rien chez les
sociétés existantes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a2): revue de code P1 — marqueur sans rôle, erreur de plan tracée, types liés par l'enum (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): revue de code P2 ciblée — close, 0 finding ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): story créée — l'arrondi au centime et l'écart en écriture (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P1 — double borne brut/arrondi, échelle du règlement manuel, sites triés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P2 — échelle normalisée, contrôle client des décimales, reste sous le demi-centime tracé (#490) (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P3 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P3 ciblée — montant reçu tel quel, décimales sur la forme big.js, test d'échelle discriminant, #490 reformulée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P4 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P4 ciblée — 0 finding, boucle close (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-b): solder au centime, l'écart d'arrondi en troisième ligne (refs #476)

Le reste dû peut porter quatre décimales (10.0050) ; QR, rappels et dialogue
réclament 10.01, que le rapprochement ne proposait pas et que le règlement
manuel refusait en trop-perçu. Toute comparaison se fait au centime
(amount_due_to_centime) ; un paiement égal au reste arrondi solde la facture,
réglée au reste brut, l'écart passant sur le compte de différences d'arrondi
(double borne : entre brut et arrondi, trop-perçu). Sans compte utilisable,
refus dédié ROUNDING_ACCOUNT_NOT_CONFIGURED, rien d'écrit. Règlement manuel à
plus de deux décimales refusé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P1 (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-b): revue de code P1 — invariant tracé au rapprochement, compte d'arrondi produit testé (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P2 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): revue de code P2 ciblée — close, aucune correction de production ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): story créée — l'arrondi à 5 centimes figé à la validation (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P1 — refus contextualisé, ordre des refus, références corrigées (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P2 — sites de la variante et emplacement du refus écrits (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P3 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P3 ciblée — l'avoir à arrondi nul n'exige aucun compte (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P4 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P4 ciblée — 0 finding, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-a): arrondir à 5 centimes le total des pièces émises, figé à la validation (refs #494)

Le total TTC d'une facture validée est arrondi au multiple de 0.05 (123.44 →
123.45, 234.52 → 234.50) ; l'écart, sans TVA, est figé sur la facture
(invoices.rounding_amount) et écrit en dernière ligne de l'écriture de vente
sur le compte de différences d'arrondi. Toutes les formes du TTC l'intègrent
(reste dû, listes, rapprochement, QR, PDF, e-mail). L'avoir le recopie et
l'annule en miroir. Réglage par société, actif par défaut. Refus à contexte :
le message d'émission ne parle plus de paiement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-a): revue de code P1 — forme jointe du crédit symétrique, manuel admin rectifié, avoir et sauvegarde testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): revue de code P2 ciblée — 0 finding, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): story créée — l'arrondi à 5 centimes, visible et réglable (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P1 — aperçu sur toute réponse brouillon, récapitulatif traduit, doc-comment rectifié (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P2 — type résolu clarifié, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-b): l'arrondi à 5 centimes visible et réglable (refs #494)

Ligne « Arrondi » signée au PDF de la facture, de l'avoir et du rappel, et
sur la fiche (aperçu « estimé » pour un brouillon, calculé par le serveur et
porté par toute réponse qui rend un brouillon, dévalidation comprise). Le
réglage roundTo5Centimes est exposé (GET/PUT, préservé s'il est absent) et
se règle dans Paramètres → Facturation ; les factures émises gardent leur
total. Récapitulatif de la fiche traduit, manuels et CHANGELOG à jour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-b): revue de code P1 — réglage lu sans écriture, arrondi décidé au centime, manuel rectifié, avoir et rappel testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): revue de code P2 ciblée — 0 réel, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): story créée — un montant minimum configurable sous lequel une facture n'est pas émise (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): validation P1 — sites qui énumèrent les colonnes nommés ; prompt P2 (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): validation P2 ciblée — sites hors dépôt explicités, boucle close (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-e): un montant minimum configurable sous lequel une facture n'est pas émise (refs #495)

Réglage company_invoice_settings.minimum_invoice_amount (NULL = aucun seuil,
le défaut) ; la validation refuse une facture dont le total arrondi est
inférieur (INVOICE_BELOW_MINIMUM, message à deux montants). Avoirs exemptés.
API qui préserve l'absent, section Montant minimum dans Paramètres →
Facturation, manuels et CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): prompt de la revue de code P1 (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-e): revue de code P1 — seuil comparé au centime, plafond, helper d'export réellement appelé (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): prompt de la revue de code P2 ciblée (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): revue de code P2 ciblée — 0 au-dessus de LOW, boucle close ; story done (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): story créée — les comptes de solde (escompte, frais bancaires, perte sur débiteur) ; 25-4-d découpée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): validation P1 — test de comptage à créer, double marqueur interdit, messages préservés ; prompt P2 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): validation P2 ciblée — boucle close (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-d1): les comptes de solde — escompte, frais bancaires, perte sur débiteur (refs #384)

Marqueur de plan writeOffNature (discount, bankFees, badDebt), validé par le
même helper que le compte d'arrondi (messages de l'arrondi inchangés), double
marqueur refusé. Plans livrés : 3805 Pertes sur créances ajouté aux trois,
6900 marqué frais bancaires, 3800 marqué escompte (PME, indépendant).

Migration 20261001000003 : trois comptes désignés dans
company_invoice_settings (BIGINT NULL, FK RESTRICT), désignés d'office à la
création d'une société par un helper commun avec l'arrondi. API (absent
préservé, null effacé, validé s'il change), section « Solde du reste » dans
Paramètres → Facturation, quatre locales, manuel admin, CHANGELOG.

Le solde lui-même (écriture, bouton) suit en 25-4-d2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): prompt de la revue de code P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d1): revue P1 — double marqueur nommé avant le type ; manuel admin précisé (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): prompt de la revue de code P2 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): revue de code P2 ciblée — 0 finding, boucle close ; story done (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): story créée — l'écriture de solde et son annulation ; 25-4-d2 découpée (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P1 — rejeu sur interblocage, CHECK distincts, garde de TVA, invariant du solde total (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P2 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P2 — annulation bloquée par un solde, version exigée, facture payée sans ligne refusée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P3 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P3 — motif d'annulation traduit à l'écran, son rang, test du sens inverse (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P4 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P4 ciblée — boucle close (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-d2a): solder le reste d'une facture — l'écriture et son annulation (refs #384, refs #490)

POST /api/v1/invoices/{id}/write-off { nature, settledOn, version } éteint
tout le reste dû d'une facture validée, imputé au compte de sa nature
(escompte, frais bancaires, perte sur débiteur, reste d'arrondi). Écriture
OD ; escompte et perte corrigent la TVA due au prorata des taux de la
facture, ventilation figée sur la ligne (write_off_vat).

Migration 20261001000004 : type write_off dans invoice_settlements, nature,
ventilation JSON, CHECK recréés. Compte de la nature relu au moment d'écrire
(cœur commun avec le compte d'arrondi). Un règlement ne s'annule pas tant
qu'un solde existe (INVOICE_WRITTEN_OFF, rang 1 bis), dé-rapprochement
compris. Route rejouée sur interblocage, sûre par la version. Un reste
inférieur au demi-centime se solde en nature rounding (#490).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de la revue de code P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2a): revue P1 — fraction de centime au compte d'arrondi, compte de TVA relu, tests du dé-rapprochement et des taux mêlés (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de la revue de code P2 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2a): revue P2 — un reste sous le demi-centime va au compte d'arrondi quelle que soit la nature ; ordre des verrous rétabli (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de la revue de code P3 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): revue de code P3 ciblée — boucle close ; story done (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4): fixture du test de la fiche (25-6-b) complétée de l'arrondi (refs #494)

La fusion de main apporte invoice-pdf-page.test.ts, dont la fixture
InvoiceResponse ignorait roundingAmount / roundingIsPreview ajoutés par
la c4 : npm run check rougissait (1 erreur), tests et build passaient.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
guycorbaz added a commit that referenced this pull request Oct 5, 2026
…loses #505) (#511)

* docs(25-4-c): story créée — le résiduel au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): arbitrages Q1–Q3 retenus par défaut, rebase sur la b2 (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P1 — 3 HIGH, 2 MED, 1 LOW remédiés (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P2 — 0 finding sans preuve, 2 MED repris par l'orchestrateur (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): références de lignes du verrou recontrôlées (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P3 consignée — 1 CRIT / 3 HIGH, découpage et arbitrages en attente (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): découpée — verrou en 25-4-c2 (#480), arrondi en 25-4-c3 (#476) ; périmètre réduit au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P4 — 1 MED, 1 LOW remédiés (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P5 ciblée — close, 0 > LOW (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): le rapprochement reconnaît le solde d'une facture réglée en partie (refs #420)

Le filtre des candidates, le score, le re-score à l'acceptation et le
montant affiché portent sur le reste dû (TTC − avoir − règlements), par
la forme jointe ; le TTC ne suit qu'en mention quand les deux diffèrent.
Manuel et brochure réécrits sur le score réel ; #481 ouverte pour le reste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): revue de code P1 — CHANGELOG replacé, traductions univoques, Playwright départagé (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): revue de code P2 — close, 0 > LOW ; story done (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): story créée — l'invariant de version au règlement, et le rejeu sur interblocage (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P1 — 1 HIGH, 2 MED, 2 LOW remédiés (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P2 — close, 0 > LOW (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): un règlement partiel marque la facture, et l'acceptation rejoue un interblocage (refs #480)

Le règlement manuel incrémente invoices.version à chaque règlement, partiel
compris : le verrou optimiste de l'acceptation refuse désormais celle qui
arrive après un règlement concurrent. Un interblocage absorbé dans une
proposition (ROLLBACK TO SAVEPOINT en 1305) remonte en TransactionAborted et
la route rejoue le lot par retry_with. Trois tests de course sans sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): revue de code P1 — gardes rows_affected, RELEASE SAVEPOINT, verrou de test détaché (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(25-4-c3): arbitrage de Guy — l'écart d'arrondi passe en écriture ; PR #485 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3): découpée en a1 / a2 / b ; story c3-a1 créée — le réglage du compte d'arrondi (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P1 — 2 MED remédiés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P2 ciblée — close, 0 > LOW (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a1): désigner le compte de différences d'arrondi dans les paramètres (refs #476)

Nouvelle colonne company_invoice_settings.default_rounding_account_id (DDL seul,
non breaking), validée charge ou produit, actif, imputable ; absente d'un PUT
elle est préservée, à null effacée. Section Différences d'arrondi dans
Paramètres > Facturation ; export ; import d'une sauvegarde antérieure prouvé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a1): revue de code P1 — compte d'arrondi validé seulement s'il change, Playwright nettoyé en finally (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): story créée — le compte de différences d'arrondi dans les plans livrés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P1 — 3 MED, 2 LOW remédiés ; #488 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P2 ciblée — close, 0 > LOW ; dev démarré (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a2): le compte 6940 Différences d'arrondi dans les plans livrés, désigné d'office (refs #476)

Marqueur de plan roundingDifference (pas de rôle, pas de numéro dans le code),
validé au chargement ; les deux insert_with_defaults* désignent le compte marqué
du plan de la société (FOR UPDATE), NULL sans erreur s'il manque. Rien chez les
sociétés existantes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a2): revue de code P1 — marqueur sans rôle, erreur de plan tracée, types liés par l'enum (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): revue de code P2 ciblée — close, 0 finding ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): story créée — l'arrondi au centime et l'écart en écriture (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P1 — double borne brut/arrondi, échelle du règlement manuel, sites triés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P2 — échelle normalisée, contrôle client des décimales, reste sous le demi-centime tracé (#490) (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P3 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P3 ciblée — montant reçu tel quel, décimales sur la forme big.js, test d'échelle discriminant, #490 reformulée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P4 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P4 ciblée — 0 finding, boucle close (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-b): solder au centime, l'écart d'arrondi en troisième ligne (refs #476)

Le reste dû peut porter quatre décimales (10.0050) ; QR, rappels et dialogue
réclament 10.01, que le rapprochement ne proposait pas et que le règlement
manuel refusait en trop-perçu. Toute comparaison se fait au centime
(amount_due_to_centime) ; un paiement égal au reste arrondi solde la facture,
réglée au reste brut, l'écart passant sur le compte de différences d'arrondi
(double borne : entre brut et arrondi, trop-perçu). Sans compte utilisable,
refus dédié ROUNDING_ACCOUNT_NOT_CONFIGURED, rien d'écrit. Règlement manuel à
plus de deux décimales refusé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P1 (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-b): revue de code P1 — invariant tracé au rapprochement, compte d'arrondi produit testé (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P2 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): revue de code P2 ciblée — close, aucune correction de production ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): story créée — l'arrondi à 5 centimes figé à la validation (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P1 — refus contextualisé, ordre des refus, références corrigées (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P2 — sites de la variante et emplacement du refus écrits (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P3 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P3 ciblée — l'avoir à arrondi nul n'exige aucun compte (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P4 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P4 ciblée — 0 finding, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-a): arrondir à 5 centimes le total des pièces émises, figé à la validation (refs #494)

Le total TTC d'une facture validée est arrondi au multiple de 0.05 (123.44 →
123.45, 234.52 → 234.50) ; l'écart, sans TVA, est figé sur la facture
(invoices.rounding_amount) et écrit en dernière ligne de l'écriture de vente
sur le compte de différences d'arrondi. Toutes les formes du TTC l'intègrent
(reste dû, listes, rapprochement, QR, PDF, e-mail). L'avoir le recopie et
l'annule en miroir. Réglage par société, actif par défaut. Refus à contexte :
le message d'émission ne parle plus de paiement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-a): revue de code P1 — forme jointe du crédit symétrique, manuel admin rectifié, avoir et sauvegarde testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): revue de code P2 ciblée — 0 finding, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): story créée — l'arrondi à 5 centimes, visible et réglable (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P1 — aperçu sur toute réponse brouillon, récapitulatif traduit, doc-comment rectifié (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P2 — type résolu clarifié, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-b): l'arrondi à 5 centimes visible et réglable (refs #494)

Ligne « Arrondi » signée au PDF de la facture, de l'avoir et du rappel, et
sur la fiche (aperçu « estimé » pour un brouillon, calculé par le serveur et
porté par toute réponse qui rend un brouillon, dévalidation comprise). Le
réglage roundTo5Centimes est exposé (GET/PUT, préservé s'il est absent) et
se règle dans Paramètres → Facturation ; les factures émises gardent leur
total. Récapitulatif de la fiche traduit, manuels et CHANGELOG à jour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-b): revue de code P1 — réglage lu sans écriture, arrondi décidé au centime, manuel rectifié, avoir et rappel testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): revue de code P2 ciblée — 0 réel, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): story créée — un montant minimum configurable sous lequel une facture n'est pas émise (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): validation P1 — sites qui énumèrent les colonnes nommés ; prompt P2 (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): validation P2 ciblée — sites hors dépôt explicités, boucle close (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-e): un montant minimum configurable sous lequel une facture n'est pas émise (refs #495)

Réglage company_invoice_settings.minimum_invoice_amount (NULL = aucun seuil,
le défaut) ; la validation refuse une facture dont le total arrondi est
inférieur (INVOICE_BELOW_MINIMUM, message à deux montants). Avoirs exemptés.
API qui préserve l'absent, section Montant minimum dans Paramètres →
Facturation, manuels et CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): prompt de la revue de code P1 (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-e): revue de code P1 — seuil comparé au centime, plafond, helper d'export réellement appelé (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): prompt de la revue de code P2 ciblée (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): revue de code P2 ciblée — 0 au-dessus de LOW, boucle close ; story done (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): story créée — les comptes de solde (escompte, frais bancaires, perte sur débiteur) ; 25-4-d découpée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): validation P1 — test de comptage à créer, double marqueur interdit, messages préservés ; prompt P2 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): validation P2 ciblée — boucle close (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-d1): les comptes de solde — escompte, frais bancaires, perte sur débiteur (refs #384)

Marqueur de plan writeOffNature (discount, bankFees, badDebt), validé par le
même helper que le compte d'arrondi (messages de l'arrondi inchangés), double
marqueur refusé. Plans livrés : 3805 Pertes sur créances ajouté aux trois,
6900 marqué frais bancaires, 3800 marqué escompte (PME, indépendant).

Migration 20261001000003 : trois comptes désignés dans
company_invoice_settings (BIGINT NULL, FK RESTRICT), désignés d'office à la
création d'une société par un helper commun avec l'arrondi. API (absent
préservé, null effacé, validé s'il change), section « Solde du reste » dans
Paramètres → Facturation, quatre locales, manuel admin, CHANGELOG.

Le solde lui-même (écriture, bouton) suit en 25-4-d2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): prompt de la revue de code P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d1): revue P1 — double marqueur nommé avant le type ; manuel admin précisé (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): prompt de la revue de code P2 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): revue de code P2 ciblée — 0 finding, boucle close ; story done (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): story créée — l'écriture de solde et son annulation ; 25-4-d2 découpée (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P1 — rejeu sur interblocage, CHECK distincts, garde de TVA, invariant du solde total (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P2 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P2 — annulation bloquée par un solde, version exigée, facture payée sans ligne refusée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P3 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P3 — motif d'annulation traduit à l'écran, son rang, test du sens inverse (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P4 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P4 ciblée — boucle close (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-d2a): solder le reste d'une facture — l'écriture et son annulation (refs #384, refs #490)

POST /api/v1/invoices/{id}/write-off { nature, settledOn, version } éteint
tout le reste dû d'une facture validée, imputé au compte de sa nature
(escompte, frais bancaires, perte sur débiteur, reste d'arrondi). Écriture
OD ; escompte et perte corrigent la TVA due au prorata des taux de la
facture, ventilation figée sur la ligne (write_off_vat).

Migration 20261001000004 : type write_off dans invoice_settlements, nature,
ventilation JSON, CHECK recréés. Compte de la nature relu au moment d'écrire
(cœur commun avec le compte d'arrondi). Un règlement ne s'annule pas tant
qu'un solde existe (INVOICE_WRITTEN_OFF, rang 1 bis), dé-rapprochement
compris. Route rejouée sur interblocage, sûre par la version. Un reste
inférieur au demi-centime se solde en nature rounding (#490).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de la revue de code P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2a): revue P1 — fraction de centime au compte d'arrondi, compte de TVA relu, tests du dé-rapprochement et des taux mêlés (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de la revue de code P2 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2a): revue P2 — un reste sous le demi-centime va au compte d'arrondi quelle que soit la nature ; ordre des verrous rétabli (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de la revue de code P3 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): revue de code P3 ciblée — boucle close ; story done (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): story créée — le bouton, le dialogue et la liste du solde (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de validation P1 (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): les deux limites assumées tracées en CR (#496, #497) (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): validation P1 — compte d'arrondi pour toute nature, annulation dite « solde », récapitulatif sans liste, version relue (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de validation P2 (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): validation P2 — 409 distingués par code, comparaisons en big.js, reste aux quatre décimales, sites du symptôme ; #496 corrigée (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de validation P3 ciblée (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): validation P3 — fermeture du dialogue et cas complémentaire reliés ; montage E2E par le formulaire (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de validation P4 ciblée (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): validation P4 ciblée — boucle close (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-d2b): solder le reste depuis la fiche — bouton, dialogue, liste (refs #384, refs #490)

Bouton « Solder le reste » (Comptable+) et dialogue : nature au choix, montant
non saisi (le reste dû, aux quatre décimales s'il porte une fraction de
centime), compte manquant signalé avant l'envoi — y compris le compte
d'arrondi pour toute nature sur une fraction de centime. Version de la
facture affichée envoyée ; refus distingués par code (409 de version : dialogue
ouvert et version relue ; facture dévalidée ou payée : fermeture).

Liste : « Solde — nature », « Annuler le solde » ; récapitulatif « Déjà réglé »
/ « Soldé », réduit au reste dû sans liste fiable. Manuels utilisateur et
admin, CHANGELOG (#496, #497 cités).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de la revue de code P1 (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2b): revue P1 — fermeture bloquée pendant l'envoi, dialogue toujours monté, reste exact à l'échéancier (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de la revue de code P2 ciblée (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2b): revue P2 — garde du parent retirée, reste inconnu expliqué, relecture après validation, échéancier au format exact (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de la revue de code P3 ciblée (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): revue de code P3 ciblée — boucle close ; story done (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4): fixture du test de la fiche (25-6-b) complétée de l'arrondi (refs #494)

La fusion de main apporte invoice-pdf-page.test.ts, dont la fixture
InvoiceResponse ignorait roundingAmount / roundingIsPreview ajoutés par
la c4 : npm run check rougissait (1 erreur), tests et build passaient.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2b): fixture du test de solde complétée du PDF figé (refs #490)

La fusion de main apporte pdfFrozenAt / pdfLanguage (25-6-b) dans
InvoiceResponse ; la fixture d'invoice-write-off-page.test.ts les
ignorait : npm run check rougissait (1 erreur), tests et E2E passaient.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
guycorbaz added a commit that referenced this pull request Oct 5, 2026
…) (#512)

* docs(25-4-c): story créée — le résiduel au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): arbitrages Q1–Q3 retenus par défaut, rebase sur la b2 (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P1 — 3 HIGH, 2 MED, 1 LOW remédiés (refs #420, refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P2 — 0 finding sans preuve, 2 MED repris par l'orchestrateur (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): références de lignes du verrou recontrôlées (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P3 consignée — 1 CRIT / 3 HIGH, découpage et arbitrages en attente (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): découpée — verrou en 25-4-c2 (#480), arrondi en 25-4-c3 (#476) ; périmètre réduit au rapprochement (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P4 — 1 MED, 1 LOW remédiés (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): validation P5 ciblée — close, 0 > LOW (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): le rapprochement reconnaît le solde d'une facture réglée en partie (refs #420)

Le filtre des candidates, le score, le re-score à l'acceptation et le
montant affiché portent sur le reste dû (TTC − avoir − règlements), par
la forme jointe ; le TTC ne suit qu'en mention quand les deux diffèrent.
Manuel et brochure réécrits sur le score réel ; #481 ouverte pour le reste.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c): revue de code P1 — CHANGELOG replacé, traductions univoques, Playwright départagé (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c): revue de code P2 — close, 0 > LOW ; story done (refs #420)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): story créée — l'invariant de version au règlement, et le rejeu sur interblocage (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P1 — 1 HIGH, 2 MED, 2 LOW remédiés (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): validation P2 — close, 0 > LOW (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): un règlement partiel marque la facture, et l'acceptation rejoue un interblocage (refs #480)

Le règlement manuel incrémente invoices.version à chaque règlement, partiel
compris : le verrou optimiste de l'acceptation refuse désormais celle qui
arrive après un règlement concurrent. Un interblocage absorbé dans une
proposition (ROLLBACK TO SAVEPOINT en 1305) remonte en TransactionAborted et
la route rejoue le lot par retry_with. Trois tests de course sans sleep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c2): revue de code P1 — gardes rows_affected, RELEASE SAVEPOINT, verrou de test détaché (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c2): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #480)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(25-4-c3): arbitrage de Guy — l'écart d'arrondi passe en écriture ; PR #485 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3): découpée en a1 / a2 / b ; story c3-a1 créée — le réglage du compte d'arrondi (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P1 — 2 MED remédiés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): validation P2 ciblée — close, 0 > LOW (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a1): désigner le compte de différences d'arrondi dans les paramètres (refs #476)

Nouvelle colonne company_invoice_settings.default_rounding_account_id (DDL seul,
non breaking), validée charge ou produit, actif, imputable ; absente d'un PUT
elle est préservée, à null effacée. Section Différences d'arrondi dans
Paramètres > Facturation ; export ; import d'une sauvegarde antérieure prouvé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a1): revue de code P1 — compte d'arrondi validé seulement s'il change, Playwright nettoyé en finally (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a1): revue de code P2 ciblée — close, 0 > LOW ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): story créée — le compte de différences d'arrondi dans les plans livrés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P1 — 3 MED, 2 LOW remédiés ; #488 ouverte (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): validation P2 ciblée — close, 0 > LOW ; dev démarré (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-a2): le compte 6940 Différences d'arrondi dans les plans livrés, désigné d'office (refs #476)

Marqueur de plan roundingDifference (pas de rôle, pas de numéro dans le code),
validé au chargement ; les deux insert_with_defaults* désignent le compte marqué
du plan de la société (FOR UPDATE), NULL sans erreur s'il manque. Rien chez les
sociétés existantes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-a2): revue de code P1 — marqueur sans rôle, erreur de plan tracée, types liés par l'enum (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-a2): revue de code P2 ciblée — close, 0 finding ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): story créée — l'arrondi au centime et l'écart en écriture (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P1 — double borne brut/arrondi, échelle du règlement manuel, sites triés (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P2 — échelle normalisée, contrôle client des décimales, reste sous le demi-centime tracé (#490) (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P3 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P3 ciblée — montant reçu tel quel, décimales sur la forme big.js, test d'échelle discriminant, #490 reformulée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la validation P4 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): validation P4 ciblée — 0 finding, boucle close (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c3-b): solder au centime, l'écart d'arrondi en troisième ligne (refs #476)

Le reste dû peut porter quatre décimales (10.0050) ; QR, rappels et dialogue
réclament 10.01, que le rapprochement ne proposait pas et que le règlement
manuel refusait en trop-perçu. Toute comparaison se fait au centime
(amount_due_to_centime) ; un paiement égal au reste arrondi solde la facture,
réglée au reste brut, l'écart passant sur le compte de différences d'arrondi
(double borne : entre brut et arrondi, trop-perçu). Sans compte utilisable,
refus dédié ROUNDING_ACCOUNT_NOT_CONFIGURED, rien d'écrit. Règlement manuel à
plus de deux décimales refusé.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P1 (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c3-b): revue de code P1 — invariant tracé au rapprochement, compte d'arrondi produit testé (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): prompt de la revue de code P2 ciblée (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c3-b): revue de code P2 ciblée — close, aucune correction de production ; story done (refs #476)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): story créée — l'arrondi à 5 centimes figé à la validation (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P1 — refus contextualisé, ordre des refus, références corrigées (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P2 — sites de la variante et emplacement du refus écrits (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P3 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P3 ciblée — l'avoir à arrondi nul n'exige aucun compte (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la validation P4 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): validation P4 ciblée — 0 finding, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-a): arrondir à 5 centimes le total des pièces émises, figé à la validation (refs #494)

Le total TTC d'une facture validée est arrondi au multiple de 0.05 (123.44 →
123.45, 234.52 → 234.50) ; l'écart, sans TVA, est figé sur la facture
(invoices.rounding_amount) et écrit en dernière ligne de l'écriture de vente
sur le compte de différences d'arrondi. Toutes les formes du TTC l'intègrent
(reste dû, listes, rapprochement, QR, PDF, e-mail). L'avoir le recopie et
l'annule en miroir. Réglage par société, actif par défaut. Refus à contexte :
le message d'émission ne parle plus de paiement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-a): revue de code P1 — forme jointe du crédit symétrique, manuel admin rectifié, avoir et sauvegarde testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-a): revue de code P2 ciblée — 0 finding, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): story créée — l'arrondi à 5 centimes, visible et réglable (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P1 — aperçu sur toute réponse brouillon, récapitulatif traduit, doc-comment rectifié (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la validation P2 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): validation P2 — type résolu clarifié, boucle close (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-c4-b): l'arrondi à 5 centimes visible et réglable (refs #494)

Ligne « Arrondi » signée au PDF de la facture, de l'avoir et du rappel, et
sur la fiche (aperçu « estimé » pour un brouillon, calculé par le serveur et
porté par toute réponse qui rend un brouillon, dévalidation comprise). Le
réglage roundTo5Centimes est exposé (GET/PUT, préservé s'il est absent) et
se règle dans Paramètres → Facturation ; les factures émises gardent leur
total. Récapitulatif de la fiche traduit, manuels et CHANGELOG à jour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P1 (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4-b): revue de code P1 — réglage lu sans écriture, arrondi décidé au centime, manuel rectifié, avoir et rappel testés (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): prompt de la revue de code P2 ciblée (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-c4-b): revue de code P2 ciblée — 0 réel, boucle close ; story done (refs #494)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): story créée — un montant minimum configurable sous lequel une facture n'est pas émise (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): validation P1 — sites qui énumèrent les colonnes nommés ; prompt P2 (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): validation P2 ciblée — sites hors dépôt explicités, boucle close (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-e): un montant minimum configurable sous lequel une facture n'est pas émise (refs #495)

Réglage company_invoice_settings.minimum_invoice_amount (NULL = aucun seuil,
le défaut) ; la validation refuse une facture dont le total arrondi est
inférieur (INVOICE_BELOW_MINIMUM, message à deux montants). Avoirs exemptés.
API qui préserve l'absent, section Montant minimum dans Paramètres →
Facturation, manuels et CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): prompt de la revue de code P1 (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-e): revue de code P1 — seuil comparé au centime, plafond, helper d'export réellement appelé (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): prompt de la revue de code P2 ciblée (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-e): revue de code P2 ciblée — 0 au-dessus de LOW, boucle close ; story done (refs #495)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): story créée — les comptes de solde (escompte, frais bancaires, perte sur débiteur) ; 25-4-d découpée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): validation P1 — test de comptage à créer, double marqueur interdit, messages préservés ; prompt P2 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): validation P2 ciblée — boucle close (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-d1): les comptes de solde — escompte, frais bancaires, perte sur débiteur (refs #384)

Marqueur de plan writeOffNature (discount, bankFees, badDebt), validé par le
même helper que le compte d'arrondi (messages de l'arrondi inchangés), double
marqueur refusé. Plans livrés : 3805 Pertes sur créances ajouté aux trois,
6900 marqué frais bancaires, 3800 marqué escompte (PME, indépendant).

Migration 20261001000003 : trois comptes désignés dans
company_invoice_settings (BIGINT NULL, FK RESTRICT), désignés d'office à la
création d'une société par un helper commun avec l'arrondi. API (absent
préservé, null effacé, validé s'il change), section « Solde du reste » dans
Paramètres → Facturation, quatre locales, manuel admin, CHANGELOG.

Le solde lui-même (écriture, bouton) suit en 25-4-d2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): prompt de la revue de code P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d1): revue P1 — double marqueur nommé avant le type ; manuel admin précisé (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): prompt de la revue de code P2 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d1): revue de code P2 ciblée — 0 finding, boucle close ; story done (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): story créée — l'écriture de solde et son annulation ; 25-4-d2 découpée (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P1 — rejeu sur interblocage, CHECK distincts, garde de TVA, invariant du solde total (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P2 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P2 — annulation bloquée par un solde, version exigée, facture payée sans ligne refusée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P3 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P3 — motif d'annulation traduit à l'écran, son rang, test du sens inverse (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de validation P4 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): validation P4 ciblée — boucle close (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-d2a): solder le reste d'une facture — l'écriture et son annulation (refs #384, refs #490)

POST /api/v1/invoices/{id}/write-off { nature, settledOn, version } éteint
tout le reste dû d'une facture validée, imputé au compte de sa nature
(escompte, frais bancaires, perte sur débiteur, reste d'arrondi). Écriture
OD ; escompte et perte corrigent la TVA due au prorata des taux de la
facture, ventilation figée sur la ligne (write_off_vat).

Migration 20261001000004 : type write_off dans invoice_settlements, nature,
ventilation JSON, CHECK recréés. Compte de la nature relu au moment d'écrire
(cœur commun avec le compte d'arrondi). Un règlement ne s'annule pas tant
qu'un solde existe (INVOICE_WRITTEN_OFF, rang 1 bis), dé-rapprochement
compris. Route rejouée sur interblocage, sûre par la version. Un reste
inférieur au demi-centime se solde en nature rounding (#490).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de la revue de code P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2a): revue P1 — fraction de centime au compte d'arrondi, compte de TVA relu, tests du dé-rapprochement et des taux mêlés (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de la revue de code P2 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2a): revue P2 — un reste sous le demi-centime va au compte d'arrondi quelle que soit la nature ; ordre des verrous rétabli (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): prompt de la revue de code P3 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2a): revue de code P3 ciblée — boucle close ; story done (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): story créée — le bouton, le dialogue et la liste du solde (refs #384, refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de validation P1 (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): les deux limites assumées tracées en CR (#496, #497) (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): validation P1 — compte d'arrondi pour toute nature, annulation dite « solde », récapitulatif sans liste, version relue (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de validation P2 (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): validation P2 — 409 distingués par code, comparaisons en big.js, reste aux quatre décimales, sites du symptôme ; #496 corrigée (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de validation P3 ciblée (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): validation P3 — fermeture du dialogue et cas complémentaire reliés ; montage E2E par le formulaire (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de validation P4 ciblée (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): validation P4 ciblée — boucle close (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-d2b): solder le reste depuis la fiche — bouton, dialogue, liste (refs #384, refs #490)

Bouton « Solder le reste » (Comptable+) et dialogue : nature au choix, montant
non saisi (le reste dû, aux quatre décimales s'il porte une fraction de
centime), compte manquant signalé avant l'envoi — y compris le compte
d'arrondi pour toute nature sur une fraction de centime. Version de la
facture affichée envoyée ; refus distingués par code (409 de version : dialogue
ouvert et version relue ; facture dévalidée ou payée : fermeture).

Liste : « Solde — nature », « Annuler le solde » ; récapitulatif « Déjà réglé »
/ « Soldé », réduit au reste dû sans liste fiable. Manuels utilisateur et
admin, CHANGELOG (#496, #497 cités).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de la revue de code P1 (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2b): revue P1 — fermeture bloquée pendant l'envoi, dialogue toujours monté, reste exact à l'échéancier (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de la revue de code P2 ciblée (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2b): revue P2 — garde du parent retirée, reste inconnu expliqué, relecture après validation, échéancier au format exact (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): prompt de la revue de code P3 ciblée (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2b): revue de code P3 ciblée — boucle close ; story done (refs #490)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): story créée — le rapport TVA retranche la TVA des soldes (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): prompt de validation P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): validation P1 — garde « vide » de l'écran, signe du delta, fixtures (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): prompt de validation P2 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): validation P2 — E2E reports ancré, limite fiscale du solde annulé, erreur CorruptData, sites du manuel (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): prompt de validation P3 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): validation P3 — E2E avant l'annulation, gardes Rust testés, rendus conditionnels ; découpage reposé à Guy (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): prompt de validation P4 ciblée (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): arbitrage de Guy — pas de découpage (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): validation P4 ciblée — boucle close (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(25-4-d2c): le rapport TVA retranche la TVA des soldes (refs #384)

Diminutions de contre-prestation par taux (escompte, perte sur débiteur)
datées dans la période, TVA due nette, solde AFC sur le net ; delta de
réconciliation net contre grand livre net. Rendus CSV, PDF, écran
conditionnels ; JSON de ventilation corrompu → 500. Manuel et CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(25-4-d2c): prompt de revue de code P1 (refs #384)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2c): revue de code P1 — 0 > LOW, boucle close (refs #384)

Test de l'agrégation de deux soldes au même taux, limite du compte
d'arrondi écrite, ligne vide du CHANGELOG. Story done.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-c4): fixture du test de la fiche (25-6-b) complétée de l'arrondi (refs #494)

La fusion de main apporte invoice-pdf-page.test.ts, dont la fixture
InvoiceResponse ignorait roundingAmount / roundingIsPreview ajoutés par
la c4 : npm run check rougissait (1 erreur), tests et build passaient.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(25-4-d2b): fixture du test de solde complétée du PDF figé (refs #490)

La fusion de main apporte pdfFrozenAt / pdfLanguage (25-6-b) dans
InvoiceResponse ; la fixture d'invoice-write-off-page.test.ts les
ignorait : npm run check rougissait (1 erreur), tests et E2E passaient.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Le rapprochement accepte une facture sans la verrouiller : double règlement possible contre un règlement manuel

1 participant