'array', 'sort_order' => 'integer', 'is_active' => 'boolean', ]; } /** * 단가 계산 방식 상수 */ public const CODE_AREA_BASED = 'area_based'; // 면적 기반 (M) public const CODE_WEIGHT_BASED = 'weight_based'; // 중량 기반 (K) public const CODE_QUANTITY_BASED = 'quantity_based'; // 수량 기반 (null) /** * 곱셈 변수 상수 */ public const MULTIPLIER_AREA = 'M'; // 면적 (㎡) public const MULTIPLIER_WEIGHT = 'K'; // 중량 (kg) /** * 테넌트 관계 */ public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class); } /** * 품목 카테고리로 해당 그룹 조회 * * @param int $tenantId 테넌트 ID * @param string $itemCategory 품목분류 (원단, 패널, 도장 등) */ public static function findByItemCategory(int $tenantId, string $itemCategory): ?self { return static::where('tenant_id', $tenantId) ->where('is_active', true) ->whereJsonContains('categories', $itemCategory) ->first(); } /** * 곱셈 변수 값 계산 * * @param array $variables 계산 변수 배열 ['M' => 6.099, 'K' => 25.5, ...] * @return float 곱셈 값 (없으면 1) */ public function getMultiplierValue(array $variables): float { if (empty($this->multiplier_variable)) { return 1.0; } return (float) ($variables[$this->multiplier_variable] ?? 1.0); } /** * 단가 계산 * * @param float $basePrice 기본 단가 * @param array $variables 계산 변수 배열 * @return array ['final_price' => float, 'calculation_note' => string, 'multiplier' => float] */ public function calculatePrice(float $basePrice, array $variables): array { $multiplier = $this->getMultiplierValue($variables); if ($multiplier === 1.0) { return [ 'final_price' => $basePrice, 'calculation_note' => '수량단가', 'multiplier' => 1.0, ]; } $unit = match ($this->multiplier_variable) { self::MULTIPLIER_AREA => '㎡', self::MULTIPLIER_WEIGHT => 'kg', default => '', }; return [ 'final_price' => $basePrice * $multiplier, 'calculation_note' => sprintf( '%s (%s원/%s × %.3f%s)', $this->name, number_format($basePrice), $unit, $multiplier, $unit ), 'multiplier' => $multiplier, ]; } }