feat: BOM 계산 debug_steps에 수식 정보 추가

- calculateKyungdongBom 메서드에 formulas 배열 추가
- Step 1: 입력값 (변수, 설명, 값, 단위)
- Step 3: 변수계산 (수식, 대입, 결과)
- Step 6-7: 품목별 수량/금액 계산 과정
- Step 9: 카테고리별 소계 계산
- Step 10: 최종합계 수식
- 프론트엔드에서 실제 계산 수식 확인 가능

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-29 08:17:34 +09:00
parent a0ffeb954b
commit 87e20e965a

View File

@@ -1059,10 +1059,13 @@ private function addProcessGroupToItems(array $items, array $groupedItems): arra
/**
* 품목 단가 조회
*
* @param string $itemCode 품목 코드
* @param int|null $tenantIdOverride 테넌트 ID (외부 호출 시 사용)
*/
private function getItemPrice(string $itemCode): float
public function getItemPrice(string $itemCode, ?int $tenantIdOverride = null): float
{
$tenantId = $this->tenantId();
$tenantId = $tenantIdOverride ?? $this->tenantId();
if (! $tenantId) {
$this->errors[] = __('error.tenant_id_required');
@@ -1580,14 +1583,20 @@ private function calculateKyungdongBom(
]);
// Step 1: 입력값 수집
$W0 = (float) ($inputVariables['W0'] ?? 0);
$H0 = (float) ($inputVariables['H0'] ?? 0);
$QTY = (int) ($inputVariables['QTY'] ?? 1);
$bracketInch = $inputVariables['bracket_inch'] ?? '5';
$productType = $inputVariables['product_type'] ?? 'screen';
$this->addDebugStep(1, '입력값수집', [
'W0' => $inputVariables['W0'] ?? null,
'H0' => $inputVariables['H0'] ?? null,
'QTY' => $inputVariables['QTY'] ?? 1,
'bracket_inch' => $inputVariables['bracket_inch'] ?? '5',
'product_type' => $inputVariables['product_type'] ?? 'screen',
'finishing_type' => $inputVariables['finishing_type'] ?? 'SUS',
'finished_goods' => $finishedGoodsCode,
'formulas' => [
['var' => 'W0', 'desc' => '개구부 폭', 'value' => $W0, 'unit' => 'mm'],
['var' => 'H0', 'desc' => '개구부 높이', 'value' => $H0, 'unit' => 'mm'],
['var' => 'QTY', 'desc' => '수량', 'value' => $QTY, 'unit' => 'EA'],
['var' => 'bracket_inch', 'desc' => '브라켓 인치', 'value' => $bracketInch, 'unit' => '인치'],
['var' => 'product_type', 'desc' => '제품 타입', 'value' => $productType, 'unit' => ''],
],
]);
// Step 2: 완제품 조회
@@ -1616,15 +1625,20 @@ private function calculateKyungdongBom(
$handler = new KyungdongFormulaHandler;
// Step 3: 경동 전용 변수 계산
$W0 = (float) ($inputVariables['W0'] ?? 0);
$H0 = (float) ($inputVariables['H0'] ?? 0);
$QTY = (int) ($inputVariables['QTY'] ?? 1);
$bracketInch = $inputVariables['bracket_inch'] ?? '5';
$productType = $inputVariables['product_type'] ?? 'screen';
// 중량 계산 (5130 로직)
$W1 = $W0 + 140;
$H1 = $H0 + 350;
$area = ($W0 * ($H0 + 550)) / 1000000;
$weight = $area * ($productType === 'steel' ? 25 : 2) + ($W0 / 1000) * 14.17;
// 중량 계산 (제품타입별)
if ($productType === 'steel') {
$weight = $area * 25;
$weightFormula = "AREA × 25";
$weightCalc = "{$area} × 25";
} else {
$weight = $area * 2 + ($W0 / 1000) * 14.17;
$weightFormula = "AREA × 2 + (W0 / 1000) × 14.17";
$weightCalc = "{$area} × 2 + ({$W0} / 1000) × 14.17";
}
// 모터 용량 결정
$motorCapacity = $handler->calculateMotorCapacity($productType, $weight, $bracketInch);
@@ -1636,8 +1650,8 @@ private function calculateKyungdongBom(
'W0' => $W0,
'H0' => $H0,
'QTY' => $QTY,
'W1' => $W0 + 140,
'H1' => $H0 + 350,
'W1' => $W1,
'H1' => $H1,
'AREA' => round($area, 4),
'WEIGHT' => round($weight, 2),
'MOTOR_CAPACITY' => $motorCapacity,
@@ -1647,13 +1661,56 @@ private function calculateKyungdongBom(
]);
$this->addDebugStep(3, '변수계산', [
'W0' => $W0,
'H0' => $H0,
'area' => round($area, 4),
'weight' => round($weight, 2),
'motor_capacity' => $motorCapacity,
'bracket_size' => $bracketSize,
'calculation_type' => '경동기업 전용 공식',
'formulas' => [
[
'var' => 'W1',
'desc' => '제작 폭',
'formula' => 'W0 + 140',
'calculation' => "{$W0} + 140",
'result' => $W1,
'unit' => 'mm',
],
[
'var' => 'H1',
'desc' => '제작 높이',
'formula' => 'H0 + 350',
'calculation' => "{$H0} + 350",
'result' => $H1,
'unit' => 'mm',
],
[
'var' => 'AREA',
'desc' => '면적',
'formula' => '(W0 × (H0 + 550)) / 1,000,000',
'calculation' => "({$W0} × ({$H0} + 550)) / 1,000,000",
'result' => round($area, 4),
'unit' => '㎡',
],
[
'var' => 'WEIGHT',
'desc' => '중량',
'formula' => $weightFormula,
'calculation' => $weightCalc,
'result' => round($weight, 2),
'unit' => 'kg',
],
[
'var' => 'MOTOR_CAPACITY',
'desc' => '모터 용량',
'formula' => '중량/브라켓 기준표 조회',
'calculation' => "WEIGHT({$weight}) + INCH({$bracketInch}) → 조회",
'result' => $motorCapacity,
'unit' => '',
],
[
'var' => 'BRACKET_SIZE',
'desc' => '브라켓 크기',
'formula' => '중량 기준표 조회',
'calculation' => "WEIGHT({$weight}) → 조회",
'result' => $bracketSize,
'unit' => '인치',
],
],
]);
// Step 4-7: 동적 항목 계산 (KyungdongFormulaHandler 사용)
@@ -1662,22 +1719,26 @@ private function calculateKyungdongBom(
$this->addDebugStep(4, 'BOM전개', [
'total_items' => count($dynamicItems),
'item_categories' => array_unique(array_column($dynamicItems, 'category')),
'items' => array_map(fn ($item) => [
'name' => $item['item_name'],
'category' => $item['category'],
], $dynamicItems),
]);
// Step 5-7: 단가 계산 (각 항목별)
$calculatedItems = [];
foreach ($dynamicItems as $item) {
$this->addDebugStep(6, '수량계산', [
'item_name' => $item['item_name'],
'quantity' => $item['quantity'],
]);
$itemFormulas = [];
$this->addDebugStep(7, '금액계산', [
'item_name' => $item['item_name'],
'quantity' => $item['quantity'],
foreach ($dynamicItems as $item) {
$itemFormulas[] = [
'item' => $item['item_name'],
'qty_formula' => $item['quantity_formula'] ?? '고정값',
'qty_result' => $item['quantity'],
'unit_price' => $item['unit_price'],
'total_price' => $item['total_price'],
]);
'price_formula' => '수량 × 단가',
'price_calc' => "{$item['quantity']} × {$item['unit_price']}",
'total' => $item['total_price'],
];
$calculatedItems[] = [
'item_code' => $item['item_code'] ?? '',
@@ -1686,13 +1747,23 @@ private function calculateKyungdongBom(
'specification' => $item['specification'] ?? '',
'unit' => $item['unit'],
'quantity' => $item['quantity'],
'quantity_formula' => $item['quantity_formula'] ?? '',
'unit_price' => $item['unit_price'],
'total_price' => $item['total_price'],
'category_group' => $item['category'],
'process_group' => $item['category'],
'calculation_note' => '경동기업 전용 계산',
];
}
$this->addDebugStep(6, '수량계산', [
'formulas' => $itemFormulas,
]);
$this->addDebugStep(7, '금액계산', [
'formulas' => $itemFormulas,
]);
// Step 8: 카테고리별 그룹화
$groupedItems = [];
foreach ($calculatedItems as $item) {
@@ -1718,22 +1789,33 @@ private function calculateKyungdongBom(
// Step 9: 소계 계산
$subtotals = [];
$subtotalFormulas = [];
foreach ($groupedItems as $category => $group) {
$subtotals[$category] = [
'name' => $group['name'],
'count' => count($group['items']),
'subtotal' => $group['subtotal'],
];
$subtotalFormulas[] = [
'category' => $group['name'],
'formula' => implode(' + ', array_map(fn ($i) => $i['item_name'], $group['items'])),
'result' => $group['subtotal'],
];
}
$this->addDebugStep(9, '소계계산', $subtotals);
$this->addDebugStep(9, '소계계산', [
'formulas' => $subtotalFormulas,
'subtotals' => $subtotals,
]);
// Step 10: 최종 합계
$grandTotal = array_sum(array_column($calculatedItems, 'total_price'));
$subtotalValues = array_column($subtotals, 'subtotal');
$this->addDebugStep(10, '최종합계', [
'item_count' => count($calculatedItems),
'grand_total' => $grandTotal,
'formula' => implode(' + ', array_column($subtotals, 'name')),
'calculation' => implode(' + ', array_map(fn ($v) => number_format($v), $subtotalValues)),
'result' => $grandTotal,
'formatted' => number_format($grandTotal).'원',
]);