# 견적 시뮬레이터 계산 로직 매핑 > **작성일**: 2025-12-23 > **목표**: design.sam.kr 계산 로직 → mng 시뮬레이터 동기화 --- ## 1. Design 계산 로직 분석 ### 1.1 핵심 계산 변수 (AutoCalculationSimulator.tsx:429-444) ```typescript const calculationVariables = { W0: quote.w0, // 오픈사이즈 폭 (입력) H0: quote.h0, // 오픈사이즈 높이 (입력) W1: quote.category === '스크린' ? W0 + 140 : W0 + 110, // 제작폭 H1: H0 + 350, // 제작높이 W: W1, // W = W1 (매핑) H: H1, // H = H1 (매핑) M: (W1 * H1) / 1000000, // 면적 (㎡) K: 0 // 중량 (미구현) }; ``` ### 1.2 수식 평가 함수 (formulaEvaluator.ts) **지원 함수:** | 함수 | 설명 | 예시 | |------|------|------| | `SUM(a, b, ...)` | 합계 | `SUM(W0, H0, 100)` | | `AVERAGE(a, b, ...)` | 평균 | `AVERAGE(W0, H0)` | | `MAX(a, b, ...)` | 최대값 | `MAX(W0, 1000)` | | `MIN(a, b, ...)` | 최소값 | `MIN(H0, 3000)` | | `ROUND(value, decimals)` | 반올림 | `ROUND(M, 2)` | | `CEIL(value)` | 올림 | `CEIL(H1 / 1000)` | | `FLOOR(value)` | 내림 | `FLOOR(W1 / 500)` | | `ABS(value)` | 절대값 | `ABS(W0 - 2000)` | | `IF(cond, true, false)` | 조건문 | `IF(W0 > 3000, 2, 1)` | | `SQRT(value)` | 제곱근 | `SQRT(M)` | | `POWER(base, exp)` | 거듭제곱 | `POWER(W1, 2)` | **평가 과정:** ```typescript // 1. 변수 치환 let expr = formula; Object.keys(vars).forEach(key => { const regex = new RegExp(`\\b${key}\\b`, 'g'); expr = expr.replace(regex, vars[key].toString()); }); // 2. 함수 처리 (CEIL, FLOOR, ROUND 등) expr = processFunctions(expr); // 3. 최종 계산 return new Function(`return (${expr})`)(); ``` ### 1.3 BOM 계산 과정 (bomCalculatorWithDebug.ts) **10단계 계산 과정:** | 단계 | 설명 | 예시 | |------|------|------| | Step 1 | 수량 공식 확인 | `H/1000` | | Step 2 | 변수 값 확인 | `{W0:2000, H0:2500, W1:2140, H1:2850, M:6.099}` | | Step 3 | 수량 계산 과정 | `H/1000 = 2850/1000 = 2.85` | | Step 4 | 계산된 수량 | `2.85` | | Step 5 | 단가 소스 | `단가관리 (15,000원)` | | Step 6 | 기본 단가 | `15,000` | | Step 7 | 카테고리 승수 | `면적단가 (15,000원/㎡ × 6.099㎡)` | | Step 8 | 최종 단가 | `91,485` | | Step 9 | 금액 계산 | `2.85 × 91,485 = 260,732` | | Step 10 | 최종 금액 | `260,732` | ### 1.4 단가 계산 방식 ```typescript // 1순위: pricing 테이블에서 조회 const itemPricing = pricings.find(p => p.itemCode === bomEntry.childItemCode); if (itemPricing && itemPricing.salesPrice) { unitPrice = itemPricing.salesPrice; } // 2순위: 품목마스터에서 조회 else if (childItem.salesPrice) { unitPrice = childItem.salesPrice; } // 면적 기반 품목 판단 (원단, 패널, 도장, 표면처리) const areaBasedCategories = ['원단', '패널', '도장', '표면처리']; if (isAreaBased && M > 0) { finalUnitPrice = unitPrice * M; // 면적 단가 } ``` --- ## 2. MNG 현재 구현 상태 ### 2.1 FormulaEvaluatorService.php **✅ 구현됨:** - `evaluate()` - 수식 평가 - `validateFormula()` - 수식 검증 - `executeAll()` - 전체 수식 실행 - `getItemPrice()` - 단가 조회 (Price 모델 연동) - `getBomTree()` - BOM 트리 조회 - `enrichItemsWithDetails()` - 품목 상세 정보 추가 **지원 함수:** - SUM, ROUND, CEIL, FLOOR, ABS, MIN, MAX, IF, AND, OR, NOT **❌ 미구현:** - 제품 카테고리별 변수 계산 규칙 (W1, H1, M) - 면적/중량 기반 단가 계산 - 공정별 분류 ### 2.2 simulator.blade.php **✅ 구현됨:** - 입력 변수 폼 (W0, H0, PC, GT, MP, CT 등) - API 호출 (`/api/admin/quote-formulas/formulas/simulate`) - 계산된 변수 표시 - 품목 목록 표시 (BOM 트리 포함) **❌ 미구현:** - 공정별 그룹화 표시 - 단가/금액 계산 결과 표시 - 총합계 표시 --- ## 3. 매핑 계획 ### 3.1 변수 계산 규칙 추가 **quote_formulas 테이블에 추가할 수식:** ```sql -- 제작폭 (W1) - 스크린 INSERT INTO quote_formulas (category_id, variable, name, type, formula, output_type, sort_order) VALUES (1, 'W1', '제작폭', 'calculation', 'IF(PC == "screen", W0 + 140, W0 + 110)', 'variable', 10); -- 제작높이 (H1) INSERT INTO quote_formulas (category_id, variable, name, type, formula, output_type, sort_order) VALUES (1, 'H1', '제작높이', 'calculation', 'H0 + 350', 'variable', 20); -- 면적 (M) INSERT INTO quote_formulas (category_id, variable, name, type, formula, output_type, sort_order) VALUES (1, 'M', '면적', 'calculation', '(W1 * H1) / 1000000', 'variable', 30); -- W, H 매핑 INSERT INTO quote_formulas (category_id, variable, name, type, formula, output_type, sort_order) VALUES (1, 'W', '제작폭', 'calculation', 'W1', 'variable', 40); INSERT INTO quote_formulas (category_id, variable, name, type, formula, output_type, sort_order) VALUES (1, 'H', '제작높이', 'calculation', 'H1', 'variable', 50); ``` ### 3.2 FormulaEvaluatorService 확장 ```php // 추가할 메서드 /** * 카테고리별 단가 계산 */ private function calculateCategoryPrice( array $item, float $basePrice, array $variables ): array { $areaBasedCategories = ['원단', '패널', '도장', '표면처리']; $itemCategory = $item['item_category'] ?? ''; if (in_array($itemCategory, $areaBasedCategories) && isset($variables['M'])) { return [ 'final_price' => $basePrice * $variables['M'], 'calculation_note' => "면적단가 ({$basePrice}원/㎡ × {$variables['M']}㎡)" ]; } return [ 'final_price' => $basePrice, 'calculation_note' => '수량단가' ]; } /** * 공정별 품목 그룹화 */ private function groupItemsByProcess(array $items): array { $processOrder = ['screen' => '스크린 공정', 'bending' => '절곡 공정', 'electric' => '전기 공정']; $grouped = []; foreach ($processOrder as $code => $label) { $grouped[$code] = [ 'label' => $label, 'items' => [], 'subtotal' => 0 ]; } foreach ($items as $item) { $process = $item['process_type'] ?? 'etc'; if (isset($grouped[$process])) { $grouped[$process]['items'][] = $item; $grouped[$process]['subtotal'] += $item['total_price'] ?? 0; } } return $grouped; } ``` ### 3.3 items 테이블 확장 ```sql -- 공정 유형 필드 추가 ALTER TABLE items ADD COLUMN process_type VARCHAR(20) DEFAULT NULL COMMENT '공정유형: screen(스크린), bending(절곡), electric(전기)'; -- 인덱스 추가 CREATE INDEX idx_items_process_type ON items(process_type); ``` --- ## 4. 구현 순서 ### Phase 1: DB 스키마 및 데이터 (1일) 1. ✅ items 테이블에 `process_type` 필드 추가 2. ✅ 기존 품목에 공정 유형 매핑 3. ✅ quote_formulas에 기본 변수 계산 수식 추가 ### Phase 2: 백엔드 로직 (2일) 1. ✅ FormulaEvaluatorService에 카테고리별 단가 계산 추가 2. ✅ 공정별 그룹화 메서드 추가 3. ✅ executeAll() 반환 구조 확장 ### Phase 3: 프론트엔드 (1일) 1. ✅ simulator.blade.php에 공정별 결과 표시 2. ✅ 단가/금액 표시 추가 3. ✅ 총합계 표시 ### Phase 4: 검증 (1일) 1. ✅ design.sam.kr과 결과 비교 2. ✅ 금액 차이 분석 및 조정 --- ## 5. 핵심 파일 참조 ### Design (참조용) ``` /SAM/design/src/components/ ├── AutoCalculationSimulator.tsx # 메인 시뮬레이터 (1068줄) ├── utils/ │ ├── formulaEvaluator.ts # 수식 평가 (312줄) │ └── bomCalculatorWithDebug.ts # BOM 계산 (232줄) └── contexts/ └── DataContext.tsx # 마스터 데이터 (9859줄) ``` ### MNG (수정 대상) ``` /SAM/mng/ ├── app/Services/Quote/ │ └── FormulaEvaluatorService.php # 핵심 서비스 (575줄) ├── resources/views/quote-formulas/ │ └── simulator.blade.php # 시뮬레이터 UI (867줄) └── app/Models/ ├── Price.php # 단가 모델 (135줄) └── Item.php # 품목 모델 ``` --- ## 6. 테스트 케이스 | 입력 | Design 결과 | MNG 목표 | |------|------------|----------| | W0=2000, H0=2500, PC=스크린 | W1=2140, H1=2850, M=6.099 | 동일 | | 스크린 원단 | 수량공식: W*H/1000000 = 6.099㎡ | 동일 | | 가이드레일 | 수량공식: H/1000 = 2.85m | 동일 | --- *이 문서는 design.sam.kr 분석 결과를 바탕으로 mng 시뮬레이터 구현 계획을 정리합니다.*