refactor: donne une source unique aux colonnes du compte rendu
L'ordre et les libellés des colonnes étaient retapés à six endroits : l'en-tête du tableau, deux boucles de cellules, la ligne « Totaux », la table des libellés et la liste des colonnes recoupées. Ces copies avaient déjà divergé — le solde antérieur, rendu hors de la boucle, était comparé aux lignes sans que son écart puisse s'afficher dans sa cellule. `COLONNES_CRG` devient la seule déclaration, et tout le reste en dérive ; l'écart du solde antérieur s'affiche du coup là où on le cherche. `ecartsAvecLignes` rapporte maintenant l'extrait, le calculé et ce qui manque entre les deux. Le composant refaisait cette soustraction pour son infobulle, avec un `|| 0` là où l'utilitaire emploie `Number` et `Number.isFinite` : deux règles de coercition pour un même calcul, libres de diverger. Le contenu déplié d'un lot passe de `v-show` à `v-if`. Le tableau des lignes compte une centaine de champs éditables ; les garder montés pour la vingtaine de lots d'un document faisait re-rendre à chaque frappe deux mille champs que personne ne regardait. `setNestedValue` était recopié à l'identique dans trois composants et `formatCurrency` redéfini dans le composant alors que `utils/format.js` existe et dit lui-même que les nouveaux affichages passent par lui. Le premier part dans `utils/chemin.js`, le second cède la place à `formatMontantPrecis`, dont le formateur `Intl` est construit une fois pour toutes. `EditableField` affirmait en dur que sa valeur venait du compte rendu. C'est vrai des trois écrans qui l'emploient aujourd'hui, mais un formulaire de saisie manuelle mentirait sans le savoir : l'origine devient une prop, avec cette valeur par défaut. Le type des lignes de report est défini des deux côtés de l'application sans lien entre eux ; chacun renvoie désormais à l'autre. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,9 +43,10 @@ function lotCharlot(surcharges = {}) {
|
||||
// Les montants sont formatés avec des espaces insécables (séparateur de milliers,
|
||||
// espace avant €) et le template en insère aux sauts de ligne : tous les blancs
|
||||
// sont ramenés à un espace simple pour pouvoir chercher un montant.
|
||||
// `highlighted` déplie la carte : le tableau n'est monté qu'à l'ouverture.
|
||||
async function rendre(locataire) {
|
||||
const app = createSSRApp({
|
||||
render: () => h(LocataireCard, { locataire }),
|
||||
render: () => h(LocataireCard, { locataire, highlighted: true }),
|
||||
})
|
||||
const html = await renderToString(app)
|
||||
return html.replace(/\s+/g, ' ')
|
||||
@@ -109,6 +110,17 @@ describe('LocataireCard', () => {
|
||||
expect(html).toContain('bg-amber-500/10')
|
||||
})
|
||||
|
||||
it('signale aussi le solde antérieur, qui n’a pas de colonne à lui', async () => {
|
||||
// Il occupe la colonne « Période » de la ligne Totaux : son écart doit y
|
||||
// apparaître comme celui des colonnes rendues par la boucle.
|
||||
const lot = lotCharlot()
|
||||
lot.totaux.solde_anterieur = 49170.47
|
||||
|
||||
const html = await rendre(lot)
|
||||
expect(html).toContain('calculé : 0,00 €')
|
||||
expect(html).toContain('A verifier')
|
||||
})
|
||||
|
||||
it('dit au survol ce qui est extrait et ce qui est calculé', async () => {
|
||||
const lot = lotCharlot()
|
||||
lot.totaux.regles = 707.29
|
||||
|
||||
@@ -138,7 +138,10 @@ describe('ecartsAvecLignes', () => {
|
||||
},
|
||||
calcules
|
||||
)
|
||||
expect(ecarts).toEqual({ total: 0, regles: 0 })
|
||||
expect(ecarts).toEqual({
|
||||
total: { extrait: 707.29, calcule: 0, manquant: 707.29 },
|
||||
regles: { extrait: 707.29, calcule: 0, manquant: 707.29 },
|
||||
})
|
||||
})
|
||||
|
||||
it('signale un divers absent des lignes extraites', () => {
|
||||
@@ -146,18 +149,22 @@ describe('ecartsAvecLignes', () => {
|
||||
{ type: 'divers', divers: { montant: -455 } },
|
||||
{ type: 'divers', divers: { montant: 23.02 } },
|
||||
])
|
||||
expect(ecartsAvecLignes({ divers: -123.22 }, calcules)).toEqual({ divers: -431.98 })
|
||||
expect(ecartsAvecLignes({ divers: -123.22 }, calcules)).toEqual({
|
||||
divers: { extrait: -123.22, calcule: -431.98, manquant: 308.76 },
|
||||
})
|
||||
})
|
||||
|
||||
it('signale un lot dont aucune ligne n’a été extraite', () => {
|
||||
// Lot 08 de S_33680000_2025-08-26 : 100 € réglés, aucune ligne.
|
||||
const ecarts = ecartsAvecLignes({ loyers: 0, regles: 100 }, totauxCalcules([]))
|
||||
expect(ecarts).toEqual({ regles: 0 })
|
||||
expect(ecarts).toEqual({ regles: { extrait: 100, calcule: 0, manquant: 100 } })
|
||||
})
|
||||
|
||||
it('renvoie la valeur déduite des lignes, jamais celle du compte rendu', () => {
|
||||
it('rapporte l’extrait, le calculé et ce qui manque entre les deux', () => {
|
||||
const calcules = totauxCalcules([{ type: 'loyer', loyers: 500 }])
|
||||
expect(ecartsAvecLignes({ loyers: 800 }, calcules)).toEqual({ loyers: 500 })
|
||||
expect(ecartsAvecLignes({ loyers: 800 }, calcules)).toEqual({
|
||||
loyers: { extrait: 800, calcule: 500, manquant: 300 },
|
||||
})
|
||||
})
|
||||
|
||||
it('tolère un écart d’arrondi sous le centime', () => {
|
||||
|
||||
Reference in New Issue
Block a user