Files
sam-api/claudedocs/[PLAN-2025-12-04] quote-api-development-plan.md
hskwon d164bb4c4a feat: [client] 거래처 API 2차 필드 추가 및 견적 계획 업데이트
- 거래처 유형(client_type), 연락처(mobile, fax), 담당자 정보 필드 추가
- 발주처 설정(account_id/password, payment_day) 필드 추가
- 약정 세금(tax_agreement, tax_amount, tax_start/end_date) 필드 추가
- 악성채권(bad_debt 관련 5개 필드) 정보 필드 추가
- Model, Service, FormRequest, Swagger 문서 업데이트
- 견적 API 계획에 문서 발송 API(email/fax/kakao) 요구사항 추가
2025-12-04 21:13:58 +09:00

507 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 견적관리 API 개발 계획서
> **작성일**: 2025-12-04
> **요청서**: `docs/front/[API-2025-12-04] quote-api-request.md`
> **상태**: ✅ Phase 1 완료 → Phase 2 진행 중
---
## 🔧 작업 진행 현황 (2025-12-04)
### ✅ Phase 1 완료 항목
#### 1. 마이그레이션 생성 및 실행 완료
- **파일**: `database/migrations/2025_12_04_164542_create_quotes_table.php`
- **생성된 테이블**: `quotes`, `quote_items`, `quote_revisions`
- **실행 상태**: ✅ 마이그레이션 완료
#### 2. Model 생성 완료
```
app/Models/Quote/
├── Quote.php ✅ 생성 완료
├── QuoteItem.php ✅ 생성 완료
└── QuoteRevision.php ✅ 생성 완료
```
**적용된 패턴:**
- `BelongsToTenant` 트레이트 적용
- `SoftDeletes` 적용 (Quote)
- 상태 상수 정의 (STATUS_DRAFT, STATUS_FINALIZED 등)
- 스코프 메서드 (draft, finalized, search, dateRange 등)
- 상태 검증 메서드 (isEditable, isDeletable, isFinalizable, isConvertible)
### 🆕 변경 요청 분석 (2025-12-04)
요청서에서 **문서 발송 API (Section 3.5)**가 신규 추가됨:
| Method | Endpoint | 설명 | 비고 |
|--------|----------|------|------|
| `POST` | `/api/v1/quotes/{id}/send/email` | 이메일 발송 | 첨부파일 포함 |
| `POST` | `/api/v1/quotes/{id}/send/fax` | 팩스 발송 | 팩스 서비스 연동 |
| `POST` | `/api/v1/quotes/{id}/send/kakao` | 카카오톡 발송 | 알림톡/친구톡 |
**영향 범위:**
- Phase 2: `QuoteDocumentService` 추가 필요
- Phase 3: 문서 발송 관련 Controller 메서드 + FormRequest 추가
- Phase 4: Swagger 문서에 발송 API 추가
**개발 우선순위 조정:**
- P1: 견적 CRUD, 자동 산출, 견적번호 생성 (기존 유지)
- P2: 상태 관리, 수정 이력 (기존 유지)
- P3: 문서 출력 + **문서 발송 API** (신규 추가)
### ⏭️ 다음 단계
- Phase 2: Service Layer 구현 (QuoteService, QuoteCalculationService, QuoteNumberService)
---
## 1. 요구사항 분석 요약
### 1.1 핵심 엔티티
| 엔티티 | 설명 | 비고 |
|--------|------|------|
| Quote | 견적 마스터 | 메인 테이블 |
| QuoteItem | 견적 품목 | BOM/수식 계산 결과 저장 |
| QuoteRevision | 수정 이력 | 버전 관리 |
### 1.2 기능 우선순위
| 우선순위 | 기능 | 설명 |
|----------|------|------|
| **P1** | 견적 CRUD | 기본 목록/등록/수정/삭제 |
| **P1** | 자동 산출 | 수식 계산 엔진 (핵심) |
| **P1** | 견적번호 생성 | 자동 채번 |
| **P2** | 상태 관리 | 확정/수주전환 |
| **P2** | 수정 이력 | 버전 관리 |
| **P3** | 문서 출력 | PDF 생성 |
### 1.3 기존 인프라 활용
- `quote_formulas` 테이블들 (수식 계산용) - **이미 존재**
- `FormulaEvaluatorService` (mng에서 사용 중) - **API로 이식 필요**
- `EstimateService` 패턴 참조 - **유사 구조**
---
## 2. 데이터베이스 설계
### 2.1 신규 테이블: quotes (견적 마스터)
```sql
CREATE TABLE quotes (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID',
-- 기본 정보
quote_number VARCHAR(50) NOT NULL COMMENT '견적번호 (예: KD-SC-251204-01)',
registration_date DATE NOT NULL COMMENT '등록일',
receipt_date DATE NULL COMMENT '접수일',
author VARCHAR(100) NULL COMMENT '작성자',
-- 발주처 정보
client_id BIGINT UNSIGNED NULL COMMENT '거래처 ID (FK)',
client_name VARCHAR(100) NULL COMMENT '거래처명 (직접입력 대응)',
manager VARCHAR(100) NULL COMMENT '담당자',
contact VARCHAR(50) NULL COMMENT '연락처',
-- 현장 정보
site_id BIGINT UNSIGNED NULL COMMENT '현장 ID',
site_name VARCHAR(200) NULL COMMENT '현장명',
site_code VARCHAR(50) NULL COMMENT '현장코드',
-- 제품 정보
product_category ENUM('SCREEN', 'STEEL') NOT NULL COMMENT '제품 카테고리',
product_id BIGINT UNSIGNED NULL COMMENT '선택된 제품 ID',
product_code VARCHAR(50) NULL COMMENT '제품코드',
product_name VARCHAR(200) NULL COMMENT '제품명',
-- 규격 정보
open_size_width INT UNSIGNED NULL COMMENT '오픈사이즈 폭 (mm)',
open_size_height INT UNSIGNED NULL COMMENT '오픈사이즈 높이 (mm)',
quantity INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '수량',
unit_symbol VARCHAR(10) NULL COMMENT '부호',
floors VARCHAR(20) NULL COMMENT '층수',
-- 금액 정보
material_cost DECIMAL(15,2) NOT NULL DEFAULT 0 COMMENT '재료비 합계',
labor_cost DECIMAL(15,2) NOT NULL DEFAULT 0 COMMENT '노무비',
install_cost DECIMAL(15,2) NOT NULL DEFAULT 0 COMMENT '설치비',
subtotal DECIMAL(15,2) NOT NULL DEFAULT 0 COMMENT '소계',
discount_rate DECIMAL(5,2) NOT NULL DEFAULT 0 COMMENT '할인율 (%)',
discount_amount DECIMAL(15,2) NOT NULL DEFAULT 0 COMMENT '할인금액',
total_amount DECIMAL(15,2) NOT NULL DEFAULT 0 COMMENT '최종 금액',
-- 상태 관리
status ENUM('draft', 'sent', 'approved', 'rejected', 'finalized', 'converted') NOT NULL DEFAULT 'draft' COMMENT '상태',
current_revision INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '현재 수정 차수',
is_final TINYINT(1) NOT NULL DEFAULT 0 COMMENT '최종확정 여부',
finalized_at DATETIME NULL COMMENT '확정일시',
finalized_by BIGINT UNSIGNED NULL COMMENT '확정자 ID',
-- 기타 정보
completion_date DATE NULL COMMENT '납기일',
remarks TEXT NULL COMMENT '비고',
memo TEXT NULL COMMENT '메모',
notes TEXT NULL COMMENT '특이사항',
-- 자동산출 입력값 저장
calculation_inputs JSON NULL COMMENT '자동산출에 사용된 입력값',
-- 감사
created_by BIGINT UNSIGNED NULL COMMENT '생성자',
updated_by BIGINT UNSIGNED NULL COMMENT '수정자',
deleted_by BIGINT UNSIGNED NULL COMMENT '삭제자',
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL,
-- 인덱스
INDEX idx_tenant_id (tenant_id),
INDEX idx_quote_number (quote_number),
INDEX idx_status (status),
INDEX idx_client_id (client_id),
INDEX idx_product_category (product_category),
INDEX idx_registration_date (registration_date),
UNIQUE INDEX uq_tenant_quote_number (tenant_id, quote_number, deleted_at),
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE SET NULL
);
```
### 2.2 신규 테이블: quote_items (견적 품목)
```sql
CREATE TABLE quote_items (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
quote_id BIGINT UNSIGNED NOT NULL COMMENT '견적 ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID',
-- 품목 정보
item_id BIGINT UNSIGNED NULL COMMENT '품목마스터 ID',
item_code VARCHAR(50) NOT NULL COMMENT '품목코드',
item_name VARCHAR(200) NOT NULL COMMENT '품명',
specification VARCHAR(100) NULL COMMENT '규격',
unit VARCHAR(20) NOT NULL COMMENT '단위',
-- 수량/금액
base_quantity DECIMAL(15,4) NOT NULL DEFAULT 1 COMMENT '기본수량',
calculated_quantity DECIMAL(15,4) NOT NULL DEFAULT 1 COMMENT '계산된 수량',
unit_price DECIMAL(15,2) NOT NULL DEFAULT 0 COMMENT '단가',
total_price DECIMAL(15,2) NOT NULL DEFAULT 0 COMMENT '금액 (수량 × 단가)',
-- 수식 정보
formula VARCHAR(500) NULL COMMENT '수식',
formula_result VARCHAR(200) NULL COMMENT '수식 계산 결과 표시',
formula_source VARCHAR(100) NULL COMMENT '수식 출처',
formula_category VARCHAR(50) NULL COMMENT '수식 카테고리',
data_source VARCHAR(200) NULL COMMENT '데이터 출처',
-- 기타
delivery_date DATE NULL COMMENT '품목별 납기일',
note TEXT NULL COMMENT '비고',
sort_order INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '정렬순서',
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
-- 인덱스
INDEX idx_quote_id (quote_id),
INDEX idx_tenant_id (tenant_id),
INDEX idx_item_code (item_code),
INDEX idx_sort_order (sort_order),
FOREIGN KEY (quote_id) REFERENCES quotes(id) ON DELETE CASCADE,
FOREIGN KEY (tenant_id) REFERENCES tenants(id)
);
```
### 2.3 신규 테이블: quote_revisions (수정 이력)
```sql
CREATE TABLE quote_revisions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
quote_id BIGINT UNSIGNED NOT NULL COMMENT '견적 ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID',
revision_number INT UNSIGNED NOT NULL COMMENT '수정 차수',
revision_date DATE NOT NULL COMMENT '수정일',
revision_by BIGINT UNSIGNED NOT NULL COMMENT '수정자 ID',
revision_by_name VARCHAR(100) NULL COMMENT '수정자 이름',
revision_reason TEXT NULL COMMENT '수정 사유',
-- 이전 버전 데이터 (JSON 스냅샷)
previous_data JSON NOT NULL COMMENT '수정 전 견적 전체 데이터',
created_at TIMESTAMP NULL,
-- 인덱스
INDEX idx_quote_id (quote_id),
INDEX idx_tenant_id (tenant_id),
INDEX idx_revision_number (revision_number),
FOREIGN KEY (quote_id) REFERENCES quotes(id) ON DELETE CASCADE,
FOREIGN KEY (tenant_id) REFERENCES tenants(id)
);
```
### 2.4 기존 테이블 활용
- `quote_formula_categories` - 수식 카테고리
- `quote_formulas` - 수식 정의
- `quote_formula_ranges` - 범위별 값
- `quote_formula_mappings` - 매핑 값
- `quote_formula_items` - 수식 품목 출력
- `clients` - 발주처
- `item_masters` - 품목 마스터 (단가 연동)
---
## 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` | 최종확정 |
| `PATCH` | `/api/v1/quotes/{id}/convert-to-order` | 수주전환 |
| `PATCH` | `/api/v1/quotes/{id}/cancel-finalize` | 확정취소 |
### 3.3 자동 산출
| Method | Endpoint | 설명 |
|--------|----------|------|
| `POST` | `/api/v1/quotes/calculate` | 자동 산출 (수식 엔진) |
| `POST` | `/api/v1/quotes/{id}/recalculate` | 기존 견적 재계산 |
| `GET` | `/api/v1/quotes/generate-number` | 견적번호 생성 |
### 3.4 문서 출력 (P3 - 후순위)
| 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 문서 발송 (P3 - 신규 추가)
| Method | Endpoint | 설명 | 비고 |
|--------|----------|------|------|
| `POST` | `/api/v1/quotes/{id}/send/email` | 이메일 발송 | 첨부파일 포함 |
| `POST` | `/api/v1/quotes/{id}/send/fax` | 팩스 발송 | 팩스 서비스 연동 |
| `POST` | `/api/v1/quotes/{id}/send/kakao` | 카카오톡 발송 | 알림톡/친구톡 |
---
## 4. 개발 Phase 계획
### Phase 1: 기반 구축 (DB + Model)
**작업 내용:**
1. 마이그레이션 생성 (3개 테이블)
2. Model 생성 (Quote, QuoteItem, QuoteRevision)
3. Trait/Scope 적용 (BelongsToTenant, SoftDeletes, 감사 컬럼)
**파일 목록:**
```
database/migrations/
├── 2025_12_XX_XXXXXX_create_quotes_table.php
├── 2025_12_XX_XXXXXX_create_quote_items_table.php
└── 2025_12_XX_XXXXXX_create_quote_revisions_table.php
app/Models/Quote/
├── Quote.php
├── QuoteItem.php
└── QuoteRevision.php
```
### Phase 2: 핵심 서비스 (Service Layer)
**작업 내용:**
1. QuoteService - CRUD + 상태관리
2. QuoteCalculationService - 자동산출 (FormulaEvaluator 연동)
3. QuoteNumberService - 번호채번
4. FormulaEvaluatorService 이식 (mng → api)
5. QuoteDocumentService - 문서 생성 및 발송 (신규 추가)
**파일 목록:**
```
app/Services/Quote/
├── QuoteService.php
├── QuoteCalculationService.php
├── QuoteNumberService.php
├── QuoteDocumentService.php (신규 - 문서 생성/발송)
└── FormulaEvaluatorService.php (mng에서 이식)
```
**의존성:**
- PricingService (단가 조회)
- ClientService (발주처 연동)
- MailService (이메일 발송)
- NotificationService (카카오톡/팩스 발송)
### Phase 3: API 구현 (Controller + Routes)
**작업 내용:**
1. QuoteController 구현
2. FormRequest 생성 (검증 규칙)
3. 라우트 추가
4. 문서 발송 엔드포인트 추가 (신규)
**파일 목록:**
```
app/Http/Controllers/Api/V1/
└── QuoteController.php
app/Http/Requests/Quote/
├── QuoteIndexRequest.php
├── QuoteStoreRequest.php
├── QuoteUpdateRequest.php
├── QuoteCalculateRequest.php
├── QuoteFinalizeRequest.php
├── QuoteSendEmailRequest.php (신규)
├── QuoteSendFaxRequest.php (신규)
└── QuoteSendKakaoRequest.php (신규)
routes/
└── api_v1.php (라우트 추가)
```
### Phase 4: 문서화 (Swagger + i18n)
**작업 내용:**
1. Swagger 문서 작성
2. i18n 메시지 키 추가
**파일 목록:**
```
app/Swagger/v1/
└── QuoteApi.php
lang/ko/
├── message.php (quote 키 추가)
└── error.php (quote 에러 키 추가)
```
---
## 5. 자동 산출 로직 상세
### 5.1 입력값 → 수식 변수 매핑
| 입력 필드 | 수식 변수 | 설명 |
|-----------|-----------|------|
| `open_size_width` | `W0` | 오픈사이즈 폭 (mm) |
| `open_size_height` | `H0` | 오픈사이즈 높이 (mm) |
| `quantity` | `Q` | 수량 |
| `floors` | `FLOORS` | 층수 |
| `options.guide_rail_install_type` | `GUIDE_TYPE` | 가이드레일 설치 유형 |
| `options.motor_power` | `MOTOR_POWER` | 모터 용량 |
| `options.controller` | `CONTROLLER_TYPE` | 제어기 유형 |
| `options.edge_wing_size` | `EDGE_SIZE` | 마구리 날개 사이즈 |
| `options.inspection_fee` | `INSP_FEE` | 검사비 |
### 5.2 처리 흐름
```
1. 입력값 수집
2. 수식 변수 초기화 (input 타입)
3. 계산 수식 실행 (calculation 타입)
- 의존성 순서대로 실행
- FormulaEvaluatorService 활용
4. 범위 판단 (range 타입)
- quote_formula_ranges 조회
5. 매핑 판단 (mapping 타입)
- quote_formula_mappings 조회
6. 품목 출력 생성 (quote_formula_items)
- 수량 계산식 적용
- 단가 조회 (품목마스터 또는 고정값)
7. 결과 반환
- items 배열
- summary (재료비, 노무비, 설치비 등)
- calculation_info (사용된 변수들)
```
### 5.3 FormulaEvaluatorService 이식 범위
mng의 `QuoteFormulaService`에서 다음 메서드 이식:
- `evaluateFormula()` - 수식 평가
- `evaluateAllFormulas()` - 전체 수식 순차 평가
- `resolveRangeValue()` - 범위 값 해석
- `resolveMappingValue()` - 매핑 값 해석
---
## 6. 예상 산출물 요약
| 구분 | 수량 | 내용 |
|------|------|------|
| 마이그레이션 | 3개 | quotes, quote_items, quote_revisions |
| Model | 3개 | Quote, QuoteItem, QuoteRevision |
| Service | 5개 | QuoteService, QuoteCalculationService, QuoteNumberService, FormulaEvaluatorService, **QuoteDocumentService** |
| Controller | 1개 | QuoteController |
| FormRequest | 8개 | Index, Store, Update, Calculate, Finalize, **SendEmail, SendFax, SendKakao** |
| Swagger | 1개 | QuoteApi.php |
| i18n | 2개 | message.php, error.php (키 추가) |
---
## 7. 질문사항 답변
### Q1. 현장(Site) 테이블
**답변:** `quotes` 테이블에 `site_*` 컬럼으로 직접 저장 (별도 테이블 불필요)
- `site_id`, `site_name`, `site_code` 컬럼 포함
- 추후 별도 테이블 필요 시 마이그레이션으로 분리 가능
### Q2. 수식 계산 BOM 템플릿 테이블 구조
**답변:** 기존 `quote_formulas` 테이블 구조 활용
- `quote_formula_categories` - 수식 카테고리
- `quote_formulas` - 수식 정의 (input/calculation/range/mapping)
- `quote_formula_ranges` - 범위별 값
- `quote_formula_mappings` - 매핑 값
- `quote_formula_items` - 품목 출력 정의
### Q3. 문서 출력 PDF 라이브러리
**답변:** P3 (후순위) 작업으로 진행
- 권장: **TCPDF** (한글 지원, Laravel 연동 용이)
- 대안: Dompdf (HTML → PDF 변환)
### Q4. 알림 (이메일/카카오톡)
**답변:** ✅ 요청서 Section 3.5에 신규 추가됨
- 이메일 발송: `POST /api/v1/quotes/{id}/send/email`
- 팩스 발송: `POST /api/v1/quotes/{id}/send/fax`
- 카카오톡 발송: `POST /api/v1/quotes/{id}/send/kakao`
- P3 우선순위로 문서 출력과 함께 개발 예정
---
## 8. 승인 요청
**개발 범위:**
- Phase 1~4 전체 구현 (P3 문서 출력 제외)
- 예상 작업량: Phase별 순차 진행
**진행 조건:**
- 이 계획서 승인 후 Phase 1부터 순차 진행
- 각 Phase 완료 시 검증 후 다음 Phase 진행
- 커밋은 각 Phase 완료 시 승인 후 진행
---
**작성자:** Claude (AI Assistant)
**검토자:** (승인 대기)