feat: Phase 1.2 - 다건 BOM 기반 자동산출 API 구현

- QuoteBomBulkCalculateRequest 생성 (React camelCase → API 약어 변환)
- QuoteCalculationService.calculateBomBulk() 메서드 추가
- POST /api/v1/quotes/calculate/bom/bulk 엔드포인트 추가
- Swagger 스키마 및 문서 업데이트

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-01-02 13:13:50 +09:00
parent 660300cebf
commit 4e59bbf574
6 changed files with 499 additions and 0 deletions

View File

@@ -113,6 +113,70 @@ public function calculateBom(string $finishedGoodsCode, array $inputs, bool $deb
return $result;
}
/**
* 다건 BOM 기반 견적 산출
*
* 여러 품목의 견적을 일괄 계산합니다.
* React 견적등록 화면에서 품목 목록의 자동 견적 산출 시 호출됩니다.
*
* @param array $inputItems 입력 품목 배열 (QuoteBomBulkCalculateRequest::getInputItems() 결과)
* @param bool $debug 디버그 모드 (기본 false)
* @return array 산출 결과 배열
*/
public function calculateBomBulk(array $inputItems, bool $debug = false): array
{
$results = [];
$successCount = 0;
$failCount = 0;
$grandTotal = 0;
foreach ($inputItems as $item) {
$index = $item['index'];
$finishedGoodsCode = $item['finished_goods_code'];
$inputs = $item['inputs'];
try {
$result = $this->calculateBom($finishedGoodsCode, $inputs, $debug);
if ($result['success'] ?? false) {
$successCount++;
$grandTotal += $result['grand_total'] ?? 0;
} else {
$failCount++;
}
$results[] = [
'index' => $index,
'finished_goods_code' => $finishedGoodsCode,
'inputs' => $inputs,
'result' => $result,
];
} catch (\Throwable $e) {
$failCount++;
$results[] = [
'index' => $index,
'finished_goods_code' => $finishedGoodsCode,
'inputs' => $inputs,
'result' => [
'success' => false,
'error' => $e->getMessage(),
],
];
}
}
return [
'success' => $failCount === 0,
'summary' => [
'total_count' => count($inputItems),
'success_count' => $successCount,
'fail_count' => $failCount,
'grand_total' => round($grandTotal, 2),
],
'items' => $results,
];
}
/**
* 견적 품목 재계산 (기존 견적 기준)
*/