feat: 견적 산출 서비스 prices 테이블 연동
- Price 모델에 getCurrentPrice(), getSalesPriceByItemCode() 메서드 추가 - Price 모델에 STATUS_*, ITEM_TYPE_* 상수 추가 - QuoteCalculationService에 setTenantId(), getUnitPrice() 메서드 추가 - 스크린 품목 단가: 원단, 케이스, 브라켓, 인건비 prices 조회로 변경 - 철재 품목 단가: 철판, 용접, 표면처리, 가공비 prices 조회로 변경 - 모터 용량별 단가: 50W~300W prices 조회로 변경 - 모든 단가는 prices 조회 실패 시 기존 하드코딩 값을 fallback으로 사용
This commit is contained in:
@@ -16,6 +16,24 @@ class Price extends Model
|
||||
|
||||
protected $table = 'prices';
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// Constants
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
// 상태
|
||||
public const STATUS_DRAFT = 'draft';
|
||||
|
||||
public const STATUS_ACTIVE = 'active';
|
||||
|
||||
public const STATUS_INACTIVE = 'inactive';
|
||||
|
||||
public const STATUS_FINALIZED = 'finalized';
|
||||
|
||||
// 품목 유형
|
||||
public const ITEM_TYPE_PRODUCT = 'PRODUCT';
|
||||
|
||||
public const ITEM_TYPE_MATERIAL = 'MATERIAL';
|
||||
|
||||
protected $fillable = [
|
||||
'tenant_id',
|
||||
'item_type_code',
|
||||
@@ -218,4 +236,93 @@ public function toSnapshot(): array
|
||||
'is_final' => $this->is_final,
|
||||
];
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// Static Query Methods (견적 산출용)
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* 특정 품목의 현재 유효 단가 조회
|
||||
*
|
||||
* @param int $tenantId 테넌트 ID
|
||||
* @param string $itemTypeCode 품목 유형 (PRODUCT/MATERIAL)
|
||||
* @param int $itemId 품목 ID
|
||||
* @param int|null $clientGroupId 고객 그룹 ID (NULL = 기본가)
|
||||
*/
|
||||
public static function getCurrentPrice(
|
||||
int $tenantId,
|
||||
string $itemTypeCode,
|
||||
int $itemId,
|
||||
?int $clientGroupId = null
|
||||
): ?self {
|
||||
$today = now()->toDateString();
|
||||
|
||||
$query = static::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('item_type_code', $itemTypeCode)
|
||||
->where('item_id', $itemId)
|
||||
->whereIn('status', [self::STATUS_ACTIVE, self::STATUS_FINALIZED])
|
||||
->where('effective_from', '<=', $today)
|
||||
->where(function ($q) use ($today) {
|
||||
$q->whereNull('effective_to')
|
||||
->orWhere('effective_to', '>=', $today);
|
||||
});
|
||||
|
||||
// 고객그룹 지정된 가격 우선, 없으면 기본가
|
||||
if ($clientGroupId) {
|
||||
$groupPrice = (clone $query)
|
||||
->where('client_group_id', $clientGroupId)
|
||||
->orderByDesc('effective_from')
|
||||
->first();
|
||||
|
||||
if ($groupPrice) {
|
||||
return $groupPrice;
|
||||
}
|
||||
}
|
||||
|
||||
// 기본가 (client_group_id = NULL)
|
||||
return $query
|
||||
->whereNull('client_group_id')
|
||||
->orderByDesc('effective_from')
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* 품목 코드로 현재 유효 판매단가 조회
|
||||
* (quote_formula_items.item_code와 연동용)
|
||||
*
|
||||
* @param int $tenantId 테넌트 ID
|
||||
* @param string $itemCode 품목 코드
|
||||
* @return float 판매단가 (없으면 0)
|
||||
*/
|
||||
public static function getSalesPriceByItemCode(int $tenantId, string $itemCode): float
|
||||
{
|
||||
// products 테이블에서 품목 코드로 검색
|
||||
$product = \Illuminate\Support\Facades\DB::table('products')
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('code', $itemCode)
|
||||
->whereNull('deleted_at')
|
||||
->first();
|
||||
|
||||
if ($product) {
|
||||
$price = static::getCurrentPrice($tenantId, self::ITEM_TYPE_PRODUCT, $product->id);
|
||||
|
||||
return (float) ($price?->sales_price ?? 0);
|
||||
}
|
||||
|
||||
// materials 테이블에서도 검색
|
||||
$material = \Illuminate\Support\Facades\DB::table('materials')
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('code', $itemCode)
|
||||
->whereNull('deleted_at')
|
||||
->first();
|
||||
|
||||
if ($material) {
|
||||
$price = static::getCurrentPrice($tenantId, self::ITEM_TYPE_MATERIAL, $material->id);
|
||||
|
||||
return (float) ($price?->sales_price ?? 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user