'decimal:2', 'completed_amount' => 'decimal:2', 'scheduled_date' => 'date', 'completed_date' => 'date', 'recurrence_end_date' => 'date', 'is_recurring' => 'boolean', ]; // ============================================================ // 관계 정의 // ============================================================ /** * 테넌트 */ public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class); } /** * 관련 은행 계좌 */ public function bankAccount(): BelongsTo { return $this->belongsTo(BankAccount::class, 'related_bank_account_id'); } // ============================================================ // Accessors // ============================================================ /** * 포맷된 금액 */ public function getFormattedAmountAttribute(): string { $amount = abs($this->amount); if ($amount >= 100000000) { return number_format($amount / 100000000, 1) . '억원'; } elseif ($amount >= 10000000) { return number_format($amount / 10000000, 1) . '천만원'; } elseif ($amount >= 10000) { return number_format($amount / 10000, 0) . '만원'; } return number_format($amount) . '원'; } /** * 일정 유형 라벨 */ public function getTypeLabelAttribute(): string { return match ($this->schedule_type) { self::TYPE_INCOME => '입금 예정', self::TYPE_EXPENSE => '지급 예정', default => '기타', }; } /** * 상태 라벨 */ public function getStatusLabelAttribute(): string { return match ($this->status) { self::STATUS_PENDING => '예정', self::STATUS_COMPLETED => '완료', self::STATUS_CANCELLED => '취소', default => '미정', }; } /** * 일정 유형별 색상 클래스 */ public function getTypeColorClassAttribute(): string { return match ($this->schedule_type) { self::TYPE_INCOME => 'bg-green-100 text-green-800 border-green-200', self::TYPE_EXPENSE => 'bg-red-100 text-red-800 border-red-200', default => 'bg-gray-100 text-gray-800 border-gray-200', }; } /** * 상태별 색상 클래스 */ public function getStatusColorClassAttribute(): string { return match ($this->status) { self::STATUS_PENDING => 'bg-yellow-100 text-yellow-800', self::STATUS_COMPLETED => 'bg-green-100 text-green-800', self::STATUS_CANCELLED => 'bg-gray-100 text-gray-500', default => 'bg-gray-100 text-gray-800', }; } // ============================================================ // Scopes // ============================================================ /** * 입금 예정만 */ public function scopeIncome($query) { return $query->where('schedule_type', self::TYPE_INCOME); } /** * 지급 예정만 */ public function scopeExpense($query) { return $query->where('schedule_type', self::TYPE_EXPENSE); } /** * 예정 상태만 */ public function scopePending($query) { return $query->where('status', self::STATUS_PENDING); } /** * 완료 상태만 */ public function scopeCompleted($query) { return $query->where('status', self::STATUS_COMPLETED); } /** * 특정 월의 일정 */ public function scopeForMonth($query, int $year, int $month) { return $query->whereYear('scheduled_date', $year) ->whereMonth('scheduled_date', $month); } /** * 날짜 범위 필터 */ public function scopeDateBetween($query, string $startDate, string $endDate) { return $query->whereBetween('scheduled_date', [$startDate, $endDate]); } /** * 정렬 (예정일 기준) */ public function scopeOrdered($query) { return $query->orderBy('scheduled_date')->orderBy('id'); } // ============================================================ // 메서드 // ============================================================ /** * 입금 예정인지 확인 */ public function isIncome(): bool { return $this->schedule_type === self::TYPE_INCOME; } /** * 지급 예정인지 확인 */ public function isExpense(): bool { return $this->schedule_type === self::TYPE_EXPENSE; } /** * 예정 상태인지 확인 */ public function isPending(): bool { return $this->status === self::STATUS_PENDING; } /** * 완료 상태인지 확인 */ public function isCompleted(): bool { return $this->status === self::STATUS_COMPLETED; } /** * 완료 처리 */ public function markAsCompleted(?float $actualAmount = null, ?string $completedDate = null): void { $this->update([ 'status' => self::STATUS_COMPLETED, 'completed_date' => $completedDate ?? now()->toDateString(), 'completed_amount' => $actualAmount ?? $this->amount, 'updated_by' => auth()->id(), ]); } /** * 취소 처리 */ public function markAsCancelled(): void { $this->update([ 'status' => self::STATUS_CANCELLED, 'updated_by' => auth()->id(), ]); } /** * 일정 유형 목록 */ public static function getTypeOptions(): array { return [ self::TYPE_INCOME => '입금 예정', self::TYPE_EXPENSE => '지급 예정', ]; } /** * 상태 목록 */ public static function getStatusOptions(): array { return [ self::STATUS_PENDING => '예정', self::STATUS_COMPLETED => '완료', self::STATUS_CANCELLED => '취소', ]; } /** * 반복 규칙 목록 */ public static function getRecurrenceOptions(): array { return [ self::RECURRENCE_DAILY => '매일', self::RECURRENCE_WEEKLY => '매주', self::RECURRENCE_MONTHLY => '매월', self::RECURRENCE_YEARLY => '매년', ]; } }