import { DRAWERS, NICHE, PLINTH, MAX_PANEL_DIMENSION_MM, MAX_PANEL_SHORT_SIDE_MM, validateHorizontalSpans } from '../../shared/manufacturing.js'; export function validateConfig(config = {}, settings = {}) { const errors = []; const warnings = []; const installationType = config.installationType || 'free'; const doorType = config.doorType || 'hinged'; const widthMm = Number(config.widthMm || 0); const heightMm = Number(config.heightMm || 0); const depthMm = Number(config.depthMm || 0); const modules = Array.isArray(config.modules) ? config.modules : []; const allowSliding = String(settings.allow_sliding_doors ?? '0') === '1'; const sanitaryGapMm = Number(settings.sanitary_gap_mm || NICHE.sanitaryGapAround); const plinthHeightMm = Number(config.plinthHeightMm ?? 100); const maxPanelLongMm = Number( settings.panel_max_width_mm ?? settings.max_panel_width_mm ?? settings.max_panel_dimension_mm ?? MAX_PANEL_DIMENSION_MM ); const maxPanelShortMm = Number( settings.panel_max_short_side_mm ?? settings.max_panel_short_side_mm ?? MAX_PANEL_SHORT_SIDE_MM ); if (widthMm > maxPanelLongMm) { errors.push({ field: 'widthMm', message: `Largeur maximale ${maxPanelLongMm} mm (capacité CNC).` }); } if (depthMm > maxPanelShortMm) { errors.push({ field: 'depthMm', message: `Profondeur maximale ${maxPanelShortMm} mm (capacité CNC).` }); } if (config.horizontalSpans != null && !Array.isArray(config.horizontalSpans)) { errors.push({ field: 'horizontalSpans', message: 'Les traverses horizontales doivent être fournies sous forme de tableau.' }); } else { validateHorizontalSpans(config, { maxPanelWidthMm: maxPanelLongMm }).forEach((issue) => { errors.push({ field: issue.field, code: issue.code, message: issue.message }); }); } if (!PLINTH.targetHeightsMm.includes(plinthHeightMm)) { errors.push({ field: 'plinthHeightMm', message: `Hauteur AXILO 78 invalide. Valeurs admises : ${PLINTH.targetHeightsMm.join(', ')} mm.` }); } if (doorType === 'sliding' && !allowSliding) { errors.push({ field: 'doorType', message: 'Portes coulissantes désactivées.' }); } if (installationType === 'niche') { const nm = config.nicheMeasurements || {}; const minW = Math.min(nm.widthTopMm || widthMm, nm.widthMidMm || widthMm, nm.widthBottomMm || widthMm); const minD = Math.min(nm.depthTopMm || depthMm, nm.depthMidMm || depthMm, nm.depthBottomMm || depthMm); const minH = Math.min(nm.heightLeftMm || heightMm, nm.heightRightMm || heightMm); const expectedW = Math.max(400, minW - sanitaryGapMm * 2); const expectedD = Math.max(400, minD - sanitaryGapMm * 2); const expectedH = Math.max(1800, minH - sanitaryGapMm * 2); if (Math.abs(expectedW - widthMm) > 2 || Math.abs(expectedD - depthMm) > 2 || Math.abs(expectedH - heightMm) > 2) { errors.push({ field: 'nicheMeasurements', message: 'Dimensions niche incohérentes avec les mesures mini et vide sanitaire.' }); } } const drawerDepthMin = Number(settings.drawer_depth_min_mm || DRAWERS.minDepth); const drawerDepthMax = Number(settings.drawer_depth_max_mm || DRAWERS.maxDepth); const drawerDepthStep = Number(settings.drawer_depth_step_mm || DRAWERS.depthStep); /** Même logique que `useWardrobeConfig` : pas de 50 mm sur la profondeur utile, puis réserve tiroir caché. */ const inferredEffectiveDrawerDepthMm = (drawerType = config.hardware?.drawerType || 'visible') => { const rawGap = depthMm - NICHE.drawerBackGap; const clamped = Math.max(drawerDepthMin, Math.min(drawerDepthMax, rawGap)); const steppedMm = Math.round(clamped / drawerDepthStep) * drawerDepthStep; const depthReductionMm = drawerType === 'hidden' || drawerType === 'hidden_with_handle' ? DRAWERS.hiddenHandleDepthReduction : 0; return Math.max(350, steppedMm - depthReductionMm); }; for (const [index, m] of modules.entries()) { const isDrawerCol = (m.drawers || 0) > 0 || m.type === 'tiroirs'; if (isDrawerCol && Number(m.widthMm || 0) > DRAWERS.maxColumnWidth) { errors.push({ field: `modules[${index}]`, message: `Colonne tiroirs > ${DRAWERS.maxColumnWidth} mm.` }); } if (m.hasRod && heightMm < 1200) { errors.push({ field: `modules[${index}]`, message: 'Tringle autorisée à partir de 1200 mm de hauteur armoire.' }); } if (isDrawerCol) { const moduleDepth = inferredEffectiveDrawerDepthMm(m.drawerType ?? config.hardware?.drawerType); if (moduleDepth < 350 || moduleDepth > drawerDepthMax) { errors.push({ field: `modules[${index}].drawerType`, message: `Profondeur tiroir utile hors bornes (350-${drawerDepthMax} mm) pour ce block.` }); } } } /** * Profondeur utile tiroir — alignée sur useWardrobeConfig (pas de 50 sur prof. caisse puis −40 si caché). * Ne pas exiger un multiple de 50 sur la valeur finale : ex. 550 − 40 = 510 mm est valide. */ const drawerModules = modules.filter((m) => (m.drawers || 0) > 0 || m.type === 'tiroirs'); const canonicalDrawerDepths = drawerModules.map((m) => inferredEffectiveDrawerDepthMm(m.drawerType ?? config.hardware?.drawerType) ); const canonicalEffectiveDrawerDepthMm = canonicalDrawerDepths[0] ?? inferredEffectiveDrawerDepthMm(); const effectiveDrawerMinMm = 350; if ( canonicalEffectiveDrawerDepthMm < effectiveDrawerMinMm || canonicalEffectiveDrawerDepthMm > drawerDepthMax ) { errors.push({ field: 'effectiveDrawerDepthMm', message: `Profondeur tiroir utile hors bornes (${effectiveDrawerMinMm}-${drawerDepthMax} mm) pour cette profondeur caisse.` }); } const explicitEff = Number(config.effectiveDrawerDepthMm); if ( Number.isFinite(explicitEff) && explicitEff > 0 && canonicalDrawerDepths.every((depth) => depth === canonicalEffectiveDrawerDepthMm) && Math.abs(explicitEff - canonicalEffectiveDrawerDepthMm) > 2 ) { warnings.push({ field: 'effectiveDrawerDepthMm', message: `Valeur stockée (${explicitEff} mm) différente du calcul attendu (${canonicalEffectiveDrawerDepthMm} mm) — le serveur utilise le calcul canonique.` }); } const handleAxis = Number(config.hardware?.handleBoreHeightMm || 1000); const stdAxis = Number(settings.standard_handle_axis_mm || 1000); const tolerance = Number(settings.standard_handle_tolerance_mm || 200); if (handleAxis < stdAxis - tolerance || handleAxis > stdAxis + tolerance) { warnings.push({ field: 'handleBoreHeightMm', message: 'Perçage poignée hors plage standard.' }); } return { errors, warnings }; } export default { validateConfig };