feat: 견적 BOM 자재 조회 기능 개선

- FormulaEvaluatorService: 품목마스터에서 규격/단위 조회 (getItemSpecAndUnit)
- QuoteService: 저장된 calculation_inputs로 BOM 자재 계산 (calculateBomMaterials)
- 견적 조회 시 bom_materials 데이터 자동 포함

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-06 13:28:10 +09:00
parent 1410cf725a
commit 31c6eced27
2 changed files with 130 additions and 11 deletions

View File

@@ -16,7 +16,8 @@
class QuoteService extends Service
{
public function __construct(
private QuoteNumberService $numberService
private QuoteNumberService $numberService,
private QuoteCalculationService $calculationService
) {}
/**
@@ -90,9 +91,79 @@ public function show(int $id): Quote
throw new NotFoundHttpException(__('error.quote_not_found'));
}
// BOM 자재 데이터 계산 및 추가
$bomMaterials = $this->calculateBomMaterials($quote);
if (! empty($bomMaterials)) {
$quote->setAttribute('bom_materials', $bomMaterials);
}
return $quote;
}
/**
* 저장된 calculation_inputs를 기반으로 BOM 자재 목록 계산
*/
private function calculateBomMaterials(Quote $quote): array
{
$calculationInputs = $quote->calculation_inputs;
// calculation_inputs가 없거나 items가 없으면 빈 배열 반환
if (empty($calculationInputs) || empty($calculationInputs['items'])) {
return [];
}
$inputItems = $calculationInputs['items'];
$allMaterials = [];
foreach ($inputItems as $index => $input) {
// 완제품 코드 찾기 (productName에 저장됨)
$finishedGoodsCode = $input['productName'] ?? null;
if (! $finishedGoodsCode) {
continue;
}
// BOM 계산을 위한 입력 변수 구성
$bomInputs = [
'W0' => (float) ($input['openWidth'] ?? 0),
'H0' => (float) ($input['openHeight'] ?? 0),
'QTY' => (float) ($input['quantity'] ?? 1),
'PC' => $input['productCategory'] ?? 'SCREEN',
'GT' => $input['guideRailType'] ?? 'wall',
'MP' => $input['motorPower'] ?? 'single',
'CT' => $input['controller'] ?? 'basic',
'WS' => (float) ($input['wingSize'] ?? 50),
'INSP' => (float) ($input['inspectionFee'] ?? 50000),
];
try {
$result = $this->calculationService->calculateBom($finishedGoodsCode, $bomInputs, false);
if (($result['success'] ?? false) && ! empty($result['items'])) {
// 각 자재 항목에 인덱스 정보 추가
foreach ($result['items'] as $material) {
$allMaterials[] = [
'item_index' => $index,
'finished_goods_code' => $finishedGoodsCode,
'item_code' => $material['item_code'] ?? '',
'item_name' => $material['item_name'] ?? '',
'specification' => $material['specification'] ?? '',
'unit' => $material['unit'] ?? 'EA',
'quantity' => $material['quantity'] ?? 0,
'unit_price' => $material['unit_price'] ?? 0,
'total_price' => $material['total_price'] ?? 0,
'formula_category' => $material['formula_category'] ?? '',
];
}
}
} catch (\Throwable) {
// BOM 계산 실패 시 해당 품목은 스킵
continue;
}
}
return $allMaterials;
}
/**
* 견적 생성
*/