fix: 경동 BOM 계산 수정 및 품목-공정 매핑
- KyungdongFormulaHandler: product_type 자동 추론(item_category 기반), 철재 주자재 EGI코일로 변경, 조인트바 steel 공통 지원 - FormulaEvaluatorService: FG item_category에서 product_type 자동 판별 - MapItemsToProcesses: 경동 품목-공정 매핑 커맨드 정비 - KyungdongItemMasterSeeder: BOM child_item_id code 기반 재매핑 - ItemsBomController: ghost ID 유효성 검증 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1587,7 +1587,14 @@ private function calculateKyungdongBom(
|
||||
$H0 = (float) ($inputVariables['H0'] ?? 0);
|
||||
$QTY = (int) ($inputVariables['QTY'] ?? 1);
|
||||
$bracketInch = $inputVariables['bracket_inch'] ?? '5';
|
||||
$productType = $inputVariables['product_type'] ?? 'screen';
|
||||
// product_type: 프론트 입력값 우선, 없으면 FG item_category에서 자동 추론
|
||||
$finishedGoods = $this->getItemDetails($finishedGoodsCode, $tenantId);
|
||||
$itemCategory = $finishedGoods['item_category'] ?? null;
|
||||
$productType = $inputVariables['product_type'] ?? match (true) {
|
||||
$itemCategory === '철재' => 'steel',
|
||||
str_contains($itemCategory ?? '', '슬랫') => 'slat',
|
||||
default => 'screen',
|
||||
};
|
||||
|
||||
$this->addDebugStep(1, '입력값수집', [
|
||||
'formulas' => [
|
||||
@@ -1602,9 +1609,7 @@ private function calculateKyungdongBom(
|
||||
],
|
||||
]);
|
||||
|
||||
// Step 2: 완제품 조회 (경동 전용 계산은 완제품 없이도 동작)
|
||||
$finishedGoods = $this->getItemDetails($finishedGoodsCode, $tenantId);
|
||||
|
||||
// Step 2: 완제품 정보 활용 (Step 1에서 이미 조회됨)
|
||||
if ($finishedGoods) {
|
||||
$this->addDebugStep(2, '완제품선택', [
|
||||
'code' => $finishedGoods['code'],
|
||||
@@ -1672,6 +1677,12 @@ private function calculateKyungdongBom(
|
||||
$finishingType = $inputVariables['finishing_type'] ?? 'SUS';
|
||||
$installationType = $inputVariables['installation_type'] ?? '벽면형';
|
||||
|
||||
// 모터 전압: 프론트 MP(single/three) → motor_voltage(220V/380V) 매핑
|
||||
$motorVoltage = $inputVariables['motor_voltage'] ?? match ($inputVariables['MP'] ?? 'single') {
|
||||
'three' => '380V',
|
||||
default => '220V',
|
||||
};
|
||||
|
||||
$calculatedVariables = array_merge($inputVariables, [
|
||||
'W0' => $W0,
|
||||
'H0' => $H0,
|
||||
@@ -1687,6 +1698,7 @@ private function calculateKyungdongBom(
|
||||
'product_model' => $productModel,
|
||||
'finishing_type' => $finishingType,
|
||||
'installation_type' => $installationType,
|
||||
'motor_voltage' => $motorVoltage,
|
||||
]);
|
||||
|
||||
$this->addDebugStep(3, '변수계산', [
|
||||
|
||||
@@ -22,49 +22,12 @@ public function __construct(?EstimatePriceService $priceService = null)
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 아이템 매핑 헬퍼 메서드 및 상수
|
||||
// 아이템 매핑 헬퍼 메서드
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* 고정 매핑 아이템 코드 → ID 테이블
|
||||
* items master에서 조회한 고정 값들
|
||||
*/
|
||||
private const FIXED_ITEM_MAPPINGS = [
|
||||
// 연기차단재
|
||||
'EST-SMOKE-케이스용' => 14912,
|
||||
'EST-SMOKE-레일용' => 14911,
|
||||
// 하장바
|
||||
'00035' => 14158, // SUS
|
||||
'00036' => 14159, // EGI
|
||||
// 보강평철
|
||||
'BD-보강평철-50' => 14790,
|
||||
// 무게평철12T (평철12T와 동일)
|
||||
'00021' => 14147,
|
||||
// 환봉 (파이별)
|
||||
'90201' => 14407, // 30파이
|
||||
'90202' => 14408, // 35파이
|
||||
'90203' => 14409, // 45파이
|
||||
'90204' => 14410, // 50파이
|
||||
// 조인트바
|
||||
'800361' => 14733,
|
||||
// 검사비
|
||||
'EST-INSPECTION' => 14913,
|
||||
// 제어기
|
||||
'EST-CTRL-노출형' => 14861,
|
||||
'EST-CTRL-매립형' => 14862,
|
||||
'EST-CTRL-뒷박스' => 14863,
|
||||
// 파이프
|
||||
'EST-PIPE-1.4-3000' => 14900,
|
||||
'EST-PIPE-1.4-6000' => 14901,
|
||||
// 모터받침 앵글
|
||||
'EST-ANGLE-BRACKET-스크린용' => 14907,
|
||||
'EST-ANGLE-BRACKET-철제300K' => 14908,
|
||||
'EST-ANGLE-BRACKET-철제400K' => 14909,
|
||||
'EST-ANGLE-BRACKET-철제800K' => 14910,
|
||||
];
|
||||
|
||||
/**
|
||||
* items master에서 코드로 아이템 조회 (캐싱 적용, id + name)
|
||||
* seeder 재실행 시 ID가 변경될 수 있으므로 항상 DB에서 동적 조회
|
||||
*
|
||||
* @param string $code 아이템 코드
|
||||
* @return array{id: int|null, name: string|null}
|
||||
@@ -76,16 +39,6 @@ private function lookupItem(string $code): array
|
||||
return $cache[$code];
|
||||
}
|
||||
|
||||
// 1. 고정 매핑에 ID만 있는 경우 → DB에서 name 조회
|
||||
if (isset(self::FIXED_ITEM_MAPPINGS[$code])) {
|
||||
$fixedId = self::FIXED_ITEM_MAPPINGS[$code];
|
||||
$name = \App\Models\Items\Item::where('id', $fixedId)->value('name');
|
||||
$cache[$code] = ['id' => $fixedId, 'name' => $name];
|
||||
|
||||
return $cache[$code];
|
||||
}
|
||||
|
||||
// 2. DB에서 동적 조회 (BD-*, EST-* 패턴)
|
||||
$item = \App\Models\Items\Item::where('tenant_id', self::TENANT_ID)
|
||||
->where('code', $code)
|
||||
->first(['id', 'name']);
|
||||
@@ -968,8 +921,9 @@ public function calculatePartItems(array $params): array
|
||||
], $itemCode);
|
||||
}
|
||||
|
||||
// 5. 조인트바 (슬랫 전용, 5130: price × col76, QTY 미적용)
|
||||
if ($productType === 'slat') {
|
||||
// 5. 조인트바 (슬랫/철재 공통, 5130: price × col76, QTY 미적용)
|
||||
// 5130 레거시: 철재(KQTS01)도 슬랫 공정에서 조인트바 사용
|
||||
if (in_array($productType, ['slat', 'steel'])) {
|
||||
$jointBarQty = (int) ($params['joint_bar_qty'] ?? 0);
|
||||
if ($jointBarQty > 0) {
|
||||
$jointBarPrice = $this->getRawMaterialPrice('조인트바');
|
||||
@@ -1044,20 +998,21 @@ public function calculateDynamicItems(array $inputs): array
|
||||
], 'EST-INSPECTION');
|
||||
}
|
||||
|
||||
// 1. 주자재 (스크린 또는 슬랫)
|
||||
if ($productType === 'slat') {
|
||||
$materialResult = $this->calculateSlatPrice($width, $height);
|
||||
$materialName = '주자재(슬랫)';
|
||||
// 슬랫 타입에 따른 코드 (기본: 방화)
|
||||
$slatType = $inputs['slat_type'] ?? '방화';
|
||||
$materialCode = "EST-RAW-슬랫-{$slatType}";
|
||||
} else {
|
||||
// 1. 주자재 (스크린 = 실리카, 철재/슬랫 = EGI 코일 슬랫)
|
||||
// 5130: KQTS01(철재)도 슬랫 공정에서 EGI 코일로 슬랫 생산 (viewSlatWork.php 참조)
|
||||
if ($productType === 'screen') {
|
||||
$materialResult = $this->calculateScreenPrice($width, $height);
|
||||
$materialName = '주자재(스크린)';
|
||||
// 스크린 타입에 따른 코드 (기본: 실리카)
|
||||
$screenType = $inputs['screen_type'] ?? '실리카';
|
||||
$materialCode = "EST-RAW-스크린-{$screenType}";
|
||||
} else {
|
||||
// steel, slat 모두 슬랫(EGI 코일) 사용
|
||||
$materialResult = $this->calculateSlatPrice($width, $height);
|
||||
$materialName = '주자재(슬랫)';
|
||||
$slatType = $inputs['slat_type'] ?? '방화';
|
||||
$materialCode = "EST-RAW-슬랫-{$slatType}";
|
||||
}
|
||||
|
||||
$items[] = $this->withItemMapping([
|
||||
'category' => 'material',
|
||||
'item_name' => $materialName,
|
||||
|
||||
Reference in New Issue
Block a user