Files
sam-docs/plans/quote-management-8issues-plan.md
kent 3bfe30ee1c 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>
2026-01-06 21:00:56 +09:00

17 KiB

견적 관리 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. 컨펌 완료 → 다음 이슈 진행                                   │
│                                                                  │
│  ⚠️ 사용자 승인 없이 다음 단계 진행 금지!                        │
└─────────────────────────────────────────────────────────────────┘

각 이슈 완료 보고 형식:

## 이슈 #N 완료 보고

**작업 내용:**
- 수정한 파일과 라인
- 변경 전/후 코드

**테스트 방법:**
- 테스트 URL
- 확인 포인트

**기대 결과:**
- 변경 전: [문제 상황]
- 변경 후: [예상 결과]

**다음 작업 진행할까요?**

1.4 핵심 발견: 필드명 불일치 문제

Quote 인터페이스 (types.ts:85-115):

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):

<TableCell>{quote.managerName || '-'}</TableCell>
// ...
<TableCell>
  <div className="max-w-[200px] line-clamp-2 text-sm">
    {quote.description || '-'}
  </div>
</TableCell>

분석:

  • 코드 자체는 정확함 (managerName, description 사용)
  • API 응답에서 managermanagerName 변환 확인 필요

변환 함수 (types.ts:254-256, 266):

// 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):

<th>담당자</th>
<td>{quote.manager || '-'}</td>     // ❌ 잘못된 필드명
// ...
<th>연락처</th>
<td>{quote.contact || '-'}</td>     // ❌ 잘못된 필드명

수정 코드:

<th>담당자</th>
<td>{quote.managerName || '-'}</td>  // ✅ 올바른 필드명
// ...
<th>연락처</th>
<td>{quote.managerContact || '-'}</td> // ✅ 올바른 필드명

단위 문제 (Line 34-42):

// 현재 코드 - 이미 올바름
const quoteItems = quote.items?.map((item, index) => ({
  // ...
  unit: item.unit || '',  // ✅ 각 품목의 단위 사용
})) || [];

3.3 이슈 #3: 상세 견적서 총 수량 계산

파일: react/src/components/quotes/QuoteDocument.tsx

현재 코드 (Line 345):

<th> 수량</th>
<td>{quote.items.reduce((sum, item) => sum + (item.quantity || 0), 0)}개소</td>
// ❌ "개소" 하드코딩

수정 코드:

<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):

<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):

<th>담당자</th>
<td>{quote.manager || '-'}</td>     // ❌ 잘못된 필드명
// ...
<th>연락처</th>
<td>{quote.contact || '-'}</td>     // ❌ 잘못된 필드명

수정 코드:

<th>담당자</th>
<td>{quote.managerName || '-'}</td>  // ✅ 올바른 필드명
// ...
<th>연락처</th>
<td>{quote.managerContact || '-'}</td> // ✅ 올바른 필드명

단위 하드코딩 (Line 394):

// 현재 코드
<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):

// 소요자재 내역 - 실제 BOM 자재 데이터 사용
const materialItems = quote.bomMaterials?.map((material, index) => ({
  // ...
})) || [];

문제:

  • 세부산출내역과 소요자재내역이 동일한 bomMaterials 사용
  • 소요자재는 leaf 노드만 표시해야 함

수정 방향:

// 세부산출내역: 전체 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):

// 작성자 (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):

// 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

현재 상태:

// calculationResults state (추정)
const [calculationResults, setCalculationResults] = useState<...>(null);

문제:

  • 새 계산 시 이전 결과가 초기화되지 않음
  • 또는 API 응답에 중복 데이터 포함

수정 방향:

// handleAutoCalculate 함수 시작 부분에 추가
const handleAutoCalculate = async () => {
  // 이전 결과 초기화
  setCalculationResults(null);

  // ... 기존 로직
};

4. 작업 순서 및 체크리스트

순서 이슈 작업 파일 라인 난이도
1 #1 API 응답 확인 + 필요시 수정 백엔드 확인 - 🟡
2 #2 managermanagerName 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):

interface Quote {
  id: string;
  quoteNumber: string;
  managerName?: string;      // 담당자
  managerContact?: string;   // 연락처
  description?: string;      // 비고
  items: QuoteItem[];
  bomMaterials?: BomMaterial[];
  // ...
}

QuoteItem 인터페이스 (types.ts:68-82):

interface QuoteItem {
  id: string;
  productName: string;
  unit?: string;            // 단위
  quantity: number;
  unitPrice: number;
  totalAmount: number;
  // ...
}

QuoteFormData (수정 화면용):

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 컨텍스트 복구 순서

1. 이 문서 읽기: docs/plans/quote-management-8issues-plan.md
2. Serena 메모리 로드: read_memory("quote-8issues-state")
3. 진행 상태 확인: 섹션 5.2 "이슈별 진행 상태"
4. 마지막 작업 지점에서 재개

9.2 작업 재개 체크리스트

  • 이 계획 문서 전체 읽기
  • Serena 메모리에서 상태 로드
  • 마지막 완료 이슈 확인
  • 다음 이슈 수정 시작
  • 수정 후 사용자 컨펌 받기
  • 진행 상태 업데이트

이 문서는 /plan 스킬로 생성되었습니다.