- standards/ 폴더 추가 (코딩 규칙: 네이밍, 스타일) - rules/ 폴더 추가 (비즈니스 규칙: 검증, 도메인 로직) - principles/ 폴더 추가 (설계 원칙: 아키텍처, API 설계) - INDEX.md에 규칙 및 원칙 섹션 추가 - 각 폴더에 README.md 생성
19 KiB
19 KiB
견적관리 API 요청서
작성일: 2025-12-04 목적: 견적관리 기능을 위한 백엔드 API 요청 참조: sam-design/QuoteManagement3Write.tsx, QuoteManagement3Detail.tsx
1. 개요
1.1 기능 요약
견적관리 시스템은 다음 기능을 지원해야 합니다:
- 견적 CRUD (등록, 조회, 수정, 삭제)
- 견적 상태 관리 (임시저장 → 확정 → 수주전환)
- 견적 수정 이력 관리 (버전 관리)
- 견적 품목(BOM) 관리
- 자동 견적 산출 (수식 기반 계산) ← 백엔드 구현
1.2 특이사항
- 자동 견적 산출 로직은 백엔드에서 구현 예정 (수식 계산 엔진)
- 프론트엔드는 입력값을 전달하고 계산 결과를 받아서 표시
2. 데이터 모델
2.1 Quote (견적) - 메인 엔티티
interface Quote {
// === 기본 정보 ===
id: number;
tenant_id: number;
quote_number: string; // 견적번호 (예: KD-SC-251204-01)
registration_date: string; // 등록일 (YYYY-MM-DD)
receipt_date: string; // 접수일
author: string; // 작성자
// === 발주처 정보 ===
client_id: number | null; // 거래처 ID (FK)
client_name: string; // 거래처명 (직접입력 대응)
manager: string | null; // 담당자
contact: string | null; // 연락처
// === 현장 정보 ===
site_id: number | null; // 현장 ID (FK, 별도 테이블 필요시)
site_name: string | null; // 현장명
site_code: string | null; // 현장코드
// === 제품 정보 ===
product_category: 'SCREEN' | 'STEEL'; // 제품 카테고리
product_id: number | null; // 선택된 제품 ID (품목마스터 FK)
product_code: string | null; // 제품코드
product_name: string | null; // 제품명
// === 규격 정보 ===
open_size_width: number | null; // 오픈사이즈 폭 (mm)
open_size_height: number | null; // 오픈사이즈 높이 (mm)
quantity: number; // 수량 (기본값: 1)
unit_symbol: string | null; // 부호
floors: string | null; // 층수
// === 금액 정보 ===
material_cost: number; // 재료비 합계
labor_cost: number; // 노무비
install_cost: number; // 설치비
subtotal: number; // 소계
discount_rate: number; // 할인율 (%)
discount_amount: number; // 할인금액
total_amount: number; // 최종 금액
// === 상태 관리 ===
status: 'draft' | 'sent' | 'approved' | 'rejected' | 'finalized' | 'converted';
current_revision: number; // 현재 수정 차수 (0부터 시작)
is_final: boolean; // 최종확정 여부
finalized_at: string | null; // 확정일시
finalized_by: number | null; // 확정자 ID
// === 기타 정보 ===
completion_date: string | null; // 납기일
remarks: string | null; // 비고
memo: string | null; // 메모
notes: string | null; // 특이사항
// === 시스템 필드 ===
created_at: string;
updated_at: string;
created_by: number | null;
updated_by: number | null;
deleted_at: string | null; // Soft Delete
}
2.2 QuoteItem (견적 품목) - BOM 계산 결과
interface QuoteItem {
id: number;
quote_id: number; // 견적 ID (FK)
tenant_id: number;
// === 품목 정보 ===
item_id: number | null; // 품목마스터 ID (FK)
item_code: string; // 품목코드
item_name: string; // 품명
specification: string | null; // 규격
unit: string; // 단위
// === 수량/금액 ===
base_quantity: number; // 기본수량
calculated_quantity: number; // 계산된 수량
unit_price: number; // 단가
total_price: number; // 금액 (수량 × 단가)
// === 수식 정보 ===
formula: string | null; // 수식 (예: "W/1000 + 0.1")
formula_source: string | null; // 수식 출처 (BOM템플릿, 제품BOM 등)
formula_category: string | null; // 수식 카테고리
data_source: string | null; // 데이터 출처
// === 기타 ===
delivery_date: string | null; // 품목별 납기일
note: string | null; // 비고
sort_order: number; // 정렬순서
created_at: string;
updated_at: string;
}
2.3 QuoteRevision (견적 수정 이력)
interface QuoteRevision {
id: number;
quote_id: number; // 견적 ID (FK)
tenant_id: number;
revision_number: number; // 수정 차수 (1, 2, 3...)
revision_date: string; // 수정일
revision_by: number; // 수정자 ID
revision_by_name: string; // 수정자 이름
revision_reason: string | null; // 수정 사유
// 이전 버전 데이터 (JSON)
previous_data: object; // 수정 전 견적 전체 데이터 (스냅샷)
created_at: string;
}
3. API 엔드포인트
3.1 견적 CRUD
| Method | Endpoint | 설명 | 비고 |
|---|---|---|---|
GET |
/api/v1/quotes |
목록 조회 | 페이지네이션, 필터, 검색 |
GET |
/api/v1/quotes/{id} |
단건 조회 | 품목(items), 이력(revisions) 포함 |
POST |
/api/v1/quotes |
생성 | 품목 배열 포함 |
PUT |
/api/v1/quotes/{id} |
수정 | 수정이력 자동 생성 |
DELETE |
/api/v1/quotes/{id} |
삭제 | Soft Delete |
DELETE |
/api/v1/quotes |
일괄 삭제 | ids[] 파라미터 |
3.2 견적 상태 관리
| Method | Endpoint | 설명 | 비고 |
|---|---|---|---|
PATCH |
/api/v1/quotes/{id}/finalize |
최종확정 | status → 'finalized', is_final → true |
PATCH |
/api/v1/quotes/{id}/convert-to-order |
수주전환 | status → 'converted', 수주 데이터 생성 |
PATCH |
/api/v1/quotes/{id}/cancel-finalize |
확정취소 | is_final → false (조건부) |
3.3 자동 견적 산출 (핵심 기능)
| Method | Endpoint | 설명 | 비고 |
|---|---|---|---|
POST |
/api/v1/quotes/calculate |
자동 산출 | 수식 계산 엔진 |
POST |
/api/v1/quotes/{id}/recalculate |
재계산 | 기존 견적 재산출 |
3.4 견적 문서 출력
| Method | Endpoint | 설명 | 비고 |
|---|---|---|---|
GET |
/api/v1/quotes/{id}/document/quote |
견적서 PDF | |
GET |
/api/v1/quotes/{id}/document/calculation |
산출내역서 PDF | |
GET |
/api/v1/quotes/{id}/document/purchase-order |
발주서 PDF |
3.5 문서 발송 API ⭐ 신규 요청
| Method | Endpoint | 설명 | 비고 |
|---|---|---|---|
POST |
/api/v1/quotes/{id}/send/email |
이메일 발송 | 첨부파일 포함 |
POST |
/api/v1/quotes/{id}/send/fax |
팩스 발송 | 팩스 서비스 연동 |
POST |
/api/v1/quotes/{id}/send/kakao |
카카오톡 발송 | 알림톡/친구톡 |
3.6 견적번호 생성
| Method | Endpoint | 설명 | 비고 |
|---|---|---|---|
GET |
/api/v1/quotes/generate-number |
견적번호 생성 | ?category=SCREEN |
4. 상세 API 명세
4.1 목록 조회 GET /api/v1/quotes
Query Parameters:
page: number (default: 1)
size: number (default: 20)
q: string (검색어 - 견적번호, 발주처, 담당자, 현장명)
status: string (상태 필터)
product_category: string (제품 카테고리)
client_id: number (발주처 ID)
date_from: string (등록일 시작)
date_to: string (등록일 종료)
sort_by: string (정렬 컬럼)
sort_order: 'asc' | 'desc'
Response:
{
"success": true,
"data": {
"current_page": 1,
"data": [
{
"id": 1,
"quote_number": "KD-SC-251204-01",
"registration_date": "2025-12-04",
"client_name": "ABC건설",
"site_name": "강남 오피스텔 현장",
"product_category": "SCREEN",
"product_name": "전동스크린 A형",
"quantity": 10,
"total_amount": 15000000,
"status": "draft",
"current_revision": 0,
"is_final": false,
"created_at": "2025-12-04T10:00:00Z"
}
],
"last_page": 5,
"per_page": 20,
"total": 100
}
}
4.2 단건 조회 GET /api/v1/quotes/{id}
Response:
{
"success": true,
"data": {
"id": 1,
"quote_number": "KD-SC-251204-01",
"registration_date": "2025-12-04",
"receipt_date": "2025-12-04",
"author": "김철수",
"client_id": 10,
"client_name": "ABC건설",
"manager": "이영희",
"contact": "010-1234-5678",
"site_id": 5,
"site_name": "강남 오피스텔 현장",
"site_code": "PJ-20251204-01",
"product_category": "SCREEN",
"product_id": 100,
"product_code": "SCR-001",
"product_name": "전동스크린 A형",
"open_size_width": 2000,
"open_size_height": 3000,
"quantity": 10,
"unit_symbol": "A",
"floors": "3층",
"material_cost": 12000000,
"labor_cost": 1500000,
"install_cost": 1500000,
"subtotal": 15000000,
"discount_rate": 0,
"discount_amount": 0,
"total_amount": 15000000,
"status": "draft",
"current_revision": 2,
"is_final": false,
"completion_date": "2025-12-31",
"remarks": "급하게 진행 필요",
"memo": "",
"notes": "",
"items": [
{
"id": 1,
"item_code": "SCR-MOTOR-001",
"item_name": "스크린 모터",
"specification": "220V, 1/4HP",
"unit": "EA",
"base_quantity": 1,
"calculated_quantity": 10,
"unit_price": 150000,
"total_price": 1500000,
"formula": "Q",
"formula_source": "제품BOM",
"sort_order": 1
}
],
"revisions": [
{
"revision_number": 2,
"revision_date": "2025-12-04",
"revision_by_name": "김철수",
"revision_reason": "고객 요청으로 수량 변경"
},
{
"revision_number": 1,
"revision_date": "2025-12-03",
"revision_by_name": "김철수",
"revision_reason": "단가 조정"
}
],
"created_at": "2025-12-04T10:00:00Z",
"updated_at": "2025-12-04T15:30:00Z"
}
}
4.3 생성 POST /api/v1/quotes
Request Body:
{
"registration_date": "2025-12-04",
"receipt_date": "2025-12-04",
"client_id": 10,
"client_name": "ABC건설",
"manager": "이영희",
"contact": "010-1234-5678",
"site_id": 5,
"site_name": "강남 오피스텔 현장",
"site_code": "PJ-20251204-01",
"product_category": "SCREEN",
"product_id": 100,
"open_size_width": 2000,
"open_size_height": 3000,
"quantity": 10,
"unit_symbol": "A",
"floors": "3층",
"completion_date": "2025-12-31",
"remarks": "급하게 진행 필요",
"items": [
{
"item_id": 50,
"item_code": "SCR-MOTOR-001",
"item_name": "스크린 모터",
"unit": "EA",
"base_quantity": 1,
"calculated_quantity": 10,
"unit_price": 150000,
"total_price": 1500000,
"formula": "Q",
"sort_order": 1
}
]
}
4.4 자동 산출 POST /api/v1/quotes/calculate ⭐ 핵심
Request Body:
{
"product_id": 100,
"product_category": "SCREEN",
"open_size_width": 2000,
"open_size_height": 3000,
"quantity": 10,
"floors": "3층",
"unit_symbol": "A",
"options": {
"guide_rail_install_type": "벽부형",
"motor_power": "1/4HP",
"controller": "표준형",
"edge_wing_size": 50,
"inspection_fee": 0
}
}
Response:
{
"success": true,
"data": {
"product_id": 100,
"product_name": "전동스크린 A형",
"product_category": "SCREEN",
"open_size": {
"width": 2000,
"height": 3000
},
"quantity": 10,
"items": [
{
"item_id": 50,
"item_code": "SCR-MOTOR-001",
"item_name": "스크린 모터",
"specification": "220V, 1/4HP",
"unit": "EA",
"base_quantity": 1,
"calculated_quantity": 10,
"unit_price": 150000,
"total_price": 1500000,
"formula": "Q",
"formula_result": "10 × 1 = 10",
"formula_source": "제품BOM: 전동스크린 A형",
"data_source": "품목마스터 [SCR-MOTOR-001]"
},
{
"item_id": 51,
"item_code": "SCR-RAIL-001",
"item_name": "가이드레일",
"specification": "알루미늄",
"unit": "M",
"base_quantity": 1,
"calculated_quantity": 60,
"unit_price": 15000,
"total_price": 900000,
"formula": "H/1000 × 2 × Q",
"formula_result": "(3000/1000) × 2 × 10 = 60",
"formula_source": "BOM템플릿: 스크린_표준",
"data_source": "품목마스터 [SCR-RAIL-001]"
}
],
"summary": {
"material_cost": 12000000,
"labor_cost": 1500000,
"install_cost": 1500000,
"subtotal": 15000000,
"total_amount": 15000000
},
"calculation_info": {
"bom_template_used": "스크린_표준",
"formula_variables": {
"W": 2000,
"H": 3000,
"Q": 10
},
"calculated_at": "2025-12-04T10:00:00Z"
}
}
}
5. 수식 계산 엔진 (백엔드 구현 요청)
5.1 수식 변수
| 변수 | 설명 | 예시 |
|---|---|---|
W |
오픈사이즈 폭 (mm) | 2000 |
H |
오픈사이즈 높이 (mm) | 3000 |
Q |
수량 | 10 |
5.2 수식 예시
수량 그대로: Q
높이 기반: H/1000
폭+높이: (W + H) / 1000
가이드레일: H/1000 × 2 × Q
스크린원단: (W/1000 + 0.1) × (H/1000 + 0.3) × Q
5.3 반올림 규칙
| 규칙 | 설명 |
|---|---|
ceil |
올림 |
floor |
내림 |
round |
반올림 |
5.4 BOM 템플릿 연동
- 제품별 BOM 템플릿에서 수식 조회
- 템플릿이 없으면 품목마스터 BOM 사용
- 수식 + 단가로 자동 금액 계산
6. 상태 흐름도
[신규등록]
↓
[draft] 임시저장
↓ (최종확정)
[finalized] 확정
↓ (수주전환)
[converted] 수주전환
6.1 상태별 제약
| 상태 | 수정 가능 | 삭제 가능 | 비고 |
|---|---|---|---|
draft |
O | O | 자유롭게 수정 |
sent |
O | O | 발송 후 수정 가능 (이력 기록) |
finalized |
X | X | 확정 후 수정 불가 |
converted |
X | X | 수주전환 후 불변 |
7. 프론트엔드 구현 현황 (2025-12-04 업데이트)
7.1 구현 완료된 파일
| 파일 | 설명 | 상태 |
|---|---|---|
quote-management/page.tsx |
견적 목록 페이지 | ✅ 완료 (샘플 데이터) |
quote-management/new/page.tsx |
견적 등록 페이지 | ✅ 완료 |
quote-management/[id]/page.tsx |
견적 상세 페이지 | ✅ 완료 |
quote-management/[id]/edit/page.tsx |
견적 수정 페이지 | ✅ 완료 |
components/quotes/QuoteRegistration.tsx |
견적 등록/수정 컴포넌트 | ✅ 완료 |
components/quotes/QuoteDocument.tsx |
견적서 문서 컴포넌트 | ✅ 완료 |
components/quotes/QuoteCalculationReport.tsx |
산출내역서 문서 컴포넌트 | ✅ 완료 |
components/quotes/PurchaseOrderDocument.tsx |
발주서 문서 컴포넌트 | ✅ 완료 |
7.2 UI 기능 구현 현황
| 기능 | 상태 | 비고 |
|---|---|---|
| 견적 목록 조회 | ✅ UI 완료 | 샘플 데이터, API 연동 필요 |
| 견적 검색/필터 | ✅ UI 완료 | 로컬 필터링, API 연동 필요 |
| 견적 등록 폼 | ✅ UI 완료 | API 연동 필요 |
| 견적 상세 페이지 | ✅ UI 완료 | API 연동 필요 |
| 견적 수정 폼 | ✅ UI 완료 | API 연동 필요 |
| 견적 삭제 | ✅ UI 완료 | 로컬 상태, API 연동 필요 |
| 견적 일괄 삭제 | ✅ UI 완료 | 로컬 상태, API 연동 필요 |
| 자동 견적 산출 | ⏳ 버튼만 | 백엔드 수식 엔진 필요 |
| 발주처 선택 | ⏳ 샘플 데이터 | /api/v1/clients 연동 필요 |
| 현장 선택 | ⏳ 샘플 데이터 | 발주처 연동 후 현장 API 필요 |
| 제품 선택 | ⏳ 샘플 데이터 | /api/v1/item-masters 연동 필요 |
| 견적서 모달 | ✅ UI 완료 | PDF/이메일/팩스/카톡 버튼, 발송 API 필요 |
| 산출내역서 모달 | ✅ UI 완료 | PDF/이메일/팩스/카톡 버튼, 발송 API 필요 |
| 발주서 모달 | ✅ UI 완료 | PDF/이메일/팩스/카톡 버튼, 발송 API 필요 |
| 최종확정 버튼 | ✅ UI 완료 | API 연동 필요 |
7.3 견적 등록/수정 폼 필드 (구현 완료)
기본 정보 섹션:
- 등록일 (readonly, 오늘 날짜)
- 작성자 (readonly, 로그인 사용자)
- 발주처 선택 * (필수)
- 현장명 (발주처 선택 시 연동)
- 발주 담당자
- 연락처
- 납기일
- 비고
자동 견적 산출 섹션 (동적 항목):
- 층수
- 부호
- 제품 카테고리 (PC) *
- 제품명 *
- 오픈사이즈 (W0) *
- 오픈사이즈 (H0) *
- 가이드레일 설치 유형 (GT) *
- 모터 전원 (MP) *
- 연동제어기 (CT) *
- 수량 (QTY) *
- 마구리 날개치수 (WS)
- 검사비 (INSP)
기능:
- 견적 항목 추가/복사/삭제
- 자동 견적 산출 버튼
- 샘플 데이터 생성 버튼
7.4 다음 단계 (API 연동)
// useQuoteList 훅 (목록)
const {
quotes,
pagination,
isLoading,
fetchQuotes,
deleteQuote,
bulkDelete
} = useQuoteList();
// useQuote 훅 (단건 CRUD)
const {
quote,
isLoading,
fetchQuote,
createQuote,
updateQuote,
finalizeQuote,
convertToOrder
} = useQuote();
// useQuoteCalculation 훅 (자동 산출)
const {
calculationResult,
isCalculating,
calculate,
recalculate
} = useQuoteCalculation();
8. 관련 참조
8.1 거래처 API 연동
- 발주처 선택 시
/api/v1/clients연동 - 직접입력 시 자동 등록 가능
8.2 현장 API (추후)
- 현장 선택 시
/api/v1/sites연동 (별도 API 필요시)
8.3 품목마스터 연동
- 제품 선택 시
/api/v1/item-masters연동 - BOM 조회 시 품목마스터 BOM 활용
9. 요청 우선순위
| 순위 | API | 설명 |
|---|---|---|
| P1 | 견적 CRUD | 기본 목록/등록/수정/삭제 |
| P1 | 자동 산출 | 수식 계산 엔진 (핵심) |
| P1 | 견적번호 생성 | 자동 채번 |
| P2 | 상태 관리 | 확정/수주전환 |
| P2 | 수정 이력 | 버전 관리 |
| P3 | 문서 출력 | PDF 생성 |
10. 질문사항
- 현장(Site) 테이블: 별도 테이블로 관리할지? (거래처 하위 개념)
- 수식 계산: BOM 템플릿 테이블 구조는?
- 문서 출력: PDF 라이브러리 선정 (TCPDF, Dompdf 등)
- 알림: 견적 발송 시 이메일/카카오톡 연동 계획?