239 lines
6.8 KiB
PHP
239 lines
6.8 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
|
|
class LiabilityAccount extends Model
|
|
{
|
|
use HasFactory, SoftDeletes;
|
|
|
|
/**
|
|
* Status do contrato
|
|
*/
|
|
public const STATUS_ACTIVE = 'active';
|
|
public const STATUS_PAID_OFF = 'paid_off';
|
|
public const STATUS_DEFAULTED = 'defaulted';
|
|
public const STATUS_RENEGOTIATED = 'renegotiated';
|
|
|
|
public const STATUSES = [
|
|
self::STATUS_ACTIVE => '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);
|
|
}
|
|
}
|