feat(budget): flip grid to income-first + add Résultat rows #285
No reviewers
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/Simpl-Resultat#285
Loading…
Reference in a new issue
No description provided.
Delete branch "issue-278-budget-grid-income-first"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Generated autonomously by /autopilot run of 2026-07-11
Aligns the budget grid (
BudgetTable) on the income-statement standard already shipped for the compare/trend reports (epic #260).Summary
TYPE_ORDER(useBudget.ts) andtypeOrder(BudgetTable.tsx) to income-first (income → expense → transfer), replacing the previous expense-first ordering.src/components/budget/budgetTableResults.ts— a new pure, tested module (computeBudgetResults) that rolls up the grid's leaves into Résultat avant transferts (income − expense) and Résultat net (+ transfers), across the previous-year-actual, budgeted-annual, and budgeted-monthly columns. Shape mirrorscompareResults.ts(studied per the issue's guidance).BudgetTable.tsx: the old unlabeled grand-"Total" row is replaced by the two Résultat rows, interleaved the same way asComparePeriodTable/CategoryOverTimeTable(Résultat avant transferts sits between the expense and transfer sections, shown only when transfers exist; Résultat net is always the bottom line). Mathematically equivalent to the old total for every input — only the labeling/positioning changed.reports.compare.resultBeforeTransfers/reports.compare.resultNeti18n keys (already FR/EN) rather than adding duplicates — no new strings needed.## [Unreleased]/### Changed.Frozen decisions honored
reorderRows) is untouched and orthogonal (reorders, never hides)..tsx.Testing
budgetTableResults.test.ts, zero regressions.npm run build(tsc + vite) green.Caveat for reviewer
useBudget.ts,budgetTableResults.ts+ test,BudgetTable.tsx);BudgetVsActualTable/budgetService.ts(sibling issue #277, BVA) and the dashboard (#279) were left untouched.Resolves #278
/pr-review— PR #285 (issue #278)VERDICT : APPROVE
Flip income-first de la grille budget + lignes Résultat, propre et bien testé. Scope respecté à la lettre (useBudget / BudgetTable / nouveau module pur + test), aucun résidu expense-first, filtre
accountIdsM1 préservé, aucune migration.Vérifications (toutes ✓)
TYPE_ORDER(useBudget.ts:74) ettypeOrder(BudgetTable.tsx:133) flippés en income→expense→transfer ; rendu piloté par des appels explicitesrenderTypeSection("income"/"expense"/"transfer"). Aucuncommon.totalni ordre expense-first résiduel sur la branche. LeTYPE_ORDERexpense-first restant dansbudgetService.ts:214alimente le rapport BVA (#277), hors scope explicite de cette PR — pas un défaut ici.resultBefore = income + expense(dépenses pré-signées négatives viasignForBudgetType, donc income − |expense|),resultNet = resultBefore + transfer.previousYearTotalnon re-signé (déjà signé en DB), conforme à l'ancien code.resultNetest mathématiquement équivalent à l'ancien grand-total pour toute entrée :category_typeest strictementincome|expense|transfer(shared/types/index.ts:145), donc aucun leaf n'est exclu du repli.computeBudgetResults/sumLeavesForTypefiltrentis_parent→ pas de double-comptage, pas de bug type-#254 (et la grille n'a de toute façon aucun repli ; togglereorderRows/subtotals intact et orthogonal).getActualTotalsForYear(year-1, ids)propageaccountIds→getActualsByCategoryRangeen SQL paramétrée (inPlaceholders+params.push,source_id IN (...)par placeholders, pas d'injection). Budgété non filtré par compte (correct, un budget n'est pas lié à un compte).budgetTableResults.test.ts), arithmétique vérifiée cas par cas (income−expense, transfert déséquilibré à une jambe, déficit, exclusion parent, pass-through prevYear non re-signé, helper de signe). Aucun.only/.skip. Build + 798 vitest annoncés verts.reports.compare.resultBeforeTransfers/resultNetréutilisées (présentes FR et EN, l.446-447) ; en-têtes viabudget.*existants. Zéro chaîne en dur.[Unreleased] / Changed. Aucune migration DB touchée. Commit conventional,Resolves #278.Suggestions (non bloquantes)
typeOrderdansBudgetTable.tsxn'est plus lu qu'au niveau type ((typeof typeOrder)[number]) — l'ordre de rendu vient désormais des appels explicites, pas de l'itération du tableau. De même le volet cross-type deTYPE_ORDER(useBudget) est masqué par le re-groupage de la table. Les deux flips sont donc « belt-and-suspenders » (corrects, mais l'ordre visuel réel tient aux appels JSX). Rien à corriger — juste à garder en tête si un futur refactor s'appuie sur ces tableaux.hasTransfers→ insertion deresultBefore) n'est pas couvert par un test composant. La logique pure l'est ; conforme à la convention du repo (tests sur modules purs). OK de laisser tel quel.reports.compare.*depuis un écran Budget crée un léger couplage de namespace ; acceptable vu les chaînes identiques et l'intention DRY.Mergée localement dans
maindans le cadre de la pile M2 (a982f9e) — merge--no-ff+ résolution des conflits CHANGELOG (union #277/#278/#279). Forgejo ne marque pas les merges locaux comme merged ; fermeture manuelle. Issue liée auto-fermée viaResolves #N. Tip cumulé validé : tsc + vite build, 811 vitest, cargo check + 98 tests Rust.Pull request closed