'datetime', 'expires_at' => 'datetime', 'cooldown_ends_at' => 'datetime', 'converted_at' => 'datetime', ]; /** * 등록한 영업파트너 */ public function registeredBy(): BelongsTo { return $this->belongsTo(User::class, 'registered_by'); } /** * 전환된 테넌트 */ public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class, 'tenant_id'); } /** * 전환 처리자 */ public function convertedBy(): BelongsTo { return $this->belongsTo(User::class, 'converted_by'); } /** * 영업권 유효 여부 */ public function isActive(): bool { return $this->status === self::STATUS_ACTIVE && now()->lt($this->expires_at); } /** * 영업권 만료 여부 */ public function isExpired(): bool { return $this->status === self::STATUS_EXPIRED || now()->gte($this->expires_at); } /** * 테넌트 전환 완료 여부 */ public function isConverted(): bool { return $this->status === self::STATUS_CONVERTED; } /** * 영업 완료 여부 */ public function isCompleted(): bool { return $this->status === self::STATUS_COMPLETED; } /** * 재등록 대기 중 여부 */ public function isInCooldown(): bool { return $this->isExpired() && now()->lt($this->cooldown_ends_at); } /** * 재등록 가능 여부 */ public function canReRegister(): bool { return $this->isExpired() && now()->gte($this->cooldown_ends_at); } /** * 상태 라벨 */ public function getStatusLabelAttribute(): string { if ($this->isConverted()) { return '계약완료'; } if ($this->isCompleted()) { return '완료'; } if ($this->isActive()) { return '영업중'; } if ($this->isInCooldown()) { return '대기중'; } return '만료'; } /** * 상태 색상 (Tailwind CSS) */ public function getStatusColorAttribute(): string { if ($this->isConverted()) { return 'bg-green-100 text-green-800'; } if ($this->isCompleted()) { return 'bg-emerald-100 text-emerald-800'; } if ($this->isActive()) { return 'bg-blue-100 text-blue-800'; } if ($this->isInCooldown()) { return 'bg-yellow-100 text-yellow-800'; } return 'bg-gray-100 text-gray-800'; } /** * 남은 일수 */ public function getRemainingDaysAttribute(): int { if (!$this->isActive()) { return 0; } return max(0, now()->diffInDays($this->expires_at, false)); } /** * 명함 이미지 URL */ public function getBusinessCardUrlAttribute(): ?string { if (!$this->business_card_path) { return null; } return Storage::disk('tenant')->url($this->business_card_path); } /** * 명함 이미지 존재 여부 */ public function hasBusinessCard(): bool { return $this->business_card_path && Storage::disk('tenant')->exists($this->business_card_path); } /** * 신분증 이미지 존재 여부 */ public function hasIdCard(): bool { return $this->id_card_path && Storage::disk('tenant')->exists($this->id_card_path); } /** * 신분증 이미지 URL */ public function getIdCardUrlAttribute(): ?string { if (!$this->id_card_path) { return null; } return Storage::disk('tenant')->url($this->id_card_path); } /** * 통장사본 이미지 존재 여부 */ public function hasBankbook(): bool { return $this->bankbook_path && Storage::disk('tenant')->exists($this->bankbook_path); } /** * 통장사본 이미지 URL */ public function getBankbookUrlAttribute(): ?string { if (!$this->bankbook_path) { return null; } return Storage::disk('tenant')->url($this->bankbook_path); } /** * 스코프: 유효한 영업권 */ public function scopeActive($query) { return $query->where('status', self::STATUS_ACTIVE) ->where('expires_at', '>', now()); } /** * 스코프: 만료된 영업권 */ public function scopeExpired($query) { return $query->where(function ($q) { $q->where('status', self::STATUS_EXPIRED) ->orWhere('expires_at', '<=', now()); }); } /** * 스코프: 전환 완료 */ public function scopeConverted($query) { return $query->where('status', self::STATUS_CONVERTED); } /** * 스코프: 특정 영업파트너의 영업권 */ public function scopeByPartner($query, int $userId) { return $query->where('registered_by', $userId); } }