# 견적/수주 UI 분석

> 분석 일시: 2024-12-18
> 소스:
> - design/mes기획서_리액트/src/components/QuoteDetailNew.jsx
> - design/mes기획서_리액트/src/components/QuoteDocumentDialogs.jsx

## QuoteDetailNew.jsx - 견적 상세

### Props
| Prop | 타입 | 설명 |
|------|------|------|
| quote | Object | 견적 데이터 |
| orders | Array | 수주 목록 (관련 수주 찾기용) |
| onNavigate | Function | 화면 이동 |
| onBack | Function | 목록으로 돌아가기 |
| onConvertToOrder | Function | 수주 전환 콜백 |
| onUpdateQuote | Function | 견적 업데이트 콜백 |
| onCreateOrder | Function | 수주 생성 콜백 |

### 견적 상태 (StatusBadge)
| 상태 | 스타일 | 설명 |
|------|--------|------|
| 최초작성 | gray | 초기 상태 |
| 최종확정 | blue | 견적 확정 |
| 수주전환 | green | 수주로 전환됨 |
| 수정중 | yellow | 수정 진행 중 |

### 화면 구성

```
┌─────────────────────────────────────────────────────────────┐
│ [헤더]                                                       │
│ 좌: 견적 상세 + [견적서] [산출내역서] [발주서] 버튼         │
│ 우: [목록] [수정] [최종확정] [수주전환] 버튼                 │
├─────────────────────────────────────────────────────────────┤
│ [기본 정보] Card                                             │
│ - 견적번호, 작성자, 발주처, 담당자, 연락처                  │
│ - 현장명, 현장코드, 상태, 접수일, 납기일, 비고              │
├─────────────────────────────────────────────────────────────┤
│ [자동 견적 산출 정보] Card                                   │
│ - 품목, 수량, 단가, 공급가액, 부가세, 총 견적금액           │
├─────────────────────────────────────────────────────────────┤
│ [특이사항] Card                                              │
│ - 특이사항 텍스트                                            │
└─────────────────────────────────────────────────────────────┘
```

### 수주전환 모달 (convertForm)

| 필드 | 타입 | 필수 | 설명 |
|------|------|------|------|
| shipDate | date | - | 출하예정일 |
| shipDateUndecided | boolean | - | 출하일 미정 여부 |
| dueDate | date | - | 납기일 |
| dueDateUndecided | boolean | - | 납기일 미정 여부 |
| deliveryMethod | select | - | 배송방법 (상차/택배/직접배송) |
| freightCost | select | - | 운임비 (선불/착불/무료) |
| receiverName | text | - | 수령자명 |
| receiverPhone | text | - | 수령자연락처 |
| deliveryAddress | text | - | 납품주소 |
| deliveryAddressDetail | text | - | 상세주소 |
| note | textarea | - | 비고 |

### 수주전환 비즈니스 로직

```javascript
// 수주번호 생성 규칙
const dateCode = new Date().toISOString().slice(2,10).replace(/-/g, '');
const newOrderNo = `KD-SO-${dateCode}-${순번2자리}`;
// 예: KD-SO-241218-01

// 생성되는 수주 데이터
const newOrder = {
  id: Date.now(),
  orderNo: newOrderNo,           // 자동생성 수주번호
  quoteNo: quote.quoteNo,        // 원본 견적번호
  quoteId: quote.id,             // 원본 견적 ID
  orderDate: '오늘 날짜',
  customerName: quote.customerName,
  siteName: quote.siteName,
  siteAddress: quote.deliveryAddress,
  manager: quote.manager,
  contact: quote.contact,
  productName: quote.productName,
  qty: quote.qty,
  totalAmount: quote.finalAmount || quote.totalAmount,
  status: '수주확정',            // 초기 상태
  dueDate: convertForm.dueDate,
  shipDate: convertForm.shipDate,
  deliveryMethod: convertForm.deliveryMethod,
  freightCost: convertForm.freightCost,
  receiverName: convertForm.receiverName,
  receiverPhone: convertForm.receiverPhone,
  deliveryAddress: convertForm.deliveryAddress,
  deliveryAddressDetail: convertForm.deliveryAddressDetail,
  note: convertForm.note,
  creditGrade: quote.creditGrade,
  items: quote.items || [],
  history: [{
    id: Date.now(),
    changedAt: '현재시간',
    changeType: '수주등록',
    description: `견적(${quote.quoteNo})에서 수주전환`,
    changedBy: '현재 사용자',
  }],
};
```

