feat(reports): BVA (actual vs budget) income-first + result lines #286
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#286
Loading…
Reference in a new issue
No description provided.
Delete branch "issue-277-bva-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?
Aligns
BudgetVsActualTable(actual vs budget) on the income-statement gold standard already shipped for the real-vs-real compare report (#253/#256).Changes
src/services/budgetService.ts:TYPE_ORDERflipped from expense-first to income-first (income → expense → transfer), matchingCOMPARE_TYPE_ORDER/OVER_TIME_TYPE_ORDER.src/components/reports/budgetVsActualResults.ts(mirrorscompareResults.ts):sumLeaves,pct,computeResultsproducingresultBefore(income + expense) andresultNet(+ transfers).src/components/reports/BudgetVsActualTable.tsx: extracted the inline section-totals reduce intorenderSection(now backed by the pure module), addedrenderResultRow, and replaced the old flat "Total" row with interleaved Result before transfers (shown only when transfers exist) and Net result lines — same structural placement asComparePeriodTable.reports.compare.resultBeforeTransfers/reports.compare.resultNetkeys (already FR+EN) per the issue's guidance.CHANGELOG.md+CHANGELOG.fr.md) under[Unreleased]/### Changed.Sign-convention note (why
computeResultsdiffers fromcompareResults)Real-vs-real compare ABS's expense magnitudes (positive), so its operating result is
income − expense. BVA'sgetBudgetVsActualDatadoes not ABS actual expenses —monthActual/ytdActualare the rawSUM(transactions.amount)(negative for expense categories, per this app'samount < 0= expense convention used throughoutreportService.ts/dashboardService.ts), and the budget figure is negated to match via the existingsignFor. So expense totals here are already ≤ 0, andresultBeforeis a straight add of income + expense (not a subtraction) — verified against the old flat grand-total, which (because of this same sign convention) was already numerically equal to what is nowresultNet; this PR only changes its position/label/section order, not its value. Leaf and section amounts are byte-for-byte unchanged.Testing
npm testbaseline on fresh branch: 791 passed. After: 797 passed (48 files) — 6 new tests inbudgetVsActualResults.test.ts, zero regressions.npm run build(tsc + vite): green.Resolves #277
Generated autonomously by /autopilot run of 2026-07-11
/pr-review — PR #286 ·
feat(reports): BVA income-first + result linesVerdict : APPROVE
Résumé
Aligne
BudgetVsActualTable(réel vs budget) sur le standard « analyse de résultat » déjà livré pour le compare réel-vs-réel (#253/#256). Extraction propre d'un module pur testé,TYPE_ORDERpassé income-first, lignes de résultat interleavées. Logique correcte, régression nulle vérifiée, CI verte.Vérifications
resultNetbyte-for-byte. Le total plat sommait toutes les feuilles (income + expense + transfer, dépense déjà signée négative viasignFor) ;resultNet = add(add(income, expense), transfer)produit exactement la même valeur. Seuls la position, le libellé et le tri de section changent — confirmé.compareResults(dépenses ABS'd positives →income − expense), BVA garde le SUM brut signé (dépense ≤ 0) →resultBeforeest un ajoutincome + expense. Le doc-comment et le test l'expliquent correctement.renderSection/ totaux de section :sumLeaves(section.rows)etpct(variation, budget)reproduisent à l'identique lereduceinline et le calcul de pct de l'ancien code (pas de×100, appliqué parpctFormatter). Aucun changement de comportement sur les feuilles/sections.hasTransfers↔transferSection:getBudgetVsActualDatane pousse une section transfert que si elle a ≥1 feuille non-nulle → les deux gardes sont toujours cohérentes (ligne « Résultat avant transferts » affichée ssi une section transfert suit).BudgetVsActualRow.category_typeest l'union"expense" | "income" | "transfer"(non-optionnelle), donc pas besoin du fallback?? "expense"decompareResults— correct.renderResultRow/ structurenonTransferSections → resultBefore → transferSection → resultNetcalquée fidèlement surComparePeriodTable.reports.compare.resultBeforeTransfers/resultNetprésentes FR+EN (aucune string en dur). CHANGELOG sous[Unreleased] / Changeddans les deux fichiers.budgetVsActualResults.test.ts(roll-up, signe dépense, transfert non nul, déficit, exclusionis_parent, YTD) — assertions vérifiées à la main, toutes exactes. Aucun.skip/.only. Suite 797 verte + CIsuccess.Suggestions (non bloquantes)
pcthomonymes coexistent désormais (compareResults.pctavec×100,budgetVsActualResults.pctsans). Chacun est correct pour son formateur respectif (formatPctdivise /pctFormattermultiplie), mais l'homonymie à signature identique est un piège au copier-coller. Le doc-comment debudgetVsActualResults.pctmitige déjà — rien à corriger.ComparePeriodTable, mais colorer un montant budgété en vert/rouge peut surprendre. Cosmétique, aligné sur le sibling — OK de garder.Beau travail, fusionnable en l'état.
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