fix: aligne le dashboard sur la règle flux / stock
All checks were successful
Build and Publish Docker Image / Build App Image (push) Successful in 22s
Build and Publish Docker Image / Build Summary (push) Successful in 3s

L'accueil et la page Revenus calculaient leurs totaux chacun de leur
côté : le premier lisait le dernier compte rendu, la seconde cumulait
tout. Les deux écrans affichaient donc deux impayés différents pour la
même notion — 49 374 € contre 247 354 €.

Les raccourcis immeubles cumulaient la dette, et les courbes mensuelles
réintégraient le report chaque mois, ce qui rendait deux mois
incomparables. Tous passent par les mêmes règles que la page Revenus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 10:50:15 +02:00
parent 3e2d103929
commit 11bd3ca539
2 changed files with 158 additions and 46 deletions

View File

@@ -0,0 +1,101 @@
"""Le dashboard et la page Revenus doivent annoncer les memes chiffres.
Les deux ecrans calculaient leurs totaux chacun de leur cote, avec des regles
differentes : l'accueil lisait le dernier compte rendu, la page Revenus cumulait
tout. Ils affichaient donc deux montants d'impayes pour la meme notion. Ces
tests verrouillent leur accord.
"""
import copy
from datetime import date, timedelta
import pytest
from plesna_gerance.database.service import DatabaseService
def _mois_glissant(recul: int) -> str:
jour = date.today().replace(day=15)
for _ in range(recul):
jour = (jour.replace(day=1) - timedelta(days=1)).replace(day=15)
return jour.isoformat()
@pytest.fixture
def deux_comptes_rendus(db_session, sample_data):
"""Un impaye de 300 ne le mois dernier, reporte et non regle ce mois-ci."""
service = DatabaseService(db_session)
premier = copy.deepcopy(sample_data)
premier["metadata"]["document"]["reference"] = "M1"
premier["metadata"]["document"]["date"] = _mois_glissant(1)
premier["situation_locataires"][0]["lignes"] = [
{
"type": "loyer",
"periode": {"debut": None, "fin": None},
"loyers": 800.0,
"total": 800.0,
"regles": 500.0,
"impayes": 300.0,
}
]
service.save_document(data=premier)
second = copy.deepcopy(sample_data)
second["metadata"]["document"]["reference"] = "M2"
second["metadata"]["document"]["date"] = _mois_glissant(0)
second["situation_locataires"][0]["lignes"] = [
{
"type": "solde_anterieur",
"periode": {"debut": None, "fin": None},
"loyers": 300.0,
"total": 300.0,
"regles": 0.0,
"impayes": 300.0,
},
{
"type": "loyer",
"periode": {"debut": None, "fin": None},
"loyers": 800.0,
"total": 800.0,
"regles": 800.0,
"impayes": 0.0,
},
]
service.save_document(data=second)
return db_session
def test_les_deux_ecrans_annoncent_le_meme_impaye(api_client, deux_comptes_rendus):
"""300 dus, vus depuis l'accueil comme depuis la page Revenus."""
accueil = api_client.get("/api/dashboard/financial-summary").json()
revenus = api_client.get("/api/revenus/summary").json()
assert accueil["impayes"] == 300.0
assert revenus["kpis"]["total_impayes"] == 300.0
def test_le_revenu_du_dernier_compte_rendu_exclut_le_report(
api_client, deux_comptes_rendus
):
"""Le mois vaut son loyer de 800, pas 1100 report compris."""
accueil = api_client.get("/api/dashboard/financial-summary").json()
assert accueil["revenus"] == 800.0
def test_les_raccourcis_immeubles_ne_cumulent_pas_la_dette(
api_client, deux_comptes_rendus
):
"""Le raccourci montre la dette en cours, pas sa somme mois apres mois."""
(raccourci,) = api_client.get("/api/dashboard/immeubles-shortcuts").json()
assert raccourci["total_impayes"] == 300.0
assert raccourci["total_revenus"] == 1600.0 # 800 + 800, report exclu
def test_la_tendance_mensuelle_reste_comparable(api_client, deux_comptes_rendus):
"""Chaque mois pese son loyer, sinon le second parait meilleur qu'il n'est."""
tendances = api_client.get("/api/dashboard/monthly-trends").json()
assert [point["revenus"] for point in tendances] == [800.0, 800.0]