# 견적관리 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) **검토자:** (승인 대기)