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:
2026-02-21 00:34:01 +09:00
parent 602702b891
commit 3ab4f24bb4
2 changed files with 89 additions and 15 deletions

View File

@@ -122,6 +122,9 @@ private function categorizeBomItem(array $bomItem): ?string
if (str_starts_with($code, 'BD-보강평철')) {
return 'detail_reinforce';
}
if (str_starts_with($code, 'EST-MOTOR-')) {
return 'motor';
}
return null;
}
@@ -180,6 +183,7 @@ private function assembleBendingInfo(array $productInfo, array $materials, array
$caseBom = $agg['bomCategories']['shutterBox_case'] ?? null;
$finCoverBom = $agg['bomCategories']['shutterBox_finCover'] ?? null;
$lbarBom = $agg['bomCategories']['detail_lbar'] ?? null;
$motorBom = $agg['bomCategories']['motor'] ?? null;
$dimGroups = $agg['dimensionGroups'];
// 가이드레일 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),
'guideRail' => $this->buildGuideRail($productInfo['guideType'], $baseSize, $materials, $dimGroups, $productInfo['productCode']),
'bottomBar' => $this->buildBottomBar($materials, $dimGroups),
'shutterBox' => $this->buildShutterBox($caseBom, $finCoverBom, $baseSize, $dimGroups),
'shutterBox' => $this->buildShutterBox($caseBom, $finCoverBom, $motorBom, $baseSize, $dimGroups),
'smokeBarrier' => $this->buildSmokeBarrier($dimGroups),
];
}
@@ -325,17 +329,24 @@ private function buildBottomBar(array $materials, array $dimGroups): array
// 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) {
return [];
}
// BD-케이스-500*380 → "500*380"
$caseSize = str_replace('BD-케이스-', '', $caseBom['item_code'] ?? '');
$caseParts = explode('*', $caseSize);
$caseWidth = (int) ($caseParts[0] ?? 0);
$caseHeight = (int) ($caseParts[1] ?? 0);
// 셔터박스 크기: 모터용량 → 브라켓 → 박스 매핑 (레거시 Slat_updateCol37)
$motorCapacity = $this->extractMotorCapacity($motorBom);
$boxSize = $motorCapacity ? $this->getShutterBoxSize($motorCapacity) : null;
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)
$guideParts = explode('*', $guideBaseSize);
@@ -355,10 +366,10 @@ private function buildShutterBox(?array $caseBom, ?array $finCoverBom, string $g
return [
[
'size' => $caseSize,
'size' => $boxSize,
'direction' => '양면',
'railWidth' => $railWidth,
'frontBottom' => $caseHeight,
'frontBottom' => $boxHeight,
'coverQty' => $coverQty,
'finCoverQty' => $finCoverQty,
'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 추출
* BD-가이드레일-KSS01-SUS-120*70 → "120*70"

View File

@@ -303,6 +303,29 @@ private function getMotorCapacityByWeight(float $weight, ?string $bracketInch =
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
$area = ($width * ($height + 50)) / 1000000;
$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 {
// 스크린/철재: W1 × (H1 + 550) / 1M
// 스크린: W1 × (H1 + 550) / 1M
$W1 = $width + 160;
$H1 = $height + 350;
$area = ($W1 * ($H1 + 550)) / 1000000;
if ($productType === 'steel') {
$weight = $area * 25;
} else {
$weight = $area * 2 + ($width / 1000) * 14.17;
}
$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);
}
// 모터 용량/브라켓 크기 계산 (입력값 우선, 없으면 자동계산)