Files
sam-docs/features/quotes/README.md
권혁성 2bbf220dc8 docs:견적관리 분석 문서 및 INDEX 업데이트
- INDEX.md 업데이트
- 견적관리 URL 마이그레이션 계획 수정
- API 분석 리포트, tenant-id 준수 계획 추가
- 견적관리 기능 문서 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 20:37:04 +09:00

13 KiB
Raw Blame History

견적 시스템 분석 문서

목적: 견적 시스템의 비즈니스 로직과 데이터 흐름을 이해하고 검증하기 위한 문서

목차

  1. 개요
  2. 데이터베이스 구조
  3. 견적 생성 흐름
  4. BOM 계산 로직 (10단계)
  5. 경동기업 전용 로직
  6. 상태 관리
  7. 금액 계산 방식
  8. 관련 파일 목록

1. 개요

1.1 견적 유형

유형 코드 설명
제조 견적 manufacturing 스크린/철재 제품 제조 견적
시공 견적 construction 현장설명회 기반 시공 견적

1.2 제품 카테고리

카테고리 코드 설명
스크린 SCREEN 방화 스크린 제품
철재 STEEL 철재 제품

1.3 핵심 서비스 클래스

QuoteService                  ← 견적 CRUD, 상태 관리, 수주 전환
├── QuoteNumberService        ← 견적번호 생성 (KD-SC-YYMMDD-NN)
├── QuoteCalculationService   ← 자동산출 실행, BOM 계산 호출
└── FormulaEvaluatorService   ← 수식 평가, 10단계 BOM 계산
    └── KyungdongFormulaHandler ← 경동기업(tenant_id=287) 전용 계산

2. 데이터베이스 구조

2.1 테이블 관계도

┌─────────────────┐
│     quotes      │ ← 견적 마스터
├─────────────────┤
│ id              │
│ tenant_id       │──→ tenants
│ quote_number    │
│ quote_type      │ ← manufacturing | construction
│ status          │ ← pending→draft→finalized→converted
│ client_id       │──→ clients
│ item_id         │──→ items (완제품)
│ site_briefing_id│──→ site_briefings (시공 견적용)
│ order_id        │──→ orders (수주 전환 후)
│ calculation_inputs (JSON) │ ← 자동산출 입력값 + BOM 결과
│ options (JSON)  │ ← 세부산출, 비용항목, 할인 정보
└────────┬────────┘
         │ 1:N
         ▼
┌─────────────────┐
│   quote_items   │ ← 견적 품목 상세
├─────────────────┤
│ id              │
│ quote_id        │──→ quotes
│ tenant_id       │
│ item_id         │──→ items
│ item_code       │
│ item_name       │
│ calculated_quantity │
│ unit_price      │
│ total_price     │
│ formula         │ ← 수량 계산 수식
│ formula_category│ ← 카테고리 (material/labor/install)
└─────────────────┘

┌─────────────────┐
│ quote_revisions │ ← 수정 이력
├─────────────────┤
│ quote_id        │──→ quotes
│ revision_number │
│ previous_data (JSON) │ ← 수정 전 스냅샷
└─────────────────┘

2.2 quotes 테이블 주요 필드

필드명 타입 설명
quote_number VARCHAR(50) 견적번호 (예: KD-SC-251204-01)
quote_type ENUM manufacturing / construction
status ENUM 상태 (pending→draft→finalized→converted)
product_category ENUM SCREEN / STEEL
open_size_width INT 개구부 폭 (mm)
open_size_height INT 개구부 높이 (mm)
quantity INT 수량
material_cost DECIMAL 재료비 합계
labor_cost DECIMAL 노무비
install_cost DECIMAL 설치비
subtotal DECIMAL 소계
discount_rate DECIMAL 할인율 (%)
total_amount DECIMAL 최종 금액
calculation_inputs JSON 자동산출 입력값 및 BOM 결과 저장
options JSON 세부산출항목, 비용항목, 할인정보
is_final BOOLEAN 최종확정 여부

2.3 calculation_inputs JSON 구조

{
  "items": [
    {
      "floor": "B1",
      "code": "A-01",
      "openWidth": 3000,
      "openHeight": 2500,
      "quantity": 2,
      "productCategory": "SCREEN",
      "productName": "KD-SCREEN-001",
      "guideRailType": "wall",
      "motorPower": "single"
    }
  ],
  "bomResults": [
    {
      "index": 0,
      "finished_goods_code": "KD-SCREEN-001",
      "items": [
        {
          "item_code": "GUIDE-001",
          "item_name": "가이드레일",
          "quantity": 2.5,
          "unit_price": 50000,
          "total_price": 125000,
          "is_manual": false
        }
      ],
      "grand_total": 1250000
    }
  ]
}

