docs: 견적 시뮬레이터 계산 로직 분석 및 동기화 계획 문서 추가
- simulator-calculation-logic-mapping.md: design.sam.kr 계산 로직 상세 분석 - 변수 계산 규칙 (W0,H0 → W1,H1,M) - 수식 평가 함수 및 지원 함수 목록 - BOM 10단계 계산 과정 - 단가 계산 방식 (pricing → itemMaster → 면적단가) - simulator-planning-page-sync-plan.md: mng 시뮬레이터 동기화 계획 - index_plans.md: 새 문서 인덱스 추가
This commit is contained in:
204
plans/index_plans.md
Normal file
204
plans/index_plans.md
Normal file
@@ -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) - 현재 작업
|
||||
|
||||
---
|
||||
|
||||
**범례**:
|
||||
- 🟢 완료
|
||||
- 🟡 진행중
|
||||
- ⚪ 대기
|
||||
- 📚 참조용
|
||||
293
plans/simulator-calculation-logic-mapping.md
Normal file
293
plans/simulator-calculation-logic-mapping.md
Normal file
@@ -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 시뮬레이터 구현 계획을 정리합니다.*
|
||||
431
plans/simulator-planning-page-sync-plan.md
Normal file
431
plans/simulator-planning-page-sync-plan.md
Normal file
@@ -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 += `
|
||||
<div class="process-group">
|
||||
<div class="process-header">
|
||||
${processIcons[process]} ${group.label}
|
||||
(${group.items.length}개 품목)
|
||||
<span class="subtotal">${formatNumber(group.subtotal)}원</span>
|
||||
</div>
|
||||
<div class="process-items">
|
||||
${renderItems(group.items)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
html += `
|
||||
<div class="total-section">
|
||||
📊 총합계: ${data.items.length}개 품목
|
||||
<span class="total">${formatNumber(data.total_amount)}원</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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 업데이트
|
||||
- [ ] 문서 업데이트
|
||||
|
||||
---
|
||||
|
||||
*이 문서는 견적 시뮬레이터와 기획 페이지 동기화 작업의 전체 계획을 담고 있습니다.*
|
||||
Reference in New Issue
Block a user