'Ativo', self::STATUS_PAID_OFF => 'Quitado', self::STATUS_DEFAULTED => 'Inadimplente', self::STATUS_RENEGOTIATED => 'Renegociado', ]; protected $fillable = [ 'user_id', 'account_id', 'name', 'contract_number', 'creditor', 'description', 'principal_amount', 'total_interest', 'total_fees', 'total_contract_value', 'total_paid', 'total_pending', 'principal_paid', 'interest_paid', 'fees_paid', 'monthly_interest_rate', 'annual_interest_rate', 'total_interest_rate', 'total_installments', 'paid_installments', 'pending_installments', 'start_date', 'end_date', 'first_due_date', 'currency', 'color', 'icon', 'status', 'is_active', ]; protected $casts = [ 'principal_amount' => 'decimal:2', 'total_interest' => 'decimal:2', 'total_fees' => 'decimal:2', 'total_contract_value' => 'decimal:2', 'total_paid' => 'decimal:2', 'total_pending' => 'decimal:2', 'principal_paid' => 'decimal:2', 'interest_paid' => 'decimal:2', 'fees_paid' => 'decimal:2', 'monthly_interest_rate' => 'decimal:4', 'annual_interest_rate' => 'decimal:4', 'total_interest_rate' => 'decimal:4', 'start_date' => 'date', 'end_date' => 'date', 'first_due_date' => 'date', 'is_active' => 'boolean', ]; protected $appends = ['progress_percentage', 'remaining_balance']; /** * Relação com o usuário */ public function user(): BelongsTo { return $this->belongsTo(User::class); } /** * Relação com a conta geral (opcional) */ public function account(): BelongsTo { return $this->belongsTo(Account::class); } /** * Parcelas do contrato */ public function installments(): HasMany { return $this->hasMany(LiabilityInstallment::class)->orderBy('installment_number'); } /** * Parcelas pagas */ public function paidInstallments(): HasMany { return $this->hasMany(LiabilityInstallment::class)->where('status', 'paid'); } /** * Parcelas pendentes */ public function pendingInstallments(): HasMany { return $this->hasMany(LiabilityInstallment::class)->where('status', 'pending'); } /** * Próxima parcela a vencer */ public function nextInstallment() { return $this->installments() ->where('status', 'pending') ->orderBy('due_date') ->first(); } /** * Percentual de progresso (quanto já foi pago do principal) */ public function getProgressPercentageAttribute(): float { if ($this->principal_amount <= 0) { return 0; } return round(($this->principal_paid / $this->principal_amount) * 100, 2); } /** * Saldo restante do principal */ public function getRemainingBalanceAttribute(): float { return $this->principal_amount - $this->principal_paid; } /** * Recalcular totais baseado nas parcelas */ public function recalculateTotals(): void { $installments = $this->installments()->get(); $this->total_installments = $installments->count(); $this->paid_installments = $installments->where('status', 'paid')->count(); $this->pending_installments = $installments->where('status', 'pending')->count(); // Totais do contrato $this->total_interest = $installments->sum('interest_amount'); $this->total_fees = $installments->sum('fee_amount'); $this->principal_amount = $installments->sum('principal_amount'); $this->total_contract_value = $installments->sum('installment_amount'); // Valores pagos $paidInstallments = $installments->where('status', 'paid'); $this->total_paid = $paidInstallments->sum('installment_amount'); $this->principal_paid = $paidInstallments->sum('principal_amount'); $this->interest_paid = $paidInstallments->sum('interest_amount'); $this->fees_paid = $paidInstallments->sum('fee_amount'); // Valores pendentes $pendingInstallments = $installments->where('status', 'pending'); $this->total_pending = $pendingInstallments->sum('installment_amount'); // Calcular taxas de juros $this->calculateInterestRates(); // Datas $firstInstallment = $installments->sortBy('due_date')->first(); $lastInstallment = $installments->sortBy('due_date')->last(); if ($firstInstallment) { $this->first_due_date = $firstInstallment->due_date; $this->start_date = $firstInstallment->due_date; } if ($lastInstallment) { $this->end_date = $lastInstallment->due_date; } // Atualizar status if ($this->pending_installments === 0 && $this->paid_installments > 0) { $this->status = self::STATUS_PAID_OFF; } $this->save(); } /** * Calcular taxas de juros baseado nos dados */ protected function calculateInterestRates(): void { if ($this->principal_amount <= 0) { return; } // Taxa total do contrato $this->total_interest_rate = round(($this->total_interest / $this->principal_amount) * 100, 4); // Taxa mensal média if ($this->total_installments > 0) { $this->monthly_interest_rate = round($this->total_interest_rate / $this->total_installments, 4); $this->annual_interest_rate = round($this->monthly_interest_rate * 12, 4); } } /** * Scope para contas ativas */ public function scopeActive($query) { return $query->where('is_active', true); } /** * Scope para um status específico */ public function scopeOfStatus($query, string $status) { return $query->where('status', $status); } }