docs: 견적 기능 개발 Phase 3 완료

- Phase 3 구현 문서 작성 (README, implementation, table-mapping)
- PROGRESS.md 업데이트 (Phase 3 완료 상태)
- getItemPrice() 연동, Price 모델 생성 기록
This commit is contained in:
2025-12-19 16:02:48 +09:00
parent 3721cfdc4b
commit 0eb96fcfc3
4 changed files with 566 additions and 15 deletions

View File

@@ -12,15 +12,15 @@
|-------|------|--------|--------|--------|
| Phase 1: 5130 분석 | ✅ 완료 | 100% | 2025-12-19 | 2025-12-19 |
| Phase 2: mng 분석 | ✅ 완료 | 100% | 2025-12-19 | 2025-12-19 |
| Phase 3: 구현 | ⏳ 대기 | 0% | - | - |
| Phase 3: 구현 | ✅ 완료 | 100% | 2025-12-19 | 2025-12-19 |
| Phase 4: API 개발 | ⏳ 대기 | 0% | - | - |
---
## 🔄 현재 작업
**현재 Phase:** Phase 2 완료, Phase 3 대기
**다음 작업:** mng 견적 기능 구현 (5130 수식 적용)
**현재 Phase:** Phase 3 완료, Phase 4 대기
**다음 작업:** 견적 API 개발
---
@@ -104,23 +104,38 @@
---
## 📋 Phase 3: mng 견적 기능 구현
## Phase 3: mng 견적 기능 구현 (완료)
### 체크리스트
- [ ] 테이블 매핑 (5130 → SAM)
- [ ] 수식 명세 작성
- [ ] UI 구현 (Livewire + Blade)
- [ ] 테스트 및 검증
- [ ] README.md 작성
- [x] 테이블 매핑 (5130 → SAM)
- [x] getItemPrice() 연동 구현
- [x] Price 모델 생성 (mng)
- [x] Seeder 확인 및 실행 방법 문서화
- [x] README.md 작성
### 산출물
- [ ] phase-3-implementation/README.md
- [ ] phase-3-implementation/table-mapping.md
- [ ] phase-3-implementation/formula-spec.md
- [ ] phase-3-implementation/implementation.md
- [x] [README.md](./phase-3-implementation/README.md) - 구현 요약
- [x] [table-mapping.md](./phase-3-implementation/table-mapping.md) - 테이블 매핑
- [x] [implementation.md](./phase-3-implementation/implementation.md) - 구현 상세
### 메모
_Phase 3 진행 시 메모 기록_
### 핵심 구현 내용
#### getItemPrice() 연동
**파일:** `mng/app/Services/Quote/FormulaEvaluatorService.php:324-335`
- prices 테이블 연동 완료
- 품목 코드 → 판매단가 조회 구현
#### Price 모델
**파일:** `mng/app/Models/Price.php`
- getCurrentPrice(): 현재 유효 단가 조회
- getSalesPriceByItemCode(): 품목 코드로 단가 조회
#### Seeder 실행 방법
```bash
cd /Users/hskwon/Works/@KD_SAM/SAM/api
php artisan db:seed --class=QuoteFormulaCategorySeeder
php artisan db:seed --class=QuoteFormulaSeeder
```
---

View File

