Initial commit

This commit is contained in:
Olivier CROGUENNEC
2026-06-13 14:57:15 +02:00
commit 48ed7fe65e
209 changed files with 49979 additions and 0 deletions
+118
View File
@@ -0,0 +1,118 @@
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';
const router = Router();
const Schema = z.object({
investisseur_id: z.number().int().positive().optional(),
plateforme_id: z.number().int().positive(),
date_operation: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
type: z.enum(['depot', 'retrait']),
montant: z.number().nonnegative(),
libelle: z.string().optional(),
reference: z.string().optional(),
notes: z.string().optional(),
});
/** Résout l'investisseur_id : body en priorité (validé), sinon header */
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;
}
/**
* GET /api/depots-retraits
*
* ?scope=all → agrège tous les investisseurs de l'utilisateur (vue "Famille")
* (défaut) → filtre sur l'investisseur donné par X-Investisseur-Id
*/
router.get('/', (req, res) => {
const scopeAll = req.query.scope === 'all';
const userId = req.user.id;
let invCond, args;
if (scopeAll) {
invCond = 'dr.investisseur_id IN (SELECT id FROM investisseurs WHERE user_id = ?)';
args = [userId];
} else {
const raw = req.header('X-Investisseur-Id');
const id = Number(raw);
if (!id) return res.status(400).json({ error: 'Missing investisseur id (header X-Investisseur-Id)' });
const row = db.prepare('SELECT id FROM investisseurs WHERE id = ? AND user_id = ?').get(id, userId);
if (!row) return res.status(403).json({ error: 'Investisseur not found or not owned by user' });
invCond = 'dr.investisseur_id = ?';
args = [id];
}
const { from, to, type, plateforme_id } = req.query;
const conds = [invCond];
if (from) { conds.push('dr.date_operation >= ?'); args.push(from); }
if (to) { conds.push('dr.date_operation <= ?'); args.push(to); }
if (type) { conds.push('dr.type = ?'); args.push(type); }
if (plateforme_id) { conds.push('dr.plateforme_id = ?'); args.push(Number(plateforme_id)); }
const rows = db.prepare(`
SELECT dr.*, p.nom AS plateforme_nom,
plat_inv.nom AS plateforme_detenteur_nom
FROM depots_retraits dr
JOIN plateformes p ON p.id = dr.plateforme_id
LEFT JOIN investisseurs plat_inv ON plat_inv.id = p.investisseur_id
WHERE ${conds.join(' AND ')}
ORDER BY dr.date_operation DESC, dr.id DESC
`).all(...args);
res.json(rows);
});
router.post('/', requireInvestisseur, (req, res, next) => {
try {
const body = Schema.parse(req.body);
const investisseurId = resolveInvestisseurId(req, body.investisseur_id);
const r = db.prepare(`
INSERT INTO depots_retraits
(investisseur_id, plateforme_id, date_operation, type, montant, libelle, reference, source, notes)
VALUES (?,?,?,?,?,?,?, 'manuel', ?)
`).run(
investisseurId, body.plateforme_id, body.date_operation, body.type,
body.montant, body.libelle || null, body.reference || null, body.notes || null,
);
res.status(201).json({ id: r.lastInsertRowid, ...body });
} catch (e) { next(e); }
});
router.put('/:id', requireInvestisseur, (req, res, next) => {
try {
const body = Schema.parse(req.body);
const investisseurId = resolveInvestisseurId(req, body.investisseur_id);
const r = db.prepare(`
UPDATE depots_retraits
SET investisseur_id=?, plateforme_id=?, date_operation=?, type=?, montant=?,
libelle=?, reference=?, notes=?, updated_at=datetime('now')
WHERE id=? AND investisseur_id IN (SELECT id FROM investisseurs WHERE user_id=?)
`).run(
investisseurId, body.plateforme_id, body.date_operation, body.type, body.montant,
body.libelle || null, body.reference || 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.delete('/:id', requireInvestisseur, (req, res, next) => {
try {
const r = db.prepare(`
DELETE FROM depots_retraits
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); }
});
export default router;