fix: distingue un lot reloué d'un lot sorti de la gestion
La fiche du lot 15 annonçait « dernier loyer connu, arrêté après févr. 26 » alors qu'un locataire y est entré le 8 juillet — et la courbe juste dessous, où la barre de juillet est bien là, la contredisait. Le loyer en vigueur se lit sur les paliers, et un mois facturé au seul prorata n'en ouvre pas : celui d'avant s'arrête donc à la dernière mensualité pleine, quatre mois avant le nouveau bail. Ne rien lire après lui confond deux états que le compte rendu sépare : un lot qui n'est plus loué, et un lot entre deux locataires. La distinction tient à la frontière qui sert déjà à séparer loyer plein et prorata, la période portée par le compte rendu : - un prorata qui finit le dernier jour du mois sans partir du premier facture la fin du mois : quelqu'un est entré, le bail court encore après ; - un prorata qui part du premier sans l'atteindre facture le début : le bail s'arrête là ; - un montant négatif ne fait ni l'un ni l'autre. Un avoir porte parfois la période exacte de la ligne qu'il annule, et le lire comme une entrée inventerait une relocation là où rien n'a été loué. L'entrée l'emporte sur la sortie parce qu'elle vient après : ce lot voit son locataire partir le 10 mars et le suivant arriver le 8 juillet, et c'est le second qui décrit son état. Le montant affiché ne bouge pas — le nouveau bail n'a été facturé qu'au prorata, et en tirer un loyer mensuel l'inventerait. Seul ce qu'on en dit change : « dernier loyer plein · nouveau bail depuis juil. 26 ». Sans relocation, la sortie date enfin la fin de la location au mois où elle a lieu : « arrêté en cours de mars 26 » plutôt qu'« arrêté après févr. 26 », qui l'avançait d'un mois. Sur le parc : 31 lots loués, 1 relouté, 1 réellement arrêté. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,10 @@ aucun mois ne peut alors le revendiquer.
|
||||
|
||||
Un mois sans loyer plein mais avec un prorata n'est donc pas une vacance : c'est
|
||||
un mois de transition, et la fiche le distingue au lieu de le confondre avec un
|
||||
trou.
|
||||
trou. La même frontière dit dans quel sens il penche : un prorata qui court
|
||||
jusqu'au dernier jour du mois ouvre un bail, un prorata qui part du premier sans
|
||||
l'atteindre en ferme un. C'est ce qui sépare un lot reloué le 8 d'un lot sorti
|
||||
de la gestion, là où le palier de loyer s'arrête dans les deux cas.
|
||||
|
||||
Le mètre carré vient de la fiche saisie (`lot_caracteristiques.surface`), pas
|
||||
des comptes rendus qui l'ignorent. Sans surface, le ratio vaut ``None`` et non
|
||||
@@ -91,6 +94,32 @@ def mois_entiers(debut: date | None, fin: date | None) -> list[str]:
|
||||
return couverts
|
||||
|
||||
|
||||
def est_entree(debut: date, fin: date, loyers: float | None) -> bool:
|
||||
"""Vrai si ce prorata ouvre un bail qui court encore le mois suivant.
|
||||
|
||||
Un prorata qui s'arrête au dernier jour du mois sans avoir commencé le
|
||||
premier facture la fin du mois : quelqu'un est entré en cours de route. La
|
||||
location ne s'arrête donc pas là, même si aucun loyer plein ne suit encore.
|
||||
|
||||
Un montant négatif est écarté : un avoir annule une facturation, il
|
||||
n'ouvre pas un bail — et il porte parfois la même période qu'elle.
|
||||
"""
|
||||
if not loyers or loyers <= 0:
|
||||
return False
|
||||
return debut.day != 1 and fin.day == monthrange(fin.year, fin.month)[1]
|
||||
|
||||
|
||||
def est_sortie(debut: date, fin: date, loyers: float | None) -> bool:
|
||||
"""Vrai si ce prorata ferme un bail en cours de mois.
|
||||
|
||||
Miroir de `est_entree` : partir du premier jour sans atteindre le dernier,
|
||||
c'est facturer le début du mois et s'arrêter.
|
||||
"""
|
||||
if not loyers or loyers <= 0:
|
||||
return False
|
||||
return debut.day == 1 and fin.day != monthrange(fin.year, fin.month)[1]
|
||||
|
||||
|
||||
@dataclass
|
||||
class MoisLoue:
|
||||
"""Ce qu'un mois a été facturé, charges et proratas à part."""
|
||||
@@ -109,6 +138,12 @@ class MoisLoue:
|
||||
prorata: float | None = None
|
||||
#: Vrai quand le loyer vient d'une ligne pluri-mensuelle répartie.
|
||||
reparti: bool = False
|
||||
#: Vrai quand un prorata du mois court jusqu'à son dernier jour sans partir
|
||||
#: du premier : un bail commence en cours de mois et continue après lui.
|
||||
entree: bool = False
|
||||
#: Vrai quand un prorata du mois part de son premier jour sans l'achever :
|
||||
#: un bail s'arrête en cours de mois.
|
||||
sortie: bool = False
|
||||
|
||||
@property
|
||||
def en_transition(self) -> bool:
|
||||
@@ -161,6 +196,8 @@ def repartir(lignes) -> Serie:
|
||||
if debut is not None and fin is not None and mois_de(debut) == mois_de(fin):
|
||||
point = cumul.setdefault(mois_de(debut), MoisLoue(mois=mois_de(debut)))
|
||||
point.prorata = (point.prorata or 0.0) + (loyers or 0.0)
|
||||
point.entree = point.entree or est_entree(debut, fin, loyers)
|
||||
point.sortie = point.sortie or est_sortie(debut, fin, loyers)
|
||||
else:
|
||||
ecartees.append(
|
||||
LigneEcartee(
|
||||
|
||||
Reference in New Issue
Block a user