---

## QuoteDocumentDialogs.jsx - 문서 출력

### 1. QuoteSheetDialog (견적서)

**구성:**
- 수신자 정보: 상호, 담당자, 연락처, 현장명
- 발신자 정보: 상호, 대표자, 사업자번호, 연락처
- 견적 요약: 견적번호, 견적일, 유효기간(30일), 견적금액
- 품목 테이블: No, 품목명, 규격, 수량, 단가, 금액
- 합계: 공급가액, 부가세(10%), 총 견적금액
- 비고

**액션 버튼:**
- 인쇄 (Printer)
- 다운로드 (Download)
- 이메일 (Mail)

### 2. CalculationSheetDialog (산출내역서)

**구성:**
- 견적번호, 현장명, 작성일
- 산출 테이블: No, 품목, 층/부호, 가로, 세로, 면적(m²), 수량, 단가, 금액
- 합계
- 산출 기준 안내

**면적 계산:**
```javascript
const area = ((item.width || 0) * (item.height || 0) / 1000000).toFixed(2);
```

### 3. PurchaseOrderDialog (발주서)

**구성:**
- 발주처 정보 (귀하): 상호, 담당자, 연락처, 현장
- 수주처 정보: 상호, 대표자, 사업자번호, 연락처
- 발주 요약: 발주번호, 발주일, 납기일, 발주금액
- 품목 테이블: No, 품목명, 규격, 수량, 단가, 금액
- 발주 합계
- 특기사항
- 서명란: 발주자(인), 수주자(인)

**발주번호 생성:**
```javascript
// 견적번호에서 변환
const purchaseOrderNo = `PO-${quote.quoteNo?.replace('QT', '')}`;
// 예: QT-2024-001 → PO-2024-001
```

---

## Quote 데이터 구조

### quote 객체

| 필드 | 타입 | 설명 |
|------|------|------|
| id | number | 견적 ID |
| quoteNo | string | 견적번호 (QT-YYMMDD-##) |
| quoteDate | string | 견적일 |
| customerName | string | 발주처명 |
| manager | string | 담당자 |
| contact | string | 연락처 |
| siteName | string | 현장명 |
| siteCode | string | 현장코드 |
| deliveryAddress | string | 납품주소 |
| productName | string | 대표 품목명 |
| qty | number | 수량 |
| unitPrice | number | 단가 |
| totalAmount | number | 총금액 (공급가액) |
| finalAmount | number | 최종금액 |
| status | string | 상태 |
| dueDate | string | 납기일 |
| createdBy | string | 작성자 |
| note | string | 비고 |
| specialNote | string | 특이사항 |
| creditGrade | string | 신용등급 |
| items | Array | 품목 목록 |

### items[] 객체

| 필드 | 타입 | 설명 |
|------|------|------|
| id | number | 품목 ID |
| productName | string | 품목명 |
| category | string | 카테고리 |
| floor | string | 층 |
| location | string | 위치 |
| width | number | 가로(mm) |
| height | number | 세로(mm) |
| qty | number | 수량 |
| unitPrice | number | 단가 |
| amount | number | 금액 |
| orderStatus | string | 수주 상태 (pending/ordered) |
| orderId | number | 연결된 수주 ID |

---

## API 추정

### 견적 → 수주 전환 API
```
POST /api/orders/from-quote/{quoteId}
Body: {
  shipDate: string | null,
  dueDate: string | null,
  deliveryMethod: string,
  freightCost: string,
  receiverName: string,
  receiverPhone: string,
  deliveryAddress: string,
  deliveryAddressDetail: string,
  note: string
}

Response: {
  order: { ... },  // 생성된 수주
  quote: { ... }   // 업데이트된 견적 (status: '수주전환')
}
```

### 문서 출력 API
```
GET /api/quotes/{id}/documents/quote-sheet      - 견적서 PDF
GET /api/quotes/{id}/documents/calculation      - 산출내역서 PDF
GET /api/quotes/{id}/documents/purchase-order   - 발주서 PDF
POST /api/quotes/{id}/documents/email           - 이메일 발송
```

---

## 다음 분석 단계

1. App.jsx 수주 섹션 추출 - 수주 목록/등록/상세 UI
2. 비즈니스 로직 통합 분석