3. 견적 생성 흐름

3.1 제조 견적 생성 흐름

[프론트엔드 - React]
        │
        ▼
1. 기본정보 입력 (거래처, 현장, 제품카테고리)
        │
        ▼
2. 위치별 규격 입력 (층/부호, 개구부 크기, 수량)
        │
        ▼
3. "견적 산출" 버튼 클릭
        │
        ▼
[API 호출: POST /api/v1/quotes/bom/calculate-bulk]
        │
        ▼
4. QuoteCalculationService.calculateBomBulk()
        │
        ├─→ 경동기업(287)? → KyungdongFormulaHandler
        │
        └─→ 기타 테넌트 → 표준 BOM 계산
        │
        ▼
5. 10단계 계산 결과 반환
        │
        ▼
6. 프론트엔드에서 결과 표시 (세부산출내역)
        │
        ▼
7. "저장" 또는 "최종확정" 버튼
        │
        ▼
[API 호출: POST /api/v1/quotes 또는 PUT /api/v1/quotes/{id}]
        │
        ▼
8. QuoteService.store() / update()
   - quotes 테이블에 마스터 정보 저장
   - quote_items 테이블에 품목 상세 저장
   - calculation_inputs에 입력값 + BOM 결과 저장

3.2 시공 견적 생성 흐름 (현장설명회 연계)

[현장설명회]
        │
        ▼
1. 현장설명회 참석완료 상태 변경
        │
        ▼
2. QuoteService.upsertFromSiteBriefing()
        │
        ▼
3. 견적 자동 생성 (status: pending)
   - 거래처, 현장 정보 복사
   - 금액 정보는 비어있음
        │
        ▼
4. 담당자가 견적 편집 화면에서 상세 입력
        │
        ▼
5. 저장 시 status: pending → draft 변경

4. BOM 계산 로직 (10단계)

4.1 계산 단계 개요

단계 명칭 설명
1 입력값수집 W0, H0, QTY, 옵션값 수집
2 완제품선택 완제품 코드로 items 테이블 조회
3 변수계산 W1, H1, AREA, WEIGHT 등 파생 변수 계산
4 BOM전개 완제품의 BOM 트리 전개
5 단가출처 품목별 단가 조회 (prices 테이블)
6 수량계산 수량 수식 평가 (변수 치환)
7 금액계산 수량 × 단가 = 금액
8 카테고리그룹화 item_category 기준 그룹화
9 소계계산 카테고리별 소계
10 최종합계 전체 합계 계산

4.2 변수 계산 (Step 3) 상세

기본 변수:
- W0: 개구부 폭 (mm) - 사용자 입력
- H0: 개구부 높이 (mm) - 사용자 입력
- QTY: 수량 - 사용자 입력

파생 변수 (스크린):
- W1 = W0 + 140  (제작 폭, 마진 140mm)
- H1 = H0 + 350  (제작 높이, 마진 350mm)
- M = (W1 × H1) / 1,000,000  (면적, ㎡)
- K = M × 2 + (W0 / 1000) × 14.17  (중량, kg)

파생 변수 (철재):
- W1 = W0 + 110  (마진 110mm)
- H1 = H0 + 350
- M = (W1 × H1) / 1,000,000
- K = M × 25  (철재 중량)

4.3 수량 수식 예시

BOM의 quantity_formula 필드에 저장된 수식:

고정값:     "1"
변수참조:   "QTY"
계산식:     "W1 / 1000"          → 가이드레일 길이
           "CEIL(H1 / 2000)"    → 분할 개수
           "M * 1.1"            → 면적 기반 수량 (여유 10%)

5. 경동기업 전용 로직

5.1 적용 조건

// tenant_id = 287 일 때만 적용
private const KYUNGDONG_TENANT_ID = 287;

if ($tenantId === self::KYUNGDONG_TENANT_ID) {
    return $this->calculateKyungdongBom(...);
}

5.2 KyungdongFormulaHandler 주요 기능

기능 설명
모터 용량 계산 제품타입 × 인치 × 중량 3차원 조건표
브라켓 크기 결정 중량 기준 브라켓 인치 결정
절곡품 계산 10종 절곡품 (케이스, 가이드레일, 하단바 등)
부자재 계산 3종 부자재 (볼트, 너트, 패킹 등)

5.3 경동기업 변수 계산

