Files
sam-api/app/Models/CategoryGroup.php
kent 7566814876 feat: Phase 1.1 - MNG 견적 계산 로직 API 동기화
- CategoryGroup 모델 추가 (카테고리별 단가 계산)
- FormulaEvaluatorService에 10단계 BOM 계산 로직 추가
- calculateBomWithDebug, calculateCategoryPrice 등 주요 메서드 구현
- MNG 시뮬레이터와 동일한 계산 결과 보장

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 23:45:22 +09:00

134 lines
3.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Models;
use App\Models\Tenants\Tenant;
use App\Traits\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* 카테고리 그룹 모델
*
* 품목 카테고리별 단가 계산 방식(면적/중량/수량 기반) 분류
* MNG 시뮬레이터와 동기화를 위한 핵심 테이블
*/
class CategoryGroup extends Model
{
use BelongsToTenant;
protected $table = 'category_groups';
protected $fillable = [
'tenant_id',
'code',
'name',
'multiplier_variable',
'categories',
'description',
'sort_order',
'is_active',
];
protected function casts(): array
{
return [
'categories' => '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,
];
}
}