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 ───────────────
|
// ── GET /api/referentiel/export — export tout le référentiel ───────────────
|
||||||
router.get('/export', (_req, res, next) => {
|
router.get('/export', (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
let rows = db.prepare('SELECT * FROM plateformes_referentiel ORDER BY nom').all();
|
let rows = db.prepare('SELECT * FROM plateformes_referentiel ORDER BY nom').all();
|
||||||
rows = attachCatsInv(rows);
|
rows = attachCatsInv(rows);
|
||||||
@@ -290,7 +290,7 @@ router.get('/export', (_req, res, next) => {
|
|||||||
|
|
||||||
const entries = [];
|
const entries = [];
|
||||||
const manifest = {
|
const manifest = {
|
||||||
version: '1.0',
|
version: '1.1',
|
||||||
app: 'crowdlending',
|
app: 'crowdlending',
|
||||||
exported_at: new Date().toISOString(),
|
exported_at: new Date().toISOString(),
|
||||||
count: rows.length,
|
count: rows.length,
|
||||||
@@ -298,6 +298,22 @@ router.get('/export', (_req, res, next) => {
|
|||||||
};
|
};
|
||||||
entries.push({ name: 'manifest.json', data: JSON.stringify(manifest, null, 2) });
|
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 => ({
|
const dataRows = rows.map(r => ({
|
||||||
nom: r.nom,
|
nom: r.nom,
|
||||||
url: r.url,
|
url: r.url,
|
||||||
@@ -333,10 +349,17 @@ router.get('/export', (_req, res, next) => {
|
|||||||
icone_filename: r.icone_filename,
|
icone_filename: r.icone_filename,
|
||||||
categories_inv: (r.categories_inv || []).map(c => c.nom),
|
categories_inv: (r.categories_inv || []).map(c => c.nom),
|
||||||
secteurs_inv: (r.secteurs_inv || []).map(s => s.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) });
|
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
|
// Include logo / icon files
|
||||||
for (const r of rows) {
|
for (const r of rows) {
|
||||||
for (const fname of [r.logo_filename, r.icone_filename]) {
|
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);
|
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
|
// Write logo / icon images from ZIP
|
||||||
for (const fname of [p.logo_filename, p.icone_filename]) {
|
for (const fname of [p.logo_filename, p.icone_filename]) {
|
||||||
if (!fname || !imageMap[fname]) continue;
|
if (!fname || !imageMap[fname]) continue;
|
||||||
@@ -552,6 +595,34 @@ router.post('/import-zip', zipUpload.single('file'), async (req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
tx();
|
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 });
|
res.json({ ok: true, created, updated, total: platforms.length });
|
||||||
} catch (e) { next(e); }
|
} catch (e) { next(e); }
|
||||||
});
|
});
|
||||||
@@ -1000,13 +1071,4 @@ router.put('/notation/:notationId', (req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// DELETE /api/referentiel/notation/:notationId
|
// DELETE /api/referentiel/notation/:notationId
|
||||||
router.delete('/notation/:notationId', (req, res, next) => {
|
rou
|
||||||
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;
|
|
||||||
Reference in New Issue
Block a user