- KdPriceTable 모델: 경동기업 단가 테이블 (motor, shaft, pipe, angle, raw_material, bdmodels) - KyungdongFormulaHandler: 모터 용량, 브라켓 크기, 절곡품(10종), 부자재(3종) 계산 - FormulaEvaluatorService: tenant_id=287 라우팅 추가 - kd_price_tables 마이그레이션 및 시더 (47건 단가 데이터) 테스트 결과: W0=3000, H0=2500 입력 시 16개 항목, 합계 751,200원 정상 계산 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
774 lines
26 KiB
PHP
774 lines
26 KiB
PHP
<?php
|
||
|
||
namespace App\Services\Quote\Handlers;
|
||
|
||
use App\Models\Kyungdong\KdPriceTable;
|
||
|
||
/**
|
||
* 경동기업 전용 견적 계산 핸들러
|
||
*
|
||
* 5130 레거시 시스템의 견적 로직을 SAM에 구현
|
||
* tenant_id = 287 전용
|
||
*/
|
||
class KyungdongFormulaHandler
|
||
{
|
||
private const TENANT_ID = 287;
|
||
|
||
// =========================================================================
|
||
// 모터 용량 계산
|
||
// =========================================================================
|
||
|
||
/**
|
||
* 모터 용량 계산 (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
|
||
{
|
||
// 면적 계산: W × (H + 550) / 1,000,000
|
||
$calculateHeight = $height + 550;
|
||
$area = ($width * $calculateHeight) / 1000000;
|
||
|
||
// 원자재 단가 조회 (실리카/스크린)
|
||
$unitPrice = $this->getRawMaterialPrice('실리카');
|
||
|
||
return [
|
||
'unit_price' => $unitPrice,
|
||
'area' => round($area, 2),
|
||
'total_price' => round($unitPrice * $area),
|
||
];
|
||
}
|
||
|
||
// =========================================================================
|
||
// 단가 조회 메서드 (KdPriceTable 사용)
|
||
// =========================================================================
|
||
|
||
/**
|
||
* BDmodels 테이블에서 단가 조회
|
||
*
|
||
* @param string $modelName 모델코드 (KSS01, KWS01 등)
|
||
* @param string $secondItem 부품분류 (케이스, 가이드레일, 하단마감재, L-BAR 등)
|
||
* @param string|null $finishingType 마감재질 (SUS, EGI)
|
||
* @param string|null $spec 규격 (120*70, 650*550 등)
|
||
* @return float 단가
|
||
*/
|
||
public function getBDModelPrice(
|
||
string $modelName,
|
||
string $secondItem,
|
||
?string $finishingType = null,
|
||
?string $spec = null
|
||
): float {
|
||
// BDmodels는 복잡한 구조이므로 items 테이블의 기존 데이터 활용
|
||
// TODO: 필요시 kd_price_tables TYPE_BDMODELS 추가
|
||
return 0.0;
|
||
}
|
||
|
||
/**
|
||
* price_* 테이블에서 단가 조회 (모터, 샤프트, 파이프, 앵글)
|
||
*
|
||
* @param string $tableName 테이블명 (motor, shaft, pipe, angle)
|
||
* @param array $conditions 조회 조건
|
||
* @return float 단가
|
||
*/
|
||
public function getPriceFromTable(string $tableName, array $conditions): float
|
||
{
|
||
$query = KdPriceTable::where('table_type', $tableName)->active();
|
||
|
||
foreach ($conditions as $field => $value) {
|
||
$query->where($field, $value);
|
||
}
|
||
|
||
$record = $query->first();
|
||
|
||
return (float) ($record?->unit_price ?? 0);
|
||
}
|
||
|
||
/**
|
||
* 원자재 단가 조회
|
||
*
|
||
* @param string $materialName 원자재명 (실리카, 스크린 등)
|
||
* @return float 단가
|
||
*/
|
||
public function getRawMaterialPrice(string $materialName): float
|
||
{
|
||
return KdPriceTable::getRawMaterialPrice($materialName);
|
||
}
|
||
|
||
/**
|
||
* 모터 단가 조회
|
||
*
|
||
* @param string $motorCapacity 모터 용량 (150K, 300K 등)
|
||
* @return float 단가
|
||
*/
|
||
public function getMotorPrice(string $motorCapacity): float
|
||
{
|
||
return KdPriceTable::getMotorPrice($motorCapacity);
|
||
}
|
||
|
||
/**
|
||
* 제어기 단가 조회
|
||
*
|
||
* @param string $controllerType 제어기 타입 (매립형, 노출형, 뒷박스)
|
||
* @return float 단가
|
||
*/
|
||
public function getControllerPrice(string $controllerType): float
|
||
{
|
||
return KdPriceTable::getControllerPrice($controllerType);
|
||
}
|
||
|
||
/**
|
||
* 샤프트 단가 조회
|
||
*
|
||
* @param string $size 사이즈 (3, 4, 5인치)
|
||
* @param float $length 길이 (m 단위)
|
||
* @return float 단가
|
||
*/
|
||
public function getShaftPrice(string $size, float $length): float
|
||
{
|
||
return KdPriceTable::getShaftPrice($size, $length);
|
||
}
|
||
|
||
/**
|
||
* 파이프 단가 조회
|
||
*
|
||
* @param string $thickness 두께 (1.4 등)
|
||
* @param int $length 길이 (3000, 6000)
|
||
* @return float 단가
|
||
*/
|
||
public function getPipePrice(string $thickness, int $length): float
|
||
{
|
||
return KdPriceTable::getPipePrice($thickness, $length);
|
||
}
|
||
|
||
/**
|
||
* 앵글 단가 조회
|
||
*
|
||
* @param string $type 타입 (스크린용, 철재용)
|
||
* @param string $bracketSize 브라켓크기 (530*320, 600*350, 690*390)
|
||
* @param string $angleType 앵글타입 (앵글3T, 앵글4T)
|
||
* @return float 단가
|
||
*/
|
||
public function getAnglePrice(string $type, string $bracketSize, string $angleType): float
|
||
{
|
||
return KdPriceTable::getAnglePrice($type, $bracketSize, $angleType);
|
||
}
|
||
|
||
// =========================================================================
|
||
// 절곡품 계산 (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'] ?? 'KSS01';
|
||
$finishingType = $params['finishing_type'] ?? 'SUS';
|
||
|
||
// 절곡품 관련 파라미터
|
||
$caseSpec = $params['case_spec'] ?? '500*380';
|
||
$caseLength = (float) ($params['case_length'] ?? $width); // mm 단위
|
||
$guideType = $params['guide_type'] ?? '벽면형'; // 벽면형, 측면형, 혼합형
|
||
$guideSpec = $params['guide_spec'] ?? '120*70'; // 120*70, 120*100
|
||
$guideLength = (float) ($params['guide_length'] ?? ($height + 550)) / 1000; // m 단위
|
||
$bottomBarLength = (float) ($params['bottombar_length'] ?? $width) / 1000; // m 단위
|
||
$lbarLength = (float) ($params['lbar_length'] ?? $width) / 1000; // m 단위
|
||
$flatBarLength = (float) ($params['flatbar_length'] ?? $width) / 1000; // m 단위
|
||
$weightPlateQty = (int) ($params['weight_plate_qty'] ?? 0); // 무게평철 수량
|
||
$roundBarQty = (int) ($params['round_bar_qty'] ?? 0); // 환봉 수량
|
||
|
||
// 1. 케이스 (단가/1000 × 길이mm × 수량)
|
||
$casePrice = KdPriceTable::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 = KdPriceTable::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. 케이스 마구리 (단가 × 수량)
|
||
$caseCapPrice = KdPriceTable::getCaseCapPrice($caseSpec);
|
||
if ($caseCapPrice > 0) {
|
||
$capQty = 2 * $quantity; // 좌우 2개
|
||
$items[] = [
|
||
'category' => 'steel',
|
||
'item_name' => '케이스 마구리',
|
||
'specification' => $caseSpec,
|
||
'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 = KdPriceTable::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 = KdPriceTable::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 = KdPriceTable::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 = KdPriceTable::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 = KdPriceTable::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 = KdPriceTable::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 = KdPriceTable::getGuideRailPrice($modelName, $finishingType, '120*70');
|
||
$price100 = KdPriceTable::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. 각파이프
|
||
$pipeThickness = '1.4';
|
||
$pipeLength = $width > 3000 ? 6000 : 3000;
|
||
$pipePrice = $this->getPipePrice($pipeThickness, $pipeLength);
|
||
if ($pipePrice > 0) {
|
||
$items[] = [
|
||
'category' => 'parts',
|
||
'item_name' => '각파이프',
|
||
'specification' => "{$pipeThickness}T {$pipeLength}mm",
|
||
'unit' => 'EA',
|
||
'quantity' => $quantity,
|
||
'unit_price' => $pipePrice,
|
||
'total_price' => $pipePrice * $quantity,
|
||
];
|
||
}
|
||
|
||
// 3. 앵글
|
||
$angleType = $productType === 'steel' ? '철재용' : '스크린용';
|
||
$angleSpec = $bracketSize === '690*390' ? '앵글4T' : '앵글3T';
|
||
$anglePrice = $this->getAnglePrice($angleType, $bracketSize, $angleSpec);
|
||
if ($anglePrice > 0) {
|
||
$items[] = [
|
||
'category' => 'parts',
|
||
'item_name' => "앵글 {$angleSpec}",
|
||
'specification' => "{$angleType} {$bracketSize}",
|
||
'unit' => 'EA',
|
||
'quantity' => 2 * $quantity, // 좌우 2개
|
||
'unit_price' => $anglePrice,
|
||
'total_price' => $anglePrice * 2 * $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 로직)
|
||
$area = ($width * ($height + 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;
|
||
|
||
// 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. 제어기
|
||
$controllerType = $inputs['controller_type'] ?? '매립형';
|
||
$controllerPrice = $this->getControllerPrice($controllerType);
|
||
$items[] = [
|
||
'category' => 'controller',
|
||
'item_code' => 'KD-CTRL-'.strtoupper($controllerType),
|
||
'item_name' => "제어기 {$controllerType}",
|
||
'specification' => $controllerType,
|
||
'unit' => 'EA',
|
||
'quantity' => $quantity,
|
||
'unit_price' => $controllerPrice,
|
||
'total_price' => $controllerPrice * $quantity,
|
||
];
|
||
|
||
// 4. 절곡품
|
||
$steelItems = $this->calculateSteelItems($inputs);
|
||
$items = array_merge($items, $steelItems);
|
||
|
||
// 5. 부자재
|
||
$partItems = $this->calculatePartItems($inputs);
|
||
$items = array_merge($items, $partItems);
|
||
|
||
return $items;
|
||
}
|
||
}
|