@@ -0,0 +1,131 @@
# Phase 3: mng 견적 기능 구현
> **목표:** 5130 수식을 mng에 적용, 품목 단가 연동 완료
> **구현일:** 2025-12-19
> **상태:** ✅ 완료
---
## 체크리스트
- [x] getItemPrice() 연동 구현
- [x] Price 모델 생성 (mng)
- [x] Seeder 확인 및 실행 방법 문서화
- [x] 구현 문서 작성
- [ ] Seeder 실행 (수동 필요)
---
## 산출물
| 파일 | 설명 | 상태 |
|------|------|------|
| [README.md](./README.md) | 구현 요약 | ✅ |
| [implementation.md](./implementation.md) | 구현 상세 | ✅ |
| [table-mapping.md](./table-mapping.md) | 테이블 매핑 | ✅ |
---
## 구현 요약
### 1. Price 모델 생성
**파일:** `mng/app/Models/Price.php`
- prices 테이블 연동 모델
- `getCurrentPrice()`: 현재 유효 단가 조회
- `getSalesPriceByItemCode()`: 품목 코드로 판매단가 조회
### 2. getItemPrice() 연동
**파일:** `mng/app/Services/Quote/FormulaEvaluatorService.php:324-335`
```php
private function getItemPrice(string $itemCode): float
{
$tenantId = session('selected_tenant_id');
if (!$tenantId) {
$this->errors[] = "테넌트 ID가 설정되지 않았습니다.";
return 0;
}
return \App\Models\Price::getSalesPriceByItemCode($tenantId, $itemCode);
}
```
### 3. Seeder 실행 방법
```bash
# api 프로젝트에서 실행
cd /Users/hskwon/Works/@KD_SAM/SAM/api
# 카테고리 먼저
php artisan db:seed --class=QuoteFormulaCategorySeeder
# 수식 데이터
php artisan db:seed --class=QuoteFormulaSeeder
# 확인
php artisan tinker --execute="echo DB::table('quote_formula_categories')->count();"
php artisan tinker --execute="echo DB::table('quote_formulas')->count();"
```
---
## 5130 vs 현재 Seeder 비교
### 5130 분석 항목 (19개)
1. 검사비
2. 주자재 (스크린/슬랫)
3. 조인트바
4. 모터
5. 연동제어기
6. 케이스
7. 케이스용 연기차단재
8. 케이스 마구리
9. 모터 받침용 앵글
10. 가이드레일
11. 레일용 연기차단재
12. 하장바
13. L바
14. 보강평철
15. 감기샤프트
16. 무게평철
17. 환봉
18. 각파이프
19. 앵글
### 현재 Seeder 포함 항목
- ✅ 오픈사이즈 (W0, H0)
- ✅ 제작사이즈 (W1, H1)
- ✅ 면적 (M)
- ✅ 중량 (K)
- ✅ 가이드레일
- ✅ 케이스
- ✅ 모터
- ✅ 제어기
- ✅ 마구리
- ✅ 검사비
### 추가 필요 항목 (Phase 4 또는 추후)
- 조인트바, 연기차단재, 하장바, L바 등 세부 항목
---
## 다음 단계
1. **Seeder 실행** - 관리자가 직접 실행
2. **Phase 4: API 개발** - 견적 계산 REST API 구현
3. **5130 세부 수식 추가** - 추후 작업
---
## 참조
- [Phase 1: 5130 분석](../phase-1-5130-analysis/README.md)
- [Phase 2: mng 분석](../phase-2-mng-analysis/README.md)
- [MASTER_PLAN.md](../MASTER_PLAN.md)

View File

