1868 lines
54 KiB
TypeScript
1868 lines
54 KiB
TypeScript
import { PrismaClient, Prisma, ModelCategory } from '@prisma/client';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
type CustomFieldSpec = {
|
|
name: string;
|
|
type: 'string' | 'number' | 'boolean' | 'date';
|
|
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[];
|
|
};
|
|
|
|
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: 'string', defaultValue: 'Acier galvanisé' },
|
|
],
|
|
},
|
|
{
|
|
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: 'string', defaultValue: 'Caoutchouc anti-statique' },
|
|
],
|
|
},
|
|
{
|
|
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: 'string', defaultValue: 'Acier perforé' },
|
|
],
|
|
},
|
|
{
|
|
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: 'string', defaultValue: 'Gaz naturel' },
|
|
],
|
|
},
|
|
{
|
|
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: 'Nombre de capteurs', type: 'number', defaultValue: '4' },
|
|
],
|
|
},
|
|
{
|
|
code: 'control-panel',
|
|
name: 'Armoire de contrôle',
|
|
description: 'Armoire électrique pilotant l\'ensemble de la ligne de triage.',
|
|
customFields: [
|
|
{ name: 'Automate principal', type: 'string', required: true },
|
|
{ name: 'Année de mise à jour', type: 'number' },
|
|
{ name: "Indice de protection", type: 'string', defaultValue: 'IP55' },
|
|
],
|
|
},
|
|
{
|
|
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: 'string', defaultValue: 'Fourches FEM' },
|
|
],
|
|
},
|
|
{
|
|
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: 'string', defaultValue: 'Gaz naturel' },
|
|
{ name: "Système d'allumage", type: 'string', defaultValue: 'Double électrode' },
|
|
],
|
|
},
|
|
{
|
|
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: 'string' },
|
|
{ name: 'Nombre de cartouches', type: 'number' },
|
|
],
|
|
},
|
|
];
|
|
|
|
const pieceTypeDefinitions: PieceTypeDefinition[] = [
|
|
{
|
|
code: 'electric-motor',
|
|
name: 'Moteur électrique',
|
|
description: 'Motorisation asynchrone IE3 pour entraînements industriels.',
|
|
customFields: [
|
|
{ name: 'Puissance nominale (kW)', type: 'number', required: true },
|
|
{ name: 'Tension (V)', type: 'number' },
|
|
{ name: "Indice de protection", type: 'string', defaultValue: 'IP55' },
|
|
],
|
|
},
|
|
{
|
|
code: 'speed-sensor',
|
|
name: 'Capteur de vitesse',
|
|
description: 'Capteur inductif contrôlant la vitesse des organes rotatifs.',
|
|
customFields: [
|
|
{ name: 'Type de sortie', type: 'string', required: true },
|
|
{ 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: 'Plage de mesure (°C)', type: 'string', required: true },
|
|
{ name: 'Type de sonde', type: 'string', defaultValue: 'PT100' },
|
|
],
|
|
},
|
|
{
|
|
code: 'belt',
|
|
name: 'Bande transporteuse',
|
|
description: 'Bande caoutchouc renforcée pour convoyeurs et élévateurs.',
|
|
customFields: [
|
|
{ name: 'Largeur (mm)', type: 'number', required: true },
|
|
{ name: 'Matériau', type: 'string' },
|
|
],
|
|
},
|
|
{
|
|
code: 'bearing',
|
|
name: 'Roulement',
|
|
description: 'Roulement à semelle pour transmissions tournantes.',
|
|
customFields: [
|
|
{ name: 'Référence fournisseur', type: 'string', required: true },
|
|
{ name: "Type d'étanchéité", type: 'string' },
|
|
],
|
|
},
|
|
{
|
|
code: 'gearbox',
|
|
name: 'Réducteur',
|
|
description: 'Réducteur de vitesse pour entraînement lourd.',
|
|
customFields: [
|
|
{ name: 'Rapport de réduction', type: 'string', required: true },
|
|
{ name: 'Couple nominal (Nm)', type: 'number' },
|
|
],
|
|
},
|
|
{
|
|
code: 'air-filter',
|
|
name: 'Filtre à air',
|
|
description: 'Cartouche filtrante pour dépoussiérage.',
|
|
customFields: [
|
|
{ name: 'Classe de filtration', type: 'string', required: true },
|
|
{ name: 'Dimensions (mm)', type: 'string' },
|
|
],
|
|
},
|
|
{
|
|
code: 'hydraulic-pump',
|
|
name: 'Pompe hydraulique',
|
|
description: 'Pompe hydraulique pour chariot télescopique.',
|
|
customFields: [
|
|
{ name: 'Débit nominal (l/min)', type: 'number', required: true },
|
|
{ name: 'Pression max (bar)', type: 'number' },
|
|
],
|
|
},
|
|
{
|
|
code: 'control-module',
|
|
name: 'Module automate',
|
|
description: 'Module PLC assurant le contrôle de ligne.',
|
|
customFields: [
|
|
{ name: "Nombre d'E/S", type: 'number', required: true },
|
|
{ name: 'Version firmware', type: 'string' },
|
|
],
|
|
},
|
|
{
|
|
code: 'load-cell',
|
|
name: 'Capteur de pesage',
|
|
description: 'Capteur de pesage pour benne peseuse.',
|
|
customFields: [
|
|
{ name: 'Capacité (kg)', type: 'number', required: true },
|
|
{ name: 'Sensibilité (mV/V)', type: 'string' },
|
|
],
|
|
},
|
|
];
|
|
|
|
const pieceModelDefinitions: PieceModelDefinition[] = [
|
|
{
|
|
code: 'motor-75kw',
|
|
name: 'Moteur IE3 75 kW',
|
|
description: 'Moteur principal pour élévateur haute capacité.',
|
|
typeCode: 'electric-motor',
|
|
structure: {
|
|
defaultCustomFieldValues: {
|
|
'Puissance nominale (kW)': '75',
|
|
'Tension (V)': '400',
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'motor-45kw',
|
|
name: 'Moteur IE3 45 kW',
|
|
description: 'Motorisation pour convoyeur ou ventilateur.',
|
|
typeCode: 'electric-motor',
|
|
structure: {
|
|
defaultCustomFieldValues: {
|
|
'Puissance nominale (kW)': '45',
|
|
'Tension (V)': '400',
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'motor-18kw',
|
|
name: 'Moteur IE3 18,5 kW',
|
|
description: 'Motorisation pour vis sans fin ou table densimétrique.',
|
|
typeCode: 'electric-motor',
|
|
structure: {
|
|
defaultCustomFieldValues: {
|
|
'Puissance nominale (kW)': '18.5',
|
|
'Tension (V)': '400',
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
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)': '0-1200',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'temp-probe-pt100',
|
|
name: 'Sonde PT100 classe A',
|
|
description: 'Sonde PT100 pour mesure d\'air chaud.',
|
|
typeCode: 'temperature-probe',
|
|
structure: {
|
|
defaultCustomFieldValues: {
|
|
'Plage de mesure (°C)': '0-250',
|
|
'Type de sonde': 'PT100 classe A',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'belt-hd-800',
|
|
name: 'Bande renforcée 800 mm',
|
|
description: 'Bande HD 800 mm anti-statique.',
|
|
typeCode: 'belt',
|
|
structure: {
|
|
defaultCustomFieldValues: {
|
|
'Largeur (mm)': '800',
|
|
'Matériau': 'Caoutchouc nitrile',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'belt-hd-650',
|
|
name: 'Bande renforcée 650 mm',
|
|
description: 'Bande HD 650 mm résistante à l\'abrasion.',
|
|
typeCode: 'belt',
|
|
structure: {
|
|
defaultCustomFieldValues: {
|
|
'Largeur (mm)': '650',
|
|
'Matériau': 'Caoutchouc anti-abrasion',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'bearing-ucp210',
|
|
name: 'Roulement UCP210',
|
|
description: 'Roulement à semelle graissable.',
|
|
typeCode: 'bearing',
|
|
structure: {
|
|
defaultCustomFieldValues: {
|
|
'Référence fournisseur': 'SKF UCP210',
|
|
"Type d'étanchéité": '2RS',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'gearbox-flender',
|
|
name: 'Réducteur Flender FZ',
|
|
description: 'Réducteur coaxial pour charge lourde.',
|
|
typeCode: 'gearbox',
|
|
structure: {
|
|
defaultCustomFieldValues: {
|
|
'Rapport de réduction': '1:28',
|
|
'Couple nominal (Nm)': '3200',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'filter-g4-500',
|
|
name: 'Filtre G4 500x500',
|
|
description: 'Cartouche filtrante G4 pour dépoussiérage.',
|
|
typeCode: 'air-filter',
|
|
structure: {
|
|
defaultCustomFieldValues: {
|
|
'Classe de filtration': 'G4',
|
|
'Dimensions (mm)': '500x500x50',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'hydraulic-pump-pvh98',
|
|
name: 'Pompe hydraulique PVH98',
|
|
description: 'Pompe haute pression pour Manitou.',
|
|
typeCode: 'hydraulic-pump',
|
|
structure: {
|
|
defaultCustomFieldValues: {
|
|
'Débit nominal (l/min)': '160',
|
|
'Pression max (bar)': '320',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'plc-module-siemens-1512',
|
|
name: 'Module PLC Siemens 1512',
|
|
description: 'Automate Siemens S7-1500 1512SP.',
|
|
typeCode: 'control-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',
|
|
'Sensibilité (mV/V)': '2.0',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
const componentModelDefinitions: ComponentModelDefinition[] = [
|
|
{
|
|
code: 'elevator-z400',
|
|
name: 'Élévateur Z400',
|
|
description: 'Élévateur à godets 120 t/h, 38 m.',
|
|
typeCode: 'bucket-elevator',
|
|
structure: {
|
|
defaultPieces: [
|
|
{ modelCode: 'motor-75kw', role: 'Motorisation principale' },
|
|
{ modelCode: 'gearbox-flender', role: 'Réducteur' },
|
|
{ modelCode: 'belt-hd-800', role: 'Courroie élévateur' },
|
|
{ modelCode: 'sensor-speed-m12', role: 'Capteur vitesse tête' },
|
|
{ modelCode: 'bearing-ucp210', role: 'Paliers de tête' },
|
|
],
|
|
recommendedCustomFields: {
|
|
'Débit nominal (t/h)': '120',
|
|
'Hauteur de levage (m)': '38',
|
|
'Matériau des godets': 'Acier galvanisé',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'conveyor-18m',
|
|
name: 'Convoyeur bande 18 m',
|
|
description: 'Convoyeur à bande 800 mm, 18 mètres.',
|
|
typeCode: 'belt-conveyor',
|
|
structure: {
|
|
defaultPieces: [
|
|
{ modelCode: 'motor-45kw', role: 'Motorisation' },
|
|
{ modelCode: 'belt-hd-800', role: 'Bande transporteuse' },
|
|
{ modelCode: 'sensor-speed-m12', role: 'Capteur rotation' },
|
|
],
|
|
recommendedCustomFields: {
|
|
'Largeur de bande (mm)': '800',
|
|
'Longueur (m)': '18',
|
|
'Type de bande': 'Caoutchouc anti-statique',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'gravity-table-tqx',
|
|
name: 'Table densimétrique TQX-120',
|
|
description: 'Table densimétrique haute précision 120 t/h.',
|
|
typeCode: 'gravity-separator',
|
|
structure: {
|
|
defaultPieces: [
|
|
{ modelCode: 'motor-18kw', role: 'Motorisation vibration' },
|
|
{ modelCode: 'sensor-speed-m12', role: 'Capteur vibration' },
|
|
],
|
|
recommendedCustomFields: {
|
|
'Capacité de tri (t/h)': '120',
|
|
'Fréquence de vibration (Hz)': '45',
|
|
'Type de plateau': 'Acier perforé',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
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: {
|
|
defaultPieces: [
|
|
{ modelCode: 'motor-45kw', role: 'Ventilateur principal' },
|
|
{ modelCode: 'temp-probe-pt100', role: 'Sonde air chaud' },
|
|
],
|
|
subComponents: [
|
|
{ modelCode: 'burner-module-3mw', role: 'Brûleur gaz principal' },
|
|
{ modelCode: 'dust-filter-fc12', role: 'Filtre cyclone' },
|
|
],
|
|
recommendedCustomFields: {
|
|
'Capacité sèche (t/h)': '60',
|
|
"Nombre d'étages": '6',
|
|
"Type d'énergie": 'Gaz naturel',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'screw-conveyor-v200',
|
|
name: 'Vis sans fin V200',
|
|
description: 'Vis de reprise diamètre 200 mm.',
|
|
typeCode: 'screw-conveyor',
|
|
structure: {
|
|
defaultPieces: [
|
|
{ modelCode: 'motor-18kw', role: 'Motorisation vis' },
|
|
{ modelCode: 'bearing-ucp210', role: 'Paliers supports' },
|
|
],
|
|
recommendedCustomFields: {
|
|
'Diamètre vis (mm)': '200',
|
|
'Inclinaison (°)': '12',
|
|
'Vitesse (rpm)': '140',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'weigh-hopper-bp5',
|
|
name: 'Benna peseuse BP-5',
|
|
description: 'Benna peseuse 5 tonnes pour chargement camion.',
|
|
typeCode: 'weigh-hopper',
|
|
structure: {
|
|
defaultPieces: [
|
|
{ modelCode: 'load-cell-5t', role: 'Capteurs de pesage' },
|
|
{ modelCode: 'sensor-speed-m12', role: 'Capteur rotation trappe' },
|
|
],
|
|
recommendedCustomFields: {
|
|
'Capacité de pesée (kg)': '5000',
|
|
'Précision (%)': '0.5',
|
|
'Nombre de capteurs': '4',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'control-panel-m340',
|
|
name: 'Armoire Schneider M340',
|
|
description: 'Armoire Schneider Electric avec automate M340.',
|
|
typeCode: 'control-panel',
|
|
structure: {
|
|
defaultPieces: [
|
|
{ modelCode: 'plc-module-siemens-1512', role: 'Automate principal' },
|
|
{ modelCode: 'sensor-speed-m12', role: 'Entrée vitesse générale' },
|
|
],
|
|
recommendedCustomFields: {
|
|
'Automate principal': 'Schneider Modicon M340',
|
|
'Année de mise à jour': '2023',
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'burner-module-3mw',
|
|
name: 'Brûleur gaz 3 MW',
|
|
description: 'Brûleur gaz modulant 3 MW pour séchoir.',
|
|
typeCode: 'burner-module',
|
|
structure: {
|
|
defaultPieces: [
|
|
{ modelCode: 'temp-probe-pt100', role: 'Sonde sécurité flamme' },
|
|
],
|
|
recommendedCustomFields: {
|
|
'Puissance thermique (kW)': '3000',
|
|
'Type de carburant': 'Gaz naturel',
|
|
"Système d'allumage": 'Double électrode',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'dust-filter-fc12',
|
|
name: 'Filtre cyclone FC-12',
|
|
description: 'Filtre cyclone avec cartouches G4.',
|
|
typeCode: 'dust-filter',
|
|
structure: {
|
|
defaultPieces: [
|
|
{ modelCode: 'filter-g4-500', role: 'Cartouche filtrante' },
|
|
],
|
|
recommendedCustomFields: {
|
|
'Efficacité de filtration (%)': '95',
|
|
'Type de média filtrant': 'Polyester',
|
|
'Nombre de cartouches': '6',
|
|
},
|
|
},
|
|
},
|
|
{
|
|
code: 'telehandler-mlt1040',
|
|
name: 'Manitou MLT 1040',
|
|
description: 'Chariot télescopique Manitou 4 t.',
|
|
typeCode: 'telehandler',
|
|
structure: {
|
|
defaultPieces: [
|
|
{ modelCode: 'hydraulic-pump-pvh98', role: 'Pompe hydraulique principale' },
|
|
{ modelCode: 'bearing-ucp210', role: 'Articulation de flèche' },
|
|
],
|
|
recommendedCustomFields: {
|
|
'Capacité de levage (t)': '4',
|
|
'Hauteur de levage (m)': '9.6',
|
|
"Type d'attache": 'Fourches FEM',
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
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',
|
|
},
|
|
];
|
|
|
|
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 }[],
|
|
): Record<string, 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 }>;
|
|
}
|
|
|
|
async function createTypeMachine(
|
|
componentTypes: Record<string, { id: string }>,
|
|
pieceTypes: Record<string, { id: string }>,
|
|
) {
|
|
console.log('🧬 Création du squelette de machine...');
|
|
|
|
const typeMachine = await prisma.typeMachine.create({
|
|
data: {
|
|
name: 'Ligne de triage et séchage céréales 120 t/h',
|
|
description:
|
|
'Chaîne automatisée de réception, triage, séchage et expédition des céréales.',
|
|
category: 'Triage et stockage',
|
|
maintenanceFrequency:
|
|
'Inspection quotidienne, graissage hebdomadaire, révision trimestrielle.',
|
|
specifications: {
|
|
nominalThroughput: 120,
|
|
moistureTarget: 14.5,
|
|
building: 'Hall principal',
|
|
shiftsPerDay: 2,
|
|
},
|
|
components: {
|
|
layout: [
|
|
{ order: 1, zone: 'Réception', type: 'bucket-elevator', model: 'elevator-z400' },
|
|
{ order: 2, zone: 'Pré-nettoyage', type: 'belt-conveyor', model: 'conveyor-18m' },
|
|
{ order: 3, zone: 'Séparation', type: 'gravity-separator', model: 'gravity-table-tqx' },
|
|
{ order: 4, zone: 'Séchage', type: 'grain-dryer', model: 'grain-dryer-cd6' },
|
|
{ order: 5, zone: 'Reprise', type: 'screw-conveyor', model: 'screw-conveyor-v200' },
|
|
{ order: 6, zone: 'Expédition', type: 'weigh-hopper', model: 'weigh-hopper-bp5' },
|
|
],
|
|
},
|
|
criticalParts: {
|
|
motors: ['motor-75kw', 'motor-45kw'],
|
|
sensors: ['sensor-speed-m12', 'temp-probe-pt100'],
|
|
wearItems: ['belt-hd-800', 'filter-g4-500'],
|
|
},
|
|
machinePieces: {
|
|
recommendedStock: [
|
|
{ model: 'motor-75kw', quantity: 1 },
|
|
{ model: 'sensor-speed-m12', quantity: 3 },
|
|
{ model: 'belt-hd-800', quantity: 1 },
|
|
],
|
|
},
|
|
customFields: {
|
|
create: [
|
|
{
|
|
name: 'Capacité nominale (t/h)',
|
|
type: 'number',
|
|
required: true,
|
|
options: [],
|
|
},
|
|
{
|
|
name: 'Produit traité',
|
|
type: 'string',
|
|
required: true,
|
|
defaultValue: 'Blé tendre',
|
|
options: [],
|
|
},
|
|
{
|
|
name: 'Date de mise en service',
|
|
type: 'date',
|
|
required: true,
|
|
options: [],
|
|
},
|
|
{
|
|
name: 'Responsable de ligne',
|
|
type: 'string',
|
|
required: false,
|
|
defaultValue: 'Lucie Bernard',
|
|
options: [],
|
|
},
|
|
],
|
|
},
|
|
componentRequirements: {
|
|
create: [
|
|
{
|
|
label: 'Élévateurs principaux',
|
|
minCount: 2,
|
|
maxCount: 2,
|
|
required: true,
|
|
typeComposant: { connect: { id: componentTypes['bucket-elevator'].id } },
|
|
},
|
|
{
|
|
label: "Convoyeurs d'alimentation",
|
|
minCount: 2,
|
|
required: true,
|
|
typeComposant: { connect: { id: componentTypes['belt-conveyor'].id } },
|
|
},
|
|
{
|
|
label: 'Table densimétrique',
|
|
minCount: 1,
|
|
maxCount: 1,
|
|
required: true,
|
|
typeComposant: { connect: { id: componentTypes['gravity-separator'].id } },
|
|
},
|
|
{
|
|
label: 'Séchoir continu',
|
|
minCount: 1,
|
|
maxCount: 1,
|
|
required: true,
|
|
typeComposant: { connect: { id: componentTypes['grain-dryer'].id } },
|
|
},
|
|
{
|
|
label: 'Vis de reprise',
|
|
minCount: 2,
|
|
required: true,
|
|
typeComposant: { connect: { id: componentTypes['screw-conveyor'].id } },
|
|
},
|
|
{
|
|
label: 'Benna peseuse',
|
|
minCount: 1,
|
|
required: true,
|
|
typeComposant: { connect: { id: componentTypes['weigh-hopper'].id } },
|
|
},
|
|
{
|
|
label: 'Armoire de contrôle',
|
|
minCount: 1,
|
|
maxCount: 1,
|
|
required: true,
|
|
typeComposant: { connect: { id: componentTypes['control-panel'].id } },
|
|
},
|
|
{
|
|
label: 'Chariot télescopique',
|
|
minCount: 1,
|
|
required: false,
|
|
typeComposant: { connect: { id: componentTypes['telehandler'].id } },
|
|
},
|
|
],
|
|
},
|
|
pieceRequirements: {
|
|
create: [
|
|
{
|
|
label: 'Moteurs de rechange',
|
|
minCount: 1,
|
|
required: false,
|
|
typePiece: { connect: { id: pieceTypes['electric-motor'].id } },
|
|
},
|
|
{
|
|
label: 'Capteurs de vitesse de secours',
|
|
minCount: 2,
|
|
required: false,
|
|
typePiece: { connect: { id: pieceTypes['speed-sensor'].id } },
|
|
},
|
|
],
|
|
},
|
|
},
|
|
include: {
|
|
customFields: true,
|
|
componentRequirements: true,
|
|
pieceRequirements: true,
|
|
},
|
|
});
|
|
|
|
return typeMachine;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
async function createMachineWithComponents(
|
|
siteId: string,
|
|
typeMachine: Awaited<ReturnType<typeof createTypeMachine>>,
|
|
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 de la machine de démonstration...');
|
|
|
|
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: 'Ligne de triage Valgrain 2024',
|
|
reference: 'VT-TRI-2024',
|
|
prix: new Prisma.Decimal('725000'),
|
|
site: { connect: { id: siteId } },
|
|
typeMachine: { connect: { id: typeMachine.id } },
|
|
constructeur: { connect: { id: context.constructeurs['buhler'].id } },
|
|
customFieldValues: buildCustomFieldValues(machineCustomFieldMap, {
|
|
'Capacité nominale (t/h)': 120,
|
|
'Produit traité': 'Blé tendre, orge brassicole',
|
|
'Date de mise en service': new Date('2024-02-01'),
|
|
'Responsable de ligne': 'Lucie Bernard',
|
|
}),
|
|
},
|
|
});
|
|
|
|
console.log('⚙️ Ajout des composants et sous-ensembles...');
|
|
|
|
const componentContext = {
|
|
...context,
|
|
requirementMap,
|
|
};
|
|
|
|
const components: ComponentInstance[] = [
|
|
{
|
|
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: 'Moteur principal 75 kW',
|
|
reference: 'MTR-75-01',
|
|
prix: '8200',
|
|
typeCode: 'electric-motor',
|
|
modelCode: 'motor-75kw',
|
|
constructeur: 'sew',
|
|
customValues: {
|
|
'Puissance nominale (kW)': 75,
|
|
'Tension (V)': 400,
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
{
|
|
name: 'Réducteur Flender FZ',
|
|
reference: 'GBX-FZ-01',
|
|
prix: '5100',
|
|
typeCode: 'gearbox',
|
|
modelCode: 'gearbox-flender',
|
|
constructeur: 'flender',
|
|
customValues: {
|
|
'Rapport de réduction': '1:28',
|
|
'Couple nominal (Nm)': 3200,
|
|
},
|
|
},
|
|
{
|
|
name: 'Courroie élévateur 800 mm',
|
|
reference: 'BLT-800-01',
|
|
prix: '2300',
|
|
typeCode: 'belt',
|
|
modelCode: 'belt-hd-800',
|
|
constructeur: 'agritech',
|
|
customValues: {
|
|
'Largeur (mm)': 800,
|
|
'Matériau': 'Caoutchouc nitrile',
|
|
},
|
|
},
|
|
{
|
|
name: 'Capteur vitesse tête',
|
|
reference: 'SNS-VIT-01',
|
|
typeCode: 'speed-sensor',
|
|
modelCode: 'sensor-speed-m12',
|
|
constructeur: 'ifm',
|
|
customValues: {
|
|
'Type de sortie': 'PNP 4-20 mA',
|
|
'Plage de mesure (rpm)': 1200,
|
|
},
|
|
},
|
|
{
|
|
name: 'Roulement tête élévateur',
|
|
reference: 'BRG-UCP210-01',
|
|
typeCode: 'bearing',
|
|
modelCode: 'bearing-ucp210',
|
|
constructeur: 'skf',
|
|
customValues: {
|
|
'Référence fournisseur': 'SKF UCP210',
|
|
"Type d'étanchéité": '2RS',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'Élévateur aval Z400',
|
|
reference: 'BE-Z400-02',
|
|
prix: '56800',
|
|
typeCode: 'bucket-elevator',
|
|
requirementLabel: 'Élévateurs principaux',
|
|
modelCode: 'elevator-z400',
|
|
constructeur: 'agritech',
|
|
customValues: {
|
|
'Débit nominal (t/h)': 115,
|
|
'Hauteur de levage (m)': 36,
|
|
'Matériau des godets': 'Acier galvanisé',
|
|
},
|
|
pieces: [
|
|
{
|
|
name: 'Moteur principal 75 kW (aval)',
|
|
reference: 'MTR-75-02',
|
|
prix: '8150',
|
|
typeCode: 'electric-motor',
|
|
modelCode: 'motor-75kw',
|
|
constructeur: 'sew',
|
|
customValues: {
|
|
'Puissance nominale (kW)': 75,
|
|
'Tension (V)': 400,
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
{
|
|
name: 'Courroie élévateur 800 mm (aval)',
|
|
reference: 'BLT-800-02',
|
|
typeCode: 'belt',
|
|
modelCode: 'belt-hd-800',
|
|
constructeur: 'agritech',
|
|
customValues: {
|
|
'Largeur (mm)': 800,
|
|
'Matériau': 'Caoutchouc nitrile',
|
|
},
|
|
},
|
|
{
|
|
name: 'Capteur vitesse aval',
|
|
reference: 'SNS-VIT-02',
|
|
typeCode: 'speed-sensor',
|
|
modelCode: 'sensor-speed-m12',
|
|
constructeur: 'ifm',
|
|
customValues: {
|
|
'Type de sortie': 'PNP 4-20 mA',
|
|
'Plage de mesure (rpm)': 1100,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: "Convoyeur alimentation réception",
|
|
reference: 'CV-ALIM-01',
|
|
prix: '24500',
|
|
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: 'Moteur convoyeur 45 kW',
|
|
reference: 'MTR-45-01',
|
|
prix: '6100',
|
|
typeCode: 'electric-motor',
|
|
modelCode: 'motor-45kw',
|
|
constructeur: 'sew',
|
|
customValues: {
|
|
'Puissance nominale (kW)': 45,
|
|
'Tension (V)': 400,
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
{
|
|
name: 'Bande transporteuse 800 mm',
|
|
reference: 'BLT-800-03',
|
|
typeCode: 'belt',
|
|
modelCode: 'belt-hd-800',
|
|
constructeur: 'valmont',
|
|
customValues: {
|
|
'Largeur (mm)': 800,
|
|
'Matériau': 'Caoutchouc anti-abrasion',
|
|
},
|
|
},
|
|
{
|
|
name: 'Capteur vitesse convoyeur',
|
|
reference: 'SNS-VIT-03',
|
|
typeCode: 'speed-sensor',
|
|
modelCode: 'sensor-speed-m12',
|
|
constructeur: 'ifm',
|
|
customValues: {
|
|
'Type de sortie': 'PNP 4-20 mA',
|
|
'Plage de mesure (rpm)': 900,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: "Convoyeur alimentation séparateur",
|
|
reference: 'CV-ALIM-02',
|
|
prix: '23200',
|
|
typeCode: 'belt-conveyor',
|
|
requirementLabel: "Convoyeurs d'alimentation",
|
|
modelCode: 'conveyor-18m',
|
|
constructeur: 'valmont',
|
|
customValues: {
|
|
'Largeur de bande (mm)': 650,
|
|
'Longueur (m)': 15,
|
|
'Type de bande': 'Caoutchouc anti-statique',
|
|
},
|
|
pieces: [
|
|
{
|
|
name: 'Moteur convoyeur 45 kW (séparateur)',
|
|
reference: 'MTR-45-02',
|
|
typeCode: 'electric-motor',
|
|
modelCode: 'motor-45kw',
|
|
constructeur: 'sew',
|
|
customValues: {
|
|
'Puissance nominale (kW)': 45,
|
|
'Tension (V)': 400,
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
{
|
|
name: 'Bande transporteuse 650 mm',
|
|
reference: 'BLT-650-01',
|
|
typeCode: 'belt',
|
|
modelCode: 'belt-hd-650',
|
|
constructeur: 'valmont',
|
|
customValues: {
|
|
'Largeur (mm)': 650,
|
|
'Matériau': 'Caoutchouc anti-abrasion',
|
|
},
|
|
},
|
|
{
|
|
name: 'Capteur vitesse convoyeur 2',
|
|
reference: 'SNS-VIT-04',
|
|
typeCode: 'speed-sensor',
|
|
modelCode: 'sensor-speed-m12',
|
|
constructeur: 'ifm',
|
|
customValues: {
|
|
'Type de sortie': 'PNP 4-20 mA',
|
|
'Plage de mesure (rpm)': 850,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'Table densimétrique TQX-120',
|
|
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: 'Moteur vibration 18,5 kW',
|
|
reference: 'MTR-18-01',
|
|
typeCode: 'electric-motor',
|
|
modelCode: 'motor-18kw',
|
|
constructeur: 'sew',
|
|
customValues: {
|
|
'Puissance nominale (kW)': 18.5,
|
|
'Tension (V)': 400,
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
{
|
|
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)': 600,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'Séchoir continu CD-6',
|
|
reference: 'DRY-CD6-01',
|
|
prix: '148000',
|
|
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: 'Ventilateur principal 45 kW',
|
|
reference: 'MTR-45-03',
|
|
typeCode: 'electric-motor',
|
|
modelCode: 'motor-45kw',
|
|
constructeur: 'sew',
|
|
customValues: {
|
|
'Puissance nominale (kW)': 45,
|
|
'Tension (V)': 400,
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
{
|
|
name: "Sonde air chaud PT100",
|
|
reference: 'TMP-PT100-01',
|
|
typeCode: 'temperature-probe',
|
|
modelCode: 'temp-probe-pt100',
|
|
constructeur: 'ifm',
|
|
customValues: {
|
|
'Plage de mesure (°C)': '0-250',
|
|
'Type de sonde': 'PT100 classe A',
|
|
},
|
|
},
|
|
],
|
|
children: [
|
|
{
|
|
name: 'Brûleur gaz modulant',
|
|
reference: 'BRN-3MW-01',
|
|
typeCode: 'burner-module',
|
|
modelCode: 'burner-module-3mw',
|
|
constructeur: 'agridry',
|
|
customValues: {
|
|
'Puissance thermique (kW)': 2950,
|
|
'Type de carburant': 'Gaz naturel',
|
|
"Système d'allumage": 'Double électrode',
|
|
},
|
|
pieces: [
|
|
{
|
|
name: 'Sonde sécurité flamme',
|
|
reference: 'TMP-PT100-02',
|
|
typeCode: 'temperature-probe',
|
|
modelCode: 'temp-probe-pt100',
|
|
constructeur: 'ifm',
|
|
customValues: {
|
|
'Plage de mesure (°C)': '0-250',
|
|
'Type de sonde': 'PT100 classe A',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'Filtre cyclone FC-12',
|
|
reference: 'FLT-FC12-01',
|
|
typeCode: 'dust-filter',
|
|
modelCode: 'dust-filter-fc12',
|
|
constructeur: 'agridry',
|
|
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: 'air-filter',
|
|
modelCode: 'filter-g4-500',
|
|
constructeur: 'agridry',
|
|
customValues: {
|
|
'Classe de filtration': 'G4',
|
|
'Dimensions (mm)': '500x500x50',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'Vis de reprise nord',
|
|
reference: 'SC-V200-01',
|
|
prix: '18400',
|
|
typeCode: 'screw-conveyor',
|
|
requirementLabel: 'Vis de reprise',
|
|
modelCode: 'screw-conveyor-v200',
|
|
constructeur: 'valmont',
|
|
customValues: {
|
|
'Diamètre vis (mm)': 200,
|
|
'Inclinaison (°)': 10,
|
|
'Vitesse (rpm)': 140,
|
|
},
|
|
pieces: [
|
|
{
|
|
name: 'Moteur vis 18,5 kW',
|
|
reference: 'MTR-18-02',
|
|
typeCode: 'electric-motor',
|
|
modelCode: 'motor-18kw',
|
|
constructeur: 'sew',
|
|
customValues: {
|
|
'Puissance nominale (kW)': 18.5,
|
|
'Tension (V)': 400,
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
{
|
|
name: 'Palier vis nord',
|
|
reference: 'BRG-UCP210-02',
|
|
typeCode: 'bearing',
|
|
modelCode: 'bearing-ucp210',
|
|
constructeur: 'skf',
|
|
customValues: {
|
|
'Référence fournisseur': 'SKF UCP210',
|
|
"Type d'étanchéité": '2RS',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'Vis de reprise sud',
|
|
reference: 'SC-V200-02',
|
|
prix: '18100',
|
|
typeCode: 'screw-conveyor',
|
|
requirementLabel: 'Vis de reprise',
|
|
modelCode: 'screw-conveyor-v200',
|
|
constructeur: 'valmont',
|
|
customValues: {
|
|
'Diamètre vis (mm)': 200,
|
|
'Inclinaison (°)': 12,
|
|
'Vitesse (rpm)': 145,
|
|
},
|
|
pieces: [
|
|
{
|
|
name: 'Moteur vis 18,5 kW (sud)',
|
|
reference: 'MTR-18-03',
|
|
typeCode: 'electric-motor',
|
|
modelCode: 'motor-18kw',
|
|
constructeur: 'sew',
|
|
customValues: {
|
|
'Puissance nominale (kW)': 18.5,
|
|
'Tension (V)': 400,
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
},
|
|
{
|
|
name: 'Palier vis sud',
|
|
reference: 'BRG-UCP210-03',
|
|
typeCode: 'bearing',
|
|
modelCode: 'bearing-ucp210',
|
|
constructeur: 'skf',
|
|
customValues: {
|
|
'Référence fournisseur': 'SKF UCP210',
|
|
"Type d'étanchéité": '2RS',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'Benna peseuse BP-5',
|
|
reference: 'BP-5000-01',
|
|
prix: '39200',
|
|
typeCode: 'weigh-hopper',
|
|
requirementLabel: 'Benna peseuse',
|
|
modelCode: 'weigh-hopper-bp5',
|
|
constructeur: 'buhler',
|
|
customValues: {
|
|
'Capacité de pesée (kg)': 5000,
|
|
'Précision (%)': 0.5,
|
|
'Nombre de capteurs': 4,
|
|
},
|
|
pieces: [
|
|
{
|
|
name: 'Capteur pesage 1',
|
|
reference: 'LC-5000-01',
|
|
typeCode: 'load-cell',
|
|
modelCode: 'load-cell-5t',
|
|
constructeur: 'ifm',
|
|
customValues: {
|
|
'Capacité (kg)': 5000,
|
|
'Sensibilité (mV/V)': '2.0',
|
|
},
|
|
},
|
|
{
|
|
name: 'Capteur pesage 2',
|
|
reference: 'LC-5000-02',
|
|
typeCode: 'load-cell',
|
|
modelCode: 'load-cell-5t',
|
|
constructeur: 'ifm',
|
|
customValues: {
|
|
'Capacité (kg)': 5000,
|
|
'Sensibilité (mV/V)': '2.0',
|
|
},
|
|
},
|
|
{
|
|
name: 'Capteur pesage 3',
|
|
reference: 'LC-5000-03',
|
|
typeCode: 'load-cell',
|
|
modelCode: 'load-cell-5t',
|
|
constructeur: 'ifm',
|
|
customValues: {
|
|
'Capacité (kg)': 5000,
|
|
'Sensibilité (mV/V)': '2.0',
|
|
},
|
|
},
|
|
{
|
|
name: 'Capteur pesage 4',
|
|
reference: 'LC-5000-04',
|
|
typeCode: 'load-cell',
|
|
modelCode: 'load-cell-5t',
|
|
constructeur: 'ifm',
|
|
customValues: {
|
|
'Capacité (kg)': 5000,
|
|
'Sensibilité (mV/V)': '2.0',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
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 Siemens 1512',
|
|
reference: 'PLC-1512-01',
|
|
typeCode: 'control-module',
|
|
modelCode: 'plc-module-siemens-1512',
|
|
constructeur: 'siemens',
|
|
customValues: {
|
|
"Nombre d'E/S": 32,
|
|
'Version firmware': 'V2.9',
|
|
},
|
|
},
|
|
{
|
|
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: 'Chariot télescopique Manitou',
|
|
reference: 'MLT-1040-01',
|
|
prix: '73500',
|
|
typeCode: 'telehandler',
|
|
requirementLabel: 'Chariot 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: 'Pompe hydraulique principale',
|
|
reference: 'HDP-PVH98-01',
|
|
typeCode: 'hydraulic-pump',
|
|
modelCode: 'hydraulic-pump-pvh98',
|
|
constructeur: 'manitou',
|
|
customValues: {
|
|
'Débit nominal (l/min)': 160,
|
|
'Pression max (bar)': 320,
|
|
},
|
|
},
|
|
{
|
|
name: 'Palier articulation flèche',
|
|
reference: 'BRG-UCP210-04',
|
|
typeCode: 'bearing',
|
|
modelCode: 'bearing-ucp210',
|
|
constructeur: 'skf',
|
|
customValues: {
|
|
'Référence fournisseur': 'SKF UCP210',
|
|
"Type d'étanchéité": '2RS',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
for (const component of components) {
|
|
await createComponentHierarchy(machine.id, component, componentContext);
|
|
}
|
|
|
|
console.log('📦 Ajout des pièces de réserve machine...');
|
|
|
|
const spareMotor = await prisma.piece.create({
|
|
data: {
|
|
name: 'Moteur IE3 75 kW de secours',
|
|
reference: 'MTR-75-SPARE',
|
|
prix: new Prisma.Decimal('7900'),
|
|
machine: { connect: { id: machine.id } },
|
|
typePiece: { connect: { id: context.pieceTypes['electric-motor'].id } },
|
|
pieceModel: { connect: { id: context.pieceModels['motor-75kw'].id } },
|
|
constructeur: { connect: { id: context.constructeurs['sew'].id } },
|
|
typeMachinePieceRequirement: {
|
|
connect: { id: pieceRequirementMap.get('Moteurs de rechange')! },
|
|
},
|
|
customFieldValues: buildCustomFieldValues(
|
|
context.pieceTypes['electric-motor'].customFields,
|
|
{
|
|
'Puissance nominale (kW)': 75,
|
|
'Tension (V)': 400,
|
|
"Indice de protection": 'IP55',
|
|
},
|
|
),
|
|
},
|
|
});
|
|
|
|
await prisma.piece.create({
|
|
data: {
|
|
name: 'Capteur vitesse M12 de secours',
|
|
reference: 'SNS-VIT-SPARE-01',
|
|
prix: new Prisma.Decimal('190'),
|
|
machine: { connect: { id: machine.id } },
|
|
typePiece: { connect: { id: context.pieceTypes['speed-sensor'].id } },
|
|
pieceModel: { connect: { id: context.pieceModels['sensor-speed-m12'].id } },
|
|
constructeur: { connect: { id: context.constructeurs['ifm'].id } },
|
|
typeMachinePieceRequirement: {
|
|
connect: { id: pieceRequirementMap.get('Capteurs de vitesse de secours')! },
|
|
},
|
|
customFieldValues: buildCustomFieldValues(
|
|
context.pieceTypes['speed-sensor'].customFields,
|
|
{
|
|
'Type de sortie': 'PNP 4-20 mA',
|
|
'Plage de mesure (rpm)': 1200,
|
|
},
|
|
),
|
|
},
|
|
});
|
|
|
|
console.log(
|
|
`✅ Machine créée avec ${components.length} composants et pièces critiques enregistrées.`,
|
|
);
|
|
|
|
return {
|
|
machine,
|
|
spareMotor,
|
|
};
|
|
}
|
|
|
|
async function main() {
|
|
try {
|
|
await clearDatabaseExceptSitesAndProfiles();
|
|
|
|
const [site, constructeurs] = await Promise.all([
|
|
ensureDemoSite(),
|
|
createConstructeurs(),
|
|
]);
|
|
|
|
const { componentTypes, pieceTypes } = await createModelTypes();
|
|
const [pieceModels, componentModels, typeMachine] = await Promise.all([
|
|
createPieceModels(pieceTypes),
|
|
createComponentModels(componentTypes),
|
|
createTypeMachine(componentTypes, pieceTypes),
|
|
]);
|
|
|
|
await createMachineWithComponents(site.id, typeMachine, {
|
|
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();
|