webmoney/backend/app/Models/LiabilityAccount.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);
}
}