fix: aligne le dashboard sur la règle flux / stock
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:
@@ -17,6 +17,7 @@ from ...database.models import (
|
||||
Lot,
|
||||
Revenu,
|
||||
)
|
||||
from ...services.revenus_query import est_flux, flux_par, restant_du_par
|
||||
|
||||
router = APIRouter(prefix="/api/dashboard", tags=["dashboard"])
|
||||
|
||||
@@ -114,10 +115,13 @@ async def get_financial_summary(
|
||||
last_document_date = str(last_doc.date)
|
||||
last_document_reference = last_doc.reference
|
||||
|
||||
# Revenus du dernier document
|
||||
# Revenus du dernier document : le solde reporte du mois precedent n'est
|
||||
# pas un revenu du mois, il est deja compte dans les impayes.
|
||||
revenus = (
|
||||
session.execute(
|
||||
select(func.sum(Revenu.total)).where(Revenu.document_id == last_doc.id)
|
||||
select(func.sum(Revenu.total))
|
||||
.where(Revenu.document_id == last_doc.id)
|
||||
.where(est_flux())
|
||||
).scalar()
|
||||
or 0.0
|
||||
)
|
||||
@@ -153,11 +157,13 @@ async def get_financial_summary(
|
||||
impayes_by_month: dict[str, float] = defaultdict(float)
|
||||
depenses_by_month: dict[str, float] = defaultdict(float)
|
||||
|
||||
# Recuperer revenus et impayes par mois
|
||||
# Recuperer revenus et impayes par mois. Le revenu du mois exclut le report
|
||||
# pour que les mois soient comparables ; l'impaye reste le solde constate ce
|
||||
# mois-la, de sorte que la courbe suive la dette au lieu de l'empiler.
|
||||
revenus_stmt = (
|
||||
select(
|
||||
Document.date,
|
||||
func.sum(Revenu.total).label("total"),
|
||||
func.sum(Revenu.total).filter(est_flux()).label("total"),
|
||||
func.sum(Revenu.impayes).label("impayes"),
|
||||
)
|
||||
.join(Revenu, Revenu.document_id == Document.id)
|
||||
@@ -277,9 +283,10 @@ async def get_monthly_trends(
|
||||
today = date.today()
|
||||
start_date = (today.replace(day=1) - timedelta(days=months * 31)).replace(day=1)
|
||||
|
||||
# Recuperer tous les revenus depuis start_date
|
||||
# Recuperer tous les revenus depuis start_date, report exclu : la courbe
|
||||
# compare des mois entre eux, pas des soldes cumules.
|
||||
revenus_stmt = (
|
||||
select(Document.date, func.sum(Revenu.total).label("total"))
|
||||
select(Document.date, func.sum(Revenu.total).filter(est_flux()).label("total"))
|
||||
.join(Revenu, Revenu.document_id == Document.id)
|
||||
.where(Document.date >= start_date)
|
||||
.group_by(Document.date)
|
||||
@@ -333,51 +340,55 @@ async def get_immeubles_shortcuts(
|
||||
|
||||
- **limit**: Nombre maximum d'immeubles (defaut: 5)
|
||||
"""
|
||||
# Requete pour les immeubles avec stats
|
||||
# Effectifs et activite, puis flux et restant du : trois granularites
|
||||
# differentes, jointes plutot que melangees pour ne pas se multiplier.
|
||||
effectifs = (
|
||||
select(
|
||||
Lot.immeuble_id.label("immeuble_id"),
|
||||
func.count(func.distinct(Lot.id)).label("nb_lots"),
|
||||
func.count(func.distinct(Locataire.id)).label("nb_locataires"),
|
||||
)
|
||||
.outerjoin(Locataire, Locataire.lot_id == Lot.id)
|
||||
.group_by(Lot.immeuble_id)
|
||||
.subquery()
|
||||
)
|
||||
activite = (
|
||||
select(
|
||||
Document.immeuble_id.label("immeuble_id"),
|
||||
func.count(Document.id).label("nb_documents"),
|
||||
)
|
||||
.group_by(Document.immeuble_id)
|
||||
.subquery()
|
||||
)
|
||||
flux = flux_par(Document.immeuble_id)
|
||||
stock = restant_du_par(Document.immeuble_id)
|
||||
|
||||
stmt = (
|
||||
select(
|
||||
Immeuble,
|
||||
func.count(func.distinct(Lot.id)).label("nb_lots"),
|
||||
func.count(func.distinct(Locataire.id)).label("nb_locataires"),
|
||||
func.count(func.distinct(Document.id)).label("nb_documents"),
|
||||
effectifs.c.nb_lots,
|
||||
effectifs.c.nb_locataires,
|
||||
flux.c.facture,
|
||||
stock.c.restant_du,
|
||||
)
|
||||
.outerjoin(Lot, Lot.immeuble_id == Immeuble.id)
|
||||
.outerjoin(Locataire, Locataire.lot_id == Lot.id)
|
||||
.outerjoin(Document, Document.immeuble_id == Immeuble.id)
|
||||
.group_by(Immeuble.id)
|
||||
.order_by(desc("nb_documents"))
|
||||
.outerjoin(effectifs, effectifs.c.immeuble_id == Immeuble.id)
|
||||
.outerjoin(activite, activite.c.immeuble_id == Immeuble.id)
|
||||
.outerjoin(flux, flux.c.cle == Immeuble.id)
|
||||
.outerjoin(stock, stock.c.cle == Immeuble.id)
|
||||
.order_by(desc(activite.c.nb_documents))
|
||||
.limit(limit)
|
||||
)
|
||||
|
||||
result = session.execute(stmt)
|
||||
immeubles = result.all()
|
||||
|
||||
# Pour chaque immeuble, recuperer les totaux revenus/impayes
|
||||
shortcuts = []
|
||||
for row in immeubles:
|
||||
immeuble = row.Immeuble
|
||||
|
||||
# Revenus de cet immeuble
|
||||
revenus_stmt = (
|
||||
select(func.sum(Revenu.total), func.sum(Revenu.impayes))
|
||||
.join(Lot, Revenu.lot_id == Lot.id)
|
||||
.where(Lot.immeuble_id == immeuble.id)
|
||||
return [
|
||||
ImmeubleShortcutResponse(
|
||||
id=row.Immeuble.id,
|
||||
code=row.Immeuble.code,
|
||||
adresse=row.Immeuble.adresse,
|
||||
ville=row.Immeuble.ville,
|
||||
nb_lots=row.nb_lots or 0,
|
||||
nb_locataires=row.nb_locataires or 0,
|
||||
total_revenus=row.facture or 0.0,
|
||||
total_impayes=row.restant_du or 0.0,
|
||||
)
|
||||
rev_result = session.execute(revenus_stmt).first()
|
||||
total_revenus = rev_result[0] or 0.0 if rev_result else 0.0
|
||||
total_impayes = rev_result[1] or 0.0 if rev_result else 0.0
|
||||
|
||||
shortcuts.append(
|
||||
ImmeubleShortcutResponse(
|
||||
id=immeuble.id,
|
||||
code=immeuble.code,
|
||||
adresse=immeuble.adresse,
|
||||
ville=immeuble.ville,
|
||||
nb_lots=row.nb_lots or 0,
|
||||
nb_locataires=row.nb_locataires or 0,
|
||||
total_revenus=total_revenus,
|
||||
total_impayes=total_impayes,
|
||||
)
|
||||
)
|
||||
|
||||
return shortcuts
|
||||
for row in session.execute(stmt)
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user