feat: detection des colonnes par libelle d'en-tete #327

Closed
opened 2026-08-12 20:14:33 +00:00 by maximus · 0 comments
Owner

Refs: spec-decisions-import-csv-format.md + spec-plan-import-csv-format.md (racine du repo).

Contexte

La detection actuelle est aveugle aux libelles et ne raisonne que sur la forme des donnees :

  • src/utils/csvAutoDetect.ts:461-470 assigne le debit et le credit par ordre de colonne (colA est toujours le debit, la boucle impose a < b). Un fichier Date;Description;Credit;Debit est inverse integralement.
  • detectHeader (:214-238) retourne !hasDate && !hasNumber : un en-tete contenant « Solde 2024 » passe pour une ligne de donnees.
  • detectDescriptionColumn (:404-434) prend la colonne la plus longue en moyenne.

Le savoir-faire manquant est dans le meme fichier : le flux d'import de titres (#245) fait du matching par libelle via normalizeHeaderCell et matchHeaderColumn (:633-666). Il s'agit de le generaliser, pas de le reecrire.

Taches

  • Remonter normalizeHeaderCell et matchHeaderColumn en helpers partages du module, sans changer leur comportement
  • Dictionnaire FR/EN : date ; description (libelle, detail, transaction) ; montant (amount) ; debit (retrait, debourse, withdrawal) ; credit (depot, encaissement, deposit) ; solde (balance)
  • Ordre debit/credit resolu par libelle plutot que par position
  • detectHeader : signal lexical en complement de la forme
  • Repli explicite sur l'heuristique de forme actuelle quand les libelles sont muets (fichier sans en-tete, libelles inconnus)
  • Tests sur les fixtures de l'issue precedente, dont l'inversion credit-avant-debit

Points d'attention

Les tests holdings existants doivent rester verts — les helpers sont partages, leur comportement ne change pas.

Criteres d'acceptation

  • Un fichier Date;Description;Credit;Debit est mappe dans le bon ordre sans intervention
  • Un en-tete contenant un nombre est reconnu comme en-tete
  • Un fichier sans en-tete continue d'etre traite par l'heuristique de forme

Revision /review-spec — 2026-08-13

Corrections a appliquer, issues de la revue 3 experts :

  • Ordre change : cette issue depend desormais de #325.
  • Retirer la tache de « remontage » des helpers — c'est un no-op : normalizeHeaderCell (:633) et matchHeaderColumn (:646) sont deja au niveau module du meme fichier. La mitigation du plan couvrait un risque inexistant.
  • Le vrai couplage est le dictionnaire : montant est un token d'exclusion pour les titres (VALUE_HEADER_KEYWORDS, :630) et le mot-cle de montant principal pour les transactions. Mettre le dictionnaire transactions dans son propre module, a cote de bankSignatures.ts, en important les deux helpers et en laissant les tables holdings intactes. csvAutoDetect.ts fait deja 856 lignes pour deux flux sans rapport.
  • Ajouter le refus du troisieme format (decision tranchee) : le document de decisions promet qu'un fichier « montant absolu + indicateur D/C » sera refuse explicitement, et aucune issue ne le livrait. Sans la regle, un tel fichier presente une colonne tous-positifs, detectSingleAmount rend positive_expense, et chaque debit est importe comme un revenu. Detecter (montants tous positifs + colonne voisine a une seule lettre D/C) et refuser avec un message dedie.

Depends on #325


Fichiers concernes

  • src/utils/headerDictionary.tscreer : dictionnaire FR/EN des libelles transactions
  • src/utils/csvAutoDetect.ts — couche lexicale en amont de l'heuristique ; ne PAS toucher les tables holdings
  • src/utils/csvAutoDetect.test.ts — tests sur fixtures

