refactor:견적 converted 상태를 데이터 기반(order_id)으로 변경
- 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 <noreply@anthropic.com>
This commit is contained in:
@@ -254,7 +254,7 @@ public function scopeFinalized($query)
|
|||||||
|
|
||||||
public function scopeConverted($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;
|
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
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -755,9 +755,8 @@ public function createFromQuote(int $quoteId, array $data = [])
|
|||||||
$order->refresh();
|
$order->refresh();
|
||||||
$order->recalculateTotals()->save();
|
$order->recalculateTotals()->save();
|
||||||
|
|
||||||
// 견적 상태를 '수주전환완료'로 변경
|
// 견적에 수주 연결 (status는 accessor가 자동으로 'converted' 반환)
|
||||||
$quote->update([
|
$quote->update([
|
||||||
'status' => Quote::STATUS_CONVERTED,
|
|
||||||
'order_id' => $order->id,
|
'order_id' => $order->id,
|
||||||
'updated_by' => $userId,
|
'updated_by' => $userId,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -73,9 +73,11 @@ public function index(array $params): LengthAwarePaginator
|
|||||||
$query->where('quote_type', $quoteType);
|
$query->where('quote_type', $quoteType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 상태 필터
|
// 상태 필터 (converted는 order_id 기반으로 판별)
|
||||||
if ($status) {
|
if ($status === Quote::STATUS_CONVERTED) {
|
||||||
$query->where('status', $status);
|
$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'));
|
throw new NotFoundHttpException(__('error.quote_not_found'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($quote->status !== Quote::STATUS_FINALIZED) {
|
if ($quote->order_id) {
|
||||||
throw new BadRequestHttpException(__('error.quote_not_finalized'));
|
throw new BadRequestHttpException(__('error.quote_already_converted'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($quote->status === Quote::STATUS_CONVERTED) {
|
if ($quote->getRawOriginal('status') !== Quote::STATUS_FINALIZED) {
|
||||||
throw new BadRequestHttpException(__('error.quote_already_converted'));
|
throw new BadRequestHttpException(__('error.quote_not_finalized'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$quote->update([
|
$quote->update([
|
||||||
@@ -705,9 +707,8 @@ public function convertToOrder(int $id): Quote
|
|||||||
$order->recalculateTotals();
|
$order->recalculateTotals();
|
||||||
$order->save();
|
$order->save();
|
||||||
|
|
||||||
// 견적 상태 변경
|
// 견적에 수주 연결 (status는 accessor가 자동으로 'converted' 반환)
|
||||||
$quote->update([
|
$quote->update([
|
||||||
'status' => Quote::STATUS_CONVERTED,
|
|
||||||
'order_id' => $order->id,
|
'order_id' => $order->id,
|
||||||
'updated_by' => $userId,
|
'updated_by' => $userId,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public function aggregateDaily(int $tenantId, Carbon $date): int
|
|||||||
COALESCE(SUM(total_amount), 0) as total_amount,
|
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 = '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 = '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();
|
->first();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user