Files
sam-api/app/Models/Bidding/Bidding.php

254 lines
5.7 KiB
PHP
Raw Normal View History

<?php
namespace App\Models\Bidding;
use App\Models\Members\User;
use App\Models\Orders\Client;
use App\Models\Quote\Quote;
use App\Traits\Auditable;
use App\Traits\BelongsToTenant;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class Bidding extends Model
{
use Auditable, BelongsToTenant, HasFactory, SoftDeletes;
protected $fillable = [
'tenant_id',
'bidding_code',
'quote_id',
// 거래처/현장
'client_id',
'client_name',
'project_name',
// 입찰 정보
'bidding_date',
'bid_date',
'submission_date',
'confirm_date',
'total_count',
'bidding_amount',
// 상태
'status',
// 입찰자
'bidder_id',
'bidder_name',
// 공사기간
'construction_start_date',
'construction_end_date',
'vat_type',
// 비고
'remarks',
// 견적 데이터 스냅샷
'expense_items',
'estimate_detail_items',
// 감사
'created_by',
'updated_by',
'deleted_by',
];
protected $casts = [
'bidding_date' => '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;
}
}