feat: [수주관리] convertToOrder 개소 파싱 로직 추가
- convertToOrder에서 calculation_inputs.items[] 파싱하여 floor_code/symbol_code 매핑 - resolveLocationMapping() 공통 메소드 추출 (note 파싱 1순위, formula_source 2순위) - syncFromQuote와 동일한 2단계 파싱 로직으로 일관성 확보 - Exception → Throwable 변경 (동기화 실패 catch 범위 확대) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -448,7 +448,7 @@ public function update(int $id, array $data): Quote
|
||||
try {
|
||||
$this->orderService->setContext($tenantId, $userId);
|
||||
$this->orderService->syncFromQuote($quote, $quote->current_revision);
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
// 수주 동기화 실패는 로그만 남기고 견적 수정은 성공 처리
|
||||
Log::warning('Failed to sync order from quote', [
|
||||
'quote_id' => $quote->id,
|
||||
@@ -597,10 +597,14 @@ public function convertToOrder(int $id): Quote
|
||||
$order->created_by = $userId;
|
||||
$order->save();
|
||||
|
||||
// 수주 상세 품목 생성
|
||||
// 수주 상세 품목 생성 (개소 매핑 포함)
|
||||
$calculationInputs = $quote->calculation_inputs ?? [];
|
||||
$productItems = $calculationInputs['items'] ?? [];
|
||||
|
||||
$serialIndex = 1;
|
||||
foreach ($quote->items as $quoteItem) {
|
||||
$orderItem = OrderItem::createFromQuoteItem($quoteItem, $order->id, $serialIndex);
|
||||
$productMapping = $this->resolveLocationMapping($quoteItem, $productItems);
|
||||
$orderItem = OrderItem::createFromQuoteItem($quoteItem, $order->id, $serialIndex, $productMapping);
|
||||
$orderItem->created_by = $userId;
|
||||
$orderItem->save();
|
||||
$serialIndex++;
|
||||
@@ -622,6 +626,45 @@ public function convertToOrder(int $id): Quote
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 견적 품목에서 개소(층/부호) 매핑 정보 추출
|
||||
*
|
||||
* 1순위: note 필드 파싱 ("4F FSS-01" → floor_code:"4F", symbol_code:"FSS-01")
|
||||
* 2순위: formula_source → calculation_inputs.items[] 매칭
|
||||
*/
|
||||
private function resolveLocationMapping(QuoteItem $quoteItem, array $productItems): array
|
||||
{
|
||||
$floorCode = null;
|
||||
$symbolCode = null;
|
||||
|
||||
// 1순위: note에서 파싱
|
||||
$note = trim($quoteItem->note ?? '');
|
||||
if ($note !== '') {
|
||||
$parts = preg_split('/\s+/', $note, 2);
|
||||
$floorCode = $parts[0] ?? null;
|
||||
$symbolCode = $parts[1] ?? null;
|
||||
}
|
||||
|
||||
// 2순위: formula_source → calculation_inputs
|
||||
if (empty($floorCode) && empty($symbolCode)) {
|
||||
$productIndex = 0;
|
||||
$formulaSource = $quoteItem->formula_source ?? '';
|
||||
if (preg_match('/product_(\d+)/', $formulaSource, $matches)) {
|
||||
$productIndex = (int) $matches[1];
|
||||
}
|
||||
|
||||
if (isset($productItems[$productIndex])) {
|
||||
$floorCode = $productItems[$productIndex]['floor'] ?? null;
|
||||
$symbolCode = $productItems[$productIndex]['code'] ?? null;
|
||||
} elseif (count($productItems) === 1) {
|
||||
$floorCode = $productItems[0]['floor'] ?? null;
|
||||
$symbolCode = $productItems[0]['code'] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
return ['floor_code' => $floorCode, 'symbol_code' => $symbolCode];
|
||||
}
|
||||
|
||||
/**
|
||||
* 수주번호 생성
|
||||
* 형식: ORD-YYMMDD-NNN (예: ORD-260105-001)
|
||||
|
||||
Reference in New Issue
Block a user