feat(API): 견적-주문 연동 필드 및 마이그레이션 추가

- Order, OrderItem 모델에 견적 연동 필드 추가
- Quote 모델에 order_id 관계 추가
- QuoteService 개선
- 관련 마이그레이션 파일 추가

🤖 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-05 15:56:46 +09:00
parent 02e268e49a
commit 1410cf725a
9 changed files with 566 additions and 32 deletions

View File

@@ -2,6 +2,8 @@
namespace App\Services\Quote;
use App\Models\Orders\Order;
use App\Models\Orders\OrderItem;
use App\Models\Quote\Quote;
use App\Models\Quote\QuoteItem;
use App\Models\Quote\QuoteRevision;
@@ -369,7 +371,10 @@ public function convertToOrder(int $id): Quote
$tenantId = $this->tenantId();
$userId = $this->apiUserId();
$quote = Quote::where('tenant_id', $tenantId)->find($id);
$quote = Quote::where('tenant_id', $tenantId)
->with(['items', 'client'])
->find($id);
if (! $quote) {
throw new NotFoundHttpException(__('error.quote_not_found'));
}
@@ -378,19 +383,69 @@ public function convertToOrder(int $id): Quote
throw new BadRequestHttpException(__('error.quote_not_convertible'));
}
return DB::transaction(function () use ($quote, $userId) {
// TODO: 수주(Order) 생성 로직 구현
// $order = $this->orderService->createFromQuote($quote);
return DB::transaction(function () use ($quote, $userId, $tenantId) {
// 수주번호 생성
$orderNo = $this->generateOrderNumber($tenantId);
// 수주 마스터 생성
$order = Order::createFromQuote($quote, $orderNo);
$order->created_by = $userId;
$order->save();
// 수주 상세 품목 생성
$serialIndex = 1;
foreach ($quote->items as $quoteItem) {
$orderItem = OrderItem::createFromQuoteItem($quoteItem, $order->id, $serialIndex);
$orderItem->created_by = $userId;
$orderItem->save();
$serialIndex++;
}
// 수주 합계 재계산
$order->load('items');
$order->recalculateTotals();
$order->save();
// 견적 상태 변경
$quote->update([
'status' => Quote::STATUS_CONVERTED,
'order_id' => $order->id,
'updated_by' => $userId,
]);
return $quote->refresh()->load(['items', 'client']);
return $quote->refresh()->load(['items', 'client', 'order']);
});
}
/**
* 수주번호 생성
* 형식: ORD-YYMMDD-NNN (예: ORD-260105-001)
*/
private function generateOrderNumber(int $tenantId): string
{
$dateStr = now()->format('ymd');
$prefix = "ORD-{$dateStr}-";
$lastOrder = Order::withTrashed()
->where('tenant_id', $tenantId)
->where('order_no', 'like', $prefix.'%')
->orderBy('order_no', 'desc')
->first();
$sequence = 1;
if ($lastOrder) {
$parts = explode('-', $lastOrder->order_no);
if (count($parts) >= 3) {
$lastSeq = (int) end($parts);
$sequence = $lastSeq + 1;
}
}
$seqStr = str_pad((string) $sequence, 3, '0', STR_PAD_LEFT);
return "{$prefix}{$seqStr}";
}
/**
* 견적 품목 생성
*/