feat(quote): quote_type 컬럼 추가 및 건설 견적 필터링 구현

- quotes 테이블에 quote_type 컬럼 추가 (manufacturing/construction)
- Quote 모델에 TYPE 상수 및 스코프 메서드 추가
- QuoteService.index()에 quote_type 필터 적용
- QuoteService.upsertFromSiteBriefing()에 construction 타입 설정
- QuoteIndexRequest에 quote_type 유효성 검증 추가
- 기존 site_briefing_id 있는 데이터는 construction으로 자동 업데이트

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-01-13 09:55:22 +09:00
parent 3a40db9444
commit 84ad9e1fc4
4 changed files with 218 additions and 0 deletions

View File

@@ -6,6 +6,7 @@
use App\Models\Members\User;
use App\Models\Orders\Client;
use App\Models\Orders\Order;
use App\Models\Tenants\SiteBriefing;
use App\Traits\BelongsToTenant;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@@ -19,7 +20,9 @@ class Quote extends Model
protected $fillable = [
'tenant_id',
'quote_type',
'order_id',
'site_briefing_id',
'quote_number',
'registration_date',
'receipt_date',
@@ -90,6 +93,18 @@ class Quote extends Model
'deleted_at' => 'datetime',
];
/**
* 견적 유형 상수
*/
public const TYPE_MANUFACTURING = 'manufacturing';
public const TYPE_CONSTRUCTION = 'construction';
public const TYPES = [
self::TYPE_MANUFACTURING,
self::TYPE_CONSTRUCTION,
];
/**
* 제품 카테고리 상수
*/
@@ -100,6 +115,8 @@ class Quote extends Model
/**
* 상태 상수
*/
public const STATUS_PENDING = 'pending'; // 견적대기 (현장설명회에서 자동생성)
public const STATUS_DRAFT = 'draft';
public const STATUS_SENT = 'sent';
@@ -112,6 +129,16 @@ class Quote extends Model
public const STATUS_CONVERTED = 'converted';
public const STATUSES = [
self::STATUS_PENDING,
self::STATUS_DRAFT,
self::STATUS_SENT,
self::STATUS_APPROVED,
self::STATUS_REJECTED,
self::STATUS_FINALIZED,
self::STATUS_CONVERTED,
];
/**
* 견적 품목들
*/
@@ -152,6 +179,14 @@ public function order(): BelongsTo
return $this->belongsTo(Order::class);
}
/**
* 현장설명회 (자동생성 시 연결)
*/
public function siteBriefing(): BelongsTo
{
return $this->belongsTo(SiteBriefing::class);
}
/**
* 확정자
*/
@@ -179,6 +214,11 @@ public function updater(): BelongsTo
/**
* 상태별 스코프
*/
public function scopePending($query)
{
return $query->where('status', self::STATUS_PENDING);
}
public function scopeDraft($query)
{
return $query->where('status', self::STATUS_DRAFT);
@@ -225,6 +265,24 @@ public function scopeSteel($query)
return $query->where('product_category', self::CATEGORY_STEEL);
}
/**
* 견적 유형별 스코프
*/
public function scopeManufacturing($query)
{
return $query->where('quote_type', self::TYPE_MANUFACTURING);
}
public function scopeConstruction($query)
{
return $query->where('quote_type', self::TYPE_CONSTRUCTION);
}
public function scopeOfType($query, string $type)
{
return $query->where('quote_type', $type);
}
/**
* 날짜 범위 스코프
*/