fix(budget): objectif — 1 seul "Assigner suggéré" par mois + masquer micro-montants #2

Closed
opened 2026-09-01 20:50:03 +02:00 by alexis · 0 comments
Owner

Contexte
Store.suggestedAssignment(c, month) (Store.kt:441) → ceil((targetCents - avail)/monthsLeft) + boutons

  • CategoryRow : TextButton "Assigner X" → Store.setAssigned(id, month, assigned+ sug) (BudgetScreen.kt:834)
  • CategoryDialog : amount = formatForInput(currentAssigned + sug) (:1005)

Repro actuel

  1. Catégorie "Vacances" → Objectif Échéance 60€ dans 4 mois → sug initial 15€ ok
  2. Assigne 15€ en M1 → M2 reste 45€ / 3 mois → 15€ … → M4 reste 4€ / 1 mois → sug 4€, puis 1€, 2€, 5€
  3. Spam : tant que currentSaved < targetTotal et sug>0, le bouton reste affiché → on peut recliquer 3-4× dans le même mois et empiler +1€/+2€/+5€
  4. Ridicule : pour enveloppe 60€ dans 4 mois, proposer 1€/2€/5€ n’a pas de sens (10-15€ attendu).

Attendu (spec)

  • 1 clic / mois max : après 1 succès sur month, bouton disparaît jusqu’au mois suivant. Pas de spam intra-mois. Implémentation : Map<"catId-YYYY-MM", Boolean> ou Set<String> suggestedUsedThisMonth persisté, check if (used) hide ; reset au changement de month.
  • Masquer micro-montants : ne pas proposer si sug est ridicule vs cible. Règle : if (sug < 500 && targetCents >= 6000) hide → seuil 5€ pour cible ≥60€ ; Générique : min = max(500, targetCents * 0.08) (≈8% de la cible, min 5€) → 60€ → 5€, 200€ → 16€

Acceptance

  • suggestedAssignment ou UI filtre sug < seuil → bouton masqué (pas de "0,50€", "1€", "2€", "5€" pour 60€)
  • Après Store.setAssigned(... + sug), marquer usedThisMonth → bouton masqué jusqu’à YearMonth+1
  • hasTxnsThisMonth gardé, mais non bloquant pour le one-shot
  • Test : 60€/4 mois à 59€ → plus de bouton 1€ ; à 45€ (M1) → 1 seul clic 15€ possible, 2e clic même mois impossible
  • Persist usedThisMonth dans budget.json (v3 → v4 tolérant)
**Contexte** `Store.suggestedAssignment(c, month)` (`Store.kt:441`) → `ceil((targetCents - avail)/monthsLeft)` + boutons - `CategoryRow` : `TextButton "Assigner X" → Store.setAssigned(id, month, assigned+ sug)` (`BudgetScreen.kt:834`) - `CategoryDialog` : `amount = formatForInput(currentAssigned + sug)` (`:1005`) **Repro actuel** 1. Catégorie "Vacances" → Objectif Échéance 60€ dans 4 mois → `sug` initial 15€ ok 2. Assigne 15€ en M1 → M2 reste 45€ / 3 mois → 15€ … → M4 reste 4€ / 1 mois → `sug` 4€, puis 1€, 2€, 5€ 3. **Spam** : tant que `currentSaved < targetTotal` et `sug>0`, le bouton reste affiché → on peut recliquer 3-4× dans le même mois et empiler +1€/+2€/+5€ 4. **Ridicule** : pour enveloppe 60€ dans 4 mois, proposer 1€/2€/5€ n’a pas de sens (10-15€ attendu). **Attendu (spec)** - **1 clic / mois max** : après 1 succès sur `month`, bouton disparaît jusqu’au mois suivant. Pas de spam intra-mois. Implémentation : `Map<"catId-YYYY-MM", Boolean>` ou `Set<String> suggestedUsedThisMonth` persisté, check `if (used) hide` ; reset au changement de `month`. - **Masquer micro-montants** : ne pas proposer si `sug` est ridicule vs cible. Règle : `if (sug < 500 && targetCents >= 6000) hide` → seuil 5€ pour cible ≥60€ ; Générique : `min = max(500, targetCents * 0.08)` (≈8% de la cible, min 5€) → 60€ → 5€, 200€ → 16€ **Acceptance** - [ ] `suggestedAssignment` ou UI filtre `sug < seuil` → bouton masqué (pas de "0,50€", "1€", "2€", "5€" pour 60€) - [ ] Après `Store.setAssigned(... + sug)`, marquer `usedThisMonth` → bouton masqué jusqu’à `YearMonth+1` - [ ] `hasTxnsThisMonth` gardé, mais non bloquant pour le one-shot - [ ] Test : 60€/4 mois à 59€ → plus de bouton 1€ ; à 45€ (M1) → 1 seul clic 15€ possible, 2e clic même mois impossible - [ ] Persist `usedThisMonth` dans `budget.json` (`v3 → v4` tolérant)
Sign in to join this conversation.
No labels
No milestone
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
alexis/demo_m3#2
No description provided.