This repository has been archived on 2026-04-01. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Inventory_backend/scripts/seed-industrial-data.ts
2025-10-01 16:44:20 +02:00

3195 lines
92 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { PrismaClient, Prisma, ModelCategory } from '@prisma/client';
const prisma = new PrismaClient();
type CustomFieldSpec = {
name: string;
type: 'string' | 'number' | 'boolean' | 'date' | 'select';
required?: boolean;
defaultValue?: string;
options?: string[];
};
type ComponentTypeDefinition = {
code: string;
name: string;
description: string;
customFields: CustomFieldSpec[];
};
type PieceTypeDefinition = {
code: string;
name: string;
description: string;
customFields: CustomFieldSpec[];
};
type PieceModelDefinition = {
code: string;
name: string;
description: string;
typeCode: string;
structure?: Prisma.InputJsonValue;
};
type ComponentModelDefinition = {
code: string;
name: string;
description: string;
typeCode: string;
structure?: Prisma.InputJsonValue;
};
type ConstructeurDefinition = {
key: string;
name: string;
email?: string;
phone?: string;
};
type ComponentPieceInstance = {
name: string;
reference?: string;
prix?: string;
typeCode: string;
modelCode: string;
constructeur?: string;
customValues?: Record<string, string | number | boolean | Date>;
};
type ComponentInstance = {
name: string;
reference?: string;
prix?: string;
typeCode: string;
requirementLabel?: string;
modelCode: string;
constructeur?: string;
customValues?: Record<string, string | number | boolean | Date>;
pieces?: ComponentPieceInstance[];
children?: ComponentInstance[];
};
type TypeMachineDefinition = {
code: string;
name: string;
description: string;
category: string;
maintenanceFrequency: string;
specifications: Prisma.InputJsonValue;
customFields: CustomFieldSpec[];
componentRequirements: {
label: string;
typeCode: string;
minCount: number;
maxCount?: number;
required: boolean;
}[];
pieceRequirements?: {
label: string;
typeCode: string;
minCount: number;
maxCount?: number;
required: boolean;
}[];
};
type MachineBuildSpec = {
code: string;
typeMachineCode: string;
name: string;
reference: string;
prix: string;
constructeurKey: string;
customFieldValues: Record<string, string | number | boolean | Date>;
components: ComponentInstance[];
sparePieces?: (ComponentPieceInstance & { requirementLabel?: string })[];
};
type TypeMachineRecord = Prisma.TypeMachineGetPayload<{
include: {
customFields: true;
componentRequirements: true;
pieceRequirements: true;
};
}>;
const componentTypeDefinitions: ComponentTypeDefinition[] = [
{
code: 'bucket-elevator',
name: 'Élévateur à godets',
description:
"Élévateur vertical utilisé pour monter les grains vers les étages supérieurs de l'usine.",
customFields: [
{ name: 'Débit nominal (t/h)', type: 'number', required: true },
{ name: 'Hauteur de levage (m)', type: 'number' },
{
name: 'Matériau des godets',
type: 'select',
defaultValue: 'Acier galvanisé',
options: ['Acier galvanisé', 'Acier inoxydable', 'Polypropylène renforcé'],
},
],
},
{
code: 'belt-conveyor',
name: 'Convoyeur à bande',
description:
'Convoyeur horizontal ou incliné assurant le transfert des grains entre les postes.',
customFields: [
{ name: 'Largeur de bande (mm)', type: 'number', required: true },
{ name: 'Longueur (m)', type: 'number' },
{
name: 'Type de bande',
type: 'select',
defaultValue: 'Caoutchouc anti-statique',
options: ['Caoutchouc anti-statique', 'PVC alimentaire', 'Polyuréthane grain'],
},
],
},
{
code: 'gravity-separator',
name: 'Table densimétrique',
description:
'Séparateur gravimétrique permettant de retirer les impuretés lourdes ou légères.',
customFields: [
{ name: 'Capacité de tri (t/h)', type: 'number', required: true },
{ name: 'Fréquence de vibration (Hz)', type: 'number' },
{
name: 'Type de plateau',
type: 'select',
defaultValue: 'Acier perforé',
options: ['Acier perforé', 'Inox poli', 'Tôle aluminium'],
},
],
},
{
code: 'grain-dryer',
name: 'Séchoir à grains',
description:
"Séchoir continu assurant la réduction du taux d'humidité des céréales.",
customFields: [
{ name: 'Capacité sèche (t/h)', type: 'number', required: true },
{ name: "Nombre d'étages", type: 'number' },
{
name: "Type d'énergie",
type: 'select',
defaultValue: 'Gaz naturel',
options: ['Gaz naturel', 'Biomasse', 'Fioul léger'],
},
],
},
{
code: 'screw-conveyor',
name: 'Vis sans fin',
description: 'Vis de transfert pour la reprise des grains et le rechargement des silos.',
customFields: [
{ name: 'Diamètre vis (mm)', type: 'number', required: true },
{ name: 'Inclinaison (°)', type: 'number' },
{ name: 'Vitesse (rpm)', type: 'number' },
],
},
{
code: 'weigh-hopper',
name: 'Benna peseuse',
description: 'Benna équipée de capteurs de pesage pour le chargement précis des camions.',
customFields: [
{ name: 'Capacité de pesée (kg)', type: 'number', required: true },
{ name: 'Précision (%)', type: 'number' },
{
name: 'Mode de vidange',
type: 'select',
defaultValue: 'Trappe motorisée',
options: ['Trappe motorisée', 'Vis doseuse', 'Vanne guillotine'],
},
],
},
{
code: 'control-panel',
name: 'Armoire de contrôle',
description: "Armoire électrique pilotant l'ensemble de la ligne de triage.",
customFields: [
{
name: 'Automate principal',
type: 'select',
required: true,
defaultValue: 'Schneider Modicon M340',
options: ['Schneider Modicon M340', 'Siemens S7-1500', 'Schneider Modicon M221'],
},
{ name: 'Année de mise à jour', type: 'number' },
{
name: "Indice de protection",
type: 'select',
defaultValue: 'IP55',
options: ['IP55', 'IP65', 'IP54'],
},
],
},
{
code: 'telehandler',
name: 'Chariot télescopique',
description:
'Manitou utilisé pour les manutentions ponctuelles et la gestion des sacs big-bags.',
customFields: [
{ name: 'Capacité de levage (t)', type: 'number', required: true },
{ name: 'Hauteur de levage (m)', type: 'number' },
{
name: "Type d'attache",
type: 'select',
defaultValue: 'Fourches FEM',
options: ['Fourches FEM', 'Godet céréales', 'Pince big-bag'],
},
],
},
{
code: 'burner-module',
name: 'Module brûleur',
description: 'Module de combustion alimentant le séchoir en air chaud.',
customFields: [
{ name: 'Puissance thermique (kW)', type: 'number', required: true },
{
name: 'Type de carburant',
type: 'select',
defaultValue: 'Gaz naturel',
options: ['Gaz naturel', 'Biométhane', 'Fioul léger'],
},
{
name: "Système d'allumage",
type: 'select',
defaultValue: 'Double électrode',
options: ['Double électrode', 'Brûleur pilote', 'Allumeur électronique'],
},
],
},
{
code: 'dust-filter',
name: 'Filtre à poussière',
description: 'Filtre à cyclone captant les poussières en sortie de séchoir.',
customFields: [
{ name: 'Efficacité de filtration (%)', type: 'number', required: true },
{
name: 'Type de média filtrant',
type: 'select',
options: ['Polyester', 'Fibre de verre', 'Polypropylène'],
defaultValue: 'Polyester',
},
{ name: 'Nombre de cartouches', type: 'number' },
],
},
{
code: 'motor-drive',
name: 'Groupe moteur',
description: 'Motorisation asynchrone montée sur bride pour entraînements industriels.',
customFields: [
{ name: 'Puissance nominale (kW)', type: 'number', required: true },
{
name: 'Classe énergétique',
type: 'select',
defaultValue: 'IE3',
options: ['IE2', 'IE3', 'IE4'],
},
{
name: "Indice de protection",
type: 'select',
defaultValue: 'IP55',
options: ['IP55', 'IP65', 'IP23'],
},
],
},
{
code: 'gearbox-assembly',
name: 'Train réducteur',
description: 'Réducteur de vitesse pour entraînement lourd.',
customFields: [
{
name: 'Rapport de réduction',
type: 'select',
defaultValue: '1:28',
options: ['1:28', '1:24', '1:18'],
},
{ name: 'Couple nominal (Nm)', type: 'number' },
{
name: 'Type de montage',
type: 'select',
options: ['À pattes', 'À bride', 'Sur arbre'],
defaultValue: 'À bride',
},
],
},
{
code: 'hydraulic-power-pack',
name: 'Groupe hydraulique',
description: "Groupe hydraulique alimentant les vérins d'un chariot télescopique.",
customFields: [
{ name: 'Débit nominal (l/min)', type: 'number', required: true },
{ name: 'Pression max (bar)', type: 'number' },
{
name: 'Type de pompe',
type: 'select',
options: ['Piston axial', 'Palette', 'Engrenages'],
defaultValue: 'Piston axial',
},
],
},
{
code: 'ventilation-fan',
name: 'Ventilateur process',
description: "Ventilateur d'extraction pour séchage et dépoussiérage.",
customFields: [
{ name: 'Débit (m³/h)', type: 'number', required: true },
{
name: 'Type de roue',
type: 'select',
options: ['Axiale', 'Centrifuge', 'Mixte'],
defaultValue: 'Centrifuge',
},
{ name: 'Vitesse nominale (rpm)', type: 'number' },
],
},
];
const pieceTypeDefinitions: PieceTypeDefinition[] = [
{
code: 'hex-screw',
name: 'Vis hexagonale',
description: 'Visserie pour assemblages mécaniques.',
customFields: [
{ name: 'Diamètre (mm)', type: 'number', required: true },
{ name: 'Longueur (mm)', type: 'number', required: true },
{
name: 'Classe acier',
type: 'select',
options: ['8.8', '10.9', '12.9'],
defaultValue: '8.8',
},
],
},
{
code: 'lock-washer',
name: 'Rondelle Grower',
description: 'Rondelle anti-desserrage.',
customFields: [
{ name: 'Diamètre (mm)', type: 'number', required: true },
{
name: 'Finition',
type: 'select',
options: ['Zinguée', 'Inox', 'Noire'],
defaultValue: 'Zinguée',
},
],
},
{
code: 'flat-gasket',
name: 'Joint plat',
description: 'Joint pour brides et trappes de maintenance.',
customFields: [
{
name: 'Matière',
type: 'select',
options: ['NBR', 'PTFE', 'Fibre compressée'],
defaultValue: 'NBR',
},
{ name: 'Épaisseur (mm)', type: 'number', required: true },
],
},
{
code: 'drive-belt',
name: 'Courroie',
description: 'Courroie transporteuse ou de transmission.',
customFields: [
{ name: 'Largeur (mm)', type: 'number', required: true },
{
name: 'Matériau',
type: 'select',
options: ['Caoutchouc nitrile', 'Polyuréthane', 'PVC'],
defaultValue: 'Caoutchouc nitrile',
},
],
},
{
code: 'roller-bearing',
name: 'Roulement',
description: 'Roulement à semelle ou palier.',
customFields: [
{
name: 'Série',
type: 'select',
options: ['UCP', 'UCFL', 'UCT'],
defaultValue: 'UCP',
},
{
name: "Type d'étanchéité",
type: 'select',
options: ['2RS', 'ZZ', 'Ouvert'],
defaultValue: '2RS',
},
],
},
{
code: 'filter-cartridge',
name: 'Cartouche filtrante',
description: 'Cartouche filtrante pour dépoussiérage.',
customFields: [
{
name: 'Classe de filtration',
type: 'select',
options: ['G4', 'F7', 'M5'],
defaultValue: 'G4',
},
{ name: 'Dimensions (mm)', type: 'string', required: true },
],
},
{
code: 'speed-sensor',
name: 'Capteur de vitesse',
description: 'Capteur inductif contrôlant la vitesse des organes rotatifs.',
customFields: [
{
name: 'Type de sortie',
type: 'select',
options: ['PNP 4-20 mA', 'PNP tout ou rien', 'NPN'],
defaultValue: 'PNP 4-20 mA',
},
{ name: 'Plage de mesure (rpm)', type: 'number' },
],
},
{
code: 'temperature-probe',
name: 'Sonde de température',
description: 'Sonde PT100 pour la surveillance thermique du séchoir.',
customFields: [
{
name: 'Type de sonde',
type: 'select',
options: ['PT100 classe A', 'PT100 classe B', 'Thermocouple K'],
defaultValue: 'PT100 classe A',
},
{ name: 'Plage de mesure (°C)', type: 'string', required: true },
],
},
{
code: 'plc-module',
name: 'Module automate',
description: 'Module PLC assurant des entrées/sorties pour la ligne.',
customFields: [
{ name: "Nombre d'E/S", type: 'number', required: true },
{
name: 'Version firmware',
type: 'select',
options: ['V2.8', 'V2.9', 'V3.0'],
defaultValue: 'V2.9',
},
],
},
{
code: 'load-cell',
name: 'Capteur de pesage',
description: 'Capteur de pesage pour benne peseuse.',
customFields: [
{ name: 'Capacité (kg)', type: 'number', required: true },
{
name: 'Type de connexion',
type: 'select',
options: ['Câble 4 fils', 'Câble 6 fils', 'Connecteur M12'],
defaultValue: 'Câble 6 fils',
},
],
},
{
code: 'fuse-cartridge',
name: 'Fusible industriel',
description: 'Fusible de protection pour armoire électrique.',
customFields: [
{ name: 'Calibre (A)', type: 'number', required: true },
{
name: 'Type de fusible',
type: 'select',
options: ['gG', 'aM', 'gR'],
defaultValue: 'gG',
},
],
},
];
const pieceModelDefinitions: PieceModelDefinition[] = [
{
code: 'screw-m10x60',
name: 'Vis M10x60 10.9',
description: 'Vis hexagonale classe 10.9 longueur 60 mm.',
typeCode: 'hex-screw',
structure: {
defaultCustomFieldValues: {
'Diamètre (mm)': '10',
'Longueur (mm)': '60',
'Classe acier': '10.9',
},
},
},
{
code: 'screw-m12x80',
name: 'Vis M12x80 8.8',
description: 'Vis hexagonale galvanisée 80 mm.',
typeCode: 'hex-screw',
structure: {
defaultCustomFieldValues: {
'Diamètre (mm)': '12',
'Longueur (mm)': '80',
'Classe acier': '8.8',
},
},
},
{
code: 'screw-m8x30',
name: 'Vis M8x30 inox',
description: 'Visserie inox pour équipements alimentaires.',
typeCode: 'hex-screw',
structure: {
defaultCustomFieldValues: {
'Diamètre (mm)': '8',
'Longueur (mm)': '30',
'Classe acier': '8.8',
},
},
},
{
code: 'washer-grower-10',
name: 'Rondelle Grower Ø10',
description: 'Rondelle Grower zinguée diamètre 10 mm.',
typeCode: 'lock-washer',
structure: {
defaultCustomFieldValues: {
'Diamètre (mm)': '10',
'Finition': 'Zinguée',
},
},
},
{
code: 'washer-grower-12',
name: 'Rondelle Grower Ø12 inox',
description: 'Rondelle Grower inox diamètre 12 mm.',
typeCode: 'lock-washer',
structure: {
defaultCustomFieldValues: {
'Diamètre (mm)': '12',
'Finition': 'Inox',
},
},
},
{
code: 'gasket-nbr-5',
name: 'Joint NBR 5 mm',
description: 'Joint plat NBR épaisseur 5 mm.',
typeCode: 'flat-gasket',
structure: {
defaultCustomFieldValues: {
Matière: 'NBR',
'Épaisseur (mm)': '5',
},
},
},
{
code: 'gasket-ptfe-3',
name: 'Joint PTFE 3 mm',
description: 'Joint plat PTFE pour brides haute température.',
typeCode: 'flat-gasket',
structure: {
defaultCustomFieldValues: {
Matière: 'PTFE',
'Épaisseur (mm)': '3',
},
},
},
{
code: 'belt-hd-800',
name: 'Courroie renforcée 800 mm',
description: 'Bande transporteuse HD 800 mm.',
typeCode: 'drive-belt',
structure: {
defaultCustomFieldValues: {
'Largeur (mm)': '800',
Matériau: 'Caoutchouc nitrile',
},
},
},
{
code: 'belt-hd-650',
name: 'Courroie renforcée 650 mm',
description: 'Bande transporteuse 650 mm.',
typeCode: 'drive-belt',
structure: {
defaultCustomFieldValues: {
'Largeur (mm)': '650',
Matériau: 'Polyuréthane',
},
},
},
{
code: 'bearing-ucp210',
name: 'Palier UCP210',
description: 'Palier fonte UCP210 graissable.',
typeCode: 'roller-bearing',
structure: {
defaultCustomFieldValues: {
Série: 'UCP',
"Type d'étanchéité": '2RS',
},
},
},
{
code: 'bearing-ucfl207',
name: 'Palier UCFL207',
description: 'Palier à semelle UCFL207.',
typeCode: 'roller-bearing',
structure: {
defaultCustomFieldValues: {
Série: 'UCFL',
"Type d'étanchéité": 'ZZ',
},
},
},
{
code: 'filter-g4-500',
name: 'Cartouche G4 500x500',
description: 'Cartouche filtrante G4.',
typeCode: 'filter-cartridge',
structure: {
defaultCustomFieldValues: {
'Classe de filtration': 'G4',
'Dimensions (mm)': '500x500x50',
},
},
},
{
code: 'filter-f7-610',
name: 'Cartouche F7 610x610',
description: 'Cartouche haute efficacité F7.',
typeCode: 'filter-cartridge',
structure: {
defaultCustomFieldValues: {
'Classe de filtration': 'F7',
'Dimensions (mm)': '610x610x75',
},
},
},
{
code: 'sensor-speed-m12',
name: 'Capteur inductif M12',
description: 'Capteur de vitesse inductif 4-20 mA.',
typeCode: 'speed-sensor',
structure: {
defaultCustomFieldValues: {
'Type de sortie': 'PNP 4-20 mA',
'Plage de mesure (rpm)': '1200',
},
},
},
{
code: 'sensor-speed-m18',
name: 'Capteur inductif M18',
description: 'Capteur de vitesse M18 robuste.',
typeCode: 'speed-sensor',
structure: {
defaultCustomFieldValues: {
'Type de sortie': 'PNP tout ou rien',
'Plage de mesure (rpm)': '900',
},
},
},
{
code: 'temp-probe-pt100',
name: 'Sonde PT100 250 mm',
description: 'Sonde PT100 pour mesure dair chaud.',
typeCode: 'temperature-probe',
structure: {
defaultCustomFieldValues: {
'Type de sonde': 'PT100 classe A',
'Plage de mesure (°C)': '0-250',
},
},
},
{
code: 'temp-probe-pt100-short',
name: 'Sonde PT100 150 mm',
description: 'Sonde PT100 courte pour supervision.',
typeCode: 'temperature-probe',
structure: {
defaultCustomFieldValues: {
'Type de sonde': 'PT100 classe B',
'Plage de mesure (°C)': '0-200',
},
},
},
{
code: 'plc-module-s71200',
name: 'Module PLC S7-1200',
description: 'Module dentrées/sorties Siemens S7-1200.',
typeCode: 'plc-module',
structure: {
defaultCustomFieldValues: {
"Nombre d'E/S": '24',
'Version firmware': 'V2.8',
},
},
},
{
code: 'plc-module-m340',
name: 'Module PLC Modicon M340',
description: 'Module entrée/sortie Modicon M340.',
typeCode: 'plc-module',
structure: {
defaultCustomFieldValues: {
"Nombre d'E/S": '32',
'Version firmware': 'V2.9',
},
},
},
{
code: 'load-cell-5t',
name: 'Capteur de pesage 5 t',
description: 'Capteur de pesage IP68 pour benne peseuse.',
typeCode: 'load-cell',
structure: {
defaultCustomFieldValues: {
'Capacité (kg)': '5000',
'Type de connexion': 'Câble 6 fils',
},
},
},
{
code: 'load-cell-10t',
name: 'Capteur de pesage 10 t',
description: 'Capteur de pesage haute capacité.',
typeCode: 'load-cell',
structure: {
defaultCustomFieldValues: {
'Capacité (kg)': '10000',
'Type de connexion': 'Connecteur M12',
},
},
},
{
code: 'fuse-gg-25a',
name: 'Fusible gG 25A',
description: 'Fusible gG calibre 25A.',
typeCode: 'fuse-cartridge',
structure: {
defaultCustomFieldValues: {
'Calibre (A)': '25',
'Type de fusible': 'gG',
},
},
},
{
code: 'fuse-gg-40a',
name: 'Fusible gG 40A',
description: 'Fusible gG calibre 40A.',
typeCode: 'fuse-cartridge',
structure: {
defaultCustomFieldValues: {
'Calibre (A)': '40',
'Type de fusible': 'gG',
},
},
},
];
const componentModelDefinitions: ComponentModelDefinition[] = [
{
code: 'elevator-z400',
name: 'Élévateur Z400',
description: 'Élévateur à godets 120 t/h, 38 m.',
typeCode: 'bucket-elevator',
structure: {
recommendedCustomFields: {
'Débit nominal (t/h)': '120',
'Hauteur de levage (m)': '38',
'Matériau des godets': 'Acier galvanisé',
},
defaultPieces: [
{ modelCode: 'belt-hd-800', role: 'Courroie élévatrice' },
{ modelCode: 'screw-m12x80', role: 'Fixations tête' },
{ modelCode: 'washer-grower-12', role: 'Sécurité visserie' },
],
subComponents: [
{ modelCode: 'motor-drive-75', role: 'Groupe moteur' },
{ modelCode: 'gearbox-flender', role: 'Train réducteur' },
],
},
},
{
code: 'elevator-z320',
name: 'Élévateur Z320',
description: 'Élévateur à godets 95 t/h, 32 m.',
typeCode: 'bucket-elevator',
structure: {
recommendedCustomFields: {
'Débit nominal (t/h)': '95',
'Hauteur de levage (m)': '32',
'Matériau des godets': 'Polypropylène renforcé',
},
defaultPieces: [
{ modelCode: 'belt-hd-650', role: 'Courroie élévatrice' },
{ modelCode: 'screw-m10x60', role: 'Fixations pied' },
{ modelCode: 'washer-grower-10', role: 'Sécurité pied' },
],
subComponents: [
{ modelCode: 'motor-drive-55', role: 'Groupe moteur' },
{ modelCode: 'gearbox-bonfiglioli', role: 'Réducteur' },
],
},
},
{
code: 'conveyor-18m',
name: 'Convoyeur bande 18 m',
description: 'Convoyeur à bande 800 mm, 18 mètres.',
typeCode: 'belt-conveyor',
structure: {
recommendedCustomFields: {
'Largeur de bande (mm)': '800',
'Longueur (m)': '18',
'Type de bande': 'Caoutchouc anti-statique',
},
defaultPieces: [
{ modelCode: 'belt-hd-800', role: 'Bande transporteuse' },
{ modelCode: 'screw-m10x60', role: 'Kit boulonnerie' },
],
subComponents: [
{ modelCode: 'motor-drive-45', role: 'Motorisation' },
{ modelCode: 'gearbox-bonfiglioli', role: 'Réducteur' },
],
},
},
{
code: 'conveyor-25m',
name: 'Convoyeur bande 25 m',
description: 'Convoyeur à bande 650 mm, 25 mètres.',
typeCode: 'belt-conveyor',
structure: {
recommendedCustomFields: {
'Largeur de bande (mm)': '650',
'Longueur (m)': '25',
'Type de bande': 'PVC alimentaire',
},
defaultPieces: [
{ modelCode: 'belt-hd-650', role: 'Bande transporteuse' },
{ modelCode: 'screw-m8x30', role: 'Kit tendeur' },
],
subComponents: [
{ modelCode: 'motor-drive-37', role: 'Motorisation' },
{ modelCode: 'gearbox-bonfiglioli', role: 'Réducteur' },
],
},
},
{
code: 'gravity-table-tqx',
name: 'Table densimétrique TQX-120',
description: 'Table densimétrique haute précision 120 t/h.',
typeCode: 'gravity-separator',
structure: {
recommendedCustomFields: {
'Capacité de tri (t/h)': '120',
'Fréquence de vibration (Hz)': '45',
'Type de plateau': 'Acier perforé',
},
defaultPieces: [
{ modelCode: 'sensor-speed-m12', role: 'Capteur vibration' },
{ modelCode: 'screw-m8x30', role: 'Fixation plateau' },
],
subComponents: [{ modelCode: 'motor-drive-18', role: 'Moteur vibration' }],
},
},
{
code: 'gravity-table-compact',
name: 'Table densimétrique Compact 80',
description: 'Table densimétrique compacte 80 t/h.',
typeCode: 'gravity-separator',
structure: {
recommendedCustomFields: {
'Capacité de tri (t/h)': '80',
'Fréquence de vibration (Hz)': '40',
'Type de plateau': 'Inox poli',
},
defaultPieces: [
{ modelCode: 'sensor-speed-m18', role: 'Capteur vibration' },
{ modelCode: 'screw-m8x30', role: 'Fixation plateau' },
],
subComponents: [{ modelCode: 'motor-drive-15', role: 'Moteur vibration' }],
},
},
{
code: 'grain-dryer-cd6',
name: 'Séchoir continu CD-6',
description: 'Séchoir continu 6 étages avec récupération de chaleur.',
typeCode: 'grain-dryer',
structure: {
recommendedCustomFields: {
'Capacité sèche (t/h)': '60',
"Nombre d'étages": '6',
"Type d'énergie": 'Gaz naturel',
},
defaultPieces: [{ modelCode: 'gasket-nbr-5', role: 'Joint trappe inspection' }],
subComponents: [
{ modelCode: 'burner-module-3mw', role: 'Brûleur principal' },
{ modelCode: 'dust-filter-fc12', role: 'Filtre cyclone' },
{ modelCode: 'ventilation-fan-axial90', role: 'Ventilateur extraction' },
],
},
},
{
code: 'grain-dryer-cd4',
name: 'Séchoir continu CD-4',
description: 'Séchoir continu 4 étages compact.',
typeCode: 'grain-dryer',
structure: {
recommendedCustomFields: {
'Capacité sèche (t/h)': '40',
"Nombre d'étages": '4',
"Type d'énergie": 'Biomasse',
},
defaultPieces: [{ modelCode: 'gasket-ptfe-3', role: 'Joint trappe inspection' }],
subComponents: [
{ modelCode: 'burner-module-2mw', role: 'Brûleur biomasse' },
{ modelCode: 'dust-filter-fc8', role: 'Filtre cyclone' },
{ modelCode: 'ventilation-fan-axial60', role: 'Ventilateur extraction' },
],
},
},
{
code: 'screw-conveyor-v200',
name: 'Vis sans fin V200',
description: 'Vis de reprise diamètre 200 mm.',
typeCode: 'screw-conveyor',
structure: {
recommendedCustomFields: {
'Diamètre vis (mm)': '200',
'Inclinaison (°)': '12',
'Vitesse (rpm)': '140',
},
defaultPieces: [
{ modelCode: 'screw-m12x80', role: 'Fixations palier' },
{ modelCode: 'bearing-ucp210', role: 'Paliers supports' },
],
subComponents: [{ modelCode: 'motor-drive-18', role: 'Motorisation vis' }],
},
},
{
code: 'screw-conveyor-v160',
name: 'Vis sans fin V160',
description: 'Vis de transfert diamètre 160 mm.',
typeCode: 'screw-conveyor',
structure: {
recommendedCustomFields: {
'Diamètre vis (mm)': '160',
'Inclinaison (°)': '8',
'Vitesse (rpm)': '110',
},
defaultPieces: [
{ modelCode: 'screw-m10x60', role: 'Fixations palier' },
{ modelCode: 'bearing-ucfl207', role: 'Paliers supports' },
],
subComponents: [{ modelCode: 'motor-drive-15', role: 'Motorisation vis' }],
},
},
{
code: 'weigh-hopper-bp5',
name: 'Benna peseuse BP-5',
description: 'Benna peseuse 5 tonnes pour chargement camion.',
typeCode: 'weigh-hopper',
structure: {
recommendedCustomFields: {
'Capacité de pesée (kg)': '5000',
'Précision (%)': '0.5',
'Mode de vidange': 'Trappe motorisée',
},
defaultPieces: [
{ modelCode: 'load-cell-5t', role: 'Capteurs de pesage' },
{ modelCode: 'screw-m10x60', role: 'Kit fixation capteur' },
],
},
},
{
code: 'weigh-hopper-bp3',
name: 'Benna peseuse BP-3',
description: 'Benna peseuse 3 tonnes pour chargement big-bags.',
typeCode: 'weigh-hopper',
structure: {
recommendedCustomFields: {
'Capacité de pesée (kg)': '3000',
'Précision (%)': '0.3',
'Mode de vidange': 'Vis doseuse',
},
defaultPieces: [
{ modelCode: 'load-cell-5t', role: 'Capteurs de pesage' },
{ modelCode: 'screw-m8x30', role: 'Kit fixation capteur' },
],
},
},
{
code: 'control-panel-m340',
name: 'Armoire Schneider M340',
description: 'Armoire Schneider Electric avec automate M340.',
typeCode: 'control-panel',
structure: {
recommendedCustomFields: {
'Automate principal': 'Schneider Modicon M340',
'Année de mise à jour': '2023',
"Indice de protection": 'IP55',
},
defaultPieces: [
{ modelCode: 'plc-module-m340', role: 'Automate principal' },
{ modelCode: 'fuse-gg-25a', role: 'Protection alimentation' },
{ modelCode: 'sensor-speed-m12', role: 'Entrée vitesse ligne' },
],
},
},
{
code: 'control-panel-s7',
name: 'Armoire Siemens S7-1500',
description: 'Armoire Siemens S7-1500 pour ligne secondaire.',
typeCode: 'control-panel',
structure: {
recommendedCustomFields: {
'Automate principal': 'Siemens S7-1500',
'Année de mise à jour': '2022',
"Indice de protection": 'IP65',
},
defaultPieces: [
{ modelCode: 'plc-module-s71200', role: 'Module E/S' },
{ modelCode: 'fuse-gg-40a', role: 'Protection puissance' },
],
},
},
{
code: 'burner-module-3mw',
name: 'Brûleur gaz 3 MW',
description: 'Brûleur gaz modulant 3 MW pour séchoir.',
typeCode: 'burner-module',
structure: {
recommendedCustomFields: {
'Puissance thermique (kW)': '3000',
'Type de carburant': 'Gaz naturel',
"Système d'allumage": 'Double électrode',
},
defaultPieces: [{ modelCode: 'temp-probe-pt100', role: 'Sonde sécurité flamme' }],
},
},
{
code: 'burner-module-2mw',
name: 'Brûleur biomasse 2 MW',
description: 'Brûleur biomasse 2 MW pour séchoir compact.',
typeCode: 'burner-module',
structure: {
recommendedCustomFields: {
'Puissance thermique (kW)': '2000',
'Type de carburant': 'Biomasse',
"Système d'allumage": 'Brûleur pilote',
},
defaultPieces: [{ modelCode: 'temp-probe-pt100-short', role: 'Sonde sécurité flamme' }],
},
},
{
code: 'dust-filter-fc12',
name: 'Filtre cyclone FC-12',
description: 'Filtre cyclone avec cartouches G4.',
typeCode: 'dust-filter',
structure: {
recommendedCustomFields: {
'Efficacité de filtration (%)': '95',
'Type de média filtrant': 'Polyester',
'Nombre de cartouches': '6',
},
defaultPieces: [{ modelCode: 'filter-g4-500', role: 'Cartouche filtrante' }],
},
},
{
code: 'dust-filter-fc8',
name: 'Filtre cyclone FC-8',
description: 'Filtre cyclone compact avec cartouches F7.',
typeCode: 'dust-filter',
structure: {
recommendedCustomFields: {
'Efficacité de filtration (%)': '90',
'Type de média filtrant': 'Fibre de verre',
'Nombre de cartouches': '4',
},
defaultPieces: [{ modelCode: 'filter-f7-610', role: 'Cartouche filtrante' }],
},
},
{
code: 'telehandler-mlt1040',
name: 'Manitou MLT 1040',
description: 'Chariot télescopique Manitou 4 t.',
typeCode: 'telehandler',
structure: {
recommendedCustomFields: {
'Capacité de levage (t)': '4',
'Hauteur de levage (m)': '9.6',
"Type d'attache": 'Fourches FEM',
},
subComponents: [
{ modelCode: 'motor-drive-75', role: 'Moteur principal' },
{ modelCode: 'hydraulic-pack-pvh98', role: 'Groupe hydraulique' },
],
defaultPieces: [
{ modelCode: 'gasket-nbr-5', role: 'Joint clapet' },
{ modelCode: 'fuse-gg-40a', role: 'Protection cabine' },
],
},
},
{
code: 'telehandler-mlt840',
name: 'Manitou MLT 840',
description: 'Chariot télescopique Manitou 3,5 t.',
typeCode: 'telehandler',
structure: {
recommendedCustomFields: {
'Capacité de levage (t)': '3.5',
'Hauteur de levage (m)': '7.5',
"Type d'attache": 'Godet céréales',
},
subComponents: [
{ modelCode: 'motor-drive-55', role: 'Moteur principal' },
{ modelCode: 'hydraulic-pack-vg80', role: 'Groupe hydraulique' },
],
defaultPieces: [{ modelCode: 'fuse-gg-25a', role: 'Protection cabine' }],
},
},
{
code: 'motor-drive-75',
name: 'Groupe moteur IE3 75 kW',
description: 'Moteur IE3 75 kW montage à bride.',
typeCode: 'motor-drive',
structure: {
recommendedCustomFields: {
'Puissance nominale (kW)': '75',
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
defaultPieces: [
{ modelCode: 'screw-m12x80', role: 'Fixations bride' },
{ modelCode: 'washer-grower-12', role: 'Sécurité bride' },
],
},
},
{
code: 'motor-drive-55',
name: 'Groupe moteur IE3 55 kW',
description: 'Moteur IE3 55 kW.',
typeCode: 'motor-drive',
structure: {
recommendedCustomFields: {
'Puissance nominale (kW)': '55',
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
defaultPieces: [
{ modelCode: 'screw-m12x80', role: 'Fixations bride' },
{ modelCode: 'washer-grower-12', role: 'Sécurité bride' },
],
},
},
{
code: 'motor-drive-45',
name: 'Groupe moteur IE3 45 kW',
description: 'Moteur IE3 45 kW pour convoyeurs.',
typeCode: 'motor-drive',
structure: {
recommendedCustomFields: {
'Puissance nominale (kW)': '45',
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
defaultPieces: [
{ modelCode: 'screw-m10x60', role: 'Fixations bride' },
{ modelCode: 'washer-grower-10', role: 'Sécurité bride' },
],
},
},
{
code: 'motor-drive-37',
name: 'Groupe moteur IE3 37 kW',
description: 'Moteur IE3 37 kW pour convoyeur long.',
typeCode: 'motor-drive',
structure: {
recommendedCustomFields: {
'Puissance nominale (kW)': '37',
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
defaultPieces: [
{ modelCode: 'screw-m10x60', role: 'Fixations bride' },
{ modelCode: 'washer-grower-10', role: 'Sécurité bride' },
],
},
},
{
code: 'motor-drive-18',
name: 'Groupe moteur IE3 18,5 kW',
description: 'Moteur IE3 pour vis sans fin.',
typeCode: 'motor-drive',
structure: {
recommendedCustomFields: {
'Puissance nominale (kW)': '18.5',
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
defaultPieces: [
{ modelCode: 'screw-m10x60', role: 'Fixations bride' },
{ modelCode: 'washer-grower-10', role: 'Sécurité bride' },
],
},
},
{
code: 'motor-drive-15',
name: 'Groupe moteur IE3 15 kW',
description: 'Moteur IE3 pour équipements auxiliaires.',
typeCode: 'motor-drive',
structure: {
recommendedCustomFields: {
'Puissance nominale (kW)': '15',
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
defaultPieces: [
{ modelCode: 'screw-m8x30', role: 'Fixations bride' },
{ modelCode: 'washer-grower-10', role: 'Sécurité bride' },
],
},
},
{
code: 'gearbox-flender',
name: 'Réducteur Flender FZ',
description: 'Réducteur coaxial pour charge lourde.',
typeCode: 'gearbox-assembly',
structure: {
recommendedCustomFields: {
'Rapport de réduction': '1:28',
'Couple nominal (Nm)': '3200',
'Type de montage': 'À bride',
},
defaultPieces: [{ modelCode: 'gasket-nbr-5', role: 'Joint de bride' }],
},
},
{
code: 'gearbox-bonfiglioli',
name: 'Réducteur Bonfiglioli TA',
description: 'Réducteur orthogonal Bonfiglioli.',
typeCode: 'gearbox-assembly',
structure: {
recommendedCustomFields: {
'Rapport de réduction': '1:24',
'Couple nominal (Nm)': '2100',
'Type de montage': 'Sur arbre',
},
defaultPieces: [{ modelCode: 'gasket-ptfe-3', role: 'Joint de bride' }],
},
},
{
code: 'hydraulic-pack-pvh98',
name: 'Groupe hydraulique PVH98',
description: 'Groupe hydraulique 160 l/min.',
typeCode: 'hydraulic-power-pack',
structure: {
recommendedCustomFields: {
'Débit nominal (l/min)': '160',
'Pression max (bar)': '320',
'Type de pompe': 'Piston axial',
},
defaultPieces: [{ modelCode: 'gasket-nbr-5', role: 'Joint collecteur' }],
},
},
{
code: 'hydraulic-pack-vg80',
name: 'Groupe hydraulique VG80',
description: 'Groupe hydraulique 110 l/min.',
typeCode: 'hydraulic-power-pack',
structure: {
recommendedCustomFields: {
'Débit nominal (l/min)': '110',
'Pression max (bar)': '260',
'Type de pompe': 'Engrenages',
},
defaultPieces: [{ modelCode: 'gasket-ptfe-3', role: 'Joint collecteur' }],
},
},
{
code: 'ventilation-fan-axial90',
name: 'Ventilateur axial 90 kW',
description: 'Ventilateur axial 90 kW.',
typeCode: 'ventilation-fan',
structure: {
recommendedCustomFields: {
'Débit (m³/h)': '48000',
'Type de roue': 'Axiale',
'Vitesse nominale (rpm)': '980',
},
defaultPieces: [{ modelCode: 'screw-m12x80', role: 'Fixations châssis' }],
},
},
{
code: 'ventilation-fan-axial60',
name: 'Ventilateur axial 60 kW',
description: 'Ventilateur axial 60 kW compact.',
typeCode: 'ventilation-fan',
structure: {
recommendedCustomFields: {
'Débit (m³/h)': '32000',
'Type de roue': 'Axiale',
'Vitesse nominale (rpm)': '1450',
},
defaultPieces: [{ modelCode: 'screw-m10x60', role: 'Fixations châssis' }],
},
},
];
const constructeurDefinitions: ConstructeurDefinition[] = [
{
key: 'agritech',
name: 'AgriTech Elevators',
email: 'support@agritech-elevators.fr',
phone: '+33 3 74 01 20 10',
},
{
key: 'valmont',
name: 'Valmont Conveyors',
email: 'info@valmont-conveyors.com',
phone: '+33 3 80 45 77 20',
},
{
key: 'buhler',
name: 'Bühler Sortex',
email: 'service@buhlergroup.com',
phone: '+41 71 955 11 11',
},
{
key: 'agridry',
name: 'AgriDry Solutions',
email: 'contact@agridry.eu',
phone: '+33 4 74 22 55 90',
},
{
key: 'sew',
name: 'SEW-Eurodrive',
email: 'contact@sew-eurodrive.fr',
phone: '+33 3 88 73 67 00',
},
{
key: 'skf',
name: 'SKF France',
email: 'support@skf.com',
phone: '+33 1 30 57 67 00',
},
{
key: 'schneider',
name: 'Schneider Electric',
email: 'contact@se.com',
phone: '+33 1 47 29 70 00',
},
{
key: 'manitou',
name: 'Manitou BF',
email: 'support@manitou-group.com',
phone: '+33 2 40 09 10 11',
},
{
key: 'flender',
name: 'Flender GmbH',
email: 'service@flender.com',
phone: '+49 521 525 0',
},
{
key: 'ifm',
name: 'ifm electronic',
email: 'info.fr@ifm.com',
phone: '+33 1 45 12 24 00',
},
{
key: 'siemens',
name: 'Siemens Industry',
email: 'industry.fr@siemens.com',
phone: '+33 1 85 57 00 00',
},
{
key: 'bonfiglioli',
name: 'Bonfiglioli Riduttori',
email: 'sales@bonfiglioli.com',
phone: '+39 051 647 3111',
},
{
key: 'agrifan',
name: 'AgriFan Ventilation',
email: 'contact@agrifan.fr',
phone: '+33 2 44 55 12 32',
},
{
key: 'poclain',
name: 'Poclain Hydraulics',
email: 'support@poclain-hydraulics.com',
phone: '+33 3 44 31 74 00',
},
];
async function clearDatabaseExceptSitesAndProfiles() {
console.log('🧹 Nettoyage des tables (hors sites et profils)...');
const deleteOrder = [
prisma.customFieldValue.deleteMany(),
prisma.document.deleteMany(),
prisma.piece.deleteMany(),
prisma.composant.deleteMany(),
prisma.machine.deleteMany(),
prisma.typeMachineComponentRequirement.deleteMany(),
prisma.typeMachinePieceRequirement.deleteMany(),
prisma.customField.deleteMany(),
prisma.pieceModel.deleteMany(),
prisma.composantModel.deleteMany(),
prisma.typeMachine.deleteMany(),
prisma.modelType.deleteMany(),
prisma.constructeur.deleteMany(),
];
for (const promise of deleteOrder) {
await promise;
}
console.log('✅ Tables nettoyées.');
}
async function ensureDemoSite() {
const existingSite = await prisma.site.findFirst();
if (existingSite) {
return existingSite;
}
console.log('🏗️ Création du site de démonstration...');
return prisma.site.create({
data: {
name: 'Usine de triage Valgrain',
contactName: 'Lucie Bernard',
contactPhone: '+33 3 80 12 45 78',
contactAddress: 'Zone industrielle des Platanes',
contactPostalCode: '21000',
contactCity: 'Dijon',
},
});
}
async function createConstructeurs() {
console.log('🏭 Création des constructeurs...');
const entries = await Promise.all(
constructeurDefinitions.map((definition) =>
prisma.constructeur
.create({
data: {
name: definition.name,
email: definition.email,
phone: definition.phone,
},
})
.then((constructeur) => [definition.key, constructeur] as const),
),
);
return Object.fromEntries(entries) as Record<string, { id: string }>;
}
function mapCustomFields(fields: { id: string; name: string }[]) {
return fields.reduce<Record<string, string>>((acc, field) => {
acc[field.name] = field.id;
return acc;
}, {});
}
async function createModelTypes() {
console.log('🗂️ Création des catégories de composants et pièces...');
const componentTypeEntries: [
string,
{ id: string; customFields: Record<string, string> },
][] = [];
for (const definition of componentTypeDefinitions) {
const record = await prisma.modelType.create({
data: {
name: definition.name,
code: definition.code,
category: ModelCategory.COMPONENT,
description: definition.description,
customFields: {
create: definition.customFields.map((field) => ({
name: field.name,
type: field.type,
required: field.required ?? false,
defaultValue: field.defaultValue,
options: field.options ?? [],
})),
},
},
include: { customFields: true },
});
componentTypeEntries.push([
definition.code,
{ id: record.id, customFields: mapCustomFields(record.customFields) },
]);
}
const pieceTypeEntries: [
string,
{ id: string; customFields: Record<string, string> },
][] = [];
for (const definition of pieceTypeDefinitions) {
const record = await prisma.modelType.create({
data: {
name: definition.name,
code: definition.code,
category: ModelCategory.PIECE,
description: definition.description,
pieceCustomFields: {
create: definition.customFields.map((field) => ({
name: field.name,
type: field.type,
required: field.required ?? false,
defaultValue: field.defaultValue,
options: field.options ?? [],
})),
},
},
include: { pieceCustomFields: true },
});
pieceTypeEntries.push([
definition.code,
{ id: record.id, customFields: mapCustomFields(record.pieceCustomFields) },
]);
}
return {
componentTypes: Object.fromEntries(componentTypeEntries) as Record<
string,
{ id: string; customFields: Record<string, string> }
>,
pieceTypes: Object.fromEntries(pieceTypeEntries) as Record<
string,
{ id: string; customFields: Record<string, string> }
>,
};
}
async function createPieceModels(pieceTypes: Record<string, { id: string }>) {
console.log('🔧 Création des modèles de pièces...');
const entries = await Promise.all(
pieceModelDefinitions.map(async (definition) => {
const record = await prisma.pieceModel.create({
data: {
name: definition.name,
description: definition.description,
typePiece: { connect: { id: pieceTypes[definition.typeCode].id } },
structure: definition.structure ?? Prisma.JsonNull,
},
});
return [definition.code, record] as const;
}),
);
return Object.fromEntries(entries) as Record<string, { id: string }>;
}
async function createComponentModels(
componentTypes: Record<string, { id: string }>,
) {
console.log('🧱 Création des modèles de composants...');
const entries = await Promise.all(
componentModelDefinitions.map(async (definition) => {
const record = await prisma.composantModel.create({
data: {
name: definition.name,
description: definition.description,
typeComposant: { connect: { id: componentTypes[definition.typeCode].id } },
structure: definition.structure ?? Prisma.JsonNull,
},
});
return [definition.code, record] as const;
}),
);
return Object.fromEntries(entries) as Record<string, { id: string }>;
}
const typeMachineDefinitions: TypeMachineDefinition[] = [
{
code: 'triage-line',
name: 'Ligne de triage céréales 120 t/h',
description:
'Chaîne automatisée de réception, triage, ventilation et expédition des céréales.',
category: 'Triage et stockage',
maintenanceFrequency:
'Inspection quotidienne, graissage hebdomadaire, révision trimestrielle.',
specifications: {
nominalThroughput: 120,
shiftsPerDay: 2,
building: 'Hall principal',
},
customFields: [
{ name: 'Capacité nominale (t/h)', type: 'number', required: true },
{
name: 'Produit traité',
type: 'select',
required: true,
defaultValue: 'Blé tendre',
options: ['Blé tendre', 'Orge brassicole', 'Maïs grain', 'Pois protéagineux'],
},
{ name: 'Date de mise en service', type: 'date', required: true },
{
name: 'Responsable de ligne',
type: 'select',
defaultValue: 'Lucie Bernard',
options: ['Lucie Bernard', 'Karim Dubois', 'Anaëlle Petit'],
},
],
componentRequirements: [
{
label: 'Élévateurs principaux',
typeCode: 'bucket-elevator',
minCount: 2,
maxCount: 2,
required: true,
},
{
label: "Convoyeurs d'alimentation",
typeCode: 'belt-conveyor',
minCount: 2,
required: true,
},
{
label: 'Table densimétrique',
typeCode: 'gravity-separator',
minCount: 1,
maxCount: 1,
required: true,
},
{
label: 'Vis de reprise',
typeCode: 'screw-conveyor',
minCount: 2,
required: true,
},
{
label: 'Poste de pesage',
typeCode: 'weigh-hopper',
minCount: 1,
maxCount: 1,
required: true,
},
{
label: 'Armoire de contrôle',
typeCode: 'control-panel',
minCount: 1,
maxCount: 1,
required: true,
},
{
label: 'Ventilation',
typeCode: 'ventilation-fan',
minCount: 1,
required: true,
},
],
pieceRequirements: [
{
label: 'Kit visserie critique',
typeCode: 'hex-screw',
minCount: 1,
required: false,
},
{
label: 'Capteurs de vitesse de secours',
typeCode: 'speed-sensor',
minCount: 2,
required: false,
},
{
label: 'Cartouches de filtration',
typeCode: 'filter-cartridge',
minCount: 2,
required: false,
},
],
},
{
code: 'grain-dryer-station',
name: 'Station de séchage et dépoussiérage',
description: 'Poste de séchage haute capacité avec filtration et reprise.',
category: 'Séchage',
maintenanceFrequency: 'Contrôle brûleur hebdomadaire, nettoyage cyclone mensuel.',
specifications: {
nominalThroughput: 60,
building: 'Tour de séchage',
nightOperation: true,
},
customFields: [
{
name: 'Produit séché',
type: 'select',
defaultValue: 'Maïs grain',
options: ['Maïs grain', 'Blé dur', 'Tournesol'],
required: true,
},
{
name: 'Mode dalimentation',
type: 'select',
options: ['Élévateur principal', 'Vis de reprise', 'Chargement manuel'],
defaultValue: 'Élévateur principal',
},
{ name: 'Date de mise en service', type: 'date', required: true },
],
componentRequirements: [
{
label: 'Séchoir continu',
typeCode: 'grain-dryer',
minCount: 1,
maxCount: 1,
required: true,
},
{
label: 'Module brûleur',
typeCode: 'burner-module',
minCount: 1,
required: true,
},
{
label: 'Filtration poussières',
typeCode: 'dust-filter',
minCount: 1,
required: true,
},
{
label: 'Ventilation process',
typeCode: 'ventilation-fan',
minCount: 1,
required: true,
},
{
label: 'Vis de reprise',
typeCode: 'screw-conveyor',
minCount: 1,
required: true,
},
{
label: 'Armoire de supervision',
typeCode: 'control-panel',
minCount: 1,
required: true,
},
],
pieceRequirements: [
{
label: 'Joints haute température',
typeCode: 'flat-gasket',
minCount: 2,
required: false,
},
{
label: 'Sondes de température de secours',
typeCode: 'temperature-probe',
minCount: 2,
required: false,
},
],
},
{
code: 'telehandler-support',
name: 'Chariot télescopique logistique',
description: 'Chariot télescopique dédié aux manutentions céréalières.',
category: 'Logistique',
maintenanceFrequency: 'Graissage hebdomadaire, contrôle hydraulique mensuel.',
specifications: {
yardArea: 'Cour logistique',
rotation: '3 équipes',
},
customFields: [
{
name: 'Usage principal',
type: 'select',
options: ['Chargement camions', 'Gestion big-bags', 'Maintenance silo'],
defaultValue: 'Chargement camions',
},
{
name: 'Lieu de stationnement',
type: 'select',
options: ['Hangar nord', 'Cour extérieure', 'Atelier maintenance'],
defaultValue: 'Hangar nord',
},
{ name: "Année d'achat", type: 'number', required: true },
],
componentRequirements: [
{
label: 'Châssis télescopique',
typeCode: 'telehandler',
minCount: 1,
maxCount: 1,
required: true,
},
{
label: 'Groupe moteur',
typeCode: 'motor-drive',
minCount: 1,
required: true,
},
{
label: 'Groupe hydraulique',
typeCode: 'hydraulic-power-pack',
minCount: 1,
required: true,
},
{
label: 'Armoire de contrôle cabine',
typeCode: 'control-panel',
minCount: 1,
required: false,
},
],
pieceRequirements: [
{
label: 'Fusibles cabine',
typeCode: 'fuse-cartridge',
minCount: 1,
required: false,
},
{
label: 'Joints hydrauliques de secours',
typeCode: 'flat-gasket',
minCount: 1,
required: false,
},
],
},
];
async function createTypeMachines(
componentTypes: Record<string, { id: string }>,
pieceTypes: Record<string, { id: string }>,
) {
console.log('🧬 Création des squelettes de machines...');
const entries = await Promise.all(
typeMachineDefinitions.map(async (definition) => {
const record = await prisma.typeMachine.create({
data: {
name: definition.name,
description: definition.description,
category: definition.category,
maintenanceFrequency: definition.maintenanceFrequency,
specifications: definition.specifications,
components: {
layout: definition.componentRequirements.map((requirement, index) => ({
order: index + 1,
zone: requirement.label,
type: requirement.typeCode,
})),
},
machinePieces: {
recommendedStock: [],
},
customFields: {
create: definition.customFields.map((field) => ({
name: field.name,
type: field.type,
required: field.required ?? false,
defaultValue: field.defaultValue,
options: field.options ?? [],
})),
},
componentRequirements: {
create: definition.componentRequirements.map((requirement) => ({
label: requirement.label,
minCount: requirement.minCount,
maxCount: requirement.maxCount,
required: requirement.required,
typeComposant: {
connect: { id: componentTypes[requirement.typeCode].id },
},
})),
},
pieceRequirements: definition.pieceRequirements
? {
create: definition.pieceRequirements.map((requirement) => ({
label: requirement.label,
minCount: requirement.minCount,
maxCount: requirement.maxCount,
required: requirement.required,
typePiece: {
connect: { id: pieceTypes[requirement.typeCode].id },
},
})),
}
: undefined,
},
include: {
customFields: true,
componentRequirements: true,
pieceRequirements: true,
},
});
return [definition.code, record] as const;
}),
);
return Object.fromEntries(entries) as Record<string, TypeMachineRecord>;
}
function buildCustomFieldValues(
fieldMap: Record<string, string>,
values?: Record<string, string | number | boolean | Date>,
) {
if (!values) {
return undefined;
}
return {
create: Object.entries(values).map(([name, value]) => {
const fieldId = fieldMap[name];
if (!fieldId) {
throw new Error(`Champ personnalisé inconnu: ${name}`);
}
return {
value: value instanceof Date ? value.toISOString() : String(value),
customField: {
connect: { id: fieldId },
},
};
}),
};
}
async function createComponentHierarchy(
machineId: string,
component: ComponentInstance,
context: {
componentTypes: Record<string, { id: string; customFields: Record<string, string> }>;
componentModels: Record<string, { id: string }>;
pieceTypes: Record<string, { id: string; customFields: Record<string, string> }>;
pieceModels: Record<string, { id: string }>;
constructeurs: Record<string, { id: string }>;
requirementMap: Map<string, string>;
},
parentId?: string,
) {
const requirementId = component.requirementLabel
? context.requirementMap.get(component.requirementLabel)
: undefined;
const record = await prisma.composant.create({
data: {
name: component.name,
reference: component.reference,
prix: component.prix ? new Prisma.Decimal(component.prix) : undefined,
machine: { connect: { id: machineId } },
parentComposant: parentId ? { connect: { id: parentId } } : undefined,
typeComposant: {
connect: { id: context.componentTypes[component.typeCode].id },
},
composantModel: {
connect: { id: context.componentModels[component.modelCode].id },
},
typeMachineComponentRequirement: requirementId
? { connect: { id: requirementId } }
: undefined,
constructeur: component.constructeur
? { connect: { id: context.constructeurs[component.constructeur].id } }
: undefined,
customFieldValues: buildCustomFieldValues(
context.componentTypes[component.typeCode].customFields,
component.customValues,
),
pieces: component.pieces
? {
create: component.pieces.map((piece) => {
const type = context.pieceTypes[piece.typeCode];
if (!type) {
throw new Error(`Type de pièce introuvable: ${piece.typeCode}`);
}
return {
name: piece.name,
reference: piece.reference,
prix: piece.prix ? new Prisma.Decimal(piece.prix) : undefined,
typePiece: { connect: { id: type.id } },
pieceModel: {
connect: { id: context.pieceModels[piece.modelCode].id },
},
constructeur: piece.constructeur
? { connect: { id: context.constructeurs[piece.constructeur].id } }
: undefined,
customFieldValues: buildCustomFieldValues(
type.customFields,
piece.customValues,
),
};
}),
}
: undefined,
},
});
if (component.children && component.children.length > 0) {
for (const child of component.children) {
await createComponentHierarchy(machineId, child, context, record.id);
}
}
return record;
}
const machineBuilds: MachineBuildSpec[] = [
{
code: 'triage-line-main',
typeMachineCode: 'triage-line',
name: 'Ligne de triage Valgrain 2024',
reference: 'VT-TRI-2024',
prix: '725000',
constructeurKey: 'buhler',
customFieldValues: {
'Capacité nominale (t/h)': 120,
'Produit traité': 'Blé tendre',
'Date de mise en service': new Date('2024-02-01'),
'Responsable de ligne': 'Lucie Bernard',
},
components: [
{
name: 'Élévateur amont Z400',
reference: 'BE-Z400-01',
prix: '58000',
typeCode: 'bucket-elevator',
requirementLabel: 'Élévateurs principaux',
modelCode: 'elevator-z400',
constructeur: 'agritech',
customValues: {
'Débit nominal (t/h)': 120,
'Hauteur de levage (m)': 38,
'Matériau des godets': 'Acier galvanisé',
},
pieces: [
{
name: 'Courroie élévateur 800 mm',
reference: 'BLT-800-01',
prix: '2300',
typeCode: 'drive-belt',
modelCode: 'belt-hd-800',
constructeur: 'agritech',
customValues: {
'Largeur (mm)': 800,
Matériau: 'Caoutchouc nitrile',
},
},
{
name: 'Kit visserie tête élévateur',
reference: 'KIT-VIS-EL-01',
typeCode: 'hex-screw',
modelCode: 'screw-m12x80',
customValues: {
'Diamètre (mm)': 12,
'Longueur (mm)': 80,
'Classe acier': '8.8',
},
},
{
name: 'Rondelles Grower Ø12',
reference: 'RW-12-EL-01',
typeCode: 'lock-washer',
modelCode: 'washer-grower-12',
customValues: {
'Diamètre (mm)': 12,
Finition: 'Inox',
},
},
],
children: [
{
name: 'Moteur élévateur 75 kW',
reference: 'MTR-75-01',
typeCode: 'motor-drive',
modelCode: 'motor-drive-75',
constructeur: 'sew',
customValues: {
'Puissance nominale (kW)': 75,
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
},
{
name: 'Réducteur tête Flender',
reference: 'GBX-FZ-01',
typeCode: 'gearbox-assembly',
modelCode: 'gearbox-flender',
constructeur: 'flender',
customValues: {
'Rapport de réduction': '1:28',
'Couple nominal (Nm)': 3200,
'Type de montage': 'À bride',
},
},
],
},
{
name: 'Élévateur aval Z320',
reference: 'BE-Z320-02',
prix: '49700',
typeCode: 'bucket-elevator',
requirementLabel: 'Élévateurs principaux',
modelCode: 'elevator-z320',
constructeur: 'agritech',
customValues: {
'Débit nominal (t/h)': 95,
'Hauteur de levage (m)': 32,
'Matériau des godets': 'Polypropylène renforcé',
},
pieces: [
{
name: 'Courroie élévateur 650 mm',
reference: 'BLT-650-02',
typeCode: 'drive-belt',
modelCode: 'belt-hd-650',
customValues: {
'Largeur (mm)': 650,
Matériau: 'Polyuréthane',
},
},
{
name: 'Kit visserie pied élévateur',
reference: 'KIT-VIS-EL-02',
typeCode: 'hex-screw',
modelCode: 'screw-m10x60',
customValues: {
'Diamètre (mm)': 10,
'Longueur (mm)': 60,
'Classe acier': '10.9',
},
},
{
name: 'Rondelles Grower Ø10',
reference: 'RW-10-EL-02',
typeCode: 'lock-washer',
modelCode: 'washer-grower-10',
customValues: {
'Diamètre (mm)': 10,
Finition: 'Zinguée',
},
},
],
children: [
{
name: 'Moteur élévateur 55 kW',
reference: 'MTR-55-02',
typeCode: 'motor-drive',
modelCode: 'motor-drive-55',
constructeur: 'sew',
customValues: {
'Puissance nominale (kW)': 55,
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
},
{
name: 'Réducteur Bonfiglioli TA',
reference: 'GBX-TA-02',
typeCode: 'gearbox-assembly',
modelCode: 'gearbox-bonfiglioli',
constructeur: 'bonfiglioli',
customValues: {
'Rapport de réduction': '1:24',
'Couple nominal (Nm)': 2100,
'Type de montage': 'Sur arbre',
},
},
],
},
{
name: "Convoyeur d'alimentation A",
reference: 'CV-18-01',
prix: '36200',
typeCode: 'belt-conveyor',
requirementLabel: "Convoyeurs d'alimentation",
modelCode: 'conveyor-18m',
constructeur: 'valmont',
customValues: {
'Largeur de bande (mm)': 800,
'Longueur (m)': 18,
'Type de bande': 'Caoutchouc anti-statique',
},
pieces: [
{
name: 'Bande transporteuse 800 mm',
reference: 'BAND-800-A',
typeCode: 'drive-belt',
modelCode: 'belt-hd-800',
customValues: {
'Largeur (mm)': 800,
Matériau: 'Caoutchouc nitrile',
},
},
{
name: 'Kit tendeur M10',
reference: 'KIT-TEN-01',
typeCode: 'hex-screw',
modelCode: 'screw-m10x60',
customValues: {
'Diamètre (mm)': 10,
'Longueur (mm)': 60,
'Classe acier': '10.9',
},
},
],
children: [
{
name: 'Motorisation convoyeur A',
reference: 'MTR-45-01',
typeCode: 'motor-drive',
modelCode: 'motor-drive-45',
constructeur: 'sew',
customValues: {
'Puissance nominale (kW)': 45,
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
},
{
name: 'Réducteur convoyeur A',
reference: 'GBX-TA-03',
typeCode: 'gearbox-assembly',
modelCode: 'gearbox-bonfiglioli',
constructeur: 'bonfiglioli',
customValues: {
'Rapport de réduction': '1:24',
'Couple nominal (Nm)': 2100,
'Type de montage': 'Sur arbre',
},
},
],
},
{
name: "Convoyeur d'expédition B",
reference: 'CV-25-02',
prix: '41800',
typeCode: 'belt-conveyor',
requirementLabel: "Convoyeurs d'alimentation",
modelCode: 'conveyor-25m',
constructeur: 'valmont',
customValues: {
'Largeur de bande (mm)': 650,
'Longueur (m)': 25,
'Type de bande': 'PVC alimentaire',
},
pieces: [
{
name: 'Bande transporteuse 650 mm',
reference: 'BAND-650-B',
typeCode: 'drive-belt',
modelCode: 'belt-hd-650',
customValues: {
'Largeur (mm)': 650,
Matériau: 'Polyuréthane',
},
},
{
name: 'Kit visserie tendeur inox',
reference: 'KIT-TEN-02',
typeCode: 'hex-screw',
modelCode: 'screw-m8x30',
customValues: {
'Diamètre (mm)': 8,
'Longueur (mm)': 30,
'Classe acier': '8.8',
},
},
],
children: [
{
name: 'Motorisation convoyeur B',
reference: 'MTR-37-02',
typeCode: 'motor-drive',
modelCode: 'motor-drive-37',
constructeur: 'sew',
customValues: {
'Puissance nominale (kW)': 37,
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
},
{
name: 'Réducteur convoyeur B',
reference: 'GBX-TA-04',
typeCode: 'gearbox-assembly',
modelCode: 'gearbox-bonfiglioli',
constructeur: 'bonfiglioli',
customValues: {
'Rapport de réduction': '1:24',
'Couple nominal (Nm)': 2100,
'Type de montage': 'Sur arbre',
},
},
],
},
{
name: 'Table densimétrique TQX',
reference: 'TBL-TQX-01',
prix: '68500',
typeCode: 'gravity-separator',
requirementLabel: 'Table densimétrique',
modelCode: 'gravity-table-tqx',
constructeur: 'buhler',
customValues: {
'Capacité de tri (t/h)': 120,
'Fréquence de vibration (Hz)': 45,
'Type de plateau': 'Acier perforé',
},
pieces: [
{
name: 'Capteur vibration table',
reference: 'SNS-VIB-01',
typeCode: 'speed-sensor',
modelCode: 'sensor-speed-m12',
constructeur: 'ifm',
customValues: {
'Type de sortie': 'PNP 4-20 mA',
'Plage de mesure (rpm)': 1200,
},
},
{
name: 'Kit visserie plateau',
reference: 'KIT-VIS-PL-01',
typeCode: 'hex-screw',
modelCode: 'screw-m8x30',
customValues: {
'Diamètre (mm)': 8,
'Longueur (mm)': 30,
'Classe acier': '8.8',
},
},
],
children: [
{
name: 'Moteur vibration 18,5 kW',
reference: 'MTR-18-01',
typeCode: 'motor-drive',
modelCode: 'motor-drive-18',
constructeur: 'sew',
customValues: {
'Puissance nominale (kW)': 18.5,
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
},
],
},
{
name: 'Vis de reprise nord',
reference: 'SC-V200-N',
prix: '27400',
typeCode: 'screw-conveyor',
requirementLabel: 'Vis de reprise',
modelCode: 'screw-conveyor-v200',
constructeur: 'valmont',
customValues: {
'Diamètre vis (mm)': 200,
'Inclinaison (°)': 12,
'Vitesse (rpm)': 140,
},
pieces: [
{
name: 'Palier UCP 210',
reference: 'BRG-UCP210-01',
typeCode: 'roller-bearing',
modelCode: 'bearing-ucp210',
constructeur: 'skf',
customValues: {
Série: 'UCP',
"Type d'étanchéité": '2RS',
},
},
{
name: 'Kit visserie palier',
reference: 'KIT-VIS-PA-01',
typeCode: 'hex-screw',
modelCode: 'screw-m12x80',
customValues: {
'Diamètre (mm)': 12,
'Longueur (mm)': 80,
'Classe acier': '8.8',
},
},
],
children: [
{
name: 'Motorisation vis nord',
reference: 'MTR-18-02',
typeCode: 'motor-drive',
modelCode: 'motor-drive-18',
constructeur: 'sew',
customValues: {
'Puissance nominale (kW)': 18.5,
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
},
],
},
{
name: 'Vis de reprise sud',
reference: 'SC-V160-S',
prix: '23600',
typeCode: 'screw-conveyor',
requirementLabel: 'Vis de reprise',
modelCode: 'screw-conveyor-v160',
constructeur: 'valmont',
customValues: {
'Diamètre vis (mm)': 160,
'Inclinaison (°)': 8,
'Vitesse (rpm)': 110,
},
pieces: [
{
name: 'Palier UCFL207',
reference: 'BRG-UCFL207-01',
typeCode: 'roller-bearing',
modelCode: 'bearing-ucfl207',
constructeur: 'skf',
customValues: {
Série: 'UCFL',
"Type d'étanchéité": 'ZZ',
},
},
{
name: 'Kit visserie palier UCFL',
reference: 'KIT-VIS-PA-02',
typeCode: 'hex-screw',
modelCode: 'screw-m10x60',
customValues: {
'Diamètre (mm)': 10,
'Longueur (mm)': 60,
'Classe acier': '10.9',
},
},
],
children: [
{
name: 'Motorisation vis sud',
reference: 'MTR-15-01',
typeCode: 'motor-drive',
modelCode: 'motor-drive-15',
constructeur: 'sew',
customValues: {
'Puissance nominale (kW)': 15,
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
},
],
},
{
name: 'Poste de pesage BP-5',
reference: 'BP-5000-01',
prix: '39200',
typeCode: 'weigh-hopper',
requirementLabel: 'Poste de pesage',
modelCode: 'weigh-hopper-bp5',
constructeur: 'buhler',
customValues: {
'Capacité de pesée (kg)': 5000,
'Précision (%)': 0.5,
'Mode de vidange': 'Trappe motorisée',
},
pieces: [
{
name: 'Capteur pesage 1',
reference: 'LC-5000-01',
typeCode: 'load-cell',
modelCode: 'load-cell-5t',
constructeur: 'ifm',
customValues: {
'Capacité (kg)': 5000,
'Type de connexion': 'Câble 6 fils',
},
},
{
name: 'Capteur pesage 2',
reference: 'LC-5000-02',
typeCode: 'load-cell',
modelCode: 'load-cell-5t',
constructeur: 'ifm',
customValues: {
'Capacité (kg)': 5000,
'Type de connexion': 'Câble 6 fils',
},
},
{
name: 'Capteur pesage 3',
reference: 'LC-5000-03',
typeCode: 'load-cell',
modelCode: 'load-cell-5t',
constructeur: 'ifm',
customValues: {
'Capacité (kg)': 5000,
'Type de connexion': 'Câble 6 fils',
},
},
{
name: 'Capteur pesage 4',
reference: 'LC-5000-04',
typeCode: 'load-cell',
modelCode: 'load-cell-5t',
constructeur: 'ifm',
customValues: {
'Capacité (kg)': 5000,
'Type de connexion': 'Câble 6 fils',
},
},
],
},
{
name: 'Armoire Schneider M340',
reference: 'CTRL-M340-01',
prix: '46500',
typeCode: 'control-panel',
requirementLabel: 'Armoire de contrôle',
modelCode: 'control-panel-m340',
constructeur: 'schneider',
customValues: {
'Automate principal': 'Schneider Modicon M340',
'Année de mise à jour': 2023,
"Indice de protection": 'IP55',
},
pieces: [
{
name: 'Module PLC M340',
reference: 'PLC-M340-01',
typeCode: 'plc-module',
modelCode: 'plc-module-m340',
constructeur: 'schneider',
customValues: {
"Nombre d'E/S": 32,
'Version firmware': 'V2.9',
},
},
{
name: 'Fusible alimentation 25A',
reference: 'FUS-25A-01',
typeCode: 'fuse-cartridge',
modelCode: 'fuse-gg-25a',
constructeur: 'schneider',
customValues: {
'Calibre (A)': 25,
'Type de fusible': 'gG',
},
},
{
name: 'Entrée vitesse ligne',
reference: 'SNS-VIT-CTRL-01',
typeCode: 'speed-sensor',
modelCode: 'sensor-speed-m12',
constructeur: 'ifm',
customValues: {
'Type de sortie': 'PNP 4-20 mA',
'Plage de mesure (rpm)': 1000,
},
},
],
},
{
name: "Ventilateur d'extraction principal",
reference: 'FAN-AX-90',
prix: '32500',
typeCode: 'ventilation-fan',
requirementLabel: 'Ventilation',
modelCode: 'ventilation-fan-axial90',
constructeur: 'agrifan',
customValues: {
'Débit (m³/h)': 48000,
'Type de roue': 'Axiale',
'Vitesse nominale (rpm)': 980,
},
pieces: [
{
name: 'Kit fixation ventilateur',
reference: 'KIT-FAN-01',
typeCode: 'hex-screw',
modelCode: 'screw-m12x80',
customValues: {
'Diamètre (mm)': 12,
'Longueur (mm)': 80,
'Classe acier': '8.8',
},
},
],
},
],
sparePieces: [
{
requirementLabel: 'Kit visserie critique',
name: 'Kit visserie M12 galvanisé',
reference: 'KIT-VIS-M12',
prix: '180',
typeCode: 'hex-screw',
modelCode: 'screw-m12x80',
constructeur: 'agritech',
customValues: {
'Diamètre (mm)': 12,
'Longueur (mm)': 80,
'Classe acier': '8.8',
},
},
{
requirementLabel: 'Capteurs de vitesse de secours',
name: 'Capteur vitesse M12 de secours',
reference: 'SNS-VIT-SPARE-01',
prix: '190',
typeCode: 'speed-sensor',
modelCode: 'sensor-speed-m12',
constructeur: 'ifm',
customValues: {
'Type de sortie': 'PNP 4-20 mA',
'Plage de mesure (rpm)': 1200,
},
},
{
requirementLabel: 'Cartouches de filtration',
name: 'Cartouche G4 de rechange',
reference: 'FLT-G4-SPARE',
prix: '140',
typeCode: 'filter-cartridge',
modelCode: 'filter-g4-500',
constructeur: 'agrifan',
customValues: {
'Classe de filtration': 'G4',
'Dimensions (mm)': '500x500x50',
},
},
],
},
{
code: 'dryer-station',
typeMachineCode: 'grain-dryer-station',
name: 'Poste de séchage CD-6',
reference: 'VT-DRY-01',
prix: '512000',
constructeurKey: 'agridry',
customFieldValues: {
'Produit séché': 'Maïs grain',
'Mode dalimentation': 'Élévateur principal',
'Date de mise en service': new Date('2023-09-15'),
},
components: [
{
name: 'Séchoir continu CD-6',
reference: 'DRY-CD6-01',
prix: '265000',
typeCode: 'grain-dryer',
requirementLabel: 'Séchoir continu',
modelCode: 'grain-dryer-cd6',
constructeur: 'agridry',
customValues: {
'Capacité sèche (t/h)': 60,
"Nombre d'étages": 6,
"Type d'énergie": 'Gaz naturel',
},
pieces: [
{
name: 'Joint trappe inspection',
reference: 'JNT-DRY-01',
typeCode: 'flat-gasket',
modelCode: 'gasket-nbr-5',
customValues: {
Matière: 'NBR',
'Épaisseur (mm)': 5,
},
},
],
children: [
{
name: 'Brûleur gaz principal',
reference: 'BRN-3MW-01',
typeCode: 'burner-module',
requirementLabel: 'Module brûleur',
modelCode: 'burner-module-3mw',
constructeur: 'agridry',
customValues: {
'Puissance thermique (kW)': 3000,
'Type de carburant': 'Gaz naturel',
"Système d'allumage": 'Double électrode',
},
pieces: [
{
name: 'Sonde flamme PT100',
reference: 'TMP-SEC-01',
typeCode: 'temperature-probe',
modelCode: 'temp-probe-pt100',
constructeur: 'ifm',
customValues: {
'Type de sonde': 'PT100 classe A',
'Plage de mesure (°C)': '0-250',
},
},
],
},
{
name: 'Filtre cyclone FC-12',
reference: 'FIL-FC12-01',
typeCode: 'dust-filter',
requirementLabel: 'Filtration poussières',
modelCode: 'dust-filter-fc12',
constructeur: 'agrifan',
customValues: {
'Efficacité de filtration (%)': 95,
'Type de média filtrant': 'Polyester',
'Nombre de cartouches': 6,
},
pieces: [
{
name: 'Cartouche filtrante G4',
reference: 'FLT-G4-01',
typeCode: 'filter-cartridge',
modelCode: 'filter-g4-500',
constructeur: 'agrifan',
customValues: {
'Classe de filtration': 'G4',
'Dimensions (mm)': '500x500x50',
},
},
],
},
],
},
{
name: 'Ventilateur extraction séchoir',
reference: 'FAN-DRY-01',
prix: '43500',
typeCode: 'ventilation-fan',
requirementLabel: 'Ventilation process',
modelCode: 'ventilation-fan-axial90',
constructeur: 'agrifan',
customValues: {
'Débit (m³/h)': 48000,
'Type de roue': 'Axiale',
'Vitesse nominale (rpm)': 980,
},
pieces: [
{
name: 'Kit fixation ventilateur séchoir',
reference: 'KIT-FAN-DRY',
typeCode: 'hex-screw',
modelCode: 'screw-m12x80',
customValues: {
'Diamètre (mm)': 12,
'Longueur (mm)': 80,
'Classe acier': '8.8',
},
},
],
},
{
name: 'Vis de reprise séchoir',
reference: 'SC-DRY-01',
prix: '24800',
typeCode: 'screw-conveyor',
requirementLabel: 'Vis de reprise',
modelCode: 'screw-conveyor-v200',
constructeur: 'valmont',
customValues: {
'Diamètre vis (mm)': 200,
'Inclinaison (°)': 10,
'Vitesse (rpm)': 130,
},
pieces: [
{
name: 'Palier UCP 210',
reference: 'BRG-UCP210-05',
typeCode: 'roller-bearing',
modelCode: 'bearing-ucp210',
constructeur: 'skf',
customValues: {
Série: 'UCP',
"Type d'étanchéité": '2RS',
},
},
],
children: [
{
name: 'Motorisation vis séchoir',
reference: 'MTR-18-05',
typeCode: 'motor-drive',
modelCode: 'motor-drive-18',
constructeur: 'sew',
customValues: {
'Puissance nominale (kW)': 18.5,
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
},
],
},
{
name: 'Armoire supervision séchage',
reference: 'CTRL-S7-DRY',
prix: '38900',
typeCode: 'control-panel',
requirementLabel: 'Armoire de supervision',
modelCode: 'control-panel-s7',
constructeur: 'siemens',
customValues: {
'Automate principal': 'Siemens S7-1500',
'Année de mise à jour': 2022,
"Indice de protection": 'IP65',
},
pieces: [
{
name: 'Module S7-1200',
reference: 'PLC-S7-01',
typeCode: 'plc-module',
modelCode: 'plc-module-s71200',
constructeur: 'siemens',
customValues: {
"Nombre d'E/S": 24,
'Version firmware': 'V2.8',
},
},
{
name: 'Fusible puissance 40A',
reference: 'FUS-40A-DRY',
typeCode: 'fuse-cartridge',
modelCode: 'fuse-gg-40a',
constructeur: 'schneider',
customValues: {
'Calibre (A)': 40,
'Type de fusible': 'gG',
},
},
],
},
],
sparePieces: [
{
requirementLabel: 'Joints haute température',
name: 'Joint PTFE 3 mm de rechange',
reference: 'JNT-PTFE-SPARE',
typeCode: 'flat-gasket',
modelCode: 'gasket-ptfe-3',
constructeur: 'agridry',
customValues: {
Matière: 'PTFE',
'Épaisseur (mm)': 3,
},
},
{
requirementLabel: 'Sondes de température de secours',
name: 'Sonde PT100 courte',
reference: 'TMP-SPARE-02',
typeCode: 'temperature-probe',
modelCode: 'temp-probe-pt100-short',
constructeur: 'ifm',
customValues: {
'Type de sonde': 'PT100 classe B',
'Plage de mesure (°C)': '0-200',
},
},
],
},
{
code: 'telehandler-logistics',
typeMachineCode: 'telehandler-support',
name: 'Manitou MLT 1040 logistique',
reference: 'VT-MAN-01',
prix: '73500',
constructeurKey: 'manitou',
customFieldValues: {
'Usage principal': 'Gestion big-bags',
'Lieu de stationnement': 'Hangar nord',
"Année d'achat": 2021,
},
components: [
{
name: 'Chariot télescopique MLT 1040',
reference: 'MLT-1040-01',
prix: '73500',
typeCode: 'telehandler',
requirementLabel: 'Châssis télescopique',
modelCode: 'telehandler-mlt1040',
constructeur: 'manitou',
customValues: {
'Capacité de levage (t)': 4,
'Hauteur de levage (m)': 9.6,
"Type d'attache": 'Fourches FEM',
},
pieces: [
{
name: 'Cartouche cabine 40A',
reference: 'FUS-CAB-40A',
typeCode: 'fuse-cartridge',
modelCode: 'fuse-gg-40a',
constructeur: 'schneider',
customValues: {
'Calibre (A)': 40,
'Type de fusible': 'gG',
},
},
{
name: 'Joint clapet direction',
reference: 'JNT-DIR-01',
typeCode: 'flat-gasket',
modelCode: 'gasket-nbr-5',
constructeur: 'manitou',
customValues: {
Matière: 'NBR',
'Épaisseur (mm)': 5,
},
},
],
children: [
{
name: 'Moteur principal 75 kW',
reference: 'MTR-MAN-01',
typeCode: 'motor-drive',
requirementLabel: 'Groupe moteur',
modelCode: 'motor-drive-75',
constructeur: 'sew',
customValues: {
'Puissance nominale (kW)': 75,
'Classe énergétique': 'IE3',
"Indice de protection": 'IP55',
},
pieces: [
{
name: 'Kit fixation moteur Manitou',
reference: 'KIT-MTR-MAN',
typeCode: 'hex-screw',
modelCode: 'screw-m12x80',
customValues: {
'Diamètre (mm)': 12,
'Longueur (mm)': 80,
'Classe acier': '8.8',
},
},
],
},
{
name: 'Groupe hydraulique PVH98',
reference: 'HYD-PVH98-01',
typeCode: 'hydraulic-power-pack',
requirementLabel: 'Groupe hydraulique',
modelCode: 'hydraulic-pack-pvh98',
constructeur: 'poclain',
customValues: {
'Débit nominal (l/min)': 160,
'Pression max (bar)': 320,
'Type de pompe': 'Piston axial',
},
pieces: [
{
name: 'Joint collecteur hydraulique',
reference: 'JNT-HYD-01',
typeCode: 'flat-gasket',
modelCode: 'gasket-nbr-5',
customValues: {
Matière: 'NBR',
'Épaisseur (mm)': 5,
},
},
],
},
{
name: 'Tableau cabine M340',
reference: 'CTRL-CAB-01',
typeCode: 'control-panel',
requirementLabel: 'Armoire de contrôle cabine',
modelCode: 'control-panel-m340',
constructeur: 'schneider',
customValues: {
'Automate principal': 'Schneider Modicon M340',
'Année de mise à jour': 2023,
"Indice de protection": 'IP55',
},
pieces: [
{
name: 'Module PLC cabine',
reference: 'PLC-CAB-01',
typeCode: 'plc-module',
modelCode: 'plc-module-m340',
constructeur: 'schneider',
customValues: {
"Nombre d'E/S": 32,
'Version firmware': 'V2.9',
},
},
{
name: 'Fusible cabine 25A',
reference: 'FUS-CAB-25A',
typeCode: 'fuse-cartridge',
modelCode: 'fuse-gg-25a',
constructeur: 'schneider',
customValues: {
'Calibre (A)': 25,
'Type de fusible': 'gG',
},
},
],
},
],
},
],
sparePieces: [
{
requirementLabel: 'Fusibles cabine',
name: 'Fusible cabine gG 25A',
reference: 'FUS-SPARE-25A',
typeCode: 'fuse-cartridge',
modelCode: 'fuse-gg-25a',
constructeur: 'schneider',
customValues: {
'Calibre (A)': 25,
'Type de fusible': 'gG',
},
},
{
requirementLabel: 'Joints hydrauliques de secours',
name: 'Kit joints NBR Manitou',
reference: 'KIT-JNT-MAN',
typeCode: 'flat-gasket',
modelCode: 'gasket-nbr-5',
constructeur: 'manitou',
customValues: {
Matière: 'NBR',
'Épaisseur (mm)': 5,
},
},
],
},
];
async function createMachines(
siteId: string,
typeMachines: Record<string, TypeMachineRecord>,
context: {
componentTypes: Record<string, { id: string; customFields: Record<string, string> }>;
componentModels: Record<string, { id: string }>;
pieceTypes: Record<string, { id: string; customFields: Record<string, string> }>;
pieceModels: Record<string, { id: string }>;
constructeurs: Record<string, { id: string }>;
},
) {
console.log('🏗️ Création des machines de démonstration...');
for (const build of machineBuilds) {
const typeMachine = typeMachines[build.typeMachineCode];
if (!typeMachine) {
throw new Error(`Type de machine introuvable pour ${build.typeMachineCode}`);
}
const requirementMap = new Map<string, string>();
typeMachine.componentRequirements.forEach((requirement) => {
if (requirement.label) {
requirementMap.set(requirement.label, requirement.id);
}
});
const pieceRequirementMap = new Map<string, string>();
typeMachine.pieceRequirements.forEach((requirement) => {
if (requirement.label) {
pieceRequirementMap.set(requirement.label, requirement.id);
}
});
const machineCustomFieldMap = mapCustomFields(typeMachine.customFields);
const machine = await prisma.machine.create({
data: {
name: build.name,
reference: build.reference,
prix: new Prisma.Decimal(build.prix),
site: { connect: { id: siteId } },
typeMachine: { connect: { id: typeMachine.id } },
constructeur: {
connect: { id: context.constructeurs[build.constructeurKey].id },
},
customFieldValues: buildCustomFieldValues(
machineCustomFieldMap,
build.customFieldValues,
),
},
});
console.log(`⚙️ ${build.name} - ajout des composants...`);
const componentContext = {
...context,
requirementMap,
};
for (const component of build.components) {
await createComponentHierarchy(machine.id, component, componentContext);
}
if (build.sparePieces && build.sparePieces.length > 0) {
console.log(`📦 ${build.name} - enregistrement des pièces de réserve...`);
for (const spare of build.sparePieces) {
const pieceType = context.pieceTypes[spare.typeCode];
const requirementId = spare.requirementLabel
? pieceRequirementMap.get(spare.requirementLabel)
: undefined;
await prisma.piece.create({
data: {
name: spare.name,
reference: spare.reference,
prix: spare.prix ? new Prisma.Decimal(spare.prix) : undefined,
machine: { connect: { id: machine.id } },
typePiece: { connect: { id: pieceType.id } },
pieceModel: { connect: { id: context.pieceModels[spare.modelCode].id } },
constructeur: spare.constructeur
? { connect: { id: context.constructeurs[spare.constructeur].id } }
: undefined,
typeMachinePieceRequirement: requirementId
? { connect: { id: requirementId } }
: undefined,
customFieldValues: buildCustomFieldValues(
pieceType.customFields,
spare.customValues,
),
},
});
}
}
}
}
async function main() {
try {
await clearDatabaseExceptSitesAndProfiles();
const [site, constructeurs] = await Promise.all([
ensureDemoSite(),
createConstructeurs(),
]);
const { componentTypes, pieceTypes } = await createModelTypes();
const [pieceModels, componentModels, typeMachines] = await Promise.all([
createPieceModels(pieceTypes),
createComponentModels(componentTypes),
createTypeMachines(componentTypes, pieceTypes),
]);
await createMachines(site.id, typeMachines, {
componentTypes,
componentModels,
pieceTypes,
pieceModels,
constructeurs,
});
console.log('🎉 Données de démonstration générées avec succès.');
} catch (error) {
console.error('❌ Erreur pendant la génération des données :', error);
process.exitCode = 1;
} finally {
await prisma.$disconnect();
}
}
main();