3195 lines
92 KiB
TypeScript
3195 lines
92 KiB
TypeScript
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 d’air 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 d’entré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 d’alimentation',
|
||
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 d’alimentation': 'É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();
|