fix: remove expense filter from Category Over Time report (#41) #42
No reviewers
Labels
No labels
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
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#42
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/simpl-resultat-41-category-time-report-filter"
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?
Summary
t.amount < 0filter from the Category Over Time report so all transaction types (expenses, income, transfers) are shown by defaultChanges
src/services/reportService.tst.amount < 0WHERE clause, added optionaltypeFilterparametersrc/hooks/useReports.tscategoryTypestate andsetCategoryTypeactionsrc/components/reports/ReportFilterPanel.tsxsrc/pages/ReportsPage.tsxsrc/i18n/locales/{fr,en}.jsonreports.filters.allTypeskeyCHANGELOG.md/CHANGELOG.fr.mddocs/guide-utilisateur.mdTest plan
npm test— all 17 tests passRef: simpl-resultat#41
Reviewer automatique — needs-fix
Le retrait du filtre
t.amount < 0résout l'issue mais introduit un problème de correctness dans le classement des top N catégories : les montants positifs (revenus) et négatifs (dépenses) sont maintenant mélangés, ce qui peut fausser le tri et masquer des catégories pertinentes. Aucun test n'est ajouté pour couvrir la nouvelle logique.Suggestions de simplification
hasCategoriesinclut déjàstate.tab === 'overTime'(quand filterCategories.length > 0). La conditionshowFilterPanelajoute maintenantstate.tab === 'overTime'séparément pour le cas où filterCategories est vide. C'est correct mais la logique devient redondante et difficile à suivre. Considérer simplifier en :const showFilterPanel = state.tab === 'overTime' || (state.tab === 'byCategory' && filterCategories.length > 0) || (state.tab === 'trends' && sources.length > 1);Problemes detectes
t.amount < 0change silencieusement la requête 'top N categories by total spend' plus bas. Avant, elle triait par montant de dépense (négatif). Maintenant, revenus (positifs) et dépenses (négatifs) sont mélangés — le SUM() peut s'annuler ou les revenus dominer le classement. Il faut adapter la requête topCategories pour trier parABS(SUM(t.amount))ou parSUM(t.amount)selon le type, sinon le top N sera incohérent quand aucun typeFilter n'est appliqué.COALESCE(c.type, 'expense')suppose que les catégories sans type sont des dépenses. Si des catégories onttype = NULLmais ne sont pas des dépenses, elles seront mal classifiées. Vérifier que cette hypothèse est correcte dans le schéma, ou utiliser un type explicite ('unknown') pour ne pas les inclure par erreur dans le filtre 'expense'.(e.target.value || null) as CategoryTypeFilter— le castascontourne le type-checking. Si une valeur inattendue apparaît, aucune validation ne la bloque. Préférer une fonction de validation ou au minimum un type guard pour garantir que seules les valeurs valides passent.Reviewer automatique — needs-fix
Les commentaires du round 1 sont largement adressés (tests ajoutés, typeFilter avec défaut 'expense' pour éviter le mélange). Cependant, le CHANGELOG est inexact (dit 'all types by default' alors que le défaut est 'expense'), et le cast non validé dans le select onChange pourrait laisser passer une valeur inattendue.
Suggestions de simplification
t.amount < 0versCOALESCE(c.type, 'expense')) est plus correct mais n'est pas équivalent : une transaction positive sur une catégorie 'expense' (ex: remboursement) sera maintenant incluse, et une dépense sans catégorie assignée ne sera plus filtrée par montant. C'est probablement le comportement voulu mais un commentaire inline clarifierait l'intention du COALESCE.Problemes detectes
initialState.categoryTypeest"expense"(useReports.ts:64). Le comportement par défaut reste filtré sur les dépenses, pas tous les types. Le CHANGELOG induit en erreur. Corriger : 'now filters by category type instead of amount sign, defaults to expense'.(e.target.value || null) as CategoryTypeFilterest un cast non sécurisé. Si le DOM est manipulé ou si une valeur inattendue arrive, elle passerait directement dans la query SQL (paramétrisée, donc pas d'injection, mais résultat silencieusement vide). Préférer une validation runtime :const val = e.target.value; const valid: CategoryTypeFilter[] = ['expense','income','transfer']; onCategoryTypeChange(valid.includes(val as any) ? val as CategoryTypeFilter : null).Reviewer automatique — approved
Les deux problèmes du round 2 sont corrigés : le CHANGELOG mentionne maintenant correctement 'dépense par défaut', et le select onChange valide la valeur contre une whitelist avant de la propager. Le code est correct, les requêtes SQL sont paramétrées, les tests couvrent les cas pertinents (filtres individuels, combinés, structure de retour, groupement Other).
Suggestions de simplification