@@ -0,0 +1,226 @@
# Phase 3 구현 상세
> **구현일:** 2025-12-19
> **상태:** ✅ 완료
---
## 1. Price 모델 구현
### 파일 위치
`mng/app/Models/Price.php`
### 주요 기능
#### 상수 정의
```php
// 상태
const STATUS_DRAFT = 'draft';
const STATUS_ACTIVE = 'active';
const STATUS_INACTIVE = 'inactive';
const STATUS_FINALIZED = 'finalized';
// 품목 유형
const ITEM_TYPE_PRODUCT = 'PRODUCT';
const ITEM_TYPE_MATERIAL = 'MATERIAL';
// 반올림 규칙
const ROUNDING_ROUND = 'round';
const ROUNDING_CEIL = 'ceil';
const ROUNDING_FLOOR = 'floor';
```
#### getCurrentPrice() 메서드
```php
/**
* 특정 품목의 현재 유효 단가 조회
*
* @param int $tenantId 테넌트 ID
* @param string $itemTypeCode 품목 유형 (PRODUCT/MATERIAL)
* @param int $itemId 품목 ID
* @param int|null $clientGroupId 고객 그룹 ID (NULL = 기본가)
* @return Price|null
*/
public static function getCurrentPrice(
int $tenantId,
string $itemTypeCode,
int $itemId,
?int $clientGroupId = null
): ?self
```
**조회 조건:**
1. tenant_id 일치
2. item_type_code 일치 (PRODUCT/MATERIAL)
3. item_id 일치
4. client_group_id 일치 또는 NULL (기본가)
5. status = 'active'
6. effective_from <= 현재일
7. effective_to >= 현재일 또는 NULL
**우선순위:**
- 고객그룹 지정된 가격 > 기본가
- 최신 effective_from 우선
#### getSalesPriceByItemCode() 메서드
```php
/**
* 품목 코드로 현재 유효 판매단가 조회
* (quote_formula_items.item_code와 연동용)
*
* @param int $tenantId 테넌트 ID
* @param string $itemCode 품목 코드
* @return float 판매단가 (없으면 0)
*/
public static function getSalesPriceByItemCode(int $tenantId, string $itemCode): float
```
**조회 순서:**
1. products 테이블에서 code로 검색
2. 발견되면 → Price::getCurrentPrice() 호출
3. 미발견시 → materials 테이블에서 검색
4. 발견되면 → Price::getCurrentPrice() 호출
5. 미발견시 → 0 반환
---
## 2. getItemPrice() 연동
### 파일 위치
`mng/app/Services/Quote/FormulaEvaluatorService.php:324-335`
### 변경 전 (TODO 상태)
```php
private function getItemPrice(string $itemCode): float
{
// TODO: 품목 마스터에서 단가 조회
return 0;
}
```
### 변경 후 (구현 완료)
```php
private function getItemPrice(string $itemCode): float
{
$tenantId = session('selected_tenant_id');
if (!$tenantId) {
$this->errors[] = "테넌트 ID가 설정되지 않았습니다.";
return 0;
}
return \App\Models\Price::getSalesPriceByItemCode($tenantId, $itemCode);
}
```
### 동작 흐름
```
quote_formula_items.item_code
FormulaEvaluatorService::getItemPrice()
Price::getSalesPriceByItemCode()
├── products 테이블 검색 (code 컬럼)
└── materials 테이블 검색 (code 컬럼)
Price::getCurrentPrice()
prices.sales_price 반환
```
---
## 3. Seeder 현황
### 기존 Seeder 파일
| 파일 | 설명 | 데이터 수 |
|------|------|----------|
| `QuoteFormulaCategorySeeder.php` | 카테고리 | 11개 |
| `QuoteFormulaSeeder.php` | 수식 | ~30개 |
| `QuoteFormulaItemSeeder.php` | 품목 출력 | 미정 |
| `QuoteFormulaMappingSeeder.php` | 매핑 | 미정 |
### 카테고리 목록 (11개)
| 코드 | 이름 | 순서 |
|------|------|------|
| OPEN_SIZE | 오픈사이즈 | 1 |
| MAKE_SIZE | 제작사이즈 | 2 |
| AREA | 면적 | 3 |
| WEIGHT | 중량 | 4 |
| GUIDE_RAIL | 가이드레일 | 5 |
| CASE | 케이스 | 6 |
| MOTOR | 모터 | 7 |
| CONTROLLER | 제어기 | 8 |
| EDGE_WING | 마구리 | 9 |
| INSPECTION | 검사 | 10 |
| PRICE_FORMULA | 단가수식 | 11 |
### 실행 명령어
```bash
# api 디렉토리에서 실행
cd /Users/hskwon/Works/@KD_SAM/SAM/api
# 순차 실행 (의존성 순서)
php artisan db:seed --class=QuoteFormulaCategorySeeder
php artisan db:seed --class=QuoteFormulaSeeder
php artisan db:seed --class=QuoteFormulaItemSeeder
php artisan db:seed --class=QuoteFormulaMappingSeeder
# 또는 한번에
php artisan db:seed --class=QuoteFormulaCategorySeeder && \
php artisan db:seed --class=QuoteFormulaSeeder
```
---
## 4. 테스트 방법
### 1) 단가 조회 테스트
```bash
cd /Users/hskwon/Works/@KD_SAM/SAM/api
php artisan tinker
# 테스트
>>> \App\Models\Price::where('tenant_id', 1)->first()
>>> DB::table('products')->where('tenant_id', 1)->first()
```
### 2) 수식 실행 테스트
```bash
cd /Users/hskwon/Works/@KD_SAM/SAM/mng
# mng UI에서 시뮬레이터 접속
# URL: /quote-formulas/simulator
```
---
## 5. 변경 파일 목록
### 신규 생성
| 파일 | 설명 |
|------|------|
| `mng/app/Models/Price.php` | 가격 모델 |
| `docs/projects/quotation/phase-3-implementation/README.md` | Phase 3 README |
| `docs/projects/quotation/phase-3-implementation/implementation.md` | 구현 상세 |
| `docs/projects/quotation/phase-3-implementation/table-mapping.md` | 테이블 매핑 |
### 수정
| 파일 | 변경 내용 |
|------|----------|
| `mng/app/Services/Quote/FormulaEvaluatorService.php` | getItemPrice() 구현 |
| `docs/projects/quotation/PROGRESS.md` | Phase 3 상태 업데이트 |
---
## 참조
- [README.md](./README.md)
- [table-mapping.md](./table-mapping.md)
- [Phase 1: js-formulas.md](../phase-1-5130-analysis/js-formulas.md)
- [Phase 2: issues.md](../phase-2-mng-analysis/issues.md)

