Mise en place de la notion de perte définitive, ainsi que la révision avec statut Polongation
This commit is contained in:
1 parent
4ad6ea79e8
commit
8e1b82d161
21 files changed
+1069
-184
No files matched your search
@@ -90,7 +90,7 @@ function invToCSV(rows) {
|
||||
function invToXLS(rows) {
|
||||
const data = rows.map(r => {
|
||||
const capInv = r.capital_total ?? r.montant_investi;
|
||||
const capRestant = Math.max(0, capInv - (r.capital_rembourse || 0));
|
||||
const capRestant = Math.max(0, capInv - (r.capital_rembourse || 0) - (r.capital_perdu || 0));
|
||||
return {
|
||||
'Date souscription': r.date_souscription,
|
||||
'Projet': r.nom_projet,
|
||||
@@ -429,7 +429,11 @@ export default function Investissements() {
|
||||
const decStart = `${yr}-12-01`;
|
||||
if (r.date_souscription > cutoff) return false; // pas encore souscrit
|
||||
const ACTIVE = ['en_cours', 'en_retard', 'procedure'];
|
||||
if (ACTIVE.includes(r.statut)) return true; // encore actif aujourd'hui
|
||||
// perte_definitive et prolongation restent "actifs" au sens de ce filtre (comme
|
||||
// en_retard/procedure dont ils découlent) : le dossier ne doit pas disparaître des
|
||||
// vues par année sous prétexte que la perte a été déclarée ou qu'une prolongation a
|
||||
// été négociée — voir project_perte_definitive.md et project_prolongation.md
|
||||
if (ACTIVE.includes(r.statut) || ['perte_definitive', 'prolongation'].includes(r.statut)) return true; // encore actif aujourd'hui
|
||||
const fin = r.date_cible ?? lastRembDateMap[r.id] ?? null;
|
||||
return !!fin && fin >= decStart; // clôturé mais actif en décembre
|
||||
};
|
||||
@@ -490,11 +494,12 @@ export default function Investissements() {
|
||||
acc.cap_remb += capRemb;
|
||||
acc.int_perc += rembParInv[r.id]?.interets_bruts || 0;
|
||||
acc.int_perc_net += rembParInv[r.id]?.interets_nets || 0;
|
||||
const capRestant = Math.max(0, capInv - capRemb);
|
||||
const capRestant = Math.max(0, capInv - capRemb - (r.capital_perdu || 0));
|
||||
acc.encours += capRestant;
|
||||
if (['en_retard', 'procedure'].includes(r.statut)) acc.defaut += capRestant;
|
||||
acc.pertes += (r.capital_perdu || 0);
|
||||
return acc;
|
||||
}, { investi: 0, cap_remb: 0, int_perc: 0, int_perc_net: 0, encours: 0, defaut: 0 }), [kpiRows, capRembParInv, rembParInv, reinvestCumulParInv]);
|
||||
}, { investi: 0, cap_remb: 0, int_perc: 0, int_perc_net: 0, encours: 0, defaut: 0, pertes: 0 }), [kpiRows, capRembParInv, rembParInv, reinvestCumulParInv]);
|
||||
|
||||
/* ── Totaux KPI année N-1 (pour TrendBadge) ── */
|
||||
const prevTotals = useMemo(() => {
|
||||
@@ -530,7 +535,7 @@ export default function Investissements() {
|
||||
acc.cap_remb += capRemb;
|
||||
acc.int_perc += prevRembParInv[r.id]?.interets_bruts || 0;
|
||||
acc.int_perc_net += prevRembParInv[r.id]?.interets_nets || 0;
|
||||
const capRestant = Math.max(0, capInv - capRemb);
|
||||
const capRestant = Math.max(0, capInv - capRemb - (r.capital_perdu || 0));
|
||||
acc.encours += capRestant;
|
||||
if (['en_retard', 'procedure'].includes(r.statut)) acc.defaut += capRestant;
|
||||
return acc;
|
||||
@@ -563,7 +568,7 @@ export default function Investissements() {
|
||||
p.cap_remb += capRemb;
|
||||
p.int_perc += rembParInv[r.id]?.interets_bruts || 0;
|
||||
p.int_perc_net += rembParInv[r.id]?.interets_nets || 0;
|
||||
const capRestant = Math.max(0, capInv - capRemb);
|
||||
const capRestant = Math.max(0, capInv - capRemb - (r.capital_perdu || 0));
|
||||
// Sans filtre année : les prêts remboursés ont capRestant=0 → pas d'impact
|
||||
// Avec filtre année : on veut le capital déployé à la coupure, quel que soit le statut actuel
|
||||
p.encours += capRestant;
|
||||
@@ -607,7 +612,7 @@ export default function Investissements() {
|
||||
.map(r => {
|
||||
const capInv = r.montant_investi + (reinvestCumulParInv[r.id] || 0);
|
||||
const capRemb = capRembParInv[r.id] || 0;
|
||||
const capRestant = Math.max(0, capInv - capRemb);
|
||||
const capRestant = Math.max(0, capInv - capRemb - (r.capital_perdu || 0));
|
||||
return { plateforme_nom: r.plateforme_nom, montant: capRestant };
|
||||
})
|
||||
.filter(r => r.montant > 0),
|
||||
@@ -847,6 +852,11 @@ export default function Investissements() {
|
||||
{platYear && totals.defaut > 0 && <TrendBadge current={totals.defaut} prev={prevTotals.defaut} invert={true} />}
|
||||
</div>
|
||||
{platYear && <div style={{ fontSize: '0.8em', color: 'var(--text-muted)', marginTop: 5 }}>{fmtEUR(prevTotals.defaut)} en {Number(platYear) - 1}</div>}
|
||||
{totals.pertes > 0 && (
|
||||
<div style={{ fontSize: '0.8em', color: '#7c2d12', marginTop: 4, fontWeight: 600 }}>
|
||||
dont {fmtEUR(totals.pertes)} déjà déclarés en perte définitive (non compris ci-dessus)
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 3 — Investissements depuis le début */}
|
||||
@@ -1148,6 +1158,8 @@ export default function Investissements() {
|
||||
<option value="en_retard">En retard</option>
|
||||
<option value="procedure">Procédure</option>
|
||||
<option value="cloture">Clôturé</option>
|
||||
<option value="perte_definitive">Perte définitive</option>
|
||||
<option value="prolongation">Prolongation</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style={{ flex: 1, minWidth: 120 }}>
|
||||
@@ -1221,7 +1233,7 @@ export default function Investissements() {
|
||||
)}
|
||||
{pagedRows.map(r => {
|
||||
const capInv = r.capital_total ?? r.montant_investi;
|
||||
const capRestant = Math.max(0, capInv - (r.capital_rembourse || 0));
|
||||
const capRestant = Math.max(0, capInv - (r.capital_rembourse || 0) - (r.capital_perdu || 0));
|
||||
return (
|
||||
<tr key={r.id}
|
||||
onClick={() => navigate(`/investissements/${r.id}`, { state: { from: { path: '/investissements', search: location.search, label: 'Investissements' } } })}
|
||||
@@ -1560,6 +1572,7 @@ export default function Investissements() {
|
||||
<option value="en_retard">En retard</option>
|
||||
<option value="procedure">Procédure</option>
|
||||
<option value="cloture">Clôturé</option>
|
||||
<option value="perte_definitive">Perte définitive</option>
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in new issue
Block a user