docs: 견적 관리 이슈 계획 및 시더 목록 문서 추가
- plans/quote-management-8issues-plan.md: 견적 관리 8개 이슈 수정 계획 - plans/SEEDERS_LIST.md: SAM API 시더 목록 및 실행 방법 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
128
plans/SEEDERS_LIST.md
Normal file
128
plans/SEEDERS_LIST.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# SAM API 시더 목록
|
||||
|
||||
> 생성일: 2025-01-05
|
||||
> 대상 테넌트: ID 287
|
||||
|
||||
## 개별 실행 방법
|
||||
|
||||
```bash
|
||||
# Docker 컨테이너 접속 후
|
||||
php artisan db:seed --class=시더클래스명
|
||||
|
||||
# Dummy 폴더 시더는 네임스페이스 포함
|
||||
php artisan db:seed --class=Dummy\\DummyClientSeeder
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. 메인 시더
|
||||
|
||||
| # | 시더 | 설명 | 실행 명령어 |
|
||||
|---|------|------|-------------|
|
||||
| 1 | `DatabaseSeeder` | 기본 시더 (테스트 유저 + 메뉴) | `php artisan db:seed` |
|
||||
| 2 | `DummyDataSeeder` | 전체 더미 데이터 (모든 Dummy 호출) | `php artisan db:seed --class=DummyDataSeeder` |
|
||||
|
||||
---
|
||||
|
||||
## 2. 기본 데이터 시더 (Dummy)
|
||||
|
||||
| # | 시더 | 테이블 | 수량 | 실행 명령어 |
|
||||
|---|------|--------|------|-------------|
|
||||
| 3 | `DummyUserSeeder` | users | 15 | `php artisan db:seed --class=Dummy\\DummyUserSeeder` |
|
||||
| 4 | `DummyDepartmentSeeder` | departments | 11 | `php artisan db:seed --class=Dummy\\DummyDepartmentSeeder` |
|
||||
| 5 | `DummyClientGroupSeeder` | client_groups | 5 | `php artisan db:seed --class=Dummy\\DummyClientGroupSeeder` |
|
||||
| 6 | `DummyBankAccountSeeder` | bank_accounts | 5 | `php artisan db:seed --class=Dummy\\DummyBankAccountSeeder` |
|
||||
| 7 | `DummyClientSeeder` | clients | 20 | `php artisan db:seed --class=Dummy\\DummyClientSeeder` |
|
||||
|
||||
---
|
||||
|
||||
## 3. 회계 데이터 시더 (Dummy)
|
||||
|
||||
| # | 시더 | 테이블 | 수량 | 실행 명령어 |
|
||||
|---|------|--------|------|-------------|
|
||||
| 8 | `DummyDepositSeeder` | deposits | 60 | `php artisan db:seed --class=Dummy\\DummyDepositSeeder` |
|
||||
| 9 | `DummyWithdrawalSeeder` | withdrawals | 60 | `php artisan db:seed --class=Dummy\\DummyWithdrawalSeeder` |
|
||||
| 10 | `DummySaleSeeder` | sales | 80 | `php artisan db:seed --class=Dummy\\DummySaleSeeder` |
|
||||
| 11 | `DummyPurchaseSeeder` | purchases | 70 | `php artisan db:seed --class=Dummy\\DummyPurchaseSeeder` |
|
||||
| 12 | `DummyBadDebtSeeder` | bad_debts | 18 | `php artisan db:seed --class=Dummy\\DummyBadDebtSeeder` |
|
||||
| 13 | `DummyBillSeeder` | bills | 30 | `php artisan db:seed --class=Dummy\\DummyBillSeeder` |
|
||||
|
||||
---
|
||||
|
||||
## 4. HR 데이터 시더 (Dummy)
|
||||
|
||||
| # | 시더 | 테이블 | 수량 | 실행 명령어 |
|
||||
|---|------|--------|------|-------------|
|
||||
| 14 | `DummyWorkSettingSeeder` | work_settings | 1 | `php artisan db:seed --class=Dummy\\DummyWorkSettingSeeder` |
|
||||
| 15 | `DummyAttendanceSettingSeeder` | attendance_settings | 1 | `php artisan db:seed --class=Dummy\\DummyAttendanceSettingSeeder` |
|
||||
| 16 | `DummyAttendanceSeeder` | attendances | ~300 | `php artisan db:seed --class=Dummy\\DummyAttendanceSeeder` |
|
||||
| 17 | `DummyLeaveGrantSeeder` | leave_grants | ~200 | `php artisan db:seed --class=Dummy\\DummyLeaveGrantSeeder` |
|
||||
| 18 | `DummyLeaveSeeder` | leaves | ~50 | `php artisan db:seed --class=Dummy\\DummyLeaveSeeder` |
|
||||
| 19 | `DummyCardSeeder` | cards | 5 | `php artisan db:seed --class=Dummy\\DummyCardSeeder` |
|
||||
| 20 | `DummySalarySeeder` | salaries | 15 | `php artisan db:seed --class=Dummy\\DummySalarySeeder` |
|
||||
|
||||
---
|
||||
|
||||
## 5. 기타 더미 시더 (Dummy)
|
||||
|
||||
| # | 시더 | 테이블 | 수량 | 실행 명령어 |
|
||||
|---|------|--------|------|-------------|
|
||||
| 21 | `DummyItemSeeder` | items | 10,000 | `php artisan db:seed --class=Dummy\\DummyItemSeeder` |
|
||||
| 22 | `DummyPopupSeeder` | popups | 8 | `php artisan db:seed --class=Dummy\\DummyPopupSeeder` |
|
||||
| 23 | `DummyPaymentSeeder` | payments | 13 | `php artisan db:seed --class=Dummy\\DummyPaymentSeeder` |
|
||||
| 24 | `ApprovalTestDataSeeder` | approvals | ~60 | `php artisan db:seed --class=ApprovalTestDataSeeder` |
|
||||
|
||||
---
|
||||
|
||||
## 6. 시스템/설정 시더
|
||||
|
||||
| # | 시더 | 설명 | 실행 명령어 |
|
||||
|---|------|------|-------------|
|
||||
| 25 | `GlobalMenuTemplateSeeder` | 글로벌 메뉴 템플릿 | `php artisan db:seed --class=GlobalMenuTemplateSeeder` |
|
||||
| 26 | `ReactMenuSeeder` | React 메뉴 | `php artisan db:seed --class=ReactMenuSeeder` |
|
||||
| 27 | `CategorySeeder` | 카테고리 | `php artisan db:seed --class=CategorySeeder` |
|
||||
| 28 | `ItemTypeSeeder` | 품목 유형 | `php artisan db:seed --class=ItemTypeSeeder` |
|
||||
| 29 | `ItemMasterSeeder` | 품목 마스터 | `php artisan db:seed --class=ItemMasterSeeder` |
|
||||
| 30 | `PositionSeeder` | 직급 | `php artisan db:seed --class=PositionSeeder` |
|
||||
| 31 | `FolderSeeder` | 폴더 | `php artisan db:seed --class=FolderSeeder` |
|
||||
| 32 | `CapabilityProfileSeeder` | 역량 프로필 | `php artisan db:seed --class=CapabilityProfileSeeder` |
|
||||
| 33 | `StockReceivingSeeder` | 입고 | `php artisan db:seed --class=StockReceivingSeeder` |
|
||||
| 34 | `ComprehensiveAnalysisSeeder` | 종합분석 | `php artisan db:seed --class=ComprehensiveAnalysisSeeder` |
|
||||
| 35 | `SystemFieldDefinitionSeeder` | 시스템 필드 정의 | `php artisan db:seed --class=SystemFieldDefinitionSeeder` |
|
||||
| 36 | `DemoSystemSeeder` | 데모 시스템 | `php artisan db:seed --class=DemoSystemSeeder` |
|
||||
| 37 | `BpMesCategoryFieldsSeeder` | MES 카테고리 필드 | `php artisan db:seed --class=BpMesCategoryFieldsSeeder` |
|
||||
| 38 | `BpMesTenantStatFieldsSeeder` | MES 테넌트 통계 필드 | `php artisan db:seed --class=BpMesTenantStatFieldsSeeder` |
|
||||
|
||||
---
|
||||
|
||||
## 7. 견적 관련 시더
|
||||
|
||||
| # | 시더 | 설명 | 실행 명령어 |
|
||||
|---|------|------|-------------|
|
||||
| 39 | `QuoteFormulaSeeder` | 견적 계산식 | `php artisan db:seed --class=QuoteFormulaSeeder` |
|
||||
| 40 | `QuoteFormulaCategorySeeder` | 견적 계산 카테고리 | `php artisan db:seed --class=QuoteFormulaCategorySeeder` |
|
||||
| 41 | `QuoteFormulaItemSeeder` | 견적 계산 품목 | `php artisan db:seed --class=QuoteFormulaItemSeeder` |
|
||||
| 42 | `QuoteFormulaMappingSeeder` | 견적 계산 매핑 | `php artisan db:seed --class=QuoteFormulaMappingSeeder` |
|
||||
|
||||
---
|
||||
|
||||
## 요약
|
||||
|
||||
| 카테고리 | 개수 |
|
||||
|----------|------|
|
||||
| 메인 시더 | 2 |
|
||||
| 기본 데이터 (Dummy) | 5 |
|
||||
| 회계 데이터 (Dummy) | 6 |
|
||||
| HR 데이터 (Dummy) | 7 |
|
||||
| 기타 더미 (Dummy) | 4 |
|
||||
| 시스템/설정 | 14 |
|
||||
| 견적 관련 | 4 |
|
||||
| **총계** | **42** |
|
||||
|
||||
---
|
||||
|
||||
## 주의사항
|
||||
|
||||
1. **Dummy 시더**는 `TENANT_ID = 287` 하드코딩
|
||||
2. **의존성 순서**: 기본 데이터 → 회계 → HR → 기타 순서로 실행 권장
|
||||
3. **중복 주의**: 이미 데이터가 있는 경우 중복 생성됨 (특히 `DummyItemSeeder` 10,000개)
|
||||
529
plans/quote-management-8issues-plan.md
Normal file
529
plans/quote-management-8issues-plan.md
Normal file
@@ -0,0 +1,529 @@
|
||||
# 견적 관리 8개 이슈 수정 계획
|
||||
|
||||
> **작성일**: 2026-01-06
|
||||
> **목적**: 견적 관리 화면 8개 이슈 수정 (리스트/상세/수정 화면)
|
||||
> **기준 문서**: react/src/components/quotes/ 컴포넌트
|
||||
> **상태**: 🔄 진행중
|
||||
|
||||
---
|
||||
|
||||
## 📍 현재 진행 상태
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **마지막 완료 작업** | 이슈 #1 분석 완료 (백엔드 API 정상 확인) |
|
||||
| **다음 작업** | 이슈 #1 분석 결과 사용자 컨펌 대기 |
|
||||
| **진행률** | 0/8 (0%) - 이슈 #1 분석 완료, 컨펌 대기 |
|
||||
| **마지막 업데이트** | 2026-01-06 |
|
||||
|
||||
---
|
||||
|
||||
## 1. 개요
|
||||
|
||||
### 1.1 배경
|
||||
견적 관리 시스템에서 담당자, 연락처, 비고, 단위 등의 필드가 제대로 표시되지 않거나 잘못된 값이 표시되는 8개 이슈 발견
|
||||
|
||||
### 1.2 핵심 원칙
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 🎯 핵심 원칙 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ - 한 이슈씩 순차적으로 수정 (사용자 컨펌 후 다음 진행) │
|
||||
│ - 프론트엔드 필드 매핑 일관성 유지 │
|
||||
│ - 백엔드 API 응답 데이터 확인 후 프론트엔드 수정 │
|
||||
│ - 커밋은 모든 작업 완료 후 일괄 진행 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.3 🔴 작업 진행 절차 (필수)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 📋 각 이슈별 작업 흐름 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ 1. 분석 → 분석 결과 보고 │
|
||||
│ 2. 사용자 컨펌 대기 (테스트 가능한 정보 제공) │
|
||||
│ 3. 컨펌 후 → 수정 작업 진행 │
|
||||
│ 4. 수정 완료 → 결과 보고 (테스트 방법 포함) │
|
||||
│ 5. 사용자 테스트 & 컨펌 │
|
||||
│ 6. 컨펌 완료 → 다음 이슈 진행 │
|
||||
│ │
|
||||
│ ⚠️ 사용자 승인 없이 다음 단계 진행 금지! │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**각 이슈 완료 보고 형식:**
|
||||
```markdown
|
||||
## 이슈 #N 완료 보고
|
||||
|
||||
**작업 내용:**
|
||||
- 수정한 파일과 라인
|
||||
- 변경 전/후 코드
|
||||
|
||||
**테스트 방법:**
|
||||
- 테스트 URL
|
||||
- 확인 포인트
|
||||
|
||||
**기대 결과:**
|
||||
- 변경 전: [문제 상황]
|
||||
- 변경 후: [예상 결과]
|
||||
|
||||
**다음 작업 진행할까요?**
|
||||
```
|
||||
|
||||
### 1.4 핵심 발견: 필드명 불일치 문제
|
||||
|
||||
**Quote 인터페이스 (types.ts:85-115):**
|
||||
```typescript
|
||||
export interface Quote {
|
||||
managerName?: string; // ← 담당자
|
||||
managerContact?: string; // ← 연락처
|
||||
description?: string; // ← 비고
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**문제점:**
|
||||
- `QuoteDocument.tsx`, `QuoteCalculationReport.tsx`에서 `quote.manager`, `quote.contact` 사용
|
||||
- Quote 인터페이스에는 `managerName`, `managerContact`로 정의됨
|
||||
- **필드명 불일치로 인해 항상 undefined → '-' 표시**
|
||||
|
||||
---
|
||||
|
||||
## 2. 대상 범위
|
||||
|
||||
### 2.1 이슈 목록
|
||||
|
||||
| # | 이슈 | 화면 | 상태 | 근본 원인 |
|
||||
|---|------|------|:----:|----------|
|
||||
| 1 | 담당자, 비고 컬럼 미표시 | 리스트 | ⏳ | API 응답 확인 필요 |
|
||||
| 2 | 담당자, 연락처 미표시 + 단위 "set" | 상세 (/8) | ⏳ | 필드명 불일치 |
|
||||
| 3 | 담당자, 연락처 미표시 + 총 수량 계산 | 상세 견적서 (/9) | ⏳ | 필드명 불일치 + 하드코딩 |
|
||||
| 4 | 단위가 모두 "개소"로 표시 | 품목내역 | ⏳ | item.unit 누락 |
|
||||
| 5 | 담당자/연락처/단위/수량 이슈 | 산출 내역서 | ⏳ | 필드명 불일치 + 하드코딩 |
|
||||
| 6 | 세부산출 vs 소요자재 동일 | 산출 내역서 | ⏳ | leaf 노드 분리 미적용 |
|
||||
| 7 | 작성자/담당자/연락처/비고 미표시 | 수정 (/edit) | ⏳ | 데이터 로딩 확인 |
|
||||
| 8 | 1개 → 14개 견적 표시 | 자동 견적 산출 | ⏳ | state 초기화 누락 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 상세 분석 및 수정 코드
|
||||
|
||||
### 3.1 이슈 #1: 리스트 화면 담당자/비고 미표시
|
||||
|
||||
**파일**: `react/src/components/quotes/QuoteManagementClient.tsx`
|
||||
|
||||
**현재 코드 (Line 421, 424):**
|
||||
```typescript
|
||||
<TableCell>{quote.managerName || '-'}</TableCell>
|
||||
// ...
|
||||
<TableCell>
|
||||
<div className="max-w-[200px] line-clamp-2 text-sm">
|
||||
{quote.description || '-'}
|
||||
</div>
|
||||
</TableCell>
|
||||
```
|
||||
|
||||
**분석:**
|
||||
- 코드 자체는 정확함 (`managerName`, `description` 사용)
|
||||
- API 응답에서 `manager` → `managerName` 변환 확인 필요
|
||||
|
||||
**변환 함수 (types.ts:254-256, 266):**
|
||||
```typescript
|
||||
// transformApiToFrontend 함수
|
||||
managerName: apiData.manager || apiData.manager_name || undefined,
|
||||
managerContact: apiData.contact || apiData.manager_contact || undefined,
|
||||
// ...
|
||||
description: apiData.remarks || apiData.description || undefined,
|
||||
```
|
||||
|
||||
**확인 필요:**
|
||||
- API 응답에 `manager`, `contact`, `remarks` 필드가 포함되는지 확인
|
||||
- 백엔드 QuoteResource에서 해당 필드 반환 여부 확인
|
||||
|
||||
---
|
||||
|
||||
### 3.2 이슈 #2: 상세 화면 담당자/연락처 미표시 + 단위 "set"
|
||||
|
||||
**파일**: `react/src/components/quotes/QuoteDocument.tsx`
|
||||
|
||||
**현재 코드 (Line 271-278):**
|
||||
```typescript
|
||||
<th>담당자</th>
|
||||
<td>{quote.manager || '-'}</td> // ❌ 잘못된 필드명
|
||||
// ...
|
||||
<th>연락처</th>
|
||||
<td>{quote.contact || '-'}</td> // ❌ 잘못된 필드명
|
||||
```
|
||||
|
||||
**수정 코드:**
|
||||
```typescript
|
||||
<th>담당자</th>
|
||||
<td>{quote.managerName || '-'}</td> // ✅ 올바른 필드명
|
||||
// ...
|
||||
<th>연락처</th>
|
||||
<td>{quote.managerContact || '-'}</td> // ✅ 올바른 필드명
|
||||
```
|
||||
|
||||
**단위 문제 (Line 34-42):**
|
||||
```typescript
|
||||
// 현재 코드 - 이미 올바름
|
||||
const quoteItems = quote.items?.map((item, index) => ({
|
||||
// ...
|
||||
unit: item.unit || '', // ✅ 각 품목의 단위 사용
|
||||
})) || [];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 이슈 #3: 상세 견적서 총 수량 계산
|
||||
|
||||
**파일**: `react/src/components/quotes/QuoteDocument.tsx`
|
||||
|
||||
**현재 코드 (Line 345):**
|
||||
```typescript
|
||||
<th>총 수량</th>
|
||||
<td>{quote.items.reduce((sum, item) => sum + (item.quantity || 0), 0)}개소</td>
|
||||
// ❌ "개소" 하드코딩
|
||||
```
|
||||
|
||||
**수정 코드:**
|
||||
```typescript
|
||||
<th>총 수량</th>
|
||||
<td>{quote.items.reduce((sum, item) => sum + (item.quantity || 0), 0)} {quote.items[0]?.unit || 'EA'}</td>
|
||||
// ✅ 첫 번째 품목의 단위 사용 또는 기본값 EA
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.4 이슈 #4: 품목내역 단위 "개소" 고정
|
||||
|
||||
**파일**: `react/src/components/quotes/QuoteDocument.tsx`
|
||||
|
||||
**현재 코드 (Line 383):**
|
||||
```typescript
|
||||
<td style={{ textAlign: 'center' }}>{item.unit}</td>
|
||||
```
|
||||
|
||||
**분석:**
|
||||
- 코드는 `item.unit`을 사용하고 있어 올바름
|
||||
- 문제는 `item.unit` 값이 API에서 오지 않거나 비어 있음
|
||||
- **확인 필요**: API 응답의 `unit` 필드 확인
|
||||
|
||||
---
|
||||
|
||||
### 3.5 이슈 #5: 산출 내역서 담당자/연락처/단위/수량
|
||||
|
||||
**파일**: `react/src/components/quotes/QuoteCalculationReport.tsx`
|
||||
|
||||
**현재 코드 (Line 307-314):**
|
||||
```typescript
|
||||
<th>담당자</th>
|
||||
<td>{quote.manager || '-'}</td> // ❌ 잘못된 필드명
|
||||
// ...
|
||||
<th>연락처</th>
|
||||
<td>{quote.contact || '-'}</td> // ❌ 잘못된 필드명
|
||||
```
|
||||
|
||||
**수정 코드:**
|
||||
```typescript
|
||||
<th>담당자</th>
|
||||
<td>{quote.managerName || '-'}</td> // ✅ 올바른 필드명
|
||||
// ...
|
||||
<th>연락처</th>
|
||||
<td>{quote.managerContact || '-'}</td> // ✅ 올바른 필드명
|
||||
```
|
||||
|
||||
**단위 하드코딩 (Line 394):**
|
||||
```typescript
|
||||
// 현재 코드
|
||||
<td style={{ textAlign: 'center' }}>SET</td> // ❌ 하드코딩
|
||||
|
||||
// 수정 코드
|
||||
<td style={{ textAlign: 'center' }}>{item.unit || 'SET'}</td> // ✅ 동적 + 기본값
|
||||
```
|
||||
|
||||
**수량 기준 문제:**
|
||||
- 현재: 1개 기준 수량 표시
|
||||
- 필요: 세트 수량(예: 10개) 기준 표시
|
||||
- **확인 필요**: 비즈니스 로직 명확화
|
||||
|
||||
---
|
||||
|
||||
### 3.6 이슈 #6: 세부산출내역 vs 소요자재내역 분리
|
||||
|
||||
**파일**: `react/src/components/quotes/QuoteCalculationReport.tsx`
|
||||
|
||||
**현재 상태 (Line 45-55):**
|
||||
```typescript
|
||||
// 소요자재 내역 - 실제 BOM 자재 데이터 사용
|
||||
const materialItems = quote.bomMaterials?.map((material, index) => ({
|
||||
// ...
|
||||
})) || [];
|
||||
```
|
||||
|
||||
**문제:**
|
||||
- 세부산출내역과 소요자재내역이 동일한 `bomMaterials` 사용
|
||||
- 소요자재는 leaf 노드만 표시해야 함
|
||||
|
||||
**수정 방향:**
|
||||
```typescript
|
||||
// 세부산출내역: 전체 BOM 항목
|
||||
const detailItems = quote.bomMaterials || [];
|
||||
|
||||
// 소요자재내역: leaf 노드만 (has_children = false 또는 별도 필드)
|
||||
const materialItems = quote.bomMaterials?.filter(m => !m.hasChildren) || [];
|
||||
// 또는 백엔드에서 별도 필드로 제공 (leafMaterials)
|
||||
```
|
||||
|
||||
**참고**: 이전 세션에서 백엔드 `getBomLeafMaterials()` 함수 추가됨
|
||||
|
||||
---
|
||||
|
||||
### 3.7 이슈 #7: 수정 화면 필드 미표시
|
||||
|
||||
**파일**: `react/src/components/quotes/QuoteRegistration.tsx`
|
||||
|
||||
**폼 필드 코드 (Line 593-683):**
|
||||
```typescript
|
||||
// 작성자 (Line 593-600)
|
||||
<FormField label="작성자" htmlFor="writer">
|
||||
<Input id="writer" value={formData.writer} disabled className="bg-gray-50" />
|
||||
</FormField>
|
||||
|
||||
// 담당자 (Line 644-651)
|
||||
<FormField label="발주 담당자" htmlFor="manager">
|
||||
<Input id="manager" value={formData.manager} onChange={...} />
|
||||
</FormField>
|
||||
|
||||
// 연락처 (Line 653-659)
|
||||
<FormField label="연락처" htmlFor="contact">
|
||||
<Input id="contact" value={formData.contact} onChange={...} />
|
||||
</FormField>
|
||||
|
||||
// 비고 (Line 675-683)
|
||||
<FormField label="비고" htmlFor="remarks">
|
||||
<Textarea id="remarks" value={formData.remarks} onChange={...} />
|
||||
</FormField>
|
||||
```
|
||||
|
||||
**데이터 로딩 (types.ts:536-541):**
|
||||
```typescript
|
||||
// transformApiDataToFormData 함수
|
||||
manager: apiData.manager || apiData.manager_name || '',
|
||||
contact: apiData.contact || apiData.manager_contact || '',
|
||||
// ...
|
||||
remarks: apiData.remarks || apiData.description || '',
|
||||
```
|
||||
|
||||
**분석:**
|
||||
- 폼 필드 코드는 정상
|
||||
- 변환 함수도 정상
|
||||
- **확인 필요**:
|
||||
1. API 응답에 `manager`, `contact`, `remarks` 필드 포함 여부
|
||||
2. `editingQuote` prop이 올바르게 전달되는지
|
||||
|
||||
---
|
||||
|
||||
### 3.8 이슈 #8: 자동 견적 산출 14개 표시
|
||||
|
||||
**파일**: `react/src/components/quotes/QuoteRegistration.tsx`
|
||||
|
||||
**현재 상태:**
|
||||
```typescript
|
||||
// calculationResults state (추정)
|
||||
const [calculationResults, setCalculationResults] = useState<...>(null);
|
||||
```
|
||||
|
||||
**문제:**
|
||||
- 새 계산 시 이전 결과가 초기화되지 않음
|
||||
- 또는 API 응답에 중복 데이터 포함
|
||||
|
||||
**수정 방향:**
|
||||
```typescript
|
||||
// handleAutoCalculate 함수 시작 부분에 추가
|
||||
const handleAutoCalculate = async () => {
|
||||
// 이전 결과 초기화
|
||||
setCalculationResults(null);
|
||||
|
||||
// ... 기존 로직
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 작업 순서 및 체크리스트
|
||||
|
||||
| 순서 | 이슈 | 작업 | 파일 | 라인 | 난이도 |
|
||||
|:----:|:----:|------|------|:----:|:------:|
|
||||
| 1 | #1 | API 응답 확인 + 필요시 수정 | 백엔드 확인 | - | 🟡 |
|
||||
| 2 | #2 | `manager` → `managerName` | QuoteDocument.tsx | 272, 278 | 🟢 |
|
||||
| 3 | #3 | 총 수량 단위 동적화 | QuoteDocument.tsx | 345 | 🟢 |
|
||||
| 4 | #4 | item.unit 확인 | API 확인 | - | 🟡 |
|
||||
| 5 | #5 | 필드명 + 단위 수정 | QuoteCalculationReport.tsx | 308, 314, 394 | 🟢 |
|
||||
| 6 | #6 | leaf 노드 분리 | QuoteCalculationReport.tsx | 45-55 | 🟡 |
|
||||
| 7 | #7 | 데이터 로딩 확인 | API 확인 | - | 🟡 |
|
||||
| 8 | #8 | state 초기화 추가 | QuoteRegistration.tsx | handleAutoCalculate | 🟢 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 진행 기록
|
||||
|
||||
### 5.1 분석 단계 (완료)
|
||||
|
||||
**2026-01-06:**
|
||||
- ✅ QuoteManagementClient.tsx 분석 (Line 410-440)
|
||||
- ✅ QuoteDocument.tsx 분석 (Line 21-42, 265-285, 335-405)
|
||||
- ✅ QuoteCalculationReport.tsx 분석 (Line 25-55, 300-320, 385-470)
|
||||
- ✅ QuoteRegistration.tsx 분석 (Line 593-683)
|
||||
- ✅ types.ts 분석 (인터페이스, 변환 함수)
|
||||
- ✅ 계획 문서 작성
|
||||
|
||||
### 5.2 이슈별 진행 상태
|
||||
|
||||
| 이슈 | 상태 | 시작 | 완료 | 컨펌 |
|
||||
|:----:|:----:|:----:|:----:|:----:|
|
||||
| #1 | 🔍 분석완료 | 2026-01-06 | - | ⏳ 대기 |
|
||||
| #2 | ⏳ 대기 | - | - | - |
|
||||
| #3 | ⏳ 대기 | - | - | - |
|
||||
| #4 | ⏳ 대기 | - | - | - |
|
||||
| #5 | ⏳ 대기 | - | - | - |
|
||||
| #6 | ⏳ 대기 | - | - | - |
|
||||
| #7 | ⏳ 대기 | - | - | - |
|
||||
| #8 | ⏳ 대기 | - | - | - |
|
||||
|
||||
### 5.3 이슈 #1 분석 결과 (2026-01-06)
|
||||
|
||||
**분석 내용:**
|
||||
- 백엔드 API 응답 확인
|
||||
- 프론트엔드 코드 검토
|
||||
|
||||
**백엔드 확인 결과:** ✅ 정상
|
||||
| 파일 | 라인 | 필드 | 상태 |
|
||||
|------|------|------|:----:|
|
||||
| `api/app/Swagger/v1/QuoteApi.php` | 21-22, 48 | manager, contact, remarks | ✅ |
|
||||
| `api/app/Models/Quote/Quote.php` | 30-31, 63 | fillable 정의 | ✅ |
|
||||
| `api/app/Services/Quote/QuoteService.php` | 212-213, 243 | 저장/반환 | ✅ |
|
||||
|
||||
**프론트엔드 확인 결과:**
|
||||
| 파일 | 현재 코드 | 문제점 |
|
||||
|------|----------|--------|
|
||||
| `QuoteManagementClient.tsx:421,424` | `quote.managerName`, `quote.description` | ✅ 올바름 |
|
||||
| `types.ts:254-266` | `transformApiToFrontend` | ✅ 올바름 |
|
||||
|
||||
**결론:**
|
||||
- 이슈 #1 (리스트 화면)은 코드가 이미 올바름
|
||||
- 담당자/비고 미표시 원인: **데이터 자체가 없거나 API 호출 확인 필요**
|
||||
|
||||
**테스트 방법:**
|
||||
1. 견적 리스트 화면: `http://sam.kr/quotes`
|
||||
2. 브라우저 개발자 도구 → Network 탭
|
||||
3. `/api/v1/quotes` 응답에서 `manager`, `contact`, `remarks` 필드 확인
|
||||
|
||||
**다음 단계 옵션:**
|
||||
- A: 데이터가 있는 견적으로 테스트 확인
|
||||
- B: 이슈 #2로 진행 (프론트엔드 필드명 수정 필요 확인됨)
|
||||
|
||||
---
|
||||
|
||||
## 6. 참고 정보
|
||||
|
||||
### 6.1 타입 정의 요약
|
||||
|
||||
**Quote 인터페이스 (types.ts:85-115):**
|
||||
```typescript
|
||||
interface Quote {
|
||||
id: string;
|
||||
quoteNumber: string;
|
||||
managerName?: string; // 담당자
|
||||
managerContact?: string; // 연락처
|
||||
description?: string; // 비고
|
||||
items: QuoteItem[];
|
||||
bomMaterials?: BomMaterial[];
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**QuoteItem 인터페이스 (types.ts:68-82):**
|
||||
```typescript
|
||||
interface QuoteItem {
|
||||
id: string;
|
||||
productName: string;
|
||||
unit?: string; // 단위
|
||||
quantity: number;
|
||||
unitPrice: number;
|
||||
totalAmount: number;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**QuoteFormData (수정 화면용):**
|
||||
```typescript
|
||||
interface QuoteFormData {
|
||||
manager: string; // 담당자 (폼용)
|
||||
contact: string; // 연락처 (폼용)
|
||||
remarks: string; // 비고 (폼용)
|
||||
writer: string; // 작성자
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 변환 함수 매핑
|
||||
|
||||
| API 필드 | Quote (리스트/상세) | QuoteFormData (수정) |
|
||||
|----------|---------------------|----------------------|
|
||||
| `manager` | `managerName` | `manager` |
|
||||
| `contact` | `managerContact` | `contact` |
|
||||
| `remarks` | `description` | `remarks` |
|
||||
| `manager_name` (레거시) | `managerName` (폴백) | `manager` (폴백) |
|
||||
| `manager_contact` (레거시) | `managerContact` (폴백) | `contact` (폴백) |
|
||||
|
||||
### 6.3 이전 세션 백엔드 작업
|
||||
|
||||
- ✅ `QuoteStoreRequest.php`: `prepareForValidation()` 추가
|
||||
- ✅ `QuoteUpdateRequest.php`: `prepareForValidation()` 추가
|
||||
- ✅ `FormulaEvaluatorService.php`: `getBomLeafMaterials()` 추가
|
||||
- ✅ `QuoteService.php`: `calculateBomMaterials()` 수정
|
||||
|
||||
---
|
||||
|
||||
## 7. 컨펌 대기 목록
|
||||
|
||||
| # | 항목 | 변경 내용 | 영향 범위 | 상태 |
|
||||
|---|------|----------|----------|------|
|
||||
| - | - | - | - | - |
|
||||
|
||||
---
|
||||
|
||||
## 8. 변경 이력
|
||||
|
||||
| 날짜 | 항목 | 변경 내용 | 파일 |
|
||||
|------|------|----------|------|
|
||||
| 2026-01-06 | 계획 | 문서 초안 작성 | - |
|
||||
| 2026-01-06 | 분석 | 상세 코드 스니펫 추가 | 5개 파일 분석 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 새 세션 시작 가이드
|
||||
|
||||
### 9.1 컨텍스트 복구 순서
|
||||
|
||||
```bash
|
||||
1. 이 문서 읽기: docs/plans/quote-management-8issues-plan.md
|
||||
2. Serena 메모리 로드: read_memory("quote-8issues-state")
|
||||
3. 진행 상태 확인: 섹션 5.2 "이슈별 진행 상태"
|
||||
4. 마지막 작업 지점에서 재개
|
||||
```
|
||||
|
||||
### 9.2 작업 재개 체크리스트
|
||||
|
||||
- [ ] 이 계획 문서 전체 읽기
|
||||
- [ ] Serena 메모리에서 상태 로드
|
||||
- [ ] 마지막 완료 이슈 확인
|
||||
- [ ] 다음 이슈 수정 시작
|
||||
- [ ] 수정 후 사용자 컨펌 받기
|
||||
- [ ] 진행 상태 업데이트
|
||||
|
||||
---
|
||||
|
||||
*이 문서는 /plan 스킬로 생성되었습니다.*
|
||||
Reference in New Issue
Block a user