From f4a902fceb52d2fbf758d01dc26b1f97525c3fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Fri, 30 Jan 2026 22:39:53 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20FormulaEvaluatorService=20=EC=8A=AC?= =?UTF-8?q?=EB=9E=AB=20=ED=86=B5=ED=95=A9=20=EB=B0=8F=20=EB=A9=B4=EC=A0=81?= =?UTF-8?q?/=EC=A4=91=EB=9F=89=20=EA=B3=B5=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FormulaEvaluatorService: 슬랫 면적 공식 분리 (W0×(H0+50) vs W1×(H1+550)) - FormulaEvaluatorService: MOTOR_CAPACITY/BRACKET_SIZE 입력값 우선 처리 - KyungdongFormulaHandler: calculateDynamicItems 면적/중량 제품타입별 분기 - KyungdongFormulaHandler: normalizeGuideType() 추가 (벽면↔벽면형 호환) - KyungdongFormulaHandler: guide_rail_spec 파라미터 별칭 지원 - 검증: 스크린/슬랫 5치수×3수량 전체 5130 정합성 확인 (±1원 이내) Co-Authored-By: Claude Opus 4.5 --- .../Quote/FormulaEvaluatorService.php | 42 ++++++++++++------ .../Handlers/KyungdongFormulaHandler.php | 43 +++++++++++++++---- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/app/Services/Quote/FormulaEvaluatorService.php b/app/Services/Quote/FormulaEvaluatorService.php index e679490..0e3098f 100644 --- a/app/Services/Quote/FormulaEvaluatorService.php +++ b/app/Services/Quote/FormulaEvaluatorService.php @@ -1627,27 +1627,45 @@ private function calculateKyungdongBom( // KyungdongFormulaHandler 인스턴스 생성 $handler = new KyungdongFormulaHandler; - // Step 3: 경동 전용 변수 계산 + // Step 3: 경동 전용 변수 계산 (제품타입별 면적/중량 공식) $W1 = $W0 + 160; $H1 = $H0 + 350; - $area = ($W1 * ($H1 + 550)) / 1000000; - // 중량 계산 (제품타입별) - if ($productType === 'steel') { + if ($productType === 'slat') { + // 슬랫: W0 × (H0 + 50) / 1M + $area = ($W0 * ($H0 + 50)) / 1000000; $weight = $area * 25; - $weightFormula = "AREA × 25"; + $areaFormula = '(W0 × (H0 + 50)) / 1,000,000'; + $areaCalc = "({$W0} × ({$H0} + 50)) / 1,000,000"; + $weightFormula = 'AREA × 25'; + $weightCalc = "{$area} × 25"; + } elseif ($productType === 'steel') { + // 철재: W1 × (H1 + 550) / 1M, 중량 = 면적 × 25 + $area = ($W1 * ($H1 + 550)) / 1000000; + $weight = $area * 25; + $areaFormula = '(W1 × (H1 + 550)) / 1,000,000'; + $areaCalc = "({$W1} × ({$H1} + 550)) / 1,000,000"; + $weightFormula = 'AREA × 25'; $weightCalc = "{$area} × 25"; } else { + // 스크린: W1 × (H1 + 550) / 1M + $area = ($W1 * ($H1 + 550)) / 1000000; $weight = $area * 2 + ($W0 / 1000) * 14.17; - $weightFormula = "AREA × 2 + (W0 / 1000) × 14.17"; + $areaFormula = '(W1 × (H1 + 550)) / 1,000,000'; + $areaCalc = "({$W1} × ({$H1} + 550)) / 1,000,000"; + $weightFormula = 'AREA × 2 + (W0 / 1000) × 14.17'; $weightCalc = "{$area} × 2 + ({$W0} / 1000) × 14.17"; } - // 모터 용량 결정 - $motorCapacity = $handler->calculateMotorCapacity($productType, $weight, $bracketInch); + // 모터 용량 결정 (입력값 우선, 없으면 자동계산) + $motorCapacity = $inputVariables['MOTOR_CAPACITY'] + ?? $inputVariables['motor_capacity'] + ?? $handler->calculateMotorCapacity($productType, $weight, $bracketInch); - // 브라켓 크기 결정 - $bracketSize = $handler->calculateBracketSize($weight, $bracketInch); + // 브라켓 크기 결정 (입력값 우선, 없으면 자동계산) + $bracketSize = $inputVariables['BRACKET_SIZE'] + ?? $inputVariables['bracket_size'] + ?? $handler->calculateBracketSize($weight, $bracketInch); // 핸들러가 필요한 키 보장 (inputVariables에서 전달되지 않으면 기본값) $productModel = $inputVariables['product_model'] ?? 'KSS01'; @@ -1692,8 +1710,8 @@ private function calculateKyungdongBom( [ 'var' => 'AREA', 'desc' => '면적', - 'formula' => '(W1 × (H1 + 550)) / 1,000,000', - 'calculation' => "({$W1} × ({$H1} + 550)) / 1,000,000", + 'formula' => $areaFormula, + 'calculation' => $areaCalc, 'result' => round($area, 4), 'unit' => '㎡', ], diff --git a/app/Services/Quote/Handlers/KyungdongFormulaHandler.php b/app/Services/Quote/Handlers/KyungdongFormulaHandler.php index af90462..9de0e0b 100644 --- a/app/Services/Quote/Handlers/KyungdongFormulaHandler.php +++ b/app/Services/Quote/Handlers/KyungdongFormulaHandler.php @@ -392,8 +392,8 @@ public function calculateSteelItems(array $params): array // 절곡품 관련 파라미터 $caseSpec = $params['case_spec'] ?? '500*380'; $caseLength = (float) ($params['case_length'] ?? ($width + 220)); // mm 단위 (레거시: W0+220) - $guideType = $params['guide_type'] ?? '벽면형'; // 벽면형, 측면형, 혼합형 - $guideSpec = $params['guide_spec'] ?? '120*70'; // 120*70, 120*100 + $guideType = $this->normalizeGuideType($params['guide_type'] ?? '벽면형'); + $guideSpec = $params['guide_spec'] ?? $params['guide_rail_spec'] ?? '120*70'; $guideLength = (float) ($params['guide_length'] ?? ($height + 250)) / 1000; // m 단위 (레거시: H0+250) $bottomBarLength = (float) ($params['bottombar_length'] ?? $width) / 1000; // m 단위 (레거시: W0) $lbarLength = (float) ($params['lbar_length'] ?? ($width + 220)) / 1000; // m 단위 (레거시: W0+220) @@ -669,6 +669,22 @@ private function calculateGuideRails( return $items; } + /** + * 가이드타입 정규화 (5130 ↔ SAM 호환) + * + * 5130: '벽면', '측면', '혼합' (col6 필드) + * SAM: '벽면형', '측면형', '혼합형' (switch case) + */ + private function normalizeGuideType(string $type): string + { + return match ($type) { + '벽면', '벽면형' => '벽면형', + '측면', '측면형' => '측면형', + '혼합', '혼합형' => '혼합형', + default => $type, + }; + } + // ========================================================================= // 부자재 계산 (3종) // ========================================================================= @@ -863,11 +879,22 @@ public function calculateDynamicItems(array $inputs): array $bracketInch = $inputs['bracket_inch'] ?? '5'; $productType = $inputs['product_type'] ?? 'screen'; - // 중량 계산 (5130 로직) - W1, H1 기반 - $W1 = $width + 160; - $H1 = $height + 350; - $area = ($W1 * ($H1 + 550)) / 1000000; - $weight = $area * ($productType === 'steel' ? 25 : 2) + ($width / 1000) * 14.17; + // 중량 계산 (5130 로직) - 제품타입별 면적/중량 공식 + if ($productType === 'slat') { + // 슬랫: W0 × (H0 + 50) / 1M, 중량 = 면적 × 25 + $area = ($width * ($height + 50)) / 1000000; + $weight = $area * 25; + } else { + // 스크린/철재: W1 × (H1 + 550) / 1M + $W1 = $width + 160; + $H1 = $height + 350; + $area = ($W1 * ($H1 + 550)) / 1000000; + if ($productType === 'steel') { + $weight = $area * 25; + } else { + $weight = $area * 2 + ($width / 1000) * 14.17; + } + } // 모터 용량/브라켓 크기 계산 (입력값 우선, 없으면 자동계산) $motorCapacity = $inputs['MOTOR_CAPACITY'] ?? $this->calculateMotorCapacity($productType, $weight, $bracketInch); @@ -967,7 +994,7 @@ public function calculateDynamicItems(array $inputs): array // 4. 절곡품 // installation_type → guide_type 매핑 (calculateSteelItems는 guide_type 사용) if (isset($inputs['installation_type']) && ! isset($inputs['guide_type'])) { - $inputs['guide_type'] = $inputs['installation_type']; + $inputs['guide_type'] = $this->normalizeGuideType($inputs['installation_type']); } $steelItems = $this->calculateSteelItems($inputs); $items = array_merge($items, $steelItems);