Decisions prises en planification

  • Emplacement du code partage : le codec formatToRow/formatFromRow et mapRow vivent dans src/utils/importFormat.ts — meme dossier que amountParser, dateParser et csvAutoDetect, qui portent deja la logique pure du domaine. Les types restent dans src/shared/types/.
  • Aucune correction retroactive des transactions deja importees a l'envers : la voie de reparation est deleteImportWithTransactions puis re-import. Ne jamais muter des montants deja ecrits.
  • L'import reste entierement en edition Free — aucun gating a ajouter.
  • Les specs spec-decisions-import-csv-format.md et spec-plan-import-csv-format.md sont committees a la racine (force-add, precedent PR #295) : elles sont lisibles depuis un worktree.

Spec source

spec-plan-import-csv-format.md + spec-decisions-import-csv-format.md (racine du repo, committees).

Refs: `spec-decisions-import-csv-format.md` + `spec-plan-import-csv-format.md` (racine du repo). ## Contexte La detection actuelle est aveugle aux libelles et ne raisonne que sur la forme des donnees : - `src/utils/csvAutoDetect.ts:461-470` assigne le debit et le credit **par ordre de colonne** (`colA` est toujours le debit, la boucle impose `a < b`). Un fichier `Date;Description;Credit;Debit` est inverse integralement. - `detectHeader` (`:214-238`) retourne `!hasDate && !hasNumber` : un en-tete contenant « Solde 2024 » passe pour une ligne de donnees. - `detectDescriptionColumn` (`:404-434`) prend la colonne la plus longue en moyenne. Le savoir-faire manquant est **dans le meme fichier** : le flux d'import de titres (#245) fait du matching par libelle via `normalizeHeaderCell` et `matchHeaderColumn` (`:633-666`). Il s'agit de le generaliser, pas de le reecrire. ## Taches - [ ] Remonter `normalizeHeaderCell` et `matchHeaderColumn` en helpers partages du module, sans changer leur comportement - [ ] Dictionnaire FR/EN : date ; description (libelle, detail, transaction) ; montant (amount) ; debit (retrait, debourse, withdrawal) ; credit (depot, encaissement, deposit) ; solde (balance) - [ ] Ordre debit/credit resolu par libelle plutot que par position - [ ] `detectHeader` : signal lexical en complement de la forme - [ ] Repli explicite sur l'heuristique de forme actuelle quand les libelles sont muets (fichier sans en-tete, libelles inconnus) - [ ] Tests sur les fixtures de l'issue precedente, dont l'inversion credit-avant-debit ## Points d'attention Les tests holdings existants doivent rester verts — les helpers sont partages, leur comportement ne change pas. ## Criteres d'acceptation - [ ] Un fichier `Date;Description;Credit;Debit` est mappe dans le bon ordre sans intervention - [ ] Un en-tete contenant un nombre est reconnu comme en-tete - [ ] Un fichier sans en-tete continue d'etre traite par l'heuristique de forme --- ## Revision /review-spec — 2026-08-13 Corrections a appliquer, issues de la revue 3 experts : - **Ordre change** : cette issue depend desormais de #325. - **Retirer la tache de « remontage » des helpers** — c'est un no-op : `normalizeHeaderCell` (`:633`) et `matchHeaderColumn` (`:646`) sont deja au niveau module du meme fichier. La mitigation du plan couvrait un risque inexistant. - **Le vrai couplage est le dictionnaire** : `montant` est un token d'**exclusion** pour les titres (`VALUE_HEADER_KEYWORDS`, `:630`) et le mot-cle de montant **principal** pour les transactions. Mettre le dictionnaire transactions dans son propre module, a cote de `bankSignatures.ts`, en important les deux helpers et en laissant les tables holdings intactes. `csvAutoDetect.ts` fait deja 856 lignes pour deux flux sans rapport. - **Ajouter le refus du troisieme format** (decision tranchee) : le document de decisions promet qu'un fichier « montant absolu + indicateur `D`/`C` » sera refuse explicitement, et aucune issue ne le livrait. Sans la regle, un tel fichier presente une colonne tous-positifs, `detectSingleAmount` rend `positive_expense`, et chaque debit est importe comme un revenu. Detecter (montants tous positifs + colonne voisine a une seule lettre D/C) et refuser avec un message dedie. Depends on #325 --- ## Fichiers concernes - `src/utils/headerDictionary.ts` — **creer** : dictionnaire FR/EN des libelles transactions - `src/utils/csvAutoDetect.ts` — couche lexicale en amont de l'heuristique ; ne PAS toucher les tables holdings - `src/utils/csvAutoDetect.test.ts` — tests sur fixtures ## Decisions prises en planification - **Emplacement du code partage** : le codec `formatToRow`/`formatFromRow` et `mapRow` vivent dans `src/utils/importFormat.ts` — meme dossier que `amountParser`, `dateParser` et `csvAutoDetect`, qui portent deja la logique pure du domaine. Les types restent dans `src/shared/types/`. - **Aucune correction retroactive** des transactions deja importees a l'envers : la voie de reparation est `deleteImportWithTransactions` puis re-import. Ne jamais muter des montants deja ecrits. - **L'import reste entierement en edition Free** — aucun gating a ajouter. - Les specs `spec-decisions-import-csv-format.md` et `spec-plan-import-csv-format.md` sont **committees a la racine** (force-add, precedent PR #295) : elles sont lisibles depuis un worktree. ## Spec source `spec-plan-import-csv-format.md` + `spec-decisions-import-csv-format.md` (racine du repo, committees).
maximus added this to the planned-2026-08-12-import-csv-format milestone 2026-08-12 20:14:33 +00:00
maximus added the
status:ready
type:feature
source:human
labels 2026-08-12 20:14:33 +00:00
maximus added
status:in-progress
and removed
status:ready
labels 2026-08-13 17:44:12 +00:00
maximus added
status:needs-fix
and removed
status:in-progress
labels 2026-08-14 15:32:49 +00:00
maximus added
status:approved
and removed
status:needs-fix
labels 2026-08-14 16:03:38 +00:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#327
No description provided.