This commit is contained in:
ocroguennec committed 2026-09-18 08:45:15 +02:00
1 parent 337d0c1a2c
commit d5792fb3e2
3 files changed
+163 -11

No files matched your search

+14
View File
@@ -3346,6 +3346,20 @@ db.exec(`
`);
db.exec('CREATE INDEX IF NOT EXISTS idx_invpeval_inv ON investissements_pe_valorisations(investissement_pe_id)');
// Migration : décomposition optionnelle de la valorisation en capital déployé / plus-value
// latente (18/09/26, demande Olivier — construire une carte de répartition façon Fundora sur la
// fiche détail PE). Capital non déployé n'est JAMAIS stocké : il se déduit à l'affichage/au
// calcul (montant_investi du deal − capital_deploye de cette valorisation). Colonnes nullables :
// une valorisation peut rester en saisie simple (un seul montant net), sans détail — c'est
// d'ailleurs le cas de toutes les valorisations existantes avant cette migration.
const invPeValCols = db.prepare('PRAGMA table_info(investissements_pe_valorisations)').all().map(c => c.name);
if (!invPeValCols.includes('capital_deploye')) {
db.exec('ALTER TABLE investissements_pe_valorisations ADD COLUMN capital_deploye REAL');
}
if (!invPeValCols.includes('plus_value_latente')) {
db.exec('ALTER TABLE investissements_pe_valorisations ADD COLUMN plus_value_latente REAL');
}
// Lien optionnel remboursement → deal PE (17/09/26) : une distribution (retour
// de capital, plus-value) perçue sur un deal PE est saisie comme un
// remboursement bonus_plateforme/interets_plateforme, comme demandé par
+36 -5
View File
@@ -38,6 +38,12 @@ const Schema = z.object({
const ValorisationSchema = z.object({
date_valorisation: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
valorisation_nette: z.number().nonnegative(),
// Répartition optionnelle (18/09/26, demande Olivier) : quand capital_deploye est renseigné,
// la valorisation_nette envoyée par le client est recalculée côté serveur (cf. POST
// /:id/valorisations) plutôt que reprise telle quelle — seule source de vérité sur ce calcul.
// Capital non déployé n'existe pas ici : toujours déduit (montant_investi du deal − capital_deploye).
capital_deploye: z.number().nonnegative().optional(),
plus_value_latente: z.number().optional(),
notes: z.string().optional(),
});
@@ -264,13 +270,38 @@ router.get('/:id/valorisations', requireInvestisseur, (req, res, next) => {
router.post('/:id/valorisations', requireInvestisseur, (req, res, next) => {
try {
const id = Number(req.params.id);
ownedDeal(req, id);
const deal = ownedDeal(req, id);
const body = ValorisationSchema.parse(req.body);
// Quand la répartition est renseignée (capital_deploye présent), la valorisation nette est
// recalculée ici plutôt que reprise du body : capital_deploye + plus_value_latente +
// capital_non_deploye (déduit = montant_investi du deal − capital_deploye, jamais négatif).
// Sans répartition (mode simple, historique), comportement inchangé : le montant saisi est
// utilisé tel quel et les deux colonnes restent NULL.
let valorisationNette = body.valorisation_nette;
let capitalDeploye = null;
let plusValueLatente = null;
if (body.capital_deploye != null) {
capitalDeploye = body.capital_deploye;
plusValueLatente = body.plus_value_latente ?? 0;
const capitalNonDeploye = Math.max(0, deal.montant_investi - capitalDeploye);
valorisationNette = Math.round((capitalDeploye + plusValueLatente + capitalNonDeploye) * 100) / 100;
}
const r = db.prepare(`
INSERT INTO investissements_pe_valorisations (investissement_pe_id, date_valorisation, valorisation_nette, notes)
VALUES (?,?,?,?)
`).run(id, body.date_valorisation, body.valorisation_nette, body.notes || null);
res.status(201).json({ id: r.lastInsertRowid, investissement_pe_id: id, ...body });
INSERT INTO investissements_pe_valorisations
(investissement_pe_id, date_valorisation, valorisation_nette, capital_deploye, plus_value_latente, notes)
VALUES (?,?,?,?,?,?)
`).run(id, body.date_valorisation, valorisationNette, capitalDeploye, plusValueLatente, body.notes || null);
res.status(201).json({
id: r.lastInsertRowid,
investissement_pe_id: id,
date_valorisation: body.date_valorisation,
valorisation_nette: valorisationNette,
capital_deploye: capitalDeploye,
plus_value_latente: plusValueLatente,
notes: body.notes,
});
} catch (e) { next(e); }
});