diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php index f0d076a..a27fddc 100644 --- a/app/Services/Quote/QuoteService.php +++ b/app/Services/Quote/QuoteService.php @@ -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)