diff --git a/plans/index_plans.md b/plans/index_plans.md new file mode 100644 index 0000000..95d0a74 --- /dev/null +++ b/plans/index_plans.md @@ -0,0 +1,204 @@ +# 기획 문서 인덱스 + +> SAM 시스템 개발 계획 및 기획 문서 모음 +> **최종 업데이트**: 2025-12-23 + +--- + +## 문서 현황 요약 + +| 분류 | 개수 | 설명 | +|------|------|------| +| 개발 계획서 | 9개 | 기능별 API 개발 계획 | +| 스토리보드 | 2개 | ERP 화면 설계 (D0.8, D1.0) | +| 플로우 테스트 | 32개 | API 검증용 JSON 테스트 케이스 | + +--- + +## 개발 계획서 + +### ERP API 개발 + +| 문서 | 상태 | 설명 | +|------|------|------| +| [erp-api-development-plan.md](./erp-api-development-plan.md) | 🟡 Phase 3 진행중 | SAM ERP API 전체 개발 계획 | +| [erp-api-development-plan-d1.0-changes.md](./erp-api-development-plan-d1.0-changes.md) | 📚 참조 | D1.0 스토리보드 변경 사항 | + +### 기능별 계획 + +| 문서 | 상태 | 설명 | +|------|------|------| +| [mng-quote-formula-development-plan.md](./mng-quote-formula-development-plan.md) | 🟢 완료 | mng 견적 수식 관리 | +| [quote-auto-calculation-development-plan.md](./quote-auto-calculation-development-plan.md) | 🟡 진행중 | 견적 자동 계산 | +| [simulator-planning-page-sync-plan.md](./simulator-planning-page-sync-plan.md) | 🟡 진행중 | 견적 시뮬레이터 동기화 | +| [simulator-calculation-logic-mapping.md](./simulator-calculation-logic-mapping.md) | 📚 참조 | 계산 로직 매핑 분석 | +| [mng-item-field-management-plan.md](./mng-item-field-management-plan.md) | 🟡 진행중 | 품목 필드 관리 | +| [items-table-unification-plan.md](./items-table-unification-plan.md) | 🟢 완료 | items 테이블 통합 | +| [mng-menu-system-plan.md](./mng-menu-system-plan.md) | 🟡 진행중 | mng 메뉴 시스템 | + +### 마이그레이션 & 연동 + +| 문서 | 상태 | 설명 | +|------|------|------| +| [5130-to-mng-migration-plan.md](./5130-to-mng-migration-plan.md) | 🟡 진행중 | 5130 → mng 마이그레이션 | +| [react-api-integration-plan.md](./react-api-integration-plan.md) | 🟡 진행중 | React ↔ API 연동 | +| [react-mock-to-api-migration-plan.md](./react-mock-to-api-migration-plan.md) | ⚪ 대기 | Mock → API 전환 | + +### 기타 + +| 문서 | 상태 | 설명 | +|------|------|------| +| [dummy-data-seeding-plan.md](./dummy-data-seeding-plan.md) | 🟢 완료 | 더미 데이터 시딩 | +| [api-explorer-development-plan.md](./api-explorer-development-plan.md) | 🟡 진행중 | API Explorer 개발 | + +--- + +## 스토리보드 + +### SAM_ERP_Storyboard_D0.8_251216 + +**경로**: `docs/plans/SAM_ERP_Storyboard_D0.8_251216/` +**일자**: 2025-12-16 +**슬라이드 수**: 113장 + +**내용**: SAM ERP 전체 화면 설계 (D0.8 버전) + +| 범위 | 슬라이드 | +|------|----------| +| 공통/인증 | 1-15 | +| 대시보드 | 16-25 | +| 인사관리 | 26-50 | +| 회계관리 | 51-80 | +| 기준정보 | 81-100 | +| 보고서 | 101-113 | + +--- + +### SAM_ERP_Storyboard_D1.0_251218 + +**경로**: `docs/plans/SAM_ERP_Storyboard_D1.0_251218/` +**일자**: 2025-12-18 +**슬라이드 수**: 38장 + +**내용**: D0.8 대비 변경/추가된 화면 (D1.0 버전) + +**변경 사항**: [erp-api-development-plan-d1.0-changes.md](./erp-api-development-plan-d1.0-changes.md) 참조 + +--- + +## 플로우 테스트 + +**경로**: `docs/plans/flow-tests/` +**용도**: Flow Tester (mng.sam.kr/dev-tools/flow-tester) 검증용 JSON + +### 인증/권한 + +| 파일 | 설명 | +|------|------| +| [auth-api-flow.json](./flow-tests/auth-api-flow.json) | 인증 API 플로우 | +| [auth-legacy-flow.json](./flow-tests/auth-legacy-flow.json) | 레거시 인증 플로우 | +| [user-invitation-flow.json](./flow-tests/user-invitation-flow.json) | 사용자 초대 | + +### 품목/BOM + +| 파일 | 설명 | +|------|------| +| [items-crud-api-flow.json](./flow-tests/items-crud-api-flow.json) | 품목 CRUD | +| [items-bom-api-flow.json](./flow-tests/items-bom-api-flow.json) | BOM API | +| [items-bom-test.json](./flow-tests/items-bom-test.json) | BOM 테스트 | +| [item-master-page-api-flow.json](./flow-tests/item-master-page-api-flow.json) | 품목 마스터 페이지 | +| [item-master-full-api-flow.json](./flow-tests/item-master-full-api-flow.json) | 품목 마스터 전체 | +| [item-master-init-api-flow.json](./flow-tests/item-master-init-api-flow.json) | 품목 마스터 초기화 | +| [item-master-field-api-flow.json](./flow-tests/item-master-field-api-flow.json) | 품목 필드 | +| [item-master-legacy-flow.json](./flow-tests/item-master-legacy-flow.json) | 레거시 품목 | +| [item-delete-legacy-flow.json](./flow-tests/item-delete-legacy-flow.json) | 품목 삭제 (레거시) | +| [item-delete-force-delete.json](./flow-tests/item-delete-force-delete.json) | 품목 강제 삭제 | +| [item-fields-is-active-test.json](./flow-tests/item-fields-is-active-test.json) | 필드 활성화 테스트 | + +### 거래처/영업 + +| 파일 | 설명 | +|------|------| +| [client-api-flow.json](./flow-tests/client-api-flow.json) | 거래처 API | +| [client-legacy-flow.json](./flow-tests/client-legacy-flow.json) | 레거시 거래처 | +| [client-group-api-flow.json](./flow-tests/client-group-api-flow.json) | 거래처 그룹 | +| [pricing-crud-flow.json](./flow-tests/pricing-crud-flow.json) | 단가 CRUD | +| [pricing-validation-test.json](./flow-tests/pricing-validation-test.json) | 단가 검증 | + +### 인사/급여 + +| 파일 | 설명 | +|------|------| +| [employee-api-crud.json](./flow-tests/employee-api-crud.json) | 사원 CRUD | +| [attendance-api-crud.json](./flow-tests/attendance-api-crud.json) | 근태 CRUD | +| [department-tree-api.json](./flow-tests/department-tree-api.json) | 부서 트리 | + +### 회계/재무 + +| 파일 | 설명 | +|------|------| +| [account-management-flow.json](./flow-tests/account-management-flow.json) | 계정 관리 | +| [sales-statement-flow.json](./flow-tests/sales-statement-flow.json) | 매출 전표 | +| [payment-flow.json](./flow-tests/payment-flow.json) | 결제 플로우 | +| [bad-debt-flow.json](./flow-tests/bad-debt-flow.json) | 대손 처리 | + +### 기타 + +| 파일 | 설명 | +|------|------| +| [popup-flow.json](./flow-tests/popup-flow.json) | 팝업 플로우 | +| [company-request-flow.json](./flow-tests/company-request-flow.json) | 회사 요청 | +| [notification-settings-flow.json](./flow-tests/notification-settings-flow.json) | 알림 설정 | +| [subscription-flow.json](./flow-tests/subscription-flow.json) | 구독 플로우 | +| [branching-example-flow.json](./flow-tests/branching-example-flow.json) | 분기 예제 | + +--- + +## 디렉토리 구조 + +``` +docs/plans/ +├── INDEX.md # 이 파일 +│ +├── erp-api-development-plan.md # ERP API 개발 계획 (핵심) +├── erp-api-development-plan-d1.0-changes.md +├── mng-quote-formula-development-plan.md +├── quote-auto-calculation-development-plan.md +├── mng-item-field-management-plan.md +├── items-table-unification-plan.md +├── mng-menu-system-plan.md +├── 5130-to-mng-migration-plan.md +├── react-api-integration-plan.md +├── react-mock-to-api-migration-plan.md +├── dummy-data-seeding-plan.md +├── api-explorer-development-plan.md +│ +├── SAM_ERP_Storyboard_D0.8_251216/ # 스토리보드 D0.8 (113장) +│ └── 슬라이드*.jpeg +│ +├── SAM_ERP_Storyboard_D1.0_251218/ # 스토리보드 D1.0 (38장) +│ └── 슬라이드*.jpeg +│ +└── flow-tests/ # 플로우 테스트 JSON (32개) + ├── auth-*.json + ├── items-*.json + ├── client-*.json + └── ... +``` + +--- + +## 관련 문서 + +- [docs/INDEX.md](../INDEX.md) - 전체 문서 인덱스 +- [docs/projects/index_projects.md](../projects/index_projects.md) - 프로젝트 문서 인덱스 +- [docs/specs/erp-analysis/](../specs/erp-analysis/) - ERP 분석 명세서 +- [CURRENT_WORKS.md](../../CURRENT_WORKS.md) - 현재 작업 + +--- + +**범례**: +- 🟢 완료 +- 🟡 진행중 +- ⚪ 대기 +- 📚 참조용 \ No newline at end of file diff --git a/plans/simulator-calculation-logic-mapping.md b/plans/simulator-calculation-logic-mapping.md new file mode 100644 index 0000000..76a1426 --- /dev/null +++ b/plans/simulator-calculation-logic-mapping.md @@ -0,0 +1,293 @@ +# 견적 시뮬레이터 계산 로직 매핑 + +> **작성일**: 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 시뮬레이터 구현 계획을 정리합니다.* \ No newline at end of file diff --git a/plans/simulator-planning-page-sync-plan.md b/plans/simulator-planning-page-sync-plan.md new file mode 100644 index 0000000..f3b2cdb --- /dev/null +++ b/plans/simulator-planning-page-sync-plan.md @@ -0,0 +1,431 @@ +# 견적 시뮬레이터 - 기획 페이지 동기화 작업 계획 + +> **작성일**: 2025-12-23 +> **수정일**: 2025-12-23 (계산 로직 분석 완료) +> **목표**: mng 시뮬레이터를 기획 페이지(design.sam.kr)와 동일한 결과 출력하도록 구현 +> **참조 문서**: [계산 로직 매핑](./simulator-calculation-logic-mapping.md) + +--- + +## 1. 현황 분석 + +### 1.1 기획 페이지 (localhost:3002) 분석 + +**입력 항목:** +| 변수 | 라벨 | 샘플값 | 설명 | +|------|------|--------|------| +| 층수 | 층수 | 1층 | 건물 층수 | +| 부호 | 부호 | A | 식별 코드 | +| PC | 제품카테고리 | 스크린 | product_category | +| PRODUCT_ID | 제품명 | 스크린 셔터 (표준형) | 제품 선택 | +| W0 | 가로 | 2000 | 오픈사이즈 가로 (mm) | +| H0 | 세로 | 2500 | 오픈사이즈 세로 (mm) | +| GT | 설치유형 | 벽면 | guide_type (벽면/천장/바닥) | +| MP | 모터전원 | 220V | motor_power | +| CT | 제어기 | 단독제어 | controller_type | +| QTY | 수량 | 1 | 수량 | + +**산출 결과 (총 12개 품목, 1,393,683원):** + +| 공정 | 품목수 | 소계 | 품목 상세 | +|------|--------|------|----------| +| 스크린 공정 | 2 | 558,441원 | 스크린 원단(518,415), 연기차단재(40,026) | +| 절곡 공정 | 8 | 385,242원 | 가이드레일, 하부베이스, 케이스, 측면덮개, 상부덮개, 하단마감재, 하단보강빔바, 샤프트 | +| 전기 공정 | 2 | 400,000원 | 모터(250,000), 제어기(150,000) | + +### 1.2 현재 mng 시뮬레이터 분석 + +**현재 구현된 기능:** +- ✅ 변수 입력 (W0, H0 등) +- ✅ 수식 계산 (FormulaEvaluatorService) +- ✅ BOM 트리 구조 표시 +- ✅ 품목 목록 표시 + +**미구현 기능:** +- ❌ 공정별 분류 (스크린/절곡/전기) +- ❌ 단가 연동 (Price 모델) +- ❌ 금액 계산 (수량 × 단가) +- ❌ 공정별 소계 +- ❌ 총합계 금액 + +### 1.3 데이터 구조 차이점 + +| 구분 | 기획 페이지 | mng 시뮬레이터 | +|------|------------|----------------| +| 데이터 소스 | DataContext.tsx (하드코딩) | DB (quote_formulas, items) | +| 공정 분류 | process 필드로 그룹화 | 미구현 | +| 단가 | 하드코딩된 가격 | prices 테이블 | +| BOM | JSON 내 quantityFormula | bom JSON 필드 | + +--- + +## 2. 작업 계획 + +### Phase 1: 데이터 구조 정비 (1-2일) + +#### 1.1 items 테이블 공정 필드 추가 +```sql +ALTER TABLE items ADD COLUMN process_type VARCHAR(20) DEFAULT NULL + COMMENT '공정유형: screen(스크린), bending(절곡), electric(전기)'; +``` + +#### 1.2 기존 품목에 공정 타입 매핑 +| 품목명 | process_type | +|--------|--------------| +| 스크린 원단 | screen | +| 연기차단재 | screen | +| 가이드레일, 하부베이스, 케이스, 측면덮개, 상부덮개, 하단마감재, 하단보강빔바, 샤프트 | bending | +| 모터, 제어기 | electric | + +#### 1.3 prices 테이블 더미 데이터 추가 +- 기획 페이지의 가격 데이터를 prices 테이블에 시딩 +- item_code와 연동 확인 + +**파일 변경:** +- `mng/database/migrations/xxxx_add_process_type_to_items.php` +- `mng/database/seeders/ItemProcessTypeSeeder.php` +- `mng/database/seeders/PriceSeeder.php` + +--- + +### Phase 2: 백엔드 수정 (2-3일) + +#### 2.1 FormulaEvaluatorService 확장 + +**현재 반환 구조:** +```php +[ + 'variables' => [...], + 'items' => [ + ['item_code' => 'SCREEN-001', 'quantity' => 5.18, ...] + ], + 'bom_tree' => [...] +] +``` + +**목표 반환 구조:** +```php +[ + 'variables' => [...], + 'items' => [ + [ + 'item_code' => 'SCREEN-001', + 'item_name' => '스크린 원단', + 'specification' => '...', + 'unit' => 'm²', + 'quantity' => 5.18, + 'unit_price' => 100000, // 신규 + 'total_price' => 518000, // 신규 + 'process_type' => 'screen', // 신규 + ] + ], + 'items_by_process' => [ // 신규 + 'screen' => ['items' => [...], 'subtotal' => 558441], + 'bending' => ['items' => [...], 'subtotal' => 385242], + 'electric' => ['items' => [...], 'subtotal' => 400000], + ], + 'total_amount' => 1393683, // 신규 + 'bom_tree' => [...] +] +``` + +#### 2.2 Price 연동 로직 추가 + +```php +// FormulaEvaluatorService.php +private function enrichItemWithPrice(array $item, int $tenantId): array +{ + $price = Price::getSalesPriceByItemCode($tenantId, $item['item_code']); + + $item['unit_price'] = $price; + $item['total_price'] = $item['quantity'] * $price; + + return $item; +} + +private function groupItemsByProcess(array $items): array +{ + $grouped = [ + 'screen' => ['items' => [], 'subtotal' => 0, 'label' => '스크린 공정'], + 'bending' => ['items' => [], 'subtotal' => 0, 'label' => '절곡 공정'], + 'electric' => ['items' => [], 'subtotal' => 0, 'label' => '전기 공정'], + ]; + + foreach ($items as $item) { + $process = $item['process_type'] ?? 'etc'; + if (isset($grouped[$process])) { + $grouped[$process]['items'][] = $item; + $grouped[$process]['subtotal'] += $item['total_price']; + } + } + + return $grouped; +} +``` + +**파일 변경:** +- `mng/app/Services/FormulaEvaluatorService.php` +- `mng/app/Models/Item.php` (process_type 필드 추가) + +--- + +### Phase 3: 프론트엔드 수정 (2-3일) + +#### 3.1 simulator.blade.php UI 개선 + +**현재 UI:** +``` +[변수 입력] → [계산] → [변수 결과] [품목 목록] [BOM 트리] +``` + +**목표 UI:** +``` +[입력 섹션] +┌─────────────────────────────────────────────────────────┐ +│ 층수 | 부호 | 제품카테고리 | 제품명 | 가로 | 세로 | ... │ +│ 1층 | A | 스크린 | 표준형 | 2000 | 2500 | ... │ +└─────────────────────────────────────────────────────────┘ + +[산출 결과] +┌─────────────────────────────────────────────────────────┐ +│ 📦 스크린 공정 (2개 품목) 558,441원 │ +│ ├─ 스크린 원단 5.18m² @100,000 = 518,415원 │ +│ └─ 연기차단재 2.00m @20,013 = 40,026원 │ +├─────────────────────────────────────────────────────────┤ +│ 🔧 절곡 공정 (8개 품목) 385,242원 │ +│ ├─ 가이드레일 2750mm @15,000 = 30,000원 │ +│ ... │ +├─────────────────────────────────────────────────────────┤ +│ ⚡ 전기 공정 (2개 품목) 400,000원 │ +│ ├─ 모터 1EA @250,000 = 250,000원 │ +│ └─ 제어기 1EA @150,000 = 150,000원 │ +├─────────────────────────────────────────────────────────┤ +│ 📊 총합계: 12개 품목 1,393,683원 │ +└─────────────────────────────────────────────────────────┘ +``` + +#### 3.2 JavaScript 수정 + +```javascript +// 공정별 결과 렌더링 +function renderProcessResults(data) { + const processOrder = ['screen', 'bending', 'electric']; + const processIcons = { + screen: '📦', bending: '🔧', electric: '⚡' + }; + + let html = ''; + processOrder.forEach(process => { + const group = data.items_by_process[process]; + if (group.items.length > 0) { + html += ` +
+
+ ${processIcons[process]} ${group.label} + (${group.items.length}개 품목) + ${formatNumber(group.subtotal)}원 +
+
+ ${renderItems(group.items)} +
+
+ `; + } + }); + + html += ` +
+ 📊 총합계: ${data.items.length}개 품목 + ${formatNumber(data.total_amount)}원 +
+ `; + + return html; +} +``` + +**파일 변경:** +- `mng/resources/views/quote-formulas/simulator.blade.php` +- `mng/public/css/simulator.css` (스타일 추가) + +--- + +### Phase 4: 테스트 및 검증 (1일) + +#### 4.1 테스트 케이스 + +| 테스트 | 입력 | 예상 결과 | +|--------|------|----------| +| 기본 테스트 | W0=2000, H0=2500 | 12개 품목, 1,393,683원 | +| 크기 변경 | W0=3000, H0=3000 | 금액 증가 확인 | +| 수량 변경 | QTY=2 | 총액 2배 확인 | + +#### 4.2 검증 항목 +- [ ] 기획 페이지와 동일한 품목 수 +- [ ] 기획 페이지와 동일한 공정별 분류 +- [ ] 기획 페이지와 동일한 금액 (±1원 오차 허용) +- [ ] 반올림 규칙 일치 확인 + +--- + +## 3. 파일 변경 목록 + +### 백엔드 (mng/) + +| 파일 | 작업 | 우선순위 | +|------|------|---------| +| `database/migrations/xxxx_add_process_type_to_items.php` | 신규 | P1 | +| `database/seeders/ItemProcessTypeSeeder.php` | 신규 | P1 | +| `database/seeders/PriceSeeder.php` | 수정 | P1 | +| `app/Models/Item.php` | 수정 (fillable 추가) | P1 | +| `app/Services/FormulaEvaluatorService.php` | 수정 (핵심) | P1 | + +### 프론트엔드 (mng/) + +| 파일 | 작업 | 우선순위 | +|------|------|---------| +| `resources/views/quote-formulas/simulator.blade.php` | 수정 | P2 | +| `public/css/simulator.css` | 신규/수정 | P2 | + +--- + +## 4. 일정 (예상 5-7일) + +| 단계 | 작업 | 예상 소요 | +|------|------|----------| +| Phase 1 | 데이터 구조 정비 | 1-2일 | +| Phase 2 | 백엔드 수정 | 2-3일 | +| Phase 3 | 프론트엔드 수정 | 2-3일 | +| Phase 4 | 테스트 및 검증 | 1일 | + +--- + +## 5. 기술적 고려사항 + +### 5.1 가격 계산 정확도 +- 소수점 처리: 4자리까지 계산 후 최종 반올림 +- 반올림 규칙: Price 모델의 `rounding_rule` 필드 활용 +- 단위: 원 단위로 표시 + +### 5.2 공정 분류 확장성 +- process_type enum: 향후 공정 추가 가능하도록 설계 +- 공정 순서: config/constants.php에서 관리 + +### 5.3 성능 고려 +- 가격 조회: 배치 조회로 N+1 문제 방지 +- 캐싱: 자주 사용되는 가격 데이터 캐싱 고려 + +--- + +## 6. 핵심 계산 로직 (2025-12-23 분석 완료) + +### 6.1 변수 계산 규칙 (design.sam.kr 기준) + +```typescript +// AutoCalculationSimulator.tsx:429-444 +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 // 미구현: 중량 +}; +``` + +### 6.2 수식 평가 (formulaEvaluator.ts) + +**지원 함수:** SUM, AVERAGE, MAX, MIN, ROUND, CEIL, FLOOR, ABS, IF, SQRT, POWER + +**평가 과정:** +1. 변수를 실제 값으로 치환 (W0 → 2000) +2. 함수를 JavaScript 코드로 변환 (CEIL → Math.ceil) +3. `new Function()` 으로 최종 계산 + +### 6.3 단가 계산 방식 + +```typescript +// 1순위: pricing 테이블 +// 2순위: 품목마스터 salesPrice + +// 면적 기반 품목 (원단, 패널, 도장, 표면처리) +if (isAreaBased && M > 0) { + finalUnitPrice = unitPrice * M; // 면적 × 기본단가 +} +``` + +### 6.4 BOM 수량 공식 예시 + +| 품목 | 수량공식 | W0=2000, H0=2500 결과 | +|------|---------|----------------------| +| 스크린 원단 | `W*H/1000000` | 2140×2850/1000000 = 6.099㎡ | +| 가이드레일 | `H/1000` | 2850/1000 = 2.85m | +| 케이스 | `(W1+100)/1000` | (2140+100)/1000 = 2.24m | + +--- + +## 7. 참고 자료 + +### 7.1 관련 파일 + +**Design (분석 완료):** +- `design/src/components/AutoCalculationSimulator.tsx` - 메인 시뮬레이터 +- `design/src/components/utils/formulaEvaluator.ts` - 수식 평가 +- `design/src/components/utils/bomCalculatorWithDebug.ts` - BOM 계산 + +**MNG (수정 대상):** +- `mng/app/Services/Quote/FormulaEvaluatorService.php` - 핵심 서비스 +- `mng/resources/views/quote-formulas/simulator.blade.php` - UI + +### 7.2 기획 데이터 +- **기획 데이터**: `react/src/contexts/DataContext.tsx.backup` +- **현재 시뮬레이터**: `mng/resources/views/quote-formulas/simulator.blade.php` +- **수식 평가**: `mng/app/Services/FormulaEvaluatorService.php` +- **가격 모델**: `mng/app/Models/Price.php` + +### 6.2 DataContext.tsx.backup 핵심 로직 + +**가이드레일 자재 선택 규칙:** +```javascript +// RULE-006: 가이드레일 제작길이 (G) = H0 + 250 +// 자재 선택 기준: +// - G <= 3000: SM-GL-3000 +// - 3000 < G <= 4000: SM-GL-4000 +// - 4000 < G <= 5000: SM-GL-5000 +// - G > 5000: SM-GL-6000 +``` + +**수량 공식 예시:** +```javascript +items: [ + { code: 'SCREEN-001', quantityFormula: '(W1 * H1) / 1000000' }, // m² + { code: 'RAIL-001', quantityFormula: '2' }, // 2개 (좌/우) + { code: 'MOTOR-001', quantityFormula: '1' }, // 1개 +] +``` + +--- + +## 7. 체크리스트 + +### 시작 전 +- [ ] 기획팀과 가격 데이터 확인 +- [ ] 공정 분류 기준 확정 +- [ ] 반올림 규칙 확정 + +### 개발 중 +- [ ] Phase 1: 마이그레이션 및 시더 작성 +- [ ] Phase 2: FormulaEvaluatorService 수정 +- [ ] Phase 3: simulator.blade.php UI 개선 +- [ ] Phase 4: 기획 페이지와 결과 비교 검증 + +### 완료 후 +- [ ] 기획팀 확인 +- [ ] CURRENT_WORKS.md 업데이트 +- [ ] 문서 업데이트 + +--- + +*이 문서는 견적 시뮬레이터와 기획 페이지 동기화 작업의 전체 계획을 담고 있습니다.* \ No newline at end of file