View File

@@ -0,0 +1,179 @@
# Phase 3 테이블 매핑
> **구현일:** 2025-12-19
> **정책 참조:** [PROJECT_DEVELOPMENT_POLICY.md](../../guides/PROJECT_DEVELOPMENT_POLICY.md)
---
## 1. 단가 테이블 매핑
### 5130 테이블 → SAM 테이블
| 5130 테이블 | SAM 테이블 | 상태 | 비고 |
|------------|-----------|------|------|
| `price_screen` | `prices` | ✅ 통합 | item_type_code='PRODUCT' |
| `price_slat` | `prices` | ✅ 통합 | item_type_code='PRODUCT' |
| `price_motor` | `prices` | ✅ 통합 | item_type_code='PRODUCT' |
| `price_controller` | `prices` | ✅ 통합 | item_type_code='PRODUCT' |
| `price_parts` | `prices` | ✅ 통합 | item_type_code='MATERIAL' |
### prices 테이블 구조
```sql
CREATE TABLE prices (
id BIGINT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
-- 품목 연결 (5130 분산 → SAM 통합)
item_type_code VARCHAR(20) NOT NULL, -- 'PRODUCT' / 'MATERIAL'
item_id BIGINT NOT NULL, -- products.id 또는 materials.id
client_group_id BIGINT NULL, -- 고객그룹별 단가 (NULL=기본가)
-- 원가 정보
purchase_price DECIMAL(15,4), -- 매입단가
processing_cost DECIMAL(15,4), -- 가공비
loss_rate DECIMAL(5,2), -- LOSS율 (%)
-- 판매가 정보
margin_rate DECIMAL(5,2), -- 마진율 (%)
sales_price DECIMAL(15,4), -- 판매단가 (★ 견적에서 사용)
-- 적용 기간
effective_from DATE NOT NULL,
effective_to DATE NULL,
-- 상태
status ENUM('draft','active','inactive','finalized'),
-- 감사
created_at, updated_at, deleted_at
);
```
---
## 2. 수식 테이블 매핑
### 5130 → SAM 구조 비교
| 5130 | SAM | 비고 |
|------|-----|------|
| JS 하드코딩 | `quote_formula_categories` | 카테고리 분류 |
| JS 하드코딩 | `quote_formulas` | 수식 정의 |
| PHP 함수 | `quote_formula_ranges` | 범위별 조건 |
| PHP 조건문 | `quote_formula_mappings` | 매핑 조건 |
| - | `quote_formula_items` | 품목 출력 |
### quote_formulas 테이블 구조
```sql
CREATE TABLE quote_formulas (
id BIGINT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
category_id BIGINT NOT NULL, -- FK: quote_formula_categories
product_id BIGINT NULL, -- 특정 제품용 (NULL=공통)
-- 수식 정보
name VARCHAR(200) NOT NULL,
variable VARCHAR(50) NOT NULL, -- 변수명 (W0, H0, M, K 등)
type ENUM('input','calculation','range','mapping'),
formula TEXT NULL, -- 계산식
output_type ENUM('variable','item'), -- 결과 유형
-- 메타
description TEXT,
sort_order INT,
is_active BOOLEAN DEFAULT TRUE,
-- 감사
created_at, updated_at, deleted_at
);
```
---
## 3. 품목 코드 매핑 로직
### 조회 흐름
```
quote_formula_items.item_code
FormulaEvaluatorService::getItemPrice($itemCode)
Price::getSalesPriceByItemCode($tenantId, $itemCode)
┌───────────────────────────────────────┐
│ 1. products 테이블 검색 │
│ WHERE tenant_id = $tenantId │
│ AND code = $itemCode │
│ AND deleted_at IS NULL │
└───────────────────────────────────────┘
↓ (발견시)
┌───────────────────────────────────────┐
│ Price::getCurrentPrice() │
│ item_type_code = 'PRODUCT' │
│ item_id = $product->id │
└───────────────────────────────────────┘
prices.sales_price 반환
```
### 품목 코드 규칙
| 분류 | 코드 형식 예시 | 설명 |
|------|--------------|------|
| 스크린 제품 | `KS-100-SC` | 스크린 주자재 |
| 철재 제품 | `KS-200-ST` | 철재(슬랫) 주자재 |
| 모터 | `MT-300K` | 모터 300K |
| 케이스 | `PT-CASE-2438` | 케이스 2438mm |
| 가이드레일 | `GR-65x80` | 가이드레일 65x80 |
---
## 4. 5130 수식 항목 → SAM 변수 매핑
### 기본 변수
| 5130 명칭 | SAM 변수 | 수식 유형 |
|----------|---------|----------|
| 오픈 가로 | W0 | input |
| 오픈 세로 | H0 | input |
| 제작 가로 | W1 | calculation |
| 제작 세로 | H1 | calculation |
| 면적 | M | calculation |
| 중량 | K | calculation |
### 항목별 변수
| 5130 항목 | SAM 변수 | 수식 유형 | 비고 |
|----------|---------|----------|------|
| 검사비 | INSP_FEE | calculation | 고정 1EA |
| 주자재 | MAT_PRICE | calculation | 면적 × 단가 |
| 모터 | MOTOR_SELECT | range | 중량 기준 선택 |
| 제어기 | CTRL_SELECT | mapping | 설치유형별 |
| 케이스 | CASE_SELECT | range | 길이 기준 선택 |
| 가이드레일 | GR_SELECT | range | 길이 기준 선택 |
| 마구리 | EDGE_QTY | calculation | 날개치수/50 |
---
## 5. 신규 테이블 생성 불필요
### 정책 준수 확인
| 항목 | 상태 | 비고 |
|------|------|------|
| 기존 테이블 활용 | ✅ | prices, quote_formulas 등 |
| 신규 테이블 생성 | ❌ 불필요 | 기존 구조 활용 |
| 컬럼 추가 | ❌ 불필요 | 기존 컬럼 활용 |
| DB 마이그레이션 | ❌ 불필요 | Seeder만 실행 |
---
## 참조
- [README.md](./README.md)
- [implementation.md](./implementation.md)
- [Phase 1: db-structure.md](../phase-1-5130-analysis/db-structure.md)
- [PROJECT_DEVELOPMENT_POLICY.md](../../guides/PROJECT_DEVELOPMENT_POLICY.md)