info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); $this->info(' 5130 → SAM 견적 계산 검증'); $this->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); $this->newLine(); // 입력 파라미터 $W0 = (float) $this->option('W0'); $H0 = (float) $this->option('H0'); $qty = (int) $this->option('qty'); $productType = $this->option('type'); $tenantId = (int) $this->option('tenant-id'); $finishedGoodsCode = $this->option('finished-goods'); $verboseMode = $this->option('verbose-mode'); $this->info('📥 입력 파라미터:'); $this->table( ['항목', '값'], [ ['개구부 폭 (W0)', "{$W0} mm"], ['개구부 높이 (H0)', "{$H0} mm"], ['수량 (QTY)', $qty], ['제품 유형', $productType], ['테넌트 ID', $tenantId], ] ); $this->newLine(); // 1. Legacy5130Calculator로 계산 (5130 호환 모드) $this->info('🔄 Step 1: Legacy5130Calculator 계산 (5130 호환)'); $legacyResult = Legacy5130Calculator::calculateEstimate($W0, $H0, $qty, $productType); $this->table( ['항목', '값'], [ ['제작 폭 (W1)', "{$legacyResult['calculated']['W1']} mm"], ['제작 높이 (H1)', "{$legacyResult['calculated']['H1']} mm"], ['면적 (M)', "{$legacyResult['calculated']['area_m2']} m²"], ['중량 (K)', "{$legacyResult['calculated']['weight_kg']} kg"], ['브라켓 인치', "{$legacyResult['calculated']['bracket_inch']} inch"], ['모터 용량', $legacyResult['motor']['capacity']], ['브라켓 사이즈', $legacyResult['motor']['bracket_dimensions']], ] ); $this->newLine(); // 2. SAM FormulaEvaluatorService로 계산 $this->info('🔄 Step 2: SAM FormulaEvaluatorService 계산'); if ($finishedGoodsCode) { // BOM 기반 계산 $samResult = $formulaEvaluator->calculateBomWithDebug( $finishedGoodsCode, ['W0' => $W0, 'H0' => $H0, 'QTY' => $qty], $tenantId ); if (! $samResult['success']) { $this->error('SAM 계산 실패: '.($samResult['error'] ?? '알 수 없는 오류')); return Command::FAILURE; } $samVariables = $samResult['variables']; } else { // 직접 계산 (변수만) $samVariables = $this->calculateSamVariables($W0, $H0, $productType); $samResult = ['success' => true, 'variables' => $samVariables]; } $this->table( ['항목', '값'], [ ['제작 폭 (W1)', ($samVariables['W1'] ?? 'N/A').' mm'], ['제작 높이 (H1)', ($samVariables['H1'] ?? 'N/A').' mm'], ['면적 (M)', round($samVariables['M'] ?? 0, 4).' m²'], ['중량 (K)', round($samVariables['K'] ?? 0, 2).' kg'], ] ); $this->newLine(); // 3. 결과 비교 $this->info('🔍 Step 3: 결과 비교'); $comparison = [ ['W1 (제작 폭)', $legacyResult['calculated']['W1'], $samVariables['W1'] ?? 0], ['H1 (제작 높이)', $legacyResult['calculated']['H1'], $samVariables['H1'] ?? 0], ['M (면적)', $legacyResult['calculated']['area_m2'], round($samVariables['M'] ?? 0, 4)], ['K (중량)', $legacyResult['calculated']['weight_kg'], round($samVariables['K'] ?? 0, 2)], ]; $allMatch = true; $comparisonTable = []; foreach ($comparison as [$name, $legacy, $sam]) { $diff = abs($legacy - $sam); $percentDiff = $legacy != 0 ? ($diff / abs($legacy)) * 100 : 0; $match = $percentDiff < 1; // 1% 이내 허용 if (! $match) { $allMatch = false; } $comparisonTable[] = [ $name, $legacy, $sam, round($diff, 4), round($percentDiff, 2).'%', $match ? '✅ 일치' : '❌ 불일치', ]; } $this->table( ['항목', '5130 (Legacy)', 'SAM', '차이', '차이율', '결과'], $comparisonTable ); $this->newLine(); // 4. 최종 결과 if ($allMatch) { $this->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); $this->info(' ✅ 검증 성공: 5130과 SAM 계산 결과가 일치합니다.'); $this->info('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); } else { $this->error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); $this->error(' ❌ 검증 실패: 5130과 SAM 계산 결과가 불일치합니다.'); $this->error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); } // 상세 출력 모드 if ($verboseMode) { $this->newLine(); $this->info('📊 상세 정보 (Legacy5130Calculator):'); $this->line(json_encode($legacyResult, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); if ($finishedGoodsCode && isset($samResult['debug_steps'])) { $this->newLine(); $this->info('📊 상세 정보 (SAM Debug Steps):'); foreach ($samResult['debug_steps'] as $step) { $this->line("Step {$step['step']}: {$step['name']}"); $this->line(json_encode($step['data'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); } } } return $allMatch ? Command::SUCCESS : Command::FAILURE; } /** * SAM 방식으로 변수 계산 (BOM 없이) */ private function calculateSamVariables(float $W0, float $H0, string $productType): array { // 마진값 결정 if (strtolower($productType) === 'steel') { $marginW = 110; $marginH = 350; } else { $marginW = 140; $marginH = 350; } $W1 = $W0 + $marginW; $H1 = $H0 + $marginH; $M = ($W1 * $H1) / 1000000; // 중량 계산 if (strtolower($productType) === 'steel') { $K = $M * 25; } else { $K = $M * 2 + ($W0 / 1000) * 14.17; } return [ 'W0' => $W0, 'H0' => $H0, 'W1' => $W1, 'H1' => $H1, 'W' => $W1, 'H' => $H1, 'M' => $M, 'K' => $K, ]; } }