- 완료된 계획 문서 22개를 plans/archive/로 이동 - tracked 16개 (git mv): bending-lot-pipeline, docs-update, fcm-notification 등 - untracked 6개 (mv): bending-worklog, formula-engine, mng-item 등 - index_plans.md 전면 업데이트 - 진행중 44개 / 완료 37개 현황 반영 - 각 문서별 실제 진행률 기재 (0%~94%) - 카테고리별 재정리 (견적/생산/품목/문서/마이그레이션/시스템/UI) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
262 lines
9.5 KiB
Markdown
262 lines
9.5 KiB
Markdown
# 견적 V2 자동 견적 산출 오류 수정 계획
|
||
|
||
> **작성일**: 2026-01-26
|
||
> **목적**: 자동 견적 산출 기능의 4가지 오류 분석 및 수정
|
||
> **기준 문서**: `QuoteRegistrationV2.tsx`, `LocationDetailPanel.tsx`, `QuoteSummaryPanel.tsx`, `actions.ts`
|
||
> **상태**: ✅ 완료
|
||
|
||
---
|
||
|
||
## 📍 현재 진행 상태
|
||
|
||
| 항목 | 내용 |
|
||
|------|------|
|
||
| **마지막 완료 작업** | 테스트 및 검증 완료 |
|
||
| **다음 작업** | - |
|
||
| **진행률** | 4/4 (100%) ✅ |
|
||
| **마지막 업데이트** | 2026-01-26 |
|
||
|
||
---
|
||
|
||
## 1. 개요
|
||
|
||
### 1.1 배경
|
||
견적 V2 페이지(`/sales/quote-management/test-new`)에서 자동 견적 산출 버튼 클릭 후 다음 4가지 문제 발생:
|
||
1. 오른쪽 패널에 제품 리스트가 표시되지 않음
|
||
2. 개소별 합계(상세소계)가 표시되지 않음
|
||
3. 상세별 합계(그룹)가 표시되지 않음
|
||
4. 예상 견적금액이 0원으로 표시됨
|
||
|
||
### 1.2 기준 원칙
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 🎯 핵심 원칙 │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ - API 응답 구조와 프론트엔드 기대 구조의 일치 확보 │
|
||
│ - Mock 데이터 fallback 로직은 디버깅/테스트용으로만 유지 │
|
||
│ - 실제 BOM 계산 결과가 UI에 정확히 반영되도록 수정 │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 1.3 변경 승인 정책
|
||
|
||
| 분류 | 예시 | 승인 |
|
||
|------|------|------|
|
||
| ✅ 즉시 가능 | 타입 캐스팅 수정, 데이터 매핑 로직 수정 | 불필요 |
|
||
| ⚠️ 컨펌 필요 | API 응답 구조 변경, 새 인터페이스 정의 | **필수** |
|
||
| 🔴 금지 | API 엔드포인트 변경, DB 스키마 변경 | 별도 협의 |
|
||
|
||
---
|
||
|
||
## 2. 근본 원인 분석
|
||
|
||
### 2.1 API 응답 구조 불일치 (핵심 원인)
|
||
|
||
**API 실제 응답** (`actions.ts:962-965`):
|
||
```typescript
|
||
return {
|
||
success: true,
|
||
data: result.data || [], // 배열을 직접 반환
|
||
};
|
||
```
|
||
|
||
**API 서버 응답** (`QuoteCalculationService.php:168-178`):
|
||
```php
|
||
return [
|
||
'success' => $failCount === 0,
|
||
'summary' => [
|
||
'total_count' => count($inputItems),
|
||
'success_count' => $successCount,
|
||
'fail_count' => $failCount,
|
||
'grand_total' => round($grandTotal, 2),
|
||
],
|
||
'items' => $results, // items 배열 안에 결과가 있음
|
||
];
|
||
```
|
||
|
||
**컴포넌트 기대 구조** (`QuoteRegistrationV2.tsx:459-462`):
|
||
```typescript
|
||
const apiData = result.data as {
|
||
summary?: { grand_total: number };
|
||
items?: Array<{ index: number; result: BomCalculationResult }>;
|
||
};
|
||
const bomItems = apiData.items || []; // ❌ result.data가 배열이면 items가 없음!
|
||
```
|
||
|
||
### 2.2 문제 발생 흐름
|
||
|
||
```
|
||
사용자 → "자동 견적 산출" 클릭
|
||
↓
|
||
calculateBomBulk(bomItems) 호출
|
||
↓
|
||
API 서버: { success, summary, items: [...] } 반환
|
||
↓
|
||
actions.ts: result.data = 전체 응답 객체 (또는 배열로 잘못 파싱)
|
||
↓
|
||
QuoteRegistrationV2.tsx: result.data.items 접근 시도
|
||
↓
|
||
❌ items가 undefined → bomItems = []
|
||
↓
|
||
locations에 bomResult 저장 안됨
|
||
↓
|
||
LocationDetailPanel: bomResult?.items 없음 → Mock 데이터 표시
|
||
QuoteSummaryPanel: bomResult?.subtotals 없음 → Mock 데이터 표시
|
||
↓
|
||
💥 모든 UI 영역에 데이터 없음
|
||
```
|
||
|
||
### 2.3 영향 받는 컴포넌트
|
||
|
||
| 컴포넌트 | 파일 | 영향 |
|
||
|----------|------|------|
|
||
| QuoteRegistrationV2 | `QuoteRegistrationV2.tsx:457-481` | bomResult 저장 안됨 |
|
||
| LocationDetailPanel | `LocationDetailPanel.tsx:152-184` | Mock 데이터로 fallback |
|
||
| QuoteSummaryPanel | `QuoteSummaryPanel.tsx:136-164` | Mock 데이터로 fallback |
|
||
|
||
---
|
||
|
||
## 3. 대상 범위
|
||
|
||
### 3.1 Phase 1: API 응답 처리 수정
|
||
|
||
| # | 작업 항목 | 상태 | 비고 |
|
||
|---|----------|:----:|------|
|
||
| 1.1 | `actions.ts` 응답 구조 확인 | ✅ | API 서버 응답과 비교 |
|
||
| 1.2 | `actions.ts` BomBulkResponse 타입 추가 | ✅ | 정확한 API 응답 구조 정의 |
|
||
| 1.3 | `QuoteRegistrationV2.tsx` handleCalculate 수정 | ✅ | 응답 매핑 로직 및 디버그 로그 추가 |
|
||
|
||
### 3.2 Phase 2: 데이터 바인딩 수정
|
||
|
||
| # | 작업 항목 | 상태 | 비고 |
|
||
|---|----------|:----:|------|
|
||
| 2.1 | `FormulaEvaluatorService.php` items에 process_group 추가 | ✅ | addProcessGroupToItems 메서드 추가 |
|
||
| 2.2 | `LocationDetailPanel.tsx` bomItemsByTab 수정 | ✅ | process_group_key 기반 매핑 |
|
||
| 2.3 | `QuoteSummaryPanel.tsx` detailTotals 수정 | ✅ | grouped_items에서 items 가져오기 |
|
||
| 2.4 | `actions.ts` BomCalculationResult 타입 확장 | ✅ | process_group, grouped_items 필드 추가 |
|
||
|
||
---
|
||
|
||
## 4. 상세 작업 내용
|
||
|
||
### 4.1 Phase 1.2: handleCalculate 함수 수정
|
||
|
||
**현재 코드** (`QuoteRegistrationV2.tsx:457-479`):
|
||
```typescript
|
||
if (result.success && result.data) {
|
||
// ❌ 잘못된 타입 캐스팅 - result.data 자체가 API 응답 객체임
|
||
const apiData = result.data as {
|
||
summary?: { grand_total: number };
|
||
items?: Array<{ index: number; result: BomCalculationResult }>;
|
||
};
|
||
const bomItems = apiData.items || []; // ❌ undefined
|
||
// ...
|
||
}
|
||
```
|
||
|
||
**수정 방안**:
|
||
`actions.ts`의 응답 처리를 확인하여 두 가지 접근법 중 선택:
|
||
|
||
#### 방안 A: actions.ts 수정 (권장)
|
||
```typescript
|
||
// actions.ts에서 API 응답 구조 유지
|
||
return {
|
||
success: true,
|
||
data: {
|
||
summary: result.data.summary,
|
||
items: result.data.items,
|
||
},
|
||
};
|
||
```
|
||
|
||
#### 방안 B: QuoteRegistrationV2.tsx 수정
|
||
```typescript
|
||
if (result.success && result.data) {
|
||
// result.data가 { summary, items } 구조인지 확인
|
||
const apiData = result.data as unknown as {
|
||
summary?: { grand_total: number };
|
||
items?: Array<{ index: number; result: BomCalculationResult }>;
|
||
};
|
||
// ...
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 컨펌 대기 목록
|
||
|
||
| # | 항목 | 변경 내용 | 영향 범위 | 상태 |
|
||
|---|------|----------|----------|------|
|
||
| 1 | API 응답 구조 | actions.ts의 result.data 반환 방식 검토 | react/actions.ts | 대기 |
|
||
|
||
---
|
||
|
||
## 6. 변경 이력
|
||
|
||
| 날짜 | 항목 | 변경 내용 | 파일 | 승인 |
|
||
|------|------|----------|------|------|
|
||
| 2026-01-26 | 분석 | 문서 초안 작성 및 근본 원인 분석 완료 | - | - |
|
||
| 2026-01-26 | 수정 | actions.ts BomBulkResponse 타입 추가 | react/src/components/quotes/actions.ts | ✅ |
|
||
| 2026-01-26 | 수정 | QuoteRegistrationV2.tsx handleCalculate 수정 | react/src/components/quotes/QuoteRegistrationV2.tsx | ✅ |
|
||
| 2026-01-26 | 수정 | FormulaEvaluatorService.php process_group 추가 | api/app/Services/Quote/FormulaEvaluatorService.php | ✅ |
|
||
| 2026-01-26 | 수정 | LocationDetailPanel.tsx bomItemsByTab 수정 | react/src/components/quotes/LocationDetailPanel.tsx | ✅ |
|
||
| 2026-01-26 | 수정 | QuoteSummaryPanel.tsx detailTotals 수정 | react/src/components/quotes/QuoteSummaryPanel.tsx | ✅ |
|
||
| 2026-01-26 | 수정 | ItemService.php has_bom 필드 추가 | api/app/Services/ItemService.php | ✅ |
|
||
| 2026-01-26 | 수정 | actions.ts FinishedGoods에 has_bom, bom 필드 추가 | react/src/components/quotes/actions.ts | ✅ |
|
||
| 2026-01-26 | 수정 | QuoteRegistrationV2.tsx DevFill BOM 필터링 | react/src/components/quotes/QuoteRegistrationV2.tsx | ✅ |
|
||
| 2026-01-26 | 검증 | 브라우저 테스트 완료 - 4가지 문제 모두 해결 확인 | - | ✅ |
|
||
|
||
---
|
||
|
||
## 7. 참고 문서
|
||
|
||
- **빠른 시작**: `docs/quickstart/quick-start.md`
|
||
- **품질 체크리스트**: `docs/standards/quality-checklist.md`
|
||
- **API 규칙**: `docs/standards/api-rules.md`
|
||
|
||
---
|
||
|
||
## 8. 검증 결과
|
||
|
||
> 브라우저 자동화 테스트 완료 (2026-01-26)
|
||
|
||
### 8.1 테스트 케이스
|
||
|
||
| 입력값 | 예상 결과 | 실제 결과 | 상태 |
|
||
|--------|----------|----------|------|
|
||
| DevFill 후 자동 견적 산출 | 제품 리스트 표시 | 볼트 M10×40, 너트 M10, 볼트 M8×30 등 6개 품목 표시 | ✅ |
|
||
| 개소 선택 | 개소별 합계 표시 | 1F / SS-01 상세소계: 3,119,555.94원 | ✅ |
|
||
| 그룹별 합계 | 상세별 합계 표시 | 절곡 공정: 735,891.24원, 철재 공정: 2,383,364.7원 | ✅ |
|
||
| 전체 금액 | 예상 견적금액 > 0 | 예상 견적금액: 3,119,555.94원 | ✅ |
|
||
|
||
### 8.2 테스트 환경
|
||
|
||
- **URL**: `http://dev.sam.kr/sales/quote-management/test-new`
|
||
- **테스트 방법**: Claude-in-Chrome 브라우저 자동화
|
||
- **데이터**: DevFill로 생성된 테스트 데이터
|
||
|
||
### 8.3 추가 발견 및 해결 사항
|
||
|
||
테스트 중 DevFill이 BOM 없는 제품을 선택하여 계산 결과가 0으로 나오는 문제 발견:
|
||
|
||
| 문제 | 원인 | 해결 |
|
||
|------|------|------|
|
||
| DevFill 후 bomItemsCount: 0 | BOM 없는 제품 선택 | DevFill에서 BOM 있는 제품만 필터링 |
|
||
| has_bom 필드 없음 | API 응답에 미포함 | ItemService.php에서 계산 필드 추가 |
|
||
| getFinishedGoods에서 필드 누락 | 매핑 시 has_bom, bom 미포함 | FinishedGoods 인터페이스 및 매핑 수정 |
|
||
|
||
### 8.4 최종 검증 결과
|
||
|
||
```
|
||
[DevFill] BOM 있는 제품: 15개 / 전체: 2017개
|
||
[BOM 계산 결과]
|
||
- bomItemsCount: 6
|
||
- bomGrandTotal: 3,119,555.94
|
||
- 공정별 그룹: 절곡, 철재
|
||
```
|
||
|
||
**모든 4가지 UI 문제 해결 확인 완료** ✅
|
||
|
||
---
|
||
|
||
*이 문서는 /sc:plan 스킬로 생성되었습니다.* |