'date', 'bid_date' => 'date', 'submission_date' => 'date', 'confirm_date' => 'date', 'construction_start_date' => 'date', 'construction_end_date' => 'date', 'bidding_amount' => 'decimal:2', 'expense_items' => 'array', 'estimate_detail_items' => 'array', 'created_at' => 'datetime', 'updated_at' => 'datetime', 'deleted_at' => 'datetime', ]; /** * 상태 상수 */ public const STATUS_WAITING = 'waiting'; // 입찰대기 public const STATUS_SUBMITTED = 'submitted'; // 투찰 public const STATUS_FAILED = 'failed'; // 탈락 public const STATUS_INVALID = 'invalid'; // 유찰 public const STATUS_AWARDED = 'awarded'; // 낙찰 public const STATUS_HOLD = 'hold'; // 보류 public const STATUSES = [ self::STATUS_WAITING, self::STATUS_SUBMITTED, self::STATUS_FAILED, self::STATUS_INVALID, self::STATUS_AWARDED, self::STATUS_HOLD, ]; /** * 부가세 유형 상수 */ public const VAT_INCLUDED = 'included'; public const VAT_EXCLUDED = 'excluded'; public const VAT_TYPES = [ self::VAT_INCLUDED, self::VAT_EXCLUDED, ]; /** * 연결된 견적 */ public function quote(): BelongsTo { return $this->belongsTo(Quote::class); } /** * 거래처 */ public function client(): BelongsTo { return $this->belongsTo(Client::class); } /** * 입찰자 */ public function bidder(): BelongsTo { return $this->belongsTo(User::class, 'bidder_id'); } /** * 생성자 */ public function creator(): BelongsTo { return $this->belongsTo(User::class, 'created_by'); } /** * 수정자 */ public function updater(): BelongsTo { return $this->belongsTo(User::class, 'updated_by'); } /** * 상태별 스코프 */ public function scopeWaiting($query) { return $query->where('status', self::STATUS_WAITING); } public function scopeSubmitted($query) { return $query->where('status', self::STATUS_SUBMITTED); } public function scopeFailed($query) { return $query->where('status', self::STATUS_FAILED); } public function scopeInvalid($query) { return $query->where('status', self::STATUS_INVALID); } public function scopeAwarded($query) { return $query->where('status', self::STATUS_AWARDED); } public function scopeHold($query) { return $query->where('status', self::STATUS_HOLD); } /** * 상태 필터 스코프 */ public function scopeOfStatus($query, ?string $status) { if ($status) { return $query->where('status', $status); } return $query; } /** * 날짜 범위 스코프 */ public function scopeDateRange($query, ?string $from, ?string $to) { if ($from) { $query->where('bidding_date', '>=', $from); } if ($to) { $query->where('bidding_date', '<=', $to); } return $query; } /** * 검색 스코프 */ public function scopeSearch($query, ?string $keyword) { if (! $keyword) { return $query; } return $query->where(function ($q) use ($keyword) { $q->where('bidding_code', 'like', "%{$keyword}%") ->orWhere('client_name', 'like', "%{$keyword}%") ->orWhere('project_name', 'like', "%{$keyword}%") ->orWhere('bidder_name', 'like', "%{$keyword}%"); }); } /** * 수정 가능 여부 확인 */ public function isEditable(): bool { return ! in_array($this->status, [self::STATUS_AWARDED, self::STATUS_FAILED, self::STATUS_INVALID]); } /** * 삭제 가능 여부 확인 */ public function isDeletable(): bool { return ! in_array($this->status, [self::STATUS_AWARDED]); } /** * 낙찰 가능 여부 확인 */ public function isAwardable(): bool { return in_array($this->status, [self::STATUS_WAITING, self::STATUS_SUBMITTED, self::STATUS_HOLD]); } /** * 계약 전환 가능 여부 확인 */ public function isConvertibleToContract(): bool { return $this->status === self::STATUS_AWARDED; } }