Files
sam-api/app/Services/Quote/Handlers/KyungdongFormulaHandler.php
권혁성 ca2dd44567 fix: 환봉·각파이프 5130 자동계산 공식 적용
- 환봉: W0 기준 자동계산 (≤3000→1, ≤6000→2, ≤9000→3, ≤12000→4 × 수량)
- 각파이프: col67(케이스길이+3000×연결수) 기준 3000mm/6000mm 수량 자동계산
- 기존 하드코딩(각파이프 1개, 환봉 0개) 제거

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 22:55:40 +09:00

892 lines
32 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\Services\Quote\Handlers;
use App\Services\Quote\EstimatePriceService;
/**
* 경동기업 전용 견적 계산 핸들러
*
* 5130 레거시 시스템의 견적 로직을 SAM에 구현
* tenant_id = 287 전용
*/
class KyungdongFormulaHandler
{
private const TENANT_ID = 287;
private EstimatePriceService $priceService;
public function __construct(?EstimatePriceService $priceService = null)
{
$this->priceService = $priceService ?? new EstimatePriceService(self::TENANT_ID);
}
// =========================================================================
// 모터 용량 계산
// =========================================================================
/**
* 모터 용량 계산 (3차원 조건: 제품타입 × 인치 × 중량)
*
* @param string $productType 제품 타입 (screen, steel)
* @param float $weight 중량 (kg)
* @param string $bracketInch 브라켓 인치 (4, 5, 6, 8)
* @return string 모터 용량 (150K, 300K, 400K, 500K, 600K, 800K, 1000K)
*/
public function calculateMotorCapacity(string $productType, float $weight, string $bracketInch): string
{
$inch = (int) $bracketInch;
if ($productType === 'screen') {
return $this->calculateScreenMotor($weight, $inch);
}
return $this->calculateSteelMotor($weight, $inch);
}
/**
* 스크린 모터 용량 계산
*/
private function calculateScreenMotor(float $weight, int $inch): string
{
if ($inch === 4) {
if ($weight <= 150) {
return '150K';
}
if ($weight <= 300) {
return '300K';
}
return '400K';
}
if ($inch === 5) {
if ($weight <= 123) {
return '150K';
}
if ($weight <= 246) {
return '300K';
}
if ($weight <= 327) {
return '400K';
}
if ($weight <= 500) {
return '500K';
}
return '600K';
}
if ($inch === 6) {
if ($weight <= 104) {
return '150K';
}
if ($weight <= 208) {
return '300K';
}
if ($weight <= 300) {
return '400K';
}
if ($weight <= 424) {
return '500K';
}
return '600K';
}
// 기본값
return '300K';
}
/**
* 철재 모터 용량 계산
*/
private function calculateSteelMotor(float $weight, int $inch): string
{
if ($inch === 4) {
if ($weight <= 300) {
return '300K';
}
return '400K';
}
if ($inch === 5) {
if ($weight <= 246) {
return '300K';
}
if ($weight <= 327) {
return '400K';
}
if ($weight <= 500) {
return '500K';
}
return '600K';
}
if ($inch === 6) {
if ($weight <= 208) {
return '300K';
}
if ($weight <= 277) {
return '400K';
}
if ($weight <= 424) {
return '500K';
}
if ($weight <= 508) {
return '600K';
}
if ($weight <= 800) {
return '800K';
}
return '1000K';
}
if ($inch === 8) {
if ($weight <= 324) {
return '500K';
}
if ($weight <= 388) {
return '600K';
}
if ($weight <= 611) {
return '800K';
}
return '1000K';
}
// 기본값
return '300K';
}
// =========================================================================
// 브라켓 크기 계산
// =========================================================================
/**
* 브라켓 크기 결정
*
* @param float $weight 중량 (kg)
* @param string|null $bracketInch 브라켓 인치 (선택)
* @return string 브라켓 크기 (530*320, 600*350, 690*390)
*/
public function calculateBracketSize(float $weight, ?string $bracketInch = null): string
{
$motorCapacity = $this->getMotorCapacityByWeight($weight, $bracketInch);
return match ($motorCapacity) {
'300K', '400K' => '530*320',
'500K', '600K' => '600*350',
'800K', '1000K' => '690*390',
default => '530*320',
};
}
/**
* 중량으로 모터 용량 판단 (인치 없을 때)
*/
private function getMotorCapacityByWeight(float $weight, ?string $bracketInch = null): string
{
if ($bracketInch) {
// 인치가 있으면 철재 기준으로 계산
return $this->calculateSteelMotor($weight, (int) $bracketInch);
}
// 인치 없으면 중량만으로 판단
if ($weight <= 300) {
return '300K';
}
if ($weight <= 400) {
return '400K';
}
if ($weight <= 500) {
return '500K';
}
if ($weight <= 600) {
return '600K';
}
if ($weight <= 800) {
return '800K';
}
return '1000K';
}
// =========================================================================
// 주자재(스크린) 계산
// =========================================================================
/**
* 스크린 주자재 가격 계산
*
* @param float $width 폭 (mm)
* @param float $height 높이 (mm)
* @return array [unit_price, area, total_price]
*/
public function calculateScreenPrice(float $width, float $height): array
{
// 면적 계산: W1 × (H1 + 550) / 1,000,000
// W1 = W0 + 160, H1 = H0 + 350 (레거시 5130 공식)
$W1 = $width + 160;
$H1 = $height + 350;
$calculateHeight = $H1 + 550;
$area = ($W1 * $calculateHeight) / 1000000;
// 원자재 단가 조회 (실리카/스크린)
$unitPrice = $this->getRawMaterialPrice('실리카');
// 5130 동일: round(area, 2) 후 단가 곱셈
$roundedArea = round($area, 2);
return [
'unit_price' => $unitPrice,
'area' => $roundedArea,
'total_price' => round($unitPrice * $roundedArea),
];
}
// =========================================================================
// 단가 조회 메서드 (EstimatePriceService 사용)
// =========================================================================
/**
* 원자재 단가 조회
*/
public function getRawMaterialPrice(string $materialName): float
{
return $this->priceService->getRawMaterialPrice($materialName);
}
/**
* 모터 단가 조회
*/
public function getMotorPrice(string $motorCapacity): float
{
return $this->priceService->getMotorPrice($motorCapacity);
}
/**
* 제어기 단가 조회
*/
public function getControllerPrice(string $controllerType): float
{
return $this->priceService->getControllerPrice($controllerType);
}
/**
* 샤프트 단가 조회
*/
public function getShaftPrice(string $size, float $length): float
{
return $this->priceService->getShaftPrice($size, $length);
}
/**
* 파이프 단가 조회
*/
public function getPipePrice(string $thickness, int $length): float
{
return $this->priceService->getPipePrice($thickness, $length);
}
/**
* 모터 받침용 앵글 단가 조회
*
* @param string $searchOption 검색옵션 (스크린용, 철제300K 등)
*/
public function getAnglePrice(string $searchOption): float
{
return $this->priceService->getAnglePrice($searchOption);
}
/**
* 부자재용 앵글 단가 조회
*
* @param string $angleType 앵글타입 (앵글3T, 앵글4T)
* @param string $size 길이 (2.5, 10)
*/
public function getMainAnglePrice(string $angleType, string $size): float
{
return $this->priceService->getMainAnglePrice($angleType, $size);
}
// =========================================================================
// 절곡품 계산 (10종)
// =========================================================================
/**
* 절곡품 항목 계산 (10종)
*
* 케이스, 케이스용 연기차단재, 케이스 마구리, 가이드레일,
* 레일용 연기차단재, 하장바, L바, 보강평철, 무게평철12T, 환봉
*
* @param array $params 입력 파라미터
* @return array 절곡품 항목 배열
*/
public function calculateSteelItems(array $params): array
{
$items = [];
// 기본 파라미터
$width = (float) ($params['W0'] ?? 0);
$height = (float) ($params['H0'] ?? 0);
$quantity = (int) ($params['QTY'] ?? 1);
$modelName = $params['model_name'] ?? $params['product_model'] ?? 'KSS01';
$finishingType = $params['finishing_type'] ?? 'SUS';
// 절곡품 관련 파라미터
$caseSpec = $params['case_spec'] ?? '500*380';
$caseLength = (float) ($params['case_length'] ?? ($width + 220)); // mm 단위 (레거시: W0+220)
$guideType = $params['guide_type'] ?? '벽면형'; // 벽면형, 측면형, 혼합형
$guideSpec = $params['guide_spec'] ?? '120*70'; // 120*70, 120*100
$guideLength = (float) ($params['guide_length'] ?? ($height + 250)) / 1000; // m 단위 (레거시: H0+250)
$bottomBarLength = (float) ($params['bottombar_length'] ?? $width) / 1000; // m 단위 (레거시: W0)
$lbarLength = (float) ($params['lbar_length'] ?? ($width + 220)) / 1000; // m 단위 (레거시: W0+220)
$flatBarLength = (float) ($params['flatbar_length'] ?? ($width + 220)) / 1000; // m 단위 (레거시: W0+220)
$weightPlateQty = (int) ($params['weight_plate_qty'] ?? 0); // 무게평철 수량
// 환봉 수량: 5130 자동계산 (col10=폭 기준)
// ≤3000→1, ≤6000→2, ≤9000→3, ≤12000→4 (× 수량)
$roundBarQty = (int) ($params['round_bar_qty'] ?? -1);
if ($roundBarQty < 0) {
if ($width <= 3000) {
$roundBarQty = 1 * $quantity;
} elseif ($width <= 6000) {
$roundBarQty = 2 * $quantity;
} elseif ($width <= 9000) {
$roundBarQty = 3 * $quantity;
} elseif ($width <= 12000) {
$roundBarQty = 4 * $quantity;
} else {
$roundBarQty = 0;
}
}
// 1. 케이스 (단가/1000 × 길이mm × 수량)
$casePrice = $this->priceService->getCasePrice($caseSpec);
if ($casePrice > 0 && $caseLength > 0) {
$totalPrice = ($casePrice / 1000) * $caseLength * $quantity;
$items[] = [
'category' => 'steel',
'item_name' => '케이스',
'specification' => "{$caseSpec} {$caseLength}mm",
'unit' => 'm',
'quantity' => $caseLength / 1000 * $quantity,
'unit_price' => $casePrice,
'total_price' => round($totalPrice),
];
}
// 2. 케이스용 연기차단재 (단가 × 길이m × 수량)
$caseSmokePrice = $this->priceService->getCaseSmokeBlockPrice();
if ($caseSmokePrice > 0 && $caseLength > 0) {
$lengthM = $caseLength / 1000;
$items[] = [
'category' => 'steel',
'item_name' => '케이스용 연기차단재',
'specification' => "{$lengthM}m",
'unit' => 'm',
'quantity' => $lengthM * $quantity,
'unit_price' => $caseSmokePrice,
'total_price' => round($caseSmokePrice * $lengthM * $quantity),
];
}
// 3. 케이스 마구리 (단가 × 수량)
// 마구리 규격 = 케이스 규격 각 치수 + 5mm (레거시 updateCol45 공식)
$caseCapSpec = $this->convertToCaseCapSpec($caseSpec);
$caseCapPrice = $this->priceService->getCaseCapPrice($caseCapSpec);
if ($caseCapPrice > 0) {
$capQty = $quantity; // 5130: maguriPrices × $su (수량)
$items[] = [
'category' => 'steel',
'item_name' => '케이스 마구리',
'specification' => $caseCapSpec,
'unit' => 'EA',
'quantity' => $capQty,
'unit_price' => $caseCapPrice,
'total_price' => round($caseCapPrice * $capQty),
];
}
// 4. 가이드레일 (단가 × 길이m × 수량) - 타입별 처리
$guideItems = $this->calculateGuideRails($modelName, $finishingType, $guideType, $guideSpec, $guideLength, $quantity);
$items = array_merge($items, $guideItems);
// 5. 레일용 연기차단재 (단가 × 길이m × 2 × 수량)
$railSmokePrice = $this->priceService->getRailSmokeBlockPrice();
if ($railSmokePrice > 0 && $guideLength > 0) {
$railSmokeQty = 2 * $quantity; // 좌우 2개
$items[] = [
'category' => 'steel',
'item_name' => '레일용 연기차단재',
'specification' => "{$guideLength}m × 2",
'unit' => 'm',
'quantity' => $guideLength * $railSmokeQty,
'unit_price' => $railSmokePrice,
'total_price' => round($railSmokePrice * $guideLength * $railSmokeQty),
];
}
// 6. 하장바 (단가 × 길이m × 수량)
$bottomBarPrice = $this->priceService->getBottomBarPrice($modelName, $finishingType);
if ($bottomBarPrice > 0 && $bottomBarLength > 0) {
$items[] = [
'category' => 'steel',
'item_name' => '하장바',
'specification' => "{$modelName} {$finishingType} {$bottomBarLength}m",
'unit' => 'm',
'quantity' => $bottomBarLength * $quantity,
'unit_price' => $bottomBarPrice,
'total_price' => round($bottomBarPrice * $bottomBarLength * $quantity),
];
}
// 7. L바 (단가 × 길이m × 수량)
$lbarPrice = $this->priceService->getLBarPrice($modelName);
if ($lbarPrice > 0 && $lbarLength > 0) {
$items[] = [
'category' => 'steel',
'item_name' => 'L바',
'specification' => "{$modelName} {$lbarLength}m",
'unit' => 'm',
'quantity' => $lbarLength * $quantity,
'unit_price' => $lbarPrice,
'total_price' => round($lbarPrice * $lbarLength * $quantity),
];
}
// 8. 보강평철 (단가 × 길이m × 수량)
$flatBarPrice = $this->priceService->getFlatBarPrice();
if ($flatBarPrice > 0 && $flatBarLength > 0) {
$items[] = [
'category' => 'steel',
'item_name' => '보강평철',
'specification' => "{$flatBarLength}m",
'unit' => 'm',
'quantity' => $flatBarLength * $quantity,
'unit_price' => $flatBarPrice,
'total_price' => round($flatBarPrice * $flatBarLength * $quantity),
];
}
// 9. 무게평철12T (고정 12,000원 × 수량)
if ($weightPlateQty > 0) {
$weightPlatePrice = 12000;
$items[] = [
'category' => 'steel',
'item_name' => '무게평철12T',
'specification' => '12T',
'unit' => 'EA',
'quantity' => $weightPlateQty * $quantity,
'unit_price' => $weightPlatePrice,
'total_price' => $weightPlatePrice * $weightPlateQty * $quantity,
];
}
// 10. 환봉 (고정 2,000원 × 수량)
if ($roundBarQty > 0) {
$roundBarPrice = 2000;
$items[] = [
'category' => 'steel',
'item_name' => '환봉',
'specification' => '',
'unit' => 'EA',
'quantity' => $roundBarQty * $quantity,
'unit_price' => $roundBarPrice,
'total_price' => $roundBarPrice * $roundBarQty * $quantity,
];
}
return $items;
}
/**
* 가이드레일 계산 (타입별 처리)
*
* @param string $modelName 모델코드
* @param string $finishingType 마감재질
* @param string $guideType 가이드레일 타입 (벽면형, 측면형, 혼합형)
* @param string $guideSpec 가이드레일 규격 (120*70, 120*100)
* @param float $guideLength 가이드레일 길이 (m)
* @param int $quantity 수량
* @return array 가이드레일 항목 배열
*/
private function calculateGuideRails(
string $modelName,
string $finishingType,
string $guideType,
string $guideSpec,
float $guideLength,
int $quantity
): array {
$items = [];
if ($guideLength <= 0) {
return $items;
}
switch ($guideType) {
case '벽면형':
// 120*70 × 2개
$price = $this->priceService->getGuideRailPrice($modelName, $finishingType, '120*70');
if ($price > 0) {
$guideQty = 2 * $quantity;
$items[] = [
'category' => 'steel',
'item_name' => '가이드레일',
'specification' => "{$modelName} {$finishingType} 120*70 {$guideLength}m × 2",
'unit' => 'm',
'quantity' => $guideLength * $guideQty,
'unit_price' => $price,
'total_price' => round($price * $guideLength * $guideQty),
];
}
break;
case '측면형':
// 120*100 × 2개
$price = $this->priceService->getGuideRailPrice($modelName, $finishingType, '120*100');
if ($price > 0) {
$guideQty = 2 * $quantity;
$items[] = [
'category' => 'steel',
'item_name' => '가이드레일',
'specification' => "{$modelName} {$finishingType} 120*100 {$guideLength}m × 2",
'unit' => 'm',
'quantity' => $guideLength * $guideQty,
'unit_price' => $price,
'total_price' => round($price * $guideLength * $guideQty),
];
}
break;
case '혼합형':
// 120*70 × 1개 + 120*100 × 1개
$price70 = $this->priceService->getGuideRailPrice($modelName, $finishingType, '120*70');
$price100 = $this->priceService->getGuideRailPrice($modelName, $finishingType, '120*100');
if ($price70 > 0) {
$items[] = [
'category' => 'steel',
'item_name' => '가이드레일',
'specification' => "{$modelName} {$finishingType} 120*70 {$guideLength}m",
'unit' => 'm',
'quantity' => $guideLength * $quantity,
'unit_price' => $price70,
'total_price' => round($price70 * $guideLength * $quantity),
];
}
if ($price100 > 0) {
$items[] = [
'category' => 'steel',
'item_name' => '가이드레일',
'specification' => "{$modelName} {$finishingType} 120*100 {$guideLength}m",
'unit' => 'm',
'quantity' => $guideLength * $quantity,
'unit_price' => $price100,
'total_price' => round($price100 * $guideLength * $quantity),
];
}
break;
}
return $items;
}
// =========================================================================
// 부자재 계산 (3종)
// =========================================================================
/**
* 부자재 항목 계산
*
* @param array $params 입력 파라미터
* @return array 부자재 항목 배열
*/
public function calculatePartItems(array $params): array
{
$items = [];
$width = (float) ($params['W0'] ?? 0);
$bracketInch = $params['bracket_inch'] ?? '5';
$bracketSize = $params['BRACKET_SIZE'] ?? $this->calculateBracketSize(100, $bracketInch);
$productType = $params['product_type'] ?? 'screen';
$quantity = (int) ($params['QTY'] ?? 1);
// 1. 감기샤프트
$shaftSize = $bracketInch;
$shaftLength = ceil($width / 1000); // mm → m 변환 후 올림
$shaftPrice = $this->getShaftPrice($shaftSize, $shaftLength);
if ($shaftPrice > 0) {
$items[] = [
'category' => 'parts',
'item_name' => "감기샤프트 {$shaftSize}인치",
'specification' => "{$shaftLength}m",
'unit' => 'EA',
'quantity' => $quantity,
'unit_price' => $shaftPrice,
'total_price' => $shaftPrice * $quantity,
];
}
// 2. 각파이프 (5130: col67 = col37 + 3000 × col66, col68/col69 자동계산)
$pipeThickness = '1.4';
$caseLength = (float) ($params['case_length'] ?? ($width + 220)); // col37 (mm)
$connectionCount = (int) ($params['connection_count'] ?? 0); // col66 (연결 수)
$pipeBaseLength = $caseLength + 3000 * $connectionCount; // col67
// 5130 자동계산 공식: col67 기준
$pipe3000Qty = (int) ($params['pipe_3000_qty'] ?? 0);
$pipe6000Qty = (int) ($params['pipe_6000_qty'] ?? 0);
if ($pipe3000Qty === 0 && $pipe6000Qty === 0) {
// col68: 3000mm 파이프 수량
if ($pipeBaseLength <= 9000) {
$pipe3000Qty = 3 * $quantity;
} elseif ($pipeBaseLength <= 12000) {
$pipe3000Qty = 4 * $quantity;
} elseif ($pipeBaseLength <= 15000) {
$pipe3000Qty = 5 * $quantity;
} elseif ($pipeBaseLength <= 18000) {
$pipe3000Qty = 6 * $quantity;
}
// col69: 6000mm 파이프 수량 (18000 초과 시)
if ($pipeBaseLength > 18000 && $pipeBaseLength <= 24000) {
$pipe6000Qty = 4 * $quantity;
} elseif ($pipeBaseLength > 24000 && $pipeBaseLength <= 30000) {
$pipe6000Qty = 5 * $quantity;
} elseif ($pipeBaseLength > 30000 && $pipeBaseLength <= 36000) {
$pipe6000Qty = 6 * $quantity;
} elseif ($pipeBaseLength > 36000 && $pipeBaseLength <= 42000) {
$pipe6000Qty = 7 * $quantity;
} elseif ($pipeBaseLength > 42000 && $pipeBaseLength <= 48000) {
$pipe6000Qty = 8 * $quantity;
}
}
if ($pipe3000Qty > 0) {
$pipe3000Price = $this->getPipePrice($pipeThickness, 3000);
if ($pipe3000Price > 0) {
$items[] = [
'category' => 'parts',
'item_name' => '각파이프',
'specification' => "{$pipeThickness}T 3000mm",
'unit' => 'EA',
'quantity' => $pipe3000Qty,
'unit_price' => $pipe3000Price,
'total_price' => $pipe3000Price * $pipe3000Qty,
];
}
}
if ($pipe6000Qty > 0) {
$pipe6000Price = $this->getPipePrice($pipeThickness, 6000);
if ($pipe6000Price > 0) {
$items[] = [
'category' => 'parts',
'item_name' => '각파이프',
'specification' => "{$pipeThickness}T 6000mm",
'unit' => 'EA',
'quantity' => $pipe6000Qty,
'unit_price' => $pipe6000Price,
'total_price' => $pipe6000Price * $pipe6000Qty,
];
}
}
// 3. 모터 받침용 앵글 (bracket angle)
// 5130: calculateAngle(qty, itemList, '스크린용') → col2 검색, qty × $su × 4
$motorCapacity = $params['MOTOR_CAPACITY'] ?? '300K';
if ($productType === 'screen') {
$angleSearchOption = '스크린용';
} else {
// 철재: bracketSize로 매핑 (530*320→철제300K, 600*350→철제400K, 690*390→철제800K)
$angleSearchOption = match ($bracketSize) {
'530*320' => '철제300K',
'600*350' => '철제400K',
'690*390' => '철제800K',
default => '철제300K',
};
}
$anglePrice = $this->getAnglePrice($angleSearchOption);
if ($anglePrice > 0) {
$angleQty = 4 * $quantity; // 5130: $su * 4
$items[] = [
'category' => 'parts',
'item_name' => '모터 받침용 앵글',
'specification' => $angleSearchOption,
'unit' => 'EA',
'quantity' => $angleQty,
'unit_price' => $anglePrice,
'total_price' => $anglePrice * $angleQty,
];
}
// 4. 부자재 앵글 (main angle)
// 5130: calculateMainAngle(1, $itemList, '앵글3T', '2.5') × col71
$mainAngleType = $bracketSize === '690*390' ? '앵글4T' : '앵글3T';
$mainAngleSize = '2.5';
$mainAngleQty = (int) ($params['main_angle_qty'] ?? 2); // col71, default 2 (좌우)
$mainAnglePrice = $this->getMainAnglePrice($mainAngleType, $mainAngleSize);
if ($mainAnglePrice > 0 && $mainAngleQty > 0) {
$items[] = [
'category' => 'parts',
'item_name' => "앵글 {$mainAngleType}",
'specification' => "{$mainAngleSize}m",
'unit' => 'EA',
'quantity' => $mainAngleQty * $quantity,
'unit_price' => $mainAnglePrice,
'total_price' => $mainAnglePrice * $mainAngleQty * $quantity,
];
}
return $items;
}
// =========================================================================
// 전체 동적 항목 계산
// =========================================================================
/**
* 동적 항목 전체 계산
*
* @param array $inputs 입력 파라미터
* @return array 계산된 항목 배열
*/
public function calculateDynamicItems(array $inputs): array
{
$items = [];
$width = (float) ($inputs['W0'] ?? 0);
$height = (float) ($inputs['H0'] ?? 0);
$quantity = (int) ($inputs['QTY'] ?? 1);
$bracketInch = $inputs['bracket_inch'] ?? '5';
$productType = $inputs['product_type'] ?? 'screen';
// 중량 계산 (5130 로직) - W1, H1 기반
$W1 = $width + 160;
$H1 = $height + 350;
$area = ($W1 * ($H1 + 550)) / 1000000;
$weight = $area * ($productType === 'steel' ? 25 : 2) + ($width / 1000) * 14.17;
// 모터 용량/브라켓 크기 계산
$motorCapacity = $this->calculateMotorCapacity($productType, $weight, $bracketInch);
$bracketSize = $this->calculateBracketSize($weight, $bracketInch);
// 입력값에 계산된 값 추가 (부자재 계산용)
$inputs['WEIGHT'] = $weight;
$inputs['MOTOR_CAPACITY'] = $motorCapacity;
$inputs['BRACKET_SIZE'] = $bracketSize;
// 0. 검사비 (5130: inspectionFee × col14, 기본 50,000원)
$inspectionFee = (int) ($inputs['inspection_fee'] ?? 50000);
if ($inspectionFee > 0) {
$items[] = [
'category' => 'inspection',
'item_code' => 'KD-INSPECTION',
'item_name' => '검사비',
'specification' => '',
'unit' => 'EA',
'quantity' => $quantity,
'unit_price' => $inspectionFee,
'total_price' => $inspectionFee * $quantity,
];
}
// 1. 주자재 (스크린)
$screenResult = $this->calculateScreenPrice($width, $height);
$items[] = [
'category' => 'material',
'item_code' => 'KD-SCREEN',
'item_name' => '주자재(스크린)',
'specification' => "면적 {$screenResult['area']}",
'unit' => '㎡',
'quantity' => $screenResult['area'] * $quantity,
'unit_price' => $screenResult['unit_price'],
'total_price' => $screenResult['total_price'] * $quantity,
];
// 2. 모터
$motorPrice = $this->getMotorPrice($motorCapacity);
$items[] = [
'category' => 'motor',
'item_code' => "KD-MOTOR-{$motorCapacity}",
'item_name' => "모터 {$motorCapacity}",
'specification' => $motorCapacity,
'unit' => 'EA',
'quantity' => $quantity,
'unit_price' => $motorPrice,
'total_price' => $motorPrice * $quantity,
];
// 3. 제어기 (5130: 매립형×col15 + 노출형×col16 + 뒷박스×col17)
$controllerType = $inputs['controller_type'] ?? '매립형';
$controllerQty = (int) ($inputs['controller_qty'] ?? 1);
$controllerPrice = $this->getControllerPrice($controllerType);
if ($controllerPrice > 0 && $controllerQty > 0) {
$items[] = [
'category' => 'controller',
'item_code' => 'KD-CTRL-'.strtoupper($controllerType),
'item_name' => "제어기 {$controllerType}",
'specification' => $controllerType,
'unit' => 'EA',
'quantity' => $controllerQty * $quantity,
'unit_price' => $controllerPrice,
'total_price' => $controllerPrice * $controllerQty * $quantity,
];
}
// 뒷박스 (5130: col17 수량)
$backboxQty = (int) ($inputs['backbox_qty'] ?? 1);
if ($backboxQty > 0) {
$backboxPrice = $this->getControllerPrice('뒷박스');
if ($backboxPrice > 0) {
$items[] = [
'category' => 'controller',
'item_code' => 'KD-CTRL-BACKBOX',
'item_name' => '뒷박스',
'specification' => '',
'unit' => 'EA',
'quantity' => $backboxQty * $quantity,
'unit_price' => $backboxPrice,
'total_price' => $backboxPrice * $backboxQty * $quantity,
];
}
}
// 4. 절곡품
$steelItems = $this->calculateSteelItems($inputs);
$items = array_merge($items, $steelItems);
// 5. 부자재
$partItems = $this->calculatePartItems($inputs);
$items = array_merge($items, $partItems);
return $items;
}
/**
* 케이스 규격 → 마구리 규격 변환
*
* 레거시 updateCol45/Slat_updateCol46 공식:
* 마구리 규격 = (케이스 가로 + 5) × (케이스 세로 + 5)
* 예: 500*380 → 505*385
*/
private function convertToCaseCapSpec(string $caseSpec): string
{
if (str_contains($caseSpec, '*')) {
$parts = explode('*', $caseSpec);
$width = (int) trim($parts[0]) + 5;
$height = (int) trim($parts[1]) + 5;
return "{$width}*{$height}";
}
return $caseSpec;
}
}