Files
hskwon 0eb96fcfc3 docs: 견적 기능 개발 Phase 3 완료
- Phase 3 구현 문서 작성 (README, implementation, table-mapping)
- PROGRESS.md 업데이트 (Phase 3 완료 상태)
- getItemPrice() 연동, Price 모델 생성 기록
2025-12-19 16:02:48 +09:00

5.3 KiB

Phase 3 구현 상세

구현일: 2025-12-19 상태: 완료


1. Price 모델 구현

파일 위치

mng/app/Models/Price.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() 메서드

/**
 * 특정 품목의 현재 유효 단가 조회
 *
 * @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() 메서드

/**
 * 품목 코드로 현재 유효 판매단가 조회
 * (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 상태)

private function getItemPrice(string $itemCode): float
{
    // TODO: 품목 마스터에서 단가 조회
    return 0;
}

변경 후 (구현 완료)

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

실행 명령어

# 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) 단가 조회 테스트

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) 수식 실행 테스트

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 상태 업데이트

참조