From 8c959f5d5f7f1fb70b67346e12598c7258e7c545 Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Fri, 31 Jul 2026 14:18:58 +0200 Subject: [PATCH] refactor: donne une source unique aux colonnes du compte rendu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- frontend/src/components/EditableField.vue | 17 +- frontend/src/components/JsonViewer.vue | 14 +- frontend/src/components/LocataireCard.vue | 158 +++++++++---------- frontend/src/components/OperationCard.vue | 14 +- frontend/src/utils/chemin.js | 20 +++ frontend/src/utils/totauxLocataire.js | 78 +++++---- frontend/tests/locataireCard.test.js | 14 +- frontend/tests/totauxLocataire.test.js | 17 +- src/plesna_gerance/services/revenus_query.py | 4 + 9 files changed, 186 insertions(+), 150 deletions(-) create mode 100644 frontend/src/utils/chemin.js diff --git a/frontend/src/components/EditableField.vue b/frontend/src/components/EditableField.vue index 24e48fc..ee7f884 100644 --- a/frontend/src/components/EditableField.vue +++ b/frontend/src/components/EditableField.vue @@ -79,6 +79,15 @@ const props = defineProps({ inputClass: { type: String, default: '' + }, + /** + * D'où vient la valeur, pour l'infobulle. Les trois écrans qui emploient ce + * champ éditent aujourd'hui de l'extraction, d'où ce défaut ; une saisie + * manuelle (référentiel, formulaire) passerait son propre libellé. + */ + origine: { + type: String, + default: 'extraite du compte rendu' } }) @@ -106,12 +115,12 @@ const displayValue = computed(() => { return props.modelValue }) -// Ce composant n'édite que des champs issus de l'extraction : le survol le dit, -// pour qu'on ne confonde jamais une valeur lue dans le PDF avec une valeur déduite. +// Le survol dit d'où vient la valeur, pour qu'on ne la confonde jamais avec une +// valeur déduite affichée à côté. const titreSurvol = computed(() => isEmpty.value - ? "Aucune valeur extraite du compte rendu — cliquer pour la saisir" - : 'Valeur extraite du compte rendu — cliquer pour la modifier' + ? `Aucune valeur ${props.origine} — cliquer pour la saisir` + : `Valeur ${props.origine} — cliquer pour la modifier` ) const inputType = computed(() => { diff --git a/frontend/src/components/JsonViewer.vue b/frontend/src/components/JsonViewer.vue index 16f7ac1..0cfbfc4 100644 --- a/frontend/src/components/JsonViewer.vue +++ b/frontend/src/components/JsonViewer.vue @@ -177,6 +177,7 @@ import DataCard from './DataCard.vue' import DataRow from './DataRow.vue' import LocataireCard from './LocataireCard.vue' import OperationCard from './OperationCard.vue' +import { setNestedValue } from '../utils/chemin' const props = defineProps({ data: { @@ -348,19 +349,6 @@ function cloneData() { return JSON.parse(JSON.stringify(props.data)) } -// Helper pour setter une valeur nested -function setNestedValue(obj, path, value) { - const parts = path.split('.') - let current = obj - for (let i = 0; i < parts.length - 1; i++) { - if (!current[parts[i]]) { - current[parts[i]] = {} - } - current = current[parts[i]] - } - current[parts[parts.length - 1]] = value -} - // Mettre a jour les metadonnees function updateMetadata(path, value) { const updated = cloneData() diff --git a/frontend/src/components/LocataireCard.vue b/frontend/src/components/LocataireCard.vue index c5426bd..4bcc02f 100644 --- a/frontend/src/components/LocataireCard.vue +++ b/frontend/src/components/LocataireCard.vue @@ -63,11 +63,11 @@ title="Valeur extraite, reportée de la ligne Totaux — déplier le lot pour la modifier" >
- {{ formatCurrency(locataire.totaux?.total) }} + {{ formatMontantPrecis(locataire.totaux?.total) }}
{{ locataire.totaux.impayes > 0 ? 'Impayes' : 'Trop-percu' }}: - {{ formatCurrency(Math.abs(locataire.totaux.impayes)) }} + {{ formatMontantPrecis(Math.abs(locataire.totaux.impayes)) }}
@@ -83,8 +83,11 @@ - -
+ +
Detail des lignes
- -
- -
- - - - -
- + + +
- - - -
+ +
@@ -233,7 +231,12 @@ Totaux - + +
Solde ant. + + calculé : {{ formatMontantPrecis(ecarts.solde_anterieur.calcule) }} +
- calculé : {{ formatCurrency(ecarts[champ]) }} + calculé : {{ formatMontantPrecis(ecarts[colonne.champ].calcule) }}
@@ -289,7 +299,14 @@