458 lines
20 KiB
JavaScript
458 lines
20 KiB
JavaScript
import { Router } from 'express';
|
|
import { z } from 'zod';
|
|
import db from '../db/index.js';
|
|
import { HttpError } from '../middleware/errorHandler.js';
|
|
import { requireInvestisseur } from '../middleware/investisseurScope.js';
|
|
import { generateSimul } from '../utils/schedule.js';
|
|
|
|
const router = Router();
|
|
|
|
const TRACKED_FIELDS = [
|
|
{ key: 'type_remb', label: 'Type de prêt' },
|
|
{ key: 'taux_interet', label: 'Taux annuel (%)' },
|
|
{ key: 'duree_mois', label: 'Durée (mois)' },
|
|
{ key: 'montant_investi', label: 'Montant investi (€)' },
|
|
{ key: 'statut', label: 'Statut' },
|
|
{ key: 'freq_interets', label: 'Fréquence des intérêts' },
|
|
{ key: 'date_premiere_echeance', label: 'Date 1ère échéance' },
|
|
{ key: 'date_cible', label: 'Date cible' },
|
|
{ key: 'date_debut_simul', label: 'Date de restructuration' },
|
|
{ key: 'plateforme_id', label: 'Plateforme' },
|
|
];
|
|
|
|
function recordHistory(investissementId, { type_evenement, changements, notes }) {
|
|
if (!changements || changements.length === 0) return;
|
|
db.prepare(`
|
|
INSERT INTO investissement_historique (investissement_id, type_evenement, changements, notes)
|
|
VALUES (?, ?, ?, ?)
|
|
`).run(investissementId, type_evenement, JSON.stringify(changements), notes || null);
|
|
}
|
|
|
|
function detectChangements(ancien, nouveau) {
|
|
const diffs = [];
|
|
for (const { key, label } of TRACKED_FIELDS) {
|
|
const av = ancien[key] ?? null;
|
|
const nv = nouveau[key] ?? null;
|
|
const avNorm = av === '' ? null : av;
|
|
const nvNorm = nv === '' ? null : nv;
|
|
if (String(avNorm) !== String(nvNorm)) {
|
|
diffs.push({ champ: key, label, ancienne_valeur: avNorm, nouvelle_valeur: nvNorm });
|
|
}
|
|
}
|
|
return diffs;
|
|
}
|
|
|
|
function detectTypeEvenement(changements) {
|
|
const champsRestructuration = ['type_remb', 'date_debut_simul'];
|
|
if (changements.some(c => champsRestructuration.includes(c.champ))) return 'restructuration';
|
|
return 'modification';
|
|
}
|
|
|
|
const Schema = z.object({
|
|
investisseur_id: z.number().int().positive().optional(),
|
|
plateforme_id: z.number().int().positive(),
|
|
nom_projet: z.string().min(1),
|
|
emetteur: z.string().optional(),
|
|
date_souscription: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
date_premiere_echeance: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().or(z.literal('')),
|
|
date_cible: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().or(z.literal('')),
|
|
date_debut_simul: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().or(z.literal('')),
|
|
montant_investi: z.number().positive(),
|
|
taux_interet: z.number().optional(),
|
|
duree_mois: z.number().int().optional(),
|
|
type_remb: z.enum(['in_fine','amortissable','differe']).optional().or(z.literal('')),
|
|
freq_interets: z.enum(['mensuel','trimestriel','in_fine']).default('mensuel'),
|
|
statut: z.enum(['en_cours','rembourse','en_retard','procedure','cloture']).default('en_cours'),
|
|
reference: z.string().optional(),
|
|
notes: z.string().optional(),
|
|
categorie_id: z.number().int().positive().nullable().optional(),
|
|
echeance_fin_de_mois: z.number().int().min(0).max(1).optional().default(0),
|
|
methode_remboursement: z.enum(['portefeuille','compte_courant']).nullable().optional(),
|
|
nom_compte_courant: z.string().nullable().optional(),
|
|
compte_id: z.number().int().positive().nullable().optional(),
|
|
pays_exposition: z.string().length(2).optional().default('FR'),
|
|
});
|
|
|
|
router.use(requireInvestisseur);
|
|
|
|
function resolveInvestisseurId(req, bodyInvestisseurId) {
|
|
if (!bodyInvestisseurId) return req.investisseur.id;
|
|
const row = db.prepare('SELECT id FROM investisseurs WHERE id = ? AND user_id = ?')
|
|
.get(bodyInvestisseurId, req.user.id);
|
|
if (!row) throw new HttpError(403, 'Investisseur non autorisé');
|
|
return bodyInvestisseurId;
|
|
}
|
|
|
|
router.get('/', (req, res) => {
|
|
const scopeAll = req.query.scope === 'all';
|
|
const { statut, plateforme_id } = req.query;
|
|
|
|
const conds = scopeAll
|
|
? ['i.investisseur_id IN (SELECT id FROM investisseurs WHERE user_id = ?)']
|
|
: ['i.investisseur_id = ?'];
|
|
const args = scopeAll ? [req.user.id] : [req.investisseur.id];
|
|
|
|
if (statut) { conds.push('i.statut = ?'); args.push(statut); }
|
|
if (plateforme_id){ conds.push('i.plateforme_id = ?'); args.push(Number(plateforme_id)); }
|
|
|
|
const rows = db.prepare(`
|
|
SELECT i.*, p.nom AS plateforme_nom,
|
|
inv.nom AS investisseur_nom,
|
|
cp.nom AS categorie_nom,
|
|
plat_inv.nom AS plateforme_detenteur_nom,
|
|
c.id AS compte_id, c.nom AS compte_nom, c.type AS compte_type,
|
|
(SELECT COALESCE(SUM(r.capital),0) FROM remboursements r WHERE r.investissement_id = i.id) AS capital_rembourse,
|
|
(SELECT COALESCE(SUM(r.interets_bruts),0) FROM remboursements r WHERE r.investissement_id = i.id) AS interets_percus,
|
|
(SELECT COALESCE(SUM(r.interets_nets),0) FROM remboursements r WHERE r.investissement_id = i.id) AS interets_nets_total,
|
|
(SELECT COALESCE(SUM(r.net_recu),0) FROM remboursements r WHERE r.investissement_id = i.id) AS net_recu_total,
|
|
(SELECT COALESCE(SUM(rv.montant),0) FROM reinvestissements rv WHERE rv.investissement_id = i.id) AS reinvestissements_total,
|
|
i.montant_investi + (SELECT COALESCE(SUM(rv.montant),0) FROM reinvestissements rv WHERE rv.investissement_id = i.id) AS capital_total
|
|
FROM investissements i
|
|
JOIN plateformes p ON p.id = i.plateforme_id
|
|
JOIN investisseurs inv ON inv.id = i.investisseur_id
|
|
LEFT JOIN investisseurs plat_inv ON plat_inv.id = p.investisseur_id
|
|
LEFT JOIN categories_plateforme cp ON cp.id = i.categorie_id
|
|
LEFT JOIN comptes c ON c.id = i.compte_id
|
|
WHERE ${conds.join(' AND ')}
|
|
ORDER BY i.date_souscription DESC, i.id DESC
|
|
`).all(...args);
|
|
|
|
// Attacher les associations catégories/secteurs d'investissement
|
|
if (rows.length > 0) {
|
|
const ids = rows.map(r => r.id);
|
|
const placeholders = ids.map(() => '?').join(',');
|
|
const cats = db.prepare(`
|
|
SELECT ic.investissement_id, c.id, c.nom,
|
|
CASE WHEN c.user_id IS NULL THEN 1 ELSE 0 END AS is_global
|
|
FROM investissement_categories_inv ic
|
|
JOIN categories_inv c ON c.id = ic.categorie_id
|
|
WHERE ic.investissement_id IN (${placeholders})
|
|
ORDER BY is_global DESC, c.nom
|
|
`).all(...ids);
|
|
const sects = db.prepare(`
|
|
SELECT is2.investissement_id, s.id, s.nom,
|
|
CASE WHEN s.user_id IS NULL THEN 1 ELSE 0 END AS is_global
|
|
FROM investissement_secteurs_inv is2
|
|
JOIN secteurs_inv s ON s.id = is2.secteur_id
|
|
WHERE is2.investissement_id IN (${placeholders})
|
|
ORDER BY is_global DESC, s.nom
|
|
`).all(...ids);
|
|
const catMap = {};
|
|
const sectMap = {};
|
|
for (const c of cats) { if (!catMap[c.investissement_id]) catMap[c.investissement_id] = []; catMap[c.investissement_id].push({ id: c.id, nom: c.nom, is_global: c.is_global }); }
|
|
for (const s of sects) { if (!sectMap[s.investissement_id]) sectMap[s.investissement_id] = []; sectMap[s.investissement_id].push({ id: s.id, nom: s.nom, is_global: s.is_global }); }
|
|
for (const r of rows) { r.categories_inv = catMap[r.id] || []; r.secteurs_inv = sectMap[r.id] || []; }
|
|
}
|
|
|
|
res.json(rows);
|
|
});
|
|
|
|
// Retourne les comptes bancaires d'un investisseur donné (pour le select dans le formulaire)
|
|
router.get('/comptes-par-investisseur/:investisseur_id', (req, res, next) => {
|
|
try {
|
|
const invId = Number(req.params.investisseur_id);
|
|
// Vérifie que l'investisseur appartient à l'utilisateur
|
|
const inv = db.prepare('SELECT id FROM investisseurs WHERE id = ? AND user_id = ?')
|
|
.get(invId, req.user.id);
|
|
if (!inv) throw new HttpError(403, 'Investisseur non autorisé');
|
|
const rows = db.prepare(
|
|
'SELECT id, nom, type, banque FROM comptes WHERE investisseur_id = ? AND user_id = ? ORDER BY type, nom'
|
|
).all(invId, req.user.id);
|
|
res.json(rows);
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
router.get('/comptes-courants', (req, res) => {
|
|
const rows = db.prepare(`
|
|
SELECT DISTINCT i.investisseur_id, i.nom_compte_courant
|
|
FROM investissements i
|
|
JOIN investisseurs inv ON inv.id = i.investisseur_id AND inv.user_id = ?
|
|
WHERE i.nom_compte_courant IS NOT NULL AND i.nom_compte_courant != ''
|
|
ORDER BY i.nom_compte_courant
|
|
`).all(req.user.id);
|
|
res.json(rows);
|
|
});
|
|
|
|
// POST /api/investissements/fix-differe-dates
|
|
// Corrige date_premiere_echeance et date_cible des prêts différés dont les dates
|
|
// s'écartent de plus de 2 ans par rapport à date_souscription + duree_mois.
|
|
router.post('/fix-differe-dates', (req, res, next) => {
|
|
try {
|
|
const rows = db.prepare(`
|
|
SELECT i.id, i.nom_projet, i.date_souscription, i.duree_mois,
|
|
i.date_premiere_echeance, i.date_cible
|
|
FROM investissements i
|
|
JOIN investisseurs inv ON inv.id = i.investisseur_id AND inv.user_id = ?
|
|
WHERE i.type_remb = 'differe'
|
|
AND i.date_souscription IS NOT NULL
|
|
AND i.duree_mois IS NOT NULL
|
|
`).all(req.user.id);
|
|
|
|
const SEUIL_JOURS = 730; // 2 ans
|
|
|
|
function addMonths(dateStr, months) {
|
|
const d = new Date(dateStr + 'T00:00:00Z');
|
|
d.setUTCMonth(d.getUTCMonth() + months);
|
|
return d.toISOString().slice(0, 10);
|
|
}
|
|
|
|
function diffJours(a, b) {
|
|
return Math.abs((new Date(a + 'T00:00:00Z') - new Date(b + 'T00:00:00Z')) / 86400000);
|
|
}
|
|
|
|
const corriges = [];
|
|
const stmt = db.prepare(`
|
|
UPDATE investissements
|
|
SET date_premiere_echeance = ?, date_cible = ?, updated_at = datetime('now')
|
|
WHERE id = ?
|
|
`);
|
|
|
|
for (const inv of rows) {
|
|
const dateCalculee = addMonths(inv.date_souscription, inv.duree_mois);
|
|
const ecartEcheance = inv.date_premiere_echeance
|
|
? diffJours(inv.date_premiere_echeance, dateCalculee) : null;
|
|
const ecartCible = inv.date_cible
|
|
? diffJours(inv.date_cible, dateCalculee) : null;
|
|
|
|
const incoherent =
|
|
(ecartEcheance !== null && ecartEcheance > SEUIL_JOURS) ||
|
|
(ecartCible !== null && ecartCible > SEUIL_JOURS) ||
|
|
(inv.date_premiere_echeance === null) ||
|
|
(inv.date_cible === null);
|
|
|
|
if (incoherent) {
|
|
stmt.run(dateCalculee, dateCalculee, inv.id);
|
|
corriges.push({
|
|
id: inv.id,
|
|
nom_projet: inv.nom_projet,
|
|
date_souscription: inv.date_souscription,
|
|
duree_mois: inv.duree_mois,
|
|
ancienne_date_premiere_echeance: inv.date_premiere_echeance,
|
|
ancienne_date_cible: inv.date_cible,
|
|
nouvelle_date: dateCalculee,
|
|
});
|
|
}
|
|
}
|
|
|
|
res.json({ updated: corriges.length, detail: corriges });
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
router.get('/:id', (req, res, next) => {
|
|
try {
|
|
const inv = db.prepare(`
|
|
SELECT i.*, p.nom AS plateforme_nom, p.fiscalite AS plateforme_fiscalite, p.logo_filename AS plateforme_logo, cp.nom AS categorie_nom,
|
|
c.id AS compte_id, c.nom AS compte_nom, c.type AS compte_type
|
|
FROM investissements i
|
|
JOIN plateformes p ON p.id = i.plateforme_id
|
|
JOIN investisseurs inv ON inv.id = i.investisseur_id AND inv.user_id = ?
|
|
LEFT JOIN categories_plateforme cp ON cp.id = i.categorie_id
|
|
LEFT JOIN comptes c ON c.id = i.compte_id
|
|
WHERE i.id = ?
|
|
`).get(req.user.id, req.params.id);
|
|
if (!inv) throw new HttpError(404, 'Not found');
|
|
const remboursements = db.prepare(
|
|
'SELECT * FROM remboursements WHERE investissement_id = ? ORDER BY date_remb'
|
|
).all(req.params.id);
|
|
const simul = db.prepare(
|
|
'SELECT * FROM simul_remboursements WHERE investissement_id = ? ORDER BY numero_echeance'
|
|
).all(req.params.id);
|
|
const historique = db.prepare(
|
|
'SELECT * FROM investissement_historique WHERE investissement_id = ? ORDER BY created_at ASC'
|
|
).all(req.params.id).map(h => ({ ...h, changements: JSON.parse(h.changements) }));
|
|
const reinvestissements = db.prepare(
|
|
'SELECT * FROM reinvestissements WHERE investissement_id = ? ORDER BY date_reinvestissement'
|
|
).all(req.params.id);
|
|
const reinvestissements_total = reinvestissements.reduce((s, r) => s + r.montant, 0);
|
|
const capital_total = inv.montant_investi + reinvestissements_total;
|
|
// Associations catégories/secteurs
|
|
const categories_inv = db.prepare(`
|
|
SELECT c.id, c.nom, CASE WHEN c.user_id IS NULL THEN 1 ELSE 0 END AS is_global
|
|
FROM investissement_categories_inv ic
|
|
JOIN categories_inv c ON c.id = ic.categorie_id
|
|
WHERE ic.investissement_id = ?
|
|
ORDER BY is_global DESC, c.nom
|
|
`).all(req.params.id);
|
|
const secteurs_inv = db.prepare(`
|
|
SELECT s.id, s.nom, CASE WHEN s.user_id IS NULL THEN 1 ELSE 0 END AS is_global
|
|
FROM investissement_secteurs_inv is2
|
|
JOIN secteurs_inv s ON s.id = is2.secteur_id
|
|
WHERE is2.investissement_id = ?
|
|
ORDER BY is_global DESC, s.nom
|
|
`).all(req.params.id);
|
|
res.json({ ...inv, capital_total, reinvestissements_total, remboursements, simul, historique, reinvestissements, categories_inv, secteurs_inv });
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
router.post('/', (req, res, next) => {
|
|
try {
|
|
const body = Schema.parse(req.body);
|
|
const investisseurId = resolveInvestisseurId(req, body.investisseur_id);
|
|
const r = db.prepare(`
|
|
INSERT INTO investissements
|
|
(investisseur_id, plateforme_id, nom_projet, emetteur, date_souscription,
|
|
date_premiere_echeance, date_cible, date_debut_simul, montant_investi, taux_interet, duree_mois,
|
|
type_remb, freq_interets, statut, reference, source, notes, categorie_id, echeance_fin_de_mois,
|
|
methode_remboursement, nom_compte_courant, compte_id, pays_exposition)
|
|
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?, 'manuel', ?,?,?,?,?,?,?)
|
|
`).run(
|
|
investisseurId, body.plateforme_id, body.nom_projet, body.emetteur || null,
|
|
body.date_souscription, body.date_premiere_echeance || null, body.date_cible || null,
|
|
body.date_debut_simul || null, body.montant_investi, body.taux_interet ?? null, body.duree_mois ?? null,
|
|
body.type_remb || null, body.freq_interets, body.statut, body.reference || null, body.notes || null,
|
|
body.categorie_id ?? null, body.echeance_fin_de_mois ?? 0,
|
|
body.methode_remboursement ?? null,
|
|
body.nom_compte_courant || null,
|
|
body.compte_id ?? null,
|
|
body.pays_exposition ?? 'FR',
|
|
);
|
|
const newId = r.lastInsertRowid;
|
|
recordHistory(newId, {
|
|
type_evenement: 'creation',
|
|
changements: [{ champ: 'creation', label: 'Création', ancienne_valeur: null, nouvelle_valeur: body.nom_projet }],
|
|
});
|
|
generateSimul(db, {
|
|
id: newId,
|
|
montant_investi: body.montant_investi,
|
|
taux_interet: body.taux_interet ?? null,
|
|
duree_mois: body.duree_mois ?? null,
|
|
type_remb: body.type_remb || 'in_fine',
|
|
freq_interets: body.freq_interets || 'mensuel',
|
|
date_premiere_echeance: body.date_premiere_echeance || null,
|
|
date_debut_simul: body.date_debut_simul || null,
|
|
date_souscription: body.date_souscription,
|
|
echeance_fin_de_mois: body.echeance_fin_de_mois ?? 0,
|
|
});
|
|
res.status(201).json({ id: newId, ...body });
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
router.put('/:id', (req, res, next) => {
|
|
try {
|
|
const body = Schema.parse(req.body);
|
|
const investisseurId = resolveInvestisseurId(req, body.investisseur_id);
|
|
const ancien = db.prepare(`
|
|
SELECT inv_data.*
|
|
FROM investissements inv_data
|
|
JOIN investisseurs inv ON inv.id = inv_data.investisseur_id AND inv.user_id = ?
|
|
WHERE inv_data.id = ?
|
|
`).get(req.user.id, req.params.id);
|
|
if (!ancien) throw new HttpError(404, 'Not found');
|
|
const r = db.prepare(`
|
|
UPDATE investissements
|
|
SET investisseur_id=?, plateforme_id=?, nom_projet=?, emetteur=?, date_souscription=?,
|
|
date_premiere_echeance=?, date_cible=?, date_debut_simul=?, montant_investi=?,
|
|
taux_interet=?, duree_mois=?, type_remb=?, freq_interets=?, statut=?,
|
|
reference=?, notes=?, categorie_id=?, echeance_fin_de_mois=?,
|
|
methode_remboursement=?, nom_compte_courant=?, compte_id=?, pays_exposition=?, updated_at=datetime('now')
|
|
WHERE id=?
|
|
`).run(
|
|
investisseurId, body.plateforme_id, body.nom_projet, body.emetteur || null,
|
|
body.date_souscription, body.date_premiere_echeance || null, body.date_cible || null,
|
|
body.date_debut_simul || null, body.montant_investi, body.taux_interet ?? null,
|
|
body.duree_mois ?? null, body.type_remb || null, body.freq_interets, body.statut,
|
|
body.reference || null, body.notes || null, body.categorie_id ?? null,
|
|
body.echeance_fin_de_mois ?? 0,
|
|
body.methode_remboursement ?? null,
|
|
body.nom_compte_courant || null,
|
|
body.compte_id ?? null,
|
|
body.pays_exposition ?? 'FR', req.params.id,
|
|
);
|
|
if (r.changes === 0) throw new HttpError(404, 'Not found');
|
|
|
|
// Cascade compte_id vers les remboursements existants de cet investissement
|
|
if (body.compte_id !== undefined) {
|
|
const newCompteId = body.methode_remboursement === 'compte_courant' ? (body.compte_id ?? null) : null;
|
|
db.prepare(
|
|
"UPDATE remboursements SET compte_id=? WHERE investissement_id=? AND methode_remboursement='compte_courant' AND compte_id IS NOT NULL"
|
|
).run(newCompteId, req.params.id);
|
|
}
|
|
|
|
const changements = detectChangements(ancien, {
|
|
...body,
|
|
date_debut_simul: body.date_debut_simul || null,
|
|
date_premiere_echeance: body.date_premiere_echeance || null,
|
|
date_cible: body.date_cible || null,
|
|
});
|
|
if (changements.length > 0) {
|
|
recordHistory(Number(req.params.id), {
|
|
type_evenement: detectTypeEvenement(changements),
|
|
changements,
|
|
});
|
|
}
|
|
generateSimul(db, {
|
|
id: Number(req.params.id),
|
|
montant_investi: body.montant_investi,
|
|
taux_interet: body.taux_interet ?? null,
|
|
duree_mois: body.duree_mois ?? null,
|
|
type_remb: body.type_remb || 'in_fine',
|
|
freq_interets: body.freq_interets || 'mensuel',
|
|
date_premiere_echeance: body.date_premiere_echeance || null,
|
|
date_debut_simul: body.date_debut_simul || null,
|
|
date_souscription: body.date_souscription,
|
|
echeance_fin_de_mois: body.echeance_fin_de_mois ?? 0,
|
|
});
|
|
res.json({ id: Number(req.params.id), ...body });
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
// PUT /api/investissements/:id/fiscalite-override { override: 'exonere' | null }
|
|
router.put('/:id/fiscalite-override', (req, res, next) => {
|
|
try {
|
|
const inv = db.prepare(
|
|
'SELECT id FROM investissements WHERE id = ? AND investisseur_id IN (SELECT id FROM investisseurs WHERE user_id = ?)'
|
|
).get(req.params.id, req.user.id);
|
|
if (!inv) throw new HttpError(404, 'Investissement introuvable');
|
|
|
|
const override = req.body.override === 'exonere' ? 'exonere' : null;
|
|
db.prepare('UPDATE investissements SET fiscalite_override = ? WHERE id = ?')
|
|
.run(override, req.params.id);
|
|
res.json({ fiscalite_override: override });
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
router.delete('/:id', (req, res, next) => {
|
|
try {
|
|
const r = db.prepare(`
|
|
DELETE FROM investissements
|
|
WHERE id = ? AND investisseur_id IN (SELECT id FROM investisseurs WHERE user_id = ?)
|
|
`).run(req.params.id, req.user.id);
|
|
if (r.changes === 0) throw new HttpError(404, 'Not found');
|
|
res.status(204).end();
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
router.delete('/:id/historique/:hid', (req, res, next) => {
|
|
try {
|
|
const r = db.prepare(`
|
|
DELETE FROM investissement_historique
|
|
WHERE id = ? AND investissement_id = ?
|
|
AND EXISTS (
|
|
SELECT 1 FROM investissements
|
|
WHERE id = ? AND investisseur_id = ?
|
|
)
|
|
`).run(req.params.hid, req.params.id, req.params.id, req.investisseur.id);
|
|
if (r.changes === 0) throw new HttpError(404, 'Not found');
|
|
res.status(204).end();
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
// PUT /api/investissements/:id/auto-reinvest { active: true|false }
|
|
router.put('/:id/auto-reinvest', (req, res, next) => {
|
|
try {
|
|
const inv = db.prepare(
|
|
'SELECT id FROM investissements WHERE id = ? AND investisseur_id = ?'
|
|
).get(req.params.id, req.investisseur.id);
|
|
if (!inv) throw new HttpError(404, 'Investissement introuvable');
|
|
|
|
const active = req.body.active ? 1 : 0;
|
|
db.prepare('UPDATE investissements SET auto_reinvest = ? WHERE id = ?')
|
|
.run(active, req.params.id);
|
|
res.json({ auto_reinvest: !!active });
|
|
} catch (e) { next(e); }
|
|
});
|
|
|
|
export default router;
|