'integer', 'acted_at' => 'datetime', 'is_read' => 'boolean', 'read_at' => 'datetime', ]; protected $fillable = [ 'approval_id', 'step_order', 'step_type', 'approver_id', 'status', 'comment', 'acted_at', 'is_read', 'read_at', ]; protected $attributes = [ 'status' => 'pending', 'is_read' => false, ]; // ========================================================================= // 상태 상수 // ========================================================================= public const STATUS_PENDING = 'pending'; // 대기 public const STATUS_APPROVED = 'approved'; // 승인 public const STATUS_REJECTED = 'rejected'; // 반려 public const STATUS_SKIPPED = 'skipped'; // 건너뜀 public const STATUSES = [ self::STATUS_PENDING, self::STATUS_APPROVED, self::STATUS_REJECTED, self::STATUS_SKIPPED, ]; // ========================================================================= // 관계 정의 // ========================================================================= /** * 결재 문서 */ public function approval(): BelongsTo { return $this->belongsTo(Approval::class, 'approval_id'); } /** * 결재자/참조자 */ public function approver(): BelongsTo { return $this->belongsTo(User::class, 'approver_id'); } // ========================================================================= // 스코프 // ========================================================================= /** * 대기 중 */ public function scopePending($query) { return $query->where('status', self::STATUS_PENDING); } /** * 승인됨 */ public function scopeApproved($query) { return $query->where('status', self::STATUS_APPROVED); } /** * 특정 결재자 */ public function scopeByApprover($query, int $userId) { return $query->where('approver_id', $userId); } /** * 결재 단계만 (참조 제외) */ public function scopeApprovalOnly($query) { return $query->whereIn('step_type', [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT]); } /** * 참조만 */ public function scopeReferenceOnly($query) { return $query->where('step_type', ApprovalLine::STEP_TYPE_REFERENCE); } // ========================================================================= // 헬퍼 메서드 // ========================================================================= /** * 결재 가능 여부 */ public function isActionable(): bool { return $this->status === self::STATUS_PENDING && in_array($this->step_type, [ApprovalLine::STEP_TYPE_APPROVAL, ApprovalLine::STEP_TYPE_AGREEMENT]); } /** * 참조인지 확인 */ public function isReference(): bool { return $this->step_type === ApprovalLine::STEP_TYPE_REFERENCE; } /** * 상태 라벨 */ public function getStatusLabelAttribute(): string { return match ($this->status) { self::STATUS_PENDING => '대기', self::STATUS_APPROVED => '승인', self::STATUS_REJECTED => '반려', self::STATUS_SKIPPED => '건너뜀', default => $this->status, }; } /** * 단계 유형 라벨 */ public function getStepTypeLabelAttribute(): string { return match ($this->step_type) { ApprovalLine::STEP_TYPE_APPROVAL => '결재', ApprovalLine::STEP_TYPE_AGREEMENT => '합의', ApprovalLine::STEP_TYPE_REFERENCE => '참조', default => $this->step_type, }; } }