Files
crowdlending-app/backend/src/routes/investisseurs.js
T
Olivier CROGUENNEC 48ed7fe65e Initial commit
2026-06-13 14:57:15 +02:00

127 lines
4.0 KiB
JavaScript

import { Router } from 'express';
import { z } from 'zod';
import db from '../db/index.js';
import { HttpError } from '../middleware/errorHandler.js';
const router = Router();
const Schema = z.object({
nom: z.string().min(1),
prenom: z.string().optional().or(z.literal('')),
type: z.enum(['famille', 'entreprise']).default('famille'),
type_fiscal: z.string().optional(),
notes: z.string().optional(),
});
router.get('/', (req, res) => {
const rows = db
.prepare(
`SELECT id, nom, prenom, type, type_fiscal, is_principal, notes, created_at
FROM investisseurs WHERE user_id = ?
ORDER BY is_principal DESC, type, nom`
)
.all(req.user.id);
res.json(rows);
});
router.post('/', (req, res, next) => {
try {
const body = Schema.parse(req.body);
const r = db
.prepare(
'INSERT INTO investisseurs (user_id, nom, prenom, type, type_fiscal, notes) VALUES (?,?,?,?,?,?)'
)
.run(
req.user.id,
body.nom,
body.prenom || null,
body.type,
body.type_fiscal || null,
body.notes || null,
);
const invId = r.lastInsertRowid;
// Auto-créer un compte courant pour ce nouveau profil
// body.nom contient déjà le nom complet (ex. "Marine CROGUENNEC")
const label = `Compte courant — ${body.nom}`;
db.prepare(
'INSERT INTO comptes (user_id, nom, type, investisseur_id) VALUES (?,?,?,?)'
).run(req.user.id, label, 'compte_courant', invId);
res.status(201).json({ id: invId, ...body });
} catch (e) { next(e); }
});
router.put('/:id', (req, res, next) => {
try {
const body = Schema.parse(req.body);
const r = db
.prepare(
`UPDATE investisseurs SET nom=?, prenom=?, type=?, type_fiscal=?, notes=?, updated_at=datetime('now')
WHERE id=? AND user_id=?`
)
.run(
body.nom,
body.prenom || null,
body.type,
body.type_fiscal || null,
body.notes || null,
req.params.id,
req.user.id,
);
if (r.changes === 0) throw new HttpError(404, 'Not found');
res.json({ id: Number(req.params.id), ...body });
} catch (e) { next(e); }
});
router.post('/reassign-to-principal', (req, res, next) => {
try {
const principal = db
.prepare('SELECT id FROM investisseurs WHERE user_id = ? AND is_principal = 1')
.get(req.user.id);
if (!principal) throw new HttpError(400, 'Aucun compte principal trouvé.');
const principalId = principal.id;
const userId = req.user.id;
const reassign = db.transaction(() => {
db.prepare(
`UPDATE investissements SET investisseur_id = ?
WHERE investisseur_id IN (SELECT id FROM investisseurs WHERE user_id = ?) AND investisseur_id != ?`
).run(principalId, userId, principalId);
db.prepare(
`UPDATE depots_retraits SET investisseur_id = ?
WHERE investisseur_id IN (SELECT id FROM investisseurs WHERE user_id = ?) AND investisseur_id != ?`
).run(principalId, userId, principalId);
});
reassign();
res.json({ ok: true, principal_id: principalId });
} catch (e) { next(e); }
});
router.delete('/:id', (req, res, next) => {
try {
// Empêcher la suppression du compte principal
const target = db
.prepare('SELECT id, is_principal FROM investisseurs WHERE id=? AND user_id=?')
.get(req.params.id, req.user.id);
if (!target) throw new HttpError(404, 'Not found');
if (target.is_principal) throw new HttpError(400, 'Impossible de supprimer le compte principal.');
// Empêcher la suppression si c'est le seul membre
const count = db
.prepare('SELECT COUNT(*) AS n FROM investisseurs WHERE user_id=?')
.get(req.user.id).n;
if (count <= 1) throw new HttpError(400, 'Impossible de supprimer le dernier profil.');
const r = db
.prepare('DELETE FROM investisseurs WHERE id=? AND 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); }
});
export default router;