From 5306b61dd270dfe69ff51d26cfa8509ddc238bce Mon Sep 17 00:00:00 2001 From: Matthieu Date: Tue, 30 Sep 2025 15:58:45 +0200 Subject: [PATCH] add seed data --- prisma/seed.ts | 379 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 prisma/seed.ts diff --git a/prisma/seed.ts b/prisma/seed.ts new file mode 100644 index 0000000..5422a5f --- /dev/null +++ b/prisma/seed.ts @@ -0,0 +1,379 @@ +/* eslint-disable no-console */ +import { PrismaClient, ModelCategory } from '@prisma/client'; + +const prisma = new PrismaClient(); + +// --------- Helpers ----------------------------------------------------------- +async function findOrCreateModelType(params: { + code: string; + name: string; + category: ModelCategory; + description?: string | null; + notes?: string | null; +}) { + const { code, name, category, description = null, notes = null } = params; + const existing = await prisma.modelType.findUnique({ where: { code } }).catch(() => null); + if (existing) return existing; + + return prisma.modelType.create({ + data: { code, name, category, description, notes }, + }); +} + +async function findOrCreateComposantModel(params: { + code: string; + name: string; + typeCode: string; // ModelType (category: COMPONENT) + manufacturerName?: string | null; + description?: string | null; +}) { + const { code, name, typeCode, manufacturerName = null, description = null } = params; + + const existing = await prisma.composantModel.findUnique({ where: { code } }).catch(() => null); + if (existing) return existing; + + const type = await prisma.modelType.findUnique({ where: { code: typeCode } }); + if (!type) throw new Error(`ComposantModel: type '${typeCode}' introuvable`); + + const manufacturer = manufacturerName + ? await prisma.constructeur.upsert({ + where: { name: manufacturerName }, + create: { name: manufacturerName }, + update: {}, + }) + : null; + + return prisma.composantModel.create({ + data: { + code, + name, + description, + typeComposant: { connect: { id: type.id } }, + ...(manufacturer ? { constructeur: { connect: { id: manufacturer.id } } } : {}), + }, + }); +} + +async function findOrCreatePieceModel(params: { + code: string; + name: string; + typeCode: string; // ModelType (category: PIECE) + manufacturerName?: string | null; + description?: string | null; +}) { + const { code, name, typeCode, manufacturerName = null, description = null } = params; + + const existing = await prisma.pieceModel.findUnique({ where: { code } }).catch(() => null); + if (existing) return existing; + + const type = await prisma.modelType.findUnique({ where: { code: typeCode } }); + if (!type) throw new Error(`PieceModel: type '${typeCode}' introuvable`); + + const manufacturer = manufacturerName + ? await prisma.constructeur.upsert({ + where: { name: manufacturerName }, + create: { name: manufacturerName }, + update: {}, + }) + : null; + + return prisma.pieceModel.create({ + data: { + code, + name, + description, + typePiece: { connect: { id: type.id } }, + ...(manufacturer ? { constructeur: { connect: { id: manufacturer.id } } } : {}), + }, + }); +} + +async function upsertTypeMachine(params: { + code: string; + name: string; + category?: string | null; + description?: string | null; +}) { + const { code, name, category = 'Convoyage', description = null } = params; + + // Beaucoup de schémas mettent un unique sur name OU code. On essaye les deux. + const existingByCode = await prisma.typeMachine.findUnique({ where: { code } }).catch(() => null); + if (existingByCode) return existingByCode; + + const existingByName = await prisma.typeMachine.findUnique({ where: { name } }).catch(() => null); + if (existingByName) return existingByName; + + return prisma.typeMachine.create({ + data: { + code, + name, + category, + description, + }, + }); +} + +async function addTypeMachineCustomFields(typeMachineId: string) { + // upsert par (typeMachineId, name) si le schéma le permet, sinon find/create + const defs = [ + { name: 'capacite_t_h', type: 'NUMBER', required: false, options: null }, + { name: 'hauteur_m', type: 'NUMBER', required: false, options: null }, + { name: 'sens', type: 'SELECT', required: false, options: ['montant', 'descendant'] }, + { name: 'vitesse_m_s', type: 'NUMBER', required: false, options: null }, + ]; + + for (const d of defs) { + const already = await prisma.customField.findFirst({ + where: { name: d.name, typeMachineId }, + }); + + if (!already) { + await prisma.customField.create({ + data: { + name: d.name, + type: d.type as any, + required: d.required, + options: d.options as any, + typeMachine: { connect: { id: typeMachineId } }, + }, + }); + } + } +} + +async function addRequirements(params: { + typeMachineId: string; + components: Array<{ + label: string; + typeCode: string; // ModelType (COMPONENT) + minCount?: number; + maxCount?: number | null; + required?: boolean; + allowNewModels?: boolean; + }>; + pieces: Array<{ + label: string; + typeCode: string; // ModelType (PIECE) + minCount?: number; + maxCount?: number | null; + required?: boolean; + allowNewModels?: boolean; + }>; +}) { + const { typeMachineId, components, pieces } = params; + + // Composants + for (const r of components) { + const type = await prisma.modelType.findUnique({ where: { code: r.typeCode } }); + if (!type) throw new Error(`Requirement component: type '${r.typeCode}' introuvable`); + + // Évite les doublons simples par (typeMachineId, typeComposantId, label) + const exists = await prisma.typeMachineComponentRequirement.findFirst({ + where: { + typeMachineId, + typeComposantId: type.id, + label: r.label, + }, + }); + + if (!exists) { + await prisma.typeMachineComponentRequirement.create({ + data: { + typeMachine: { connect: { id: typeMachineId } }, + typeComposant: { connect: { id: type.id } }, + label: r.label, + minCount: r.minCount ?? 0, + maxCount: r.maxCount ?? null, + required: r.required ?? true, + allowNewModels: r.allowNewModels ?? true, + }, + }); + } + } + + // Pièces + for (const r of pieces) { + const type = await prisma.modelType.findUnique({ where: { code: r.typeCode } }); + if (!type) throw new Error(`Requirement piece: type '${r.typeCode}' introuvable`); + + const exists = await prisma.typeMachinePieceRequirement.findFirst({ + where: { + typeMachineId, + typePieceId: type.id, + label: r.label, + }, + }); + + if (!exists) { + await prisma.typeMachinePieceRequirement.create({ + data: { + typeMachine: { connect: { id: typeMachineId } }, + typePiece: { connect: { id: type.id } }, + label: r.label, + minCount: r.minCount ?? 0, + maxCount: r.maxCount ?? null, + required: r.required ?? false, + allowNewModels: r.allowNewModels ?? true, + }, + }); + } + } +} + +// --------- Seed principal ---------------------------------------------------- +async function main() { + // 1) Quelques constructeurs de base + await prisma.constructeur.upsert({ + where: { name: 'SEW' }, + update: {}, + create: { name: 'SEW' }, + }); + await prisma.constructeur.upsert({ + where: { name: 'NORD' }, + update: {}, + create: { name: 'NORD' }, + }); + await prisma.constructeur.upsert({ + where: { name: 'SKF' }, + update: {}, + create: { name: 'SKF' }, + }); + + // 2) Familles (ModelType) + // COMPONENT + const compTypes = [ + { code: 'elev-tete', name: 'Tête', category: ModelCategory.COMPONENT }, + { code: 'elev-pied', name: 'Pied', category: ModelCategory.COMPONENT }, + { code: 'elev-gaine', name: 'Gaine', category: ModelCategory.COMPONENT }, + { code: 'elev-entrainement', name: 'Entraînement', category: ModelCategory.COMPONENT }, + { code: 'elev-retour', name: 'Retour', category: ModelCategory.COMPONENT }, + { code: 'elev-sangle-chaine', name: 'Sangle / Chaîne', category: ModelCategory.COMPONENT }, + { code: 'elev-godets-comp', name: 'Rangée de godets', category: ModelCategory.COMPONENT }, + ]; + + // PIECE + const pieceTypes = [ + { code: 'roulement', name: 'Roulement', category: ModelCategory.PIECE }, + { code: 'courroie', name: 'Courroie', category: ModelCategory.PIECE }, + { code: 'visserie', name: 'Visserie', category: ModelCategory.PIECE }, + { code: 'joint', name: 'Joint', category: ModelCategory.PIECE }, + { code: 'capteur', name: 'Capteur', category: ModelCategory.PIECE }, + { code: 'moteur', name: 'Moteur électrique', category: ModelCategory.PIECE }, + { code: 'reducteur', name: 'Réducteur', category: ModelCategory.PIECE }, + { code: 'godet', name: 'Godet', category: ModelCategory.PIECE }, + { code: 'sangle', name: 'Sangle', category: ModelCategory.PIECE }, + { code: 'chaine', name: 'Chaîne', category: ModelCategory.PIECE }, + ]; + + for (const t of [...compTypes, ...pieceTypes]) { + await findOrCreateModelType(t); + } + + // 3) Modèles (catalogues) + // Composants + await findOrCreateComposantModel({ + code: 'tete-standard-500', + name: 'Tête standard 500', + typeCode: 'elev-tete', + manufacturerName: null, + description: 'Sortie latérale, trappe inspection, tambour d’entraînement', + }); + await findOrCreateComposantModel({ + code: 'pied-standard-500', + name: 'Pied standard 500', + typeCode: 'elev-pied', + description: 'Trémie d’alimentation, tambour de retour', + }); + await findOrCreateComposantModel({ + code: 'gaine-1m', + name: 'Gaine 1 m', + typeCode: 'elev-gaine', + }); + await findOrCreateComposantModel({ + code: 'drive-unit-sew', + name: 'Groupe moto-réducteur SEW', + typeCode: 'elev-entrainement', + manufacturerName: 'SEW', + }); + await findOrCreateComposantModel({ + code: 'belt-assembly', + name: 'Ensemble sangle + jonction', + typeCode: 'elev-sangle-chaine', + }); + + // Pièces + await findOrCreatePieceModel({ + code: 'roulement-2208-skf', + name: 'Roulement 2208', + typeCode: 'roulement', + manufacturerName: 'SKF', + }); + await findOrCreatePieceModel({ + code: 'moteur-5-5kw', + name: 'Moteur 5.5 kW', + typeCode: 'moteur', + manufacturerName: 'SEW', + }); + await findOrCreatePieceModel({ + code: 'reducteur-sew-k', + name: 'Réducteur K', + typeCode: 'reducteur', + manufacturerName: 'SEW', + }); + await findOrCreatePieceModel({ + code: 'godet-2l-poly', + name: 'Godet 2 L poly', + typeCode: 'godet', + }); + await findOrCreatePieceModel({ + code: 'sangle-500mm-ep500', + name: 'Sangle 500 mm EP500', + typeCode: 'sangle', + }); + + // 4) TypeMachine “Élévateur à godets” + const elevType = await upsertTypeMachine({ + code: 'elevateur_godets', + name: 'Élévateur à godets', + category: 'Convoyage', + description: 'Élévateur à godets vertical', + }); + + // Champs personnalisés du type + await addTypeMachineCustomFields(elevType.id); + + // Requirements (groupes logiques implicites via label) + await addRequirements({ + typeMachineId: elevType.id, + components: [ + { label: 'Tête', typeCode: 'elev-tete', minCount: 1, maxCount: 1, required: true }, + { label: 'Pied', typeCode: 'elev-pied', minCount: 1, maxCount: 1, required: true }, + { label: 'Gaines', typeCode: 'elev-gaine', minCount: 1, maxCount: null, required: true }, + { label: 'Entraînement', typeCode: 'elev-entrainement', minCount: 1, maxCount: 1, required: true, allowNewModels: true }, + { label: 'Retour', typeCode: 'elev-retour', minCount: 1, maxCount: 1, required: false }, + { label: 'Sangle/Chaîne', typeCode: 'elev-sangle-chaine', minCount: 1, maxCount: 1, required: true }, + { label: 'Rangée de godets', typeCode: 'elev-godets-comp', minCount: 1, maxCount: null, required: true }, + ], + pieces: [ + { label: 'Roulements d’arbres', typeCode: 'roulement', minCount: 2, maxCount: null, required: true }, + { label: 'Moteur', typeCode: 'moteur', minCount: 1, maxCount: 1, required: true }, + { label: 'Réducteur', typeCode: 'reducteur', minCount: 1, maxCount: 1, required: true }, + { label: 'Godets', typeCode: 'godet', minCount: 1, maxCount: null, required: true }, + { label: 'Sangle (si sangle)', typeCode: 'sangle', minCount: 1, maxCount: 1, required: false }, + { label: 'Chaîne (si chaîne)', typeCode: 'chaine', minCount: 1, maxCount: 2, required: false }, + { label: 'Capteurs', typeCode: 'capteur', minCount: 0, maxCount: 4, required: false }, + { label: 'Visserie', typeCode: 'visserie', minCount: 0, maxCount: null, required: false }, + ], + }); + + console.log('✅ Seed terminé.'); +} + +main() + .catch((e) => { + console.error('❌ Seed error:', e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + });