feat: export/import ZIP référentiel inclut garantie_types + referentiel_notation
This commit is contained in:
@@ -281,7 +281,7 @@ const zipUpload = multer({
|
||||
});
|
||||
|
||||
// ── GET /api/referentiel/export — export tout le référentiel ───────────────
|
||||
router.get('/export', (_req, res, next) => {
|
||||
router.get('/export', (req, res, next) => {
|
||||
try {
|
||||
let rows = db.prepare('SELECT * FROM plateformes_referentiel ORDER BY nom').all();
|
||||
rows = attachCatsInv(rows);
|
||||
@@ -290,7 +290,7 @@ router.get('/export', (_req, res, next) => {
|
||||
|
||||
const entries = [];
|
||||
const manifest = {
|
||||
version: '1.0',
|
||||
version: '1.1',
|
||||
app: 'crowdlending',
|
||||
exported_at: new Date().toISOString(),
|
||||
count: rows.length,
|
||||
@@ -298,6 +298,22 @@ router.get('/export', (_req, res, next) => {
|
||||
};
|
||||
entries.push({ name: 'manifest.json', data: JSON.stringify(manifest, null, 2) });
|
||||
|
||||
// Attach referentiel_notation to each platform
|
||||
const notationByRef = {};
|
||||
const notRows = db.prepare('SELECT * FROM referentiel_notation ORDER BY referentiel_id, ordre, id').all();
|
||||
for (const n of notRows) {
|
||||
if (!notationByRef[n.referentiel_id]) notationByRef[n.referentiel_id] = [];
|
||||
notationByRef[n.referentiel_id].push({
|
||||
nom: n.nom,
|
||||
type: n.type,
|
||||
valeurs: n.valeurs ? JSON.parse(n.valeurs) : null,
|
||||
min_val: n.min_val,
|
||||
max_val: n.max_val,
|
||||
description: n.description,
|
||||
ordre: n.ordre,
|
||||
});
|
||||
}
|
||||
|
||||
const dataRows = rows.map(r => ({
|
||||
nom: r.nom,
|
||||
url: r.url,
|
||||
@@ -333,10 +349,17 @@ router.get('/export', (_req, res, next) => {
|
||||
icone_filename: r.icone_filename,
|
||||
categories_inv: (r.categories_inv || []).map(c => c.nom),
|
||||
secteurs_inv: (r.secteurs_inv || []).map(s => s.nom),
|
||||
notation: notationByRef[r.id] || [],
|
||||
}));
|
||||
|
||||
entries.push({ name: 'data.json', data: JSON.stringify(dataRows, null, 2) });
|
||||
|
||||
// Types de garanties du user courant
|
||||
const garanties = db.prepare(
|
||||
'SELECT libelle, description, ordre FROM garantie_types WHERE user_id = ? ORDER BY ordre, id'
|
||||
).all(req.user.id);
|
||||
entries.push({ name: 'garanties.json', data: JSON.stringify(garanties, null, 2) });
|
||||
|
||||
// Include logo / icon files
|
||||
for (const r of rows) {
|
||||
for (const fname of [r.logo_filename, r.icone_filename]) {
|
||||
@@ -542,6 +565,26 @@ router.post('/import-zip', zipUpload.single('file'), async (req, res, next) => {
|
||||
db.prepare('INSERT OR IGNORE INTO referentiel_secteurs_inv (referentiel_id, secteur_id) VALUES (?,?)').run(refId, id);
|
||||
}
|
||||
|
||||
// Sync referentiel_notation
|
||||
if (Array.isArray(p.notation) && p.notation.length) {
|
||||
db.prepare('DELETE FROM referentiel_notation WHERE referentiel_id = ?').run(refId);
|
||||
for (const n of p.notation) {
|
||||
db.prepare(`
|
||||
INSERT INTO referentiel_notation (referentiel_id, nom, type, valeurs, min_val, max_val, description, ordre)
|
||||
VALUES (?,?,?,?,?,?,?,?)
|
||||
`).run(
|
||||
refId,
|
||||
(n.nom || '').trim(),
|
||||
n.type || 'etoiles',
|
||||
n.valeurs ? JSON.stringify(Array.isArray(n.valeurs) ? n.valeurs : [n.valeurs]) : null,
|
||||
n.min_val ?? null,
|
||||
n.max_val ?? null,
|
||||
n.description ?? null,
|
||||
n.ordre ?? 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Write logo / icon images from ZIP
|
||||
for (const fname of [p.logo_filename, p.icone_filename]) {
|
||||
if (!fname || !imageMap[fname]) continue;
|
||||
@@ -552,6 +595,34 @@ router.post('/import-zip', zipUpload.single('file'), async (req, res, next) => {
|
||||
});
|
||||
|
||||
tx();
|
||||
|
||||
// ── Import garanties ──────────────────────────────────────────────────────
|
||||
const garantiesEntry = zipEntries.find(e => e.name === 'garanties.json');
|
||||
if (garantiesEntry) {
|
||||
const garanties = JSON.parse(garantiesEntry.data.toString('utf8'));
|
||||
if (Array.isArray(garanties) && garanties.length) {
|
||||
const gtx = db.transaction(() => {
|
||||
for (const g of garanties) {
|
||||
const libelle = (g.libelle || '').trim();
|
||||
if (!libelle) continue;
|
||||
const existing = db.prepare(
|
||||
'SELECT id FROM garantie_types WHERE user_id = ? AND LOWER(libelle) = LOWER(?)'
|
||||
).get(req.user.id, libelle);
|
||||
if (existing) {
|
||||
db.prepare(
|
||||
'UPDATE garantie_types SET description=?, ordre=? WHERE id=?'
|
||||
).run(g.description ?? null, g.ordre ?? 0, existing.id);
|
||||
} else {
|
||||
db.prepare(
|
||||
'INSERT INTO garantie_types (user_id, libelle, description, ordre) VALUES (?,?,?,?)'
|
||||
).run(req.user.id, libelle, g.description ?? null, g.ordre ?? 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
gtx();
|
||||
}
|
||||
}
|
||||
|
||||
res.json({ ok: true, created, updated, total: platforms.length });
|
||||
} catch (e) { next(e); }
|
||||
});
|
||||
@@ -1000,13 +1071,4 @@ router.put('/notation/:notationId', (req, res, next) => {
|
||||
});
|
||||
|
||||
// DELETE /api/referentiel/notation/:notationId
|
||||
router.delete('/notation/:notationId', (req, res, next) => {
|
||||
try {
|
||||
const existing = db.prepare('SELECT id FROM referentiel_notation WHERE id = ?').get(req.params.notationId);
|
||||
if (!existing) throw new HttpError(404, 'Critere introuvable');
|
||||
db.prepare('DELETE FROM referentiel_notation WHERE id = ?').run(req.params.notationId);
|
||||
res.json({ deleted: true });
|
||||
} catch (e) { next(e); }
|
||||
});
|
||||
|
||||
export default router;
|
||||
rou
|
||||
Reference in New Issue
Block a user