From 659a33c37a025165fe9024bb55e5453994f63a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Fri, 20 Mar 2026 08:17:14 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20[pricing]=20=EB=8B=A8=EA=B0=80=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84=20=EA=B4=80=EB=A6=AC=20=EC=8B=9C=EC=8A=A4?= =?UTF-8?q?=ED=85=9C=20=EA=B8=B0=ED=9A=8D=EC=84=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - price_versions / price_version_items 테이블 설계 - 버전 생명주기 (draft→review→approved→active→archived) - 일괄 단가 변경, 영향 분석, 버전 비교 기능 설계 - 4 Phase 구현 계획 (기반→핵심→분석+UI→고도화) - 기존 시스템 하위 호환성 보장 전략 --- INDEX.md | 1 + .../price-version-management-plan.md | 474 ++++++++++++++++++ 2 files changed, 475 insertions(+) create mode 100644 dev/dev_plans/price-version-management-plan.md diff --git a/INDEX.md b/INDEX.md index 2a2969f..ddaef71 100644 --- a/INDEX.md +++ b/INDEX.md @@ -21,6 +21,7 @@ | 이메일 연동 | `dev/guides/tenant-email-integration-guide.md` | 테넌트 메일 연동, SMTP 프리셋, MNG 관리 | | 품목관리 | `rules/item-policy.md` | 품목 정책 | | 단가관리 | `rules/pricing-policy.md` | 6 Depth 단가 체계, 흐름도, 계산공식, 버전관리 개선방향 | +| 단가 버전관리 기획 | `dev/dev_plans/price-version-management-plan.md` | 단가 버전 그룹, 일괄변경, 영향분석, 적용 워크플로우 | | 견적관리 | `features/quotes/README.md` | 견적 시스템, BOM 계산 | | 급여관리 API | `frontend/api-specs/payroll-api.md` | 급여관리 API 전체 명세 (18개 엔드포인트) | | 바로빌 회계 API | `frontend/api-specs/barobill-api.md` | 카드/은행/홈택스 REST API (42개 엔드포인트) | diff --git a/dev/dev_plans/price-version-management-plan.md b/dev/dev_plans/price-version-management-plan.md new file mode 100644 index 0000000..5e86026 --- /dev/null +++ b/dev/dev_plans/price-version-management-plan.md @@ -0,0 +1,474 @@ +# 단가 버전 관리 시스템 기획 + +> **작성일**: 2026-03-20 +> **상태**: 기획 +> **관련 정책**: [단가 정책](../../rules/pricing-policy.md) §10 개선방향 + +--- + +## 1. 배경 + +### 1.1 현재 시스템 + +| 기능 | 현재 상태 | +|------|----------| +| 시간 기반 유효기간 (effective_from/to) | ✅ 구현 | +| 개별 리비전 이력 (price_revisions) | ✅ 구현 | +| 고객그룹 차등가 | ✅ 구현 | +| 무기한 단가 자동 종료 | ✅ 구현 | +| 확정 후 불변 (finalized) | ✅ 구현 | + +### 1.2 현재 한계 + +| 문제 | 영향 | +|------|------| +| 품목별 개별 수정만 가능 | 원자재 인상 시 수백 건 수동 변경 | +| 변경 전 영향 분석 불가 | 마진 축소/확대를 사전에 파악 못함 | +| 버전 개념 없음 | "2026년 Q2 단가" 같은 그룹 관리 불가 | +| 이전 단가로 롤백 불가 | 잘못 적용 시 전부 수동 복원 | +| 견적/수주 시점 원가 역추적 불가 | 수주 마진 사후 분석이 어려움 | + +--- + +## 2. 목표 + +``` +분기/반기 단위로 "단가 버전"을 생성하여 + → 이전 버전 복사 → 변경 대상 품목 수정 + → 영향 분석 → 승인 → 예약 적용 + → 이전 버전 자동 보관 +``` + +--- + +## 3. 시스템 설계 + +### 3.1 신규 테이블 + +#### price_versions (단가 버전) + +```sql +CREATE TABLE price_versions ( + id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT UNSIGNED NOT NULL, + + -- 버전 정보 -- + version_code VARCHAR(30) NOT NULL COMMENT '버전 코드 (v2026-Q2)', + version_name VARCHAR(100) NOT NULL COMMENT '버전명 (2026년 2분기 단가)', + description TEXT NULL COMMENT '변경 요약', + + -- 계보 -- + parent_version_id BIGINT UNSIGNED NULL COMMENT '기반 버전 ID', + + -- 적용 일정 -- + effective_from DATE NOT NULL COMMENT '적용 시작일', + effective_to DATE NULL COMMENT '적용 종료일', + + -- 상태 -- + status ENUM('draft','review','approved','active','archived') + DEFAULT 'draft', + approved_by BIGINT UNSIGNED NULL, + approved_at DATETIME NULL, + activated_at DATETIME NULL, + archived_at DATETIME NULL, + + -- 변경 통계 (승인 시 계산) -- + summary JSON NULL COMMENT '변경 요약 통계', + -- summary 구조: + -- { total_items: 150, changed_items: 23, + -- increased: 15, decreased: 5, unchanged: 3, + -- avg_change_rate: 3.2, max_increase: "가이드레일 +12.5%" } + + -- 감사 -- + created_by BIGINT UNSIGNED NULL, + updated_by BIGINT UNSIGNED NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted_at TIMESTAMP NULL, + + UNIQUE idx_version_code (tenant_id, version_code, deleted_at), + INDEX idx_version_status (tenant_id, status) +); +``` + +#### price_version_items (버전별 품목 단가) + +```sql +CREATE TABLE price_version_items ( + id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT UNSIGNED NOT NULL, + version_id BIGINT UNSIGNED NOT NULL, + + -- 품목 -- + item_type_code VARCHAR(20) NOT NULL, + item_id BIGINT UNSIGNED NOT NULL, + client_group_id BIGINT UNSIGNED NULL, + + -- 단가 정보 (prices 테이블과 동일 구조) -- + purchase_price DECIMAL(15,4) NULL, + processing_cost DECIMAL(15,4) NULL, + loss_rate DECIMAL(5,2) NULL, + margin_rate DECIMAL(5,2) NULL, + sales_price DECIMAL(15,4) NULL, + rounding_rule ENUM('round','ceil','floor') DEFAULT 'round', + rounding_unit INT DEFAULT 1, + supplier VARCHAR(255) NULL, + + -- 변경 추적 -- + change_type ENUM('unchanged','increased','decreased','new','removed') + DEFAULT 'unchanged', + prev_sales_price DECIMAL(15,4) NULL COMMENT '이전 버전 판매단가', + change_rate DECIMAL(8,4) NULL COMMENT '변동률 (%)', + + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + FOREIGN KEY (version_id) REFERENCES price_versions(id) ON DELETE CASCADE, + UNIQUE idx_version_item (version_id, item_type_code, item_id, client_group_id), + INDEX idx_change_type (version_id, change_type) +); +``` + +### 3.2 기존 테이블 변경 + +#### prices 테이블 추가 컬럼 + +```sql +ALTER TABLE prices + ADD COLUMN version_id BIGINT UNSIGNED NULL COMMENT '소속 버전 ID' AFTER client_group_id, + ADD INDEX idx_prices_version (tenant_id, version_id); +``` + +### 3.3 ERD + +``` +┌──────────────────┐ +│ price_versions │ ← 버전 마스터 +│ (v2026-Q1 등) │ +└────────┬─────────┘ + │ 1:N + ┌────┴─────────────────┐ + │ │ + ▼ ▼ +┌──────────────────┐ ┌──────────┐ +│price_version_items│ │ prices │ ← 활성 버전 적용 시 생성/갱신 +│ (버전별 품목단가) │ │(단가마스터)│ +└──────────────────┘ └──────────┘ + │ 1:N + ▼ + ┌──────────────┐ + │price_revisions│ + └──────────────┘ +``` + +--- + +## 4. 버전 생명주기 + +### 4.1 상태 전이 + +``` +draft ──→ review ──→ approved ──→ active ──→ archived +(작성) (검토) (승인) (적용중) (보관) + +언제든 draft로 돌아갈 수 있음 (active/archived 제외) +``` + +### 4.2 각 상태별 동작 + +| 상태 | 설명 | 가능한 작업 | +|------|------|-----------| +| `draft` | 작성 중, 품목 단가 자유 수정 | 품목 추가/수정/삭제, 영향 분석 | +| `review` | 검토 요청, 영향 분석 확정 | 조회, 승인/반려 | +| `approved` | 승인됨, 적용 대기 | 적용 예약, 즉시 적용 | +| `active` | 현재 적용 중인 버전 | 조회만 (수정 불가) | +| `archived` | 새 버전으로 대체됨 | 조회만 (이력 보관) | + +### 4.3 워크플로우 + +``` +1. 신규 버전 생성 + └→ 이전 active 버전의 모든 품목 단가를 복사 + └→ status = 'draft' + +2. 단가 수정 (draft 상태에서) + └→ 개별 수정: 특정 품목 매입단가/마진율 등 변경 + └→ 일괄 수정: 품목 유형별 일괄 인상/인하 (예: 원자재 전체 +5%) + └→ 변경 시 change_type, change_rate 자동 계산 + +3. 영향 분석 실행 + └→ 변경된 품목 수, 인상/인하 비율 + └→ 기존 미확정 견적에 미치는 영향 + └→ 마진 변동 시뮬레이션 + +4. 검토 요청 (draft → review) + └→ 분석 결과를 summary JSON에 저장 + +5. 승인 (review → approved) + └→ approved_by, approved_at 기록 + +6. 적용 (approved → active) + └→ price_version_items → prices 테이블 반영 + └→ 기존 active 버전 → archived 전환 + └→ 기존 prices의 effective_to 자동 설정 + └→ 새 prices의 effective_from = 버전의 effective_from +``` + +--- + +## 5. 핵심 기능 + +### 5.1 버전 생성 (이전 버전 복사) + +```php +// PriceVersionService::createFromVersion($parentVersionId) +1. parent_version의 모든 price_version_items 조회 +2. 새 version 생성 (parent_version_id = 원본) +3. 모든 items 복사 (change_type = 'unchanged') +``` + +### 5.2 일괄 단가 변경 + +```php +// PriceVersionService::bulkAdjust($versionId, $criteria, $adjustment) +// 예: 원자재(RM) 전체 매입단가 +5% + +$criteria = [ + 'item_type_code' => 'RM', // 원자재만 + 'supplier' => '(주)한국철강', // 특정 공급업체 (선택) +]; +$adjustment = [ + 'type' => 'percentage', // percentage | fixed + 'field' => 'purchase_price', // 변경 대상 필드 + 'value' => 5.0, // +5% + 'recalculate_sales_price' => true, // 판매단가 자동 재계산 +]; +``` + +### 5.3 영향 분석 + +```php +// PriceVersionService::analyze($versionId) +// 반환 구조: +{ + "version": { "code": "v2026-Q2", "name": "2026년 2분기 단가" }, + "changes": { + "total_items": 150, + "changed": 23, + "increased": 15, + "decreased": 5, + "new": 3, + "removed": 0 + }, + "price_impact": { + "avg_change_rate": 3.2, + "max_increase": { "item": "가이드레일 STS304", "rate": 12.5 }, + "max_decrease": { "item": "볼트 M8", "rate": -3.0 } + }, + "affected_quotes": [ + { + "quote_id": 789, + "quote_number": "KD-SC-260301-01", + "status": "draft", + "current_total": 1250000, + "projected_total": 1295000, + "diff": "+45,000 (+3.6%)" + } + ], + "margin_simulation": { + "current_avg_margin": 25.3, + "projected_avg_margin": 23.1, + "margin_change": -2.2 + } +} +``` + +### 5.4 버전 적용 (Activation) + +```php +// PriceVersionService::activate($versionId) +DB::transaction(function () { + // 1. 기존 active 버전 → archived + // 2. price_version_items 각각에 대해: + // - 기존 prices의 effective_to 설정 (적용일 -1일) + // - 새 prices 레코드 생성 (version_id 포함) + // - price_revisions 기록 + // 3. 새 버전 status = 'active', activated_at = now() +}); +``` + +### 5.5 버전 비교 + +```php +// PriceVersionService::compare($versionA, $versionB) +// 두 버전 간 품목별 단가 차이 리스트 +[ + { + "item_code": "GR-STS304-50", + "item_name": "가이드레일 STS304 50mm", + "version_a": { "sales_price": 15800, "margin_rate": 25 }, + "version_b": { "sales_price": 17400, "margin_rate": 25 }, + "diff": { "sales_price": "+1600 (+10.1%)", "margin_rate": "0%" } + } +] +``` + +--- + +## 6. API 엔드포인트 + +| Method | Endpoint | 설명 | +|--------|----------|------| +| GET | `/api/v1/price-versions` | 버전 목록 | +| POST | `/api/v1/price-versions` | 신규 버전 (빈 버전 또는 복사) | +| GET | `/api/v1/price-versions/{id}` | 버전 상세 + 통계 | +| PUT | `/api/v1/price-versions/{id}` | 버전 메타 수정 (이름, 적용일 등) | +| DELETE | `/api/v1/price-versions/{id}` | 버전 삭제 (draft만) | +| GET | `/api/v1/price-versions/{id}/items` | 버전 내 품목 단가 목록 | +| PUT | `/api/v1/price-versions/{id}/items/{itemId}` | 개별 품목 단가 수정 | +| POST | `/api/v1/price-versions/{id}/bulk-adjust` | 일괄 단가 변경 | +| POST | `/api/v1/price-versions/{id}/analyze` | 영향 분석 | +| POST | `/api/v1/price-versions/{id}/submit-review` | 검토 요청 | +| POST | `/api/v1/price-versions/{id}/approve` | 승인 | +| POST | `/api/v1/price-versions/{id}/activate` | 적용 | +| GET | `/api/v1/price-versions/compare` | 버전 비교 (?a=1&b=2) | +| GET | `/api/v1/price-versions/active` | 현재 적용 중인 버전 | + +--- + +## 7. UI 화면 구성 + +### 7.1 버전 목록 + +``` +┌──────────────────────────────────────────────────────────────┐ +│ 단가 버전 관리 [+ 신규 버전] │ +├──────┬──────────────┬──────────┬────────┬─────────┬─────────┤ +│ 상태 │ 버전코드 │ 버전명 │ 적용일 │ 변경품목 │ 평균변동 │ +├──────┼──────────────┼──────────┼────────┼─────────┼─────────┤ +│🟢활성│ v2026-Q1 │ 1분기단가 │ 01-01 │ — │ — │ +│🟡승인│ v2026-Q2 │ 2분기단가 │ 04-01 │ 23건 │ +3.2% │ +│⚪작성│ v2026-H2 │ 하반기단가 │ 07-01 │ 작성중 │ — │ +│🔘보관│ v2025-Q4 │ 4분기단가 │ 10-01 │ 18건 │ +1.5% │ +└──────┴──────────────┴──────────┴────────┴─────────┴─────────┘ +``` + +### 7.2 버전 상세 (품목 단가 편집) + +``` +┌──────────────────────────────────────────────────────────────┐ +│ v2026-Q2 | 2026년 2분기 단가 | 상태: 작성중 │ +│ 적용 예정일: 2026-04-01 │ +├──────────────────────────────────────────────────────────────┤ +│ [일괄변경▼] [영향분석] [검토요청] │ +│ │ +│ 필터: [전체▼] [변경된 항목만 ☐] │ +├──────┬──────────┬────────┬────────┬────────┬────────┬───────┤ +│ 변동 │ 품목명 │ 매입단가 │ 마진율 │ 이전단가 │ 신규단가 │ 변동률 │ +├──────┼──────────┼────────┼────────┼────────┼────────┼───────┤ +│ 🔺 │ 가이드레일 │ 11,200 │ 25% │ 15,800 │ 17,400 │+10.1% │ +│ 🔺 │ 케이스 │ 8,500 │ 25% │ 12,300 │ 13,100 │ +6.5% │ +│ — │ 모터 0.4kW│ 45,000 │ 30% │ 58,500 │ 58,500 │ 0% │ +│ 🔻 │ 볼트 M8 │ 120 │ 20% │ 155 │ 150 │ -3.2% │ +└──────┴──────────┴────────┴────────┴────────┴────────┴───────┘ +``` + +### 7.3 영향 분석 결과 + +``` +┌──────────────────────────────────────────────────────────────┐ +│ 영향 분석 | v2026-Q1 → v2026-Q2 │ +├──────────────────────────────────────────────────────────────┤ +│ │ +│ 전체 품목: 150건 │ +│ ├ 인상: 15건 (평균 +5.8%) │ +│ ├ 인하: 5건 (평균 -2.1%) │ +│ ├ 신규: 3건 │ +│ └ 변동없음: 127건 │ +│ │ +│ 평균 마진율: 25.3% → 23.1% (▼ 2.2%p) │ +│ │ +│ 영향받는 미확정 견적: 3건 │ +│ ├ KD-SC-260301-01 (draft) 1,250,000 → 1,295,000 (+3.6%) │ +│ ├ KD-SC-260305-02 (draft) 890,000 → 912,000 (+2.5%) │ +│ └ KD-SC-260312-01 (sent) 750,000 → 780,000 (+4.0%) │ +│ │ +│ ※ 확정/수주전환 완료된 건은 영향 없음 (복제된 단가 사용) │ +│ │ +│ [닫기] [검토 요청 →] │ +└──────────────────────────────────────────────────────────────┘ +``` + +--- + +## 8. 구현 계획 + +### Phase 1: 기반 구조 (1주) + +| 작업 | 내용 | +|------|------| +| DB | `price_versions`, `price_version_items` 테이블 생성 | +| DB | `prices` 테이블에 `version_id` 컬럼 추가 | +| Model | PriceVersion, PriceVersionItem 모델 생성 | +| Service | PriceVersionService 기본 CRUD | +| API | 버전 CRUD 엔드포인트 | + +### Phase 2: 핵심 기능 (1주) + +| 작업 | 내용 | +|------|------| +| 복사 | 이전 버전 기반 신규 버전 생성 (전체 복사) | +| 수정 | 개별/일괄 단가 변경 + change_type/change_rate 자동 계산 | +| 적용 | 버전 활성화 → prices 테이블 반영 + 기존 버전 보관 | +| 비교 | 두 버전 간 품목별 차이 조회 | + +### Phase 3: 분석 + UI (1주) + +| 작업 | 내용 | +|------|------| +| 분석 | 영향 분석 API (변경 통계, 견적 영향, 마진 시뮬레이션) | +| UI | React 버전 목록/상세/편집 화면 | +| UI | 영향 분석 다이얼로그 | +| UI | 버전 비교 화면 | + +### Phase 4: 고도화 (선택) + +| 작업 | 내용 | +|------|------| +| 예약 적용 | effective_from 날짜에 자동 활성화 (스케줄러) | +| 결재 연동 | 승인 프로세스를 결재관리와 연동 | +| 견적 스냅샷 | 견적/수주 생성 시 적용된 버전 정보 기록 | +| 알림 | 적용 예정 알림, 승인 요청 알림 | + +--- + +## 9. 기존 시스템과의 호환 + +### 9.1 하위 호환성 + +| 기존 기능 | 영향 | 대응 | +|----------|------|------| +| `Price::getCurrentPrice()` | 변경 없음 | version_id 무관하게 effective 기반 조회 유지 | +| `EstimatePriceService` | 변경 없음 | 기존 prices 테이블 조회 로직 그대로 | +| 개별 단가 CRUD | 유지 | 버전에 속하지 않는 개별 단가도 계속 가능 | +| 기존 리비전 | 유지 | 버전 적용 시에도 price_revisions 자동 기록 | + +### 9.2 전환 전략 + +``` +1단계: price_versions 테이블 생성, 기존 시스템 영향 없음 +2단계: 현재 모든 active 단가를 "v1 (초기 버전)"으로 그룹핑 +3단계: 이후 단가 변경은 버전 단위로 관리 권장 (개별 수정도 허용) +``` + +--- + +## 관련 문서 + +- [단가 정책](../../rules/pricing-policy.md) — 6 Depth 단가 체계 +- [단가 수정 가이드](../../guides/pricing-modification-guide.md) — 현재 수정 절차 +- [견적 시스템](../../features/quotes/README.md) — BOM 산출 흐름 + +--- + +**최종 업데이트**: 2026-03-20