# 견적/수주 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. 비즈니스 로직 통합 분석