기본 변수:
- W0, H0, QTY: 사용자 입력
- bracket_inch: 브라켓 인치 (5", 6", 7")
- product_type: 제품 타입 (screen/steel)

파생 변수:
- W1 = W0 + 140
- H1 = H0 + 350
- AREA = (W0 × (H0 + 550)) / 1,000,000
- WEIGHT = AREA × 2 + (W0 / 1000) × 14.17  (스크린)
         = AREA × 25  (철재)
- MOTOR_CAPACITY: 모터 용량 (조건표 조회)
- BRACKET_SIZE: 브라켓 크기 (조건표 조회)

6. 상태 관리

6.1 견적 상태 흐름

pending ─────→ draft ─────→ finalized ─────→ converted
(견적대기)     (작성중)      (최종확정)        (수주전환)
    │              │              │
    │              ▼              │
    │          sent ────────────→│
    │         (발송됨)             │
    │              │              │
    │              ▼              │
    │         approved            │
    │         (승인됨)             │
    │              │              │
    └──────────────┴──────────────┘
                   │
                   ▼
              rejected
              (거절됨)

6.2 상태별 가능 작업

상태 수정 삭제 확정 수주전환
pending - -
draft -
sent -
approved -
finalized - - -
converted - - - -
rejected - -

7. 금액 계산 방식

7.1 카테고리 기반 단가 계산

CategoryGroup 모델을 사용하여 품목 카테고리별 단가 계산 방식 결정:

카테고리 그룹 계산 방식 수식
area_based 면적 기반 단가 × M (면적)
weight_based 중량 기반 단가 × K (중량)
quantity_based 수량 기반 단가 × 수량

7.2 총 금액 계산

material_cost = SUM(재료비 카테고리 품목의 total_price)
labor_cost = SUM(노무비 카테고리 품목의 total_price)
install_cost = SUM(설치비 카테고리 품목의 total_price)

subtotal = material_cost + labor_cost + install_cost
discount_amount = subtotal × (discount_rate / 100)
total_amount = subtotal - discount_amount

7.3 단가 조회 우선순위

  1. prices 테이블 (Price::getSalesPriceByItemCode)
  2. items.attributes.salesPrice (JSON 필드)
  3. 기본값 0

8. 관련 파일 목록

8.1 백엔드 (API)

app/Services/Quote/
├── QuoteService.php              ← 견적 CRUD, 상태 관리
├── QuoteCalculationService.php   ← BOM 계산 진입점
├── QuoteNumberService.php        ← 견적번호 생성
├── QuoteDocumentService.php      ← 견적서/거래명세서 PDF
├── FormulaEvaluatorService.php   ← 수식 평가, 10단계 계산
└── Handlers/
    └── KyungdongFormulaHandler.php ← 경동기업 전용

app/Models/Quote/
├── Quote.php           ← 견적 마스터 모델
├── QuoteItem.php       ← 견적 품목 모델
├── QuoteRevision.php   ← 수정 이력 모델
├── QuoteFormula.php    ← 수식 정의 모델
├── QuoteFormulaCategory.php
├── QuoteFormulaRange.php
├── QuoteFormulaMapping.php
└── QuoteFormulaItem.php

database/migrations/
├── 2025_12_04_164542_create_quotes_table.php
└── 2025_12_04_133410_create_quote_formula_tables.php

8.2 프론트엔드 (React)

react/src/components/quotes/
├── types.ts              ← 타입 정의 (LocationItem, BomCalculationResult)
├── actions.ts            ← API 액션 (calculateBomBulk)
├── QuoteFooterBar.tsx    ← 하단 버튼바 (견적서보기, 저장, 최종확정)
├── FormulaViewModal.tsx  ← 수식 보기 모달 (개발용)
└── ...

9. 검증 체크리스트

9.1 데이터 정합성 검증

  • quotes.total_amount = subtotal - discount_amount
  • quotes.subtotal = material_cost + labor_cost + install_cost
  • quote_items의 합계 = quotes의 비용 합계
  • calculation_inputs.bomResults의 grand_total = 품목 합계

9.2 상태 전이 검증

  • pending → draft: 첫 수정 시 자동 전환
  • draft → finalized: 확정 버튼 클릭 + total_amount > 0
  • finalized → converted: 수주 전환 시 + order_id 설정

9.3 BOM 계산 검증

  • W1 = W0 + 마진값 (SCREEN: 140, STEEL: 110)
  • H1 = H0 + 350
  • 면적(M) = (W1 × H1) / 1,000,000
  • 중량(K) 계산식 제품타입별 확인
  • 수량 수식의 변수 치환 정확성
  • 단가 조회 우선순위 준수

문서 작성일: 2026-01-29 작성자: Claude Code