fix(WEB): 철재 모터용량/셔터박스 계산 레거시 일치 수정
- FormulaHandler: 철재 면적 공식 W1×(H1+550) → W1×H1 (레거시 Slat_updateCol12and13 동일) - FormulaHandler: 샤프트 인치 자동계산 추가 (레거시 Slat_updateCol22 동일) - BendingInfoBuilder: 셔터박스 크기를 모터용량→브라켓→박스 매핑으로 결정 (BOM 원자재 코드 BD-케이스-500*380 대신 조립 크기 650*550 등 사용) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -122,6 +122,9 @@ private function categorizeBomItem(array $bomItem): ?string
|
|||||||
if (str_starts_with($code, 'BD-보강평철')) {
|
if (str_starts_with($code, 'BD-보강평철')) {
|
||||||
return 'detail_reinforce';
|
return 'detail_reinforce';
|
||||||
}
|
}
|
||||||
|
if (str_starts_with($code, 'EST-MOTOR-')) {
|
||||||
|
return 'motor';
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -180,6 +183,7 @@ private function assembleBendingInfo(array $productInfo, array $materials, array
|
|||||||
$caseBom = $agg['bomCategories']['shutterBox_case'] ?? null;
|
$caseBom = $agg['bomCategories']['shutterBox_case'] ?? null;
|
||||||
$finCoverBom = $agg['bomCategories']['shutterBox_finCover'] ?? null;
|
$finCoverBom = $agg['bomCategories']['shutterBox_finCover'] ?? null;
|
||||||
$lbarBom = $agg['bomCategories']['detail_lbar'] ?? null;
|
$lbarBom = $agg['bomCategories']['detail_lbar'] ?? null;
|
||||||
|
$motorBom = $agg['bomCategories']['motor'] ?? null;
|
||||||
$dimGroups = $agg['dimensionGroups'];
|
$dimGroups = $agg['dimensionGroups'];
|
||||||
|
|
||||||
// 가이드레일 baseSize 추출: BD-가이드레일-KSS01-SUS-120*70 → "120*70"
|
// 가이드레일 baseSize 추출: BD-가이드레일-KSS01-SUS-120*70 → "120*70"
|
||||||
@@ -192,7 +196,7 @@ private function assembleBendingInfo(array $productInfo, array $materials, array
|
|||||||
'detailParts' => $this->buildDetailParts($guideRailBom, $lbarBom, $materials),
|
'detailParts' => $this->buildDetailParts($guideRailBom, $lbarBom, $materials),
|
||||||
'guideRail' => $this->buildGuideRail($productInfo['guideType'], $baseSize, $materials, $dimGroups, $productInfo['productCode']),
|
'guideRail' => $this->buildGuideRail($productInfo['guideType'], $baseSize, $materials, $dimGroups, $productInfo['productCode']),
|
||||||
'bottomBar' => $this->buildBottomBar($materials, $dimGroups),
|
'bottomBar' => $this->buildBottomBar($materials, $dimGroups),
|
||||||
'shutterBox' => $this->buildShutterBox($caseBom, $finCoverBom, $baseSize, $dimGroups),
|
'shutterBox' => $this->buildShutterBox($caseBom, $finCoverBom, $motorBom, $baseSize, $dimGroups),
|
||||||
'smokeBarrier' => $this->buildSmokeBarrier($dimGroups),
|
'smokeBarrier' => $this->buildSmokeBarrier($dimGroups),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -325,17 +329,24 @@ private function buildBottomBar(array $materials, array $dimGroups): array
|
|||||||
// shutterBox 섹션
|
// shutterBox 섹션
|
||||||
// ─────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────
|
||||||
|
|
||||||
private function buildShutterBox(?array $caseBom, ?array $finCoverBom, string $guideBaseSize, array $dimGroups): array
|
private function buildShutterBox(?array $caseBom, ?array $finCoverBom, ?array $motorBom, string $guideBaseSize, array $dimGroups): array
|
||||||
{
|
{
|
||||||
if (! $caseBom) {
|
if (! $caseBom) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// BD-케이스-500*380 → "500*380"
|
// 셔터박스 크기: 모터용량 → 브라켓 → 박스 매핑 (레거시 Slat_updateCol37)
|
||||||
$caseSize = str_replace('BD-케이스-', '', $caseBom['item_code'] ?? '');
|
$motorCapacity = $this->extractMotorCapacity($motorBom);
|
||||||
$caseParts = explode('*', $caseSize);
|
$boxSize = $motorCapacity ? $this->getShutterBoxSize($motorCapacity) : null;
|
||||||
$caseWidth = (int) ($caseParts[0] ?? 0);
|
|
||||||
$caseHeight = (int) ($caseParts[1] ?? 0);
|
if (! $boxSize) {
|
||||||
|
// fallback: BOM 케이스 item_code에서 추출 (BD-케이스-500*380 → "500*380")
|
||||||
|
$boxSize = str_replace('BD-케이스-', '', $caseBom['item_code'] ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
$boxParts = explode('*', $boxSize);
|
||||||
|
$boxWidth = (int) ($boxParts[0] ?? 0);
|
||||||
|
$boxHeight = (int) ($boxParts[1] ?? 0);
|
||||||
|
|
||||||
// railWidth: 가이드레일 baseSize에서 첫 번째 숫자 (120*70 → 120)
|
// railWidth: 가이드레일 baseSize에서 첫 번째 숫자 (120*70 → 120)
|
||||||
$guideParts = explode('*', $guideBaseSize);
|
$guideParts = explode('*', $guideBaseSize);
|
||||||
@@ -355,10 +366,10 @@ private function buildShutterBox(?array $caseBom, ?array $finCoverBom, string $g
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
'size' => $caseSize,
|
'size' => $boxSize,
|
||||||
'direction' => '양면',
|
'direction' => '양면',
|
||||||
'railWidth' => $railWidth,
|
'railWidth' => $railWidth,
|
||||||
'frontBottom' => $caseHeight,
|
'frontBottom' => $boxHeight,
|
||||||
'coverQty' => $coverQty,
|
'coverQty' => $coverQty,
|
||||||
'finCoverQty' => $finCoverQty,
|
'finCoverQty' => $finCoverQty,
|
||||||
'lengthData' => $widthData,
|
'lengthData' => $widthData,
|
||||||
@@ -647,6 +658,39 @@ private function getMaterialMapping(string $productCode, string $finishMaterial)
|
|||||||
// 유틸리티 메서드
|
// 유틸리티 메서드
|
||||||
// ─────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 모터 BOM item_code에서 용량 추출
|
||||||
|
* EST-MOTOR-220V-500K → "500K"
|
||||||
|
*/
|
||||||
|
private function extractMotorCapacity(?array $motorBom): ?string
|
||||||
|
{
|
||||||
|
if (! $motorBom) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$code = $motorBom['item_code'] ?? '';
|
||||||
|
if (preg_match('/(\d+K)$/', $code, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 모터용량 → 셔터박스 조립 크기 매핑
|
||||||
|
* 레거시 체인: 모터용량(col20) → 브라켓(col21) → 박스크기(col37)
|
||||||
|
*
|
||||||
|
* @see 5130/estimate/common/common_addrowJS.php Slat_updateCol21(), Slat_updateCol37()
|
||||||
|
*/
|
||||||
|
private function getShutterBoxSize(string $motorCapacity): string
|
||||||
|
{
|
||||||
|
return match ($motorCapacity) {
|
||||||
|
'300K', '400K' => '650*550',
|
||||||
|
'500K', '600K' => '700*600',
|
||||||
|
'800K', '1000K' => '780*650',
|
||||||
|
default => '650*550',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 가이드레일 item_code에서 baseSize 추출
|
* 가이드레일 item_code에서 baseSize 추출
|
||||||
* BD-가이드레일-KSS01-SUS-120*70 → "120*70"
|
* BD-가이드레일-KSS01-SUS-120*70 → "120*70"
|
||||||
|
|||||||
@@ -303,6 +303,29 @@ private function getMotorCapacityByWeight(float $weight, ?string $bracketInch =
|
|||||||
return '1000K';
|
return '1000K';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 샤프트(브라켓) 인치 자동 계산
|
||||||
|
* 레거시 5130 Slat_updateCol22() 동일: W1(셔터기장)과 중량으로 결정
|
||||||
|
*
|
||||||
|
* @param float $W1 제조폭 (mm)
|
||||||
|
* @param float $weight 중량 (kg)
|
||||||
|
* @return int 샤프트 인치 (4, 5, 6, 8)
|
||||||
|
*/
|
||||||
|
private function calculateShaftInch(float $W1, float $weight): int
|
||||||
|
{
|
||||||
|
if ($W1 <= 4500) {
|
||||||
|
return $weight <= 400 ? 4 : 5;
|
||||||
|
}
|
||||||
|
if ($W1 <= 5600) {
|
||||||
|
return $weight <= 600 ? 5 : 6;
|
||||||
|
}
|
||||||
|
if ($W1 <= 7800) {
|
||||||
|
return $weight <= 800 ? 6 : 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 주자재(스크린) 계산
|
// 주자재(스크린) 계산
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@@ -983,16 +1006,23 @@ public function calculateDynamicItems(array $inputs): array
|
|||||||
// 슬랫: W0 × (H0 + 50) / 1M, 중량 = 면적 × 25
|
// 슬랫: W0 × (H0 + 50) / 1M, 중량 = 면적 × 25
|
||||||
$area = ($width * ($height + 50)) / 1000000;
|
$area = ($width * ($height + 50)) / 1000000;
|
||||||
$weight = $area * 25;
|
$weight = $area * 25;
|
||||||
|
} elseif ($productType === 'steel') {
|
||||||
|
// 철재: W1 × H1 / 1M (레거시 Slat_updateCol12and13 동일)
|
||||||
|
$W1 = $width + 110;
|
||||||
|
$H1 = $height + 350;
|
||||||
|
$area = ($W1 * $H1) / 1000000;
|
||||||
|
$weight = $area * 25;
|
||||||
} else {
|
} else {
|
||||||
// 스크린/철재: W1 × (H1 + 550) / 1M
|
// 스크린: W1 × (H1 + 550) / 1M
|
||||||
$W1 = $width + 160;
|
$W1 = $width + 160;
|
||||||
$H1 = $height + 350;
|
$H1 = $height + 350;
|
||||||
$area = ($W1 * ($H1 + 550)) / 1000000;
|
$area = ($W1 * ($H1 + 550)) / 1000000;
|
||||||
if ($productType === 'steel') {
|
$weight = $area * 2 + ($width / 1000) * 14.17;
|
||||||
$weight = $area * 25;
|
}
|
||||||
} else {
|
|
||||||
$weight = $area * 2 + ($width / 1000) * 14.17;
|
// 샤프트 인치: 철재는 W1/중량 기반 자동계산 (레거시 Slat_updateCol22 동일)
|
||||||
}
|
if ($productType === 'steel' && ! isset($inputs['bracket_inch'])) {
|
||||||
|
$bracketInch = (string) $this->calculateShaftInch($W1 ?? ($width + 110), $weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 모터 용량/브라켓 크기 계산 (입력값 우선, 없으면 자동계산)
|
// 모터 용량/브라켓 크기 계산 (입력값 우선, 없으면 자동계산)
|
||||||
|
|||||||
Reference in New Issue
Block a user