import { Router } from 'express'; import { z } from 'zod'; import db from '../db/index.js'; import { HttpError } from '../middleware/errorHandler.js'; const router = Router(); // Toutes ces routes sont montées sous requireAdmin dans server.js /* GET /api/ref-categories — liste complète */ router.get('/', (_req, res) => { const rows = db.prepare(` SELECT c.id, c.nom, COUNT(rc.referentiel_id) AS nb_utilises FROM categories_inv c LEFT JOIN referentiel_categories_inv rc ON rc.categorie_id = c.id GROUP BY c.id ORDER BY c.nom `).all(); res.json(rows); }); /* POST /api/ref-categories — 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_inv 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_inv (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/: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_inv WHERE id = ?').get(req.params.id); if (!row) throw new HttpError(404, 'Catégorie introuvable'); const dup = db.prepare('SELECT id FROM categories_inv 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_inv SET nom = ? WHERE id = ?').run(nom.trim(), row.id); const nb = db.prepare('SELECT COUNT(*) AS n FROM referentiel_categories_inv 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/:id — supprimer si non utilisée */ router.delete('/:id', (req, res, next) => { try { const row = db.prepare('SELECT id FROM categories_inv 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_inv WHERE categorie_id = ?').get(row.id).n; if (nb > 0) throw new HttpError(409, `Catégorie utilisée par ${nb} référentiel(s) — retirez-la d'abord.`); db.prepare('DELETE FROM categories_inv WHERE id = ?').run(row.id); res.status(204).end(); } catch (e) { next(e); } }); /* POST /api/ref-categories/: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_inv 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_inv 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 referentiel_id FROM referentiel_categories_inv WHERE categorie_id = ?' ).all(source.id); let added = 0, skipped = 0; for (const { referentiel_id } of refs) { const exists = db.prepare( 'SELECT 1 FROM referentiel_categories_inv WHERE referentiel_id = ? AND categorie_id = ?' ).get(referentiel_id, target.id); if (!exists) { db.prepare( 'INSERT INTO referentiel_categories_inv (referentiel_id, categorie_id) VALUES (?, ?)' ).run(referentiel_id, target.id); added++; } else { skipped++; } } db.prepare('DELETE FROM referentiel_categories_inv WHERE categorie_id = ?').run(source.id); db.prepare('DELETE FROM categories_inv 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;