Reférentiel des institutions financières
This commit is contained in:
1 parent
f2bdf29b16
commit
1dcb33aa74
19 files changed
+1265
No files matched your search
@@ -0,0 +1,104 @@
|
||||
import { Router } from 'express';
|
||||
import { z } from 'zod';
|
||||
import db from '../db/index.js';
|
||||
import { HttpError } from '../middleware/errorHandler.js';
|
||||
|
||||
/**
|
||||
* routes/ref-categories-institutions.js — liste globale des catégories du référentiel
|
||||
* "Institutions financières" (type d'établissement : Banque, Courtier, Assureur...).
|
||||
* Même patron que routes/ref-categories.js (categories_inv), table dédiée
|
||||
* (categories_institutions) — cf. institutionsReferentiel.js.
|
||||
*/
|
||||
|
||||
const router = Router();
|
||||
// Toutes ces routes sont montées sous requireAdmin dans server.js
|
||||
|
||||
/* GET /api/ref-categories-institutions — liste complète */
|
||||
router.get('/', (_req, res) => {
|
||||
const rows = db.prepare(`
|
||||
SELECT c.id, c.nom,
|
||||
COUNT(rc.institution_id) AS nb_utilises
|
||||
FROM categories_institutions c
|
||||
LEFT JOIN referentiel_categories_institutions rc ON rc.categorie_id = c.id
|
||||
GROUP BY c.id
|
||||
ORDER BY c.nom
|
||||
`).all();
|
||||
res.json(rows);
|
||||
});
|
||||
|
||||
/* POST /api/ref-categories-institutions — créer */
|
||||
router.post('/', (req, res, next) => {
|
||||
try {
|
||||
const { nom } = z.object({ nom: z.string().min(1).max(200) }).parse(req.body);
|
||||
const exists = db.prepare('SELECT id FROM categories_institutions WHERE nom = ?').get(nom.trim());
|
||||
if (exists) throw new HttpError(409, `La catégorie "${nom.trim()}" existe déjà.`);
|
||||
const r = db.prepare('INSERT INTO categories_institutions (nom) VALUES (?)').run(nom.trim());
|
||||
res.status(201).json({ id: r.lastInsertRowid, nom: nom.trim(), nb_utilises: 0 });
|
||||
} catch (e) { next(e); }
|
||||
});
|
||||
|
||||
/* PUT /api/ref-categories-institutions/:id — renommer (propage automatiquement) */
|
||||
router.put('/:id', (req, res, next) => {
|
||||
try {
|
||||
const { nom } = z.object({ nom: z.string().min(1).max(200) }).parse(req.body);
|
||||
const row = db.prepare('SELECT id, nom FROM categories_institutions WHERE id = ?').get(req.params.id);
|
||||
if (!row) throw new HttpError(404, 'Catégorie introuvable');
|
||||
const dup = db.prepare('SELECT id FROM categories_institutions WHERE nom = ? AND id != ?').get(nom.trim(), row.id);
|
||||
if (dup) throw new HttpError(409, `La catégorie "${nom.trim()}" existe déjà.`);
|
||||
db.prepare('UPDATE categories_institutions SET nom = ? WHERE id = ?').run(nom.trim(), row.id);
|
||||
const nb = db.prepare('SELECT COUNT(*) AS n FROM referentiel_categories_institutions WHERE categorie_id = ?').get(row.id).n;
|
||||
res.json({ id: row.id, nom: nom.trim(), nb_utilises: nb });
|
||||
} catch (e) { next(e); }
|
||||
});
|
||||
|
||||
/* DELETE /api/ref-categories-institutions/:id — supprimer si non utilisée */
|
||||
router.delete('/:id', (req, res, next) => {
|
||||
try {
|
||||
const row = db.prepare('SELECT id FROM categories_institutions WHERE id = ?').get(req.params.id);
|
||||
if (!row) throw new HttpError(404, 'Catégorie introuvable');
|
||||
const nb = db.prepare('SELECT COUNT(*) AS n FROM referentiel_categories_institutions WHERE categorie_id = ?').get(row.id).n;
|
||||
if (nb > 0) throw new HttpError(409, `Catégorie utilisée par ${nb} institution(s) — retirez-la d'abord.`);
|
||||
db.prepare('DELETE FROM categories_institutions WHERE id = ?').run(row.id);
|
||||
res.status(204).end();
|
||||
} catch (e) { next(e); }
|
||||
});
|
||||
|
||||
/* POST /api/ref-categories-institutions/:id/merge — fusionner dans une autre catégorie */
|
||||
router.post('/:id/merge', (req, res, next) => {
|
||||
try {
|
||||
const { target_id } = z.object({ target_id: z.number().int() }).parse(req.body);
|
||||
const source = db.prepare('SELECT id, nom FROM categories_institutions WHERE id = ?').get(req.params.id);
|
||||
if (!source) throw new HttpError(404, 'Catégorie source introuvable');
|
||||
const target = db.prepare('SELECT id, nom FROM categories_institutions WHERE id = ?').get(target_id);
|
||||
if (!target) throw new HttpError(404, 'Catégorie cible introuvable');
|
||||
if (source.id === target.id) throw new HttpError(400, 'Source et cible identiques');
|
||||
|
||||
const result = db.transaction(() => {
|
||||
const refs = db.prepare(
|
||||
'SELECT institution_id FROM referentiel_categories_institutions WHERE categorie_id = ?'
|
||||
).all(source.id);
|
||||
let added = 0, skipped = 0;
|
||||
for (const { institution_id } of refs) {
|
||||
const exists = db.prepare(
|
||||
'SELECT 1 FROM referentiel_categories_institutions WHERE institution_id = ? AND categorie_id = ?'
|
||||
).get(institution_id, target.id);
|
||||
if (!exists) {
|
||||
db.prepare(
|
||||
'INSERT INTO referentiel_categories_institutions (institution_id, categorie_id) VALUES (?, ?)'
|
||||
).run(institution_id, target.id);
|
||||
added++;
|
||||
} else {
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
db.prepare('DELETE FROM referentiel_categories_institutions WHERE categorie_id = ?').run(source.id);
|
||||
db.prepare('DELETE FROM categories_institutions WHERE id = ?').run(source.id);
|
||||
return { added, skipped, total: refs.length };
|
||||
})();
|
||||
|
||||
res.json({ ok: true, ...result,
|
||||
message: `Fusion terminée : ${result.added} lien(s) ajouté(s), ${result.skipped} déjà présent(s). "${source.nom}" supprimée.` });
|
||||
} catch (e) { next(e); }
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in new issue
Block a user