From d7ca8cfa007df46a552312bbffe84e7db74b5afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Sat, 21 Feb 2026 07:43:21 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=EA=B2=AC=EC=A0=81=20converted=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=EB=A5=BC=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EA=B8=B0=EB=B0=98(order=5Fid)=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Quote 모델에 getStatusAttribute() accessor 추가: order_id 존재 시 자동으로 'converted' 반환 - scopeConverted() → whereNotNull('order_id') 변경 - QuoteService/OrderService에서 status='converted' 직접 세팅 제거, order_id만 세팅 - 상태 필터 쿼리: converted는 order_id IS NOT NULL 기반 - 통계 쿼리: status='converted' → order_id IS NOT NULL - 수주 직접 등록 시에도 자동으로 수주전환 상태 반영 Co-Authored-By: Claude Opus 4.6 --- app/Models/Quote/Quote.php | 21 +++++++++++++++++++-- app/Services/OrderService.php | 3 +-- app/Services/Quote/QuoteService.php | 19 ++++++++++--------- app/Services/Stats/QuoteStatService.php | 2 +- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/app/Models/Quote/Quote.php b/app/Models/Quote/Quote.php index c8bde74..2a6a900 100644 --- a/app/Models/Quote/Quote.php +++ b/app/Models/Quote/Quote.php @@ -254,7 +254,7 @@ public function scopeFinalized($query) public function scopeConverted($query) { - return $query->where('status', self::STATUS_CONVERTED); + return $query->whereNotNull('order_id'); } /** @@ -339,12 +339,29 @@ public function isEditable(): bool return true; } + /** + * 상태 접근자: order_id가 존재하면 자동으로 'converted' 반환 + * DB에 status='converted'를 저장하지 않고, 수주 존재 여부로 판별 + */ + public function getStatusAttribute($value): string + { + if ($this->order_id) { + return self::STATUS_CONVERTED; + } + + return $value; + } + /** * 삭제 가능 여부 확인 */ public function isDeletable(): bool { - return ! in_array($this->status, [self::STATUS_FINALIZED, self::STATUS_CONVERTED]); + if ($this->order_id) { + return false; + } + + return $this->getRawOriginal('status') !== self::STATUS_FINALIZED; } /** diff --git a/app/Services/OrderService.php b/app/Services/OrderService.php index 8e8399b..59d32ed 100644 --- a/app/Services/OrderService.php +++ b/app/Services/OrderService.php @@ -755,9 +755,8 @@ public function createFromQuote(int $quoteId, array $data = []) $order->refresh(); $order->recalculateTotals()->save(); - // 견적 상태를 '수주전환완료'로 변경 + // 견적에 수주 연결 (status는 accessor가 자동으로 'converted' 반환) $quote->update([ - 'status' => Quote::STATUS_CONVERTED, 'order_id' => $order->id, 'updated_by' => $userId, ]); diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php index 021b3f1..cc71695 100644 --- a/app/Services/Quote/QuoteService.php +++ b/app/Services/Quote/QuoteService.php @@ -73,9 +73,11 @@ public function index(array $params): LengthAwarePaginator $query->where('quote_type', $quoteType); } - // 상태 필터 - if ($status) { - $query->where('status', $status); + // 상태 필터 (converted는 order_id 기반으로 판별) + if ($status === Quote::STATUS_CONVERTED) { + $query->whereNotNull('order_id'); + } elseif ($status) { + $query->where('status', $status)->whereNull('order_id'); } // 제품 카테고리 필터 @@ -592,12 +594,12 @@ public function cancelFinalize(int $id): Quote throw new NotFoundHttpException(__('error.quote_not_found')); } - if ($quote->status !== Quote::STATUS_FINALIZED) { - throw new BadRequestHttpException(__('error.quote_not_finalized')); + if ($quote->order_id) { + throw new BadRequestHttpException(__('error.quote_already_converted')); } - if ($quote->status === Quote::STATUS_CONVERTED) { - throw new BadRequestHttpException(__('error.quote_already_converted')); + if ($quote->getRawOriginal('status') !== Quote::STATUS_FINALIZED) { + throw new BadRequestHttpException(__('error.quote_not_finalized')); } $quote->update([ @@ -705,9 +707,8 @@ public function convertToOrder(int $id): Quote $order->recalculateTotals(); $order->save(); - // 견적 상태 변경 + // 견적에 수주 연결 (status는 accessor가 자동으로 'converted' 반환) $quote->update([ - 'status' => Quote::STATUS_CONVERTED, 'order_id' => $order->id, 'updated_by' => $userId, ]); diff --git a/app/Services/Stats/QuoteStatService.php b/app/Services/Stats/QuoteStatService.php index 5a09be9..49c6694 100644 --- a/app/Services/Stats/QuoteStatService.php +++ b/app/Services/Stats/QuoteStatService.php @@ -23,7 +23,7 @@ public function aggregateDaily(int $tenantId, Carbon $date): int COALESCE(SUM(total_amount), 0) as total_amount, SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END) as approved_count, SUM(CASE WHEN status = 'rejected' THEN 1 ELSE 0 END) as rejected_count, - SUM(CASE WHEN status = 'converted' THEN 1 ELSE 0 END) as conversion_count + SUM(CASE WHEN order_id IS NOT NULL THEN 1 ELSE 0 END) as conversion_count ") ->first();