webmoney/backend/app/Models/LiabilityInstallment.php
marco 54cccdd095 refactor: migração para desenvolvimento direto no servidor
- Removido README.md padrão do Laravel (backend)
- Removidos scripts de deploy (não mais necessários)
- Atualizado copilot-instructions.md para novo fluxo
- Adicionada documentação de auditoria do servidor
- Sincronizado código de produção com repositório

Novo workflow:
- Trabalhamos diretamente em /root/webmoney (symlink para /var/www/webmoney)
- Mudanças PHP são instantâneas
- Mudanças React requerem 'npm run build'
- Commit após validação funcional
2025-12-19 11:45:32 +01:00

148 lines
3.8 KiB
PHP
Executable File

<?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;
class LiabilityInstallment extends Model
{
use HasFactory, SoftDeletes;
/**
* Status da parcela
*/
public const STATUS_PENDING = 'pending';
public const STATUS_PAID = 'paid';
public const STATUS_PARTIAL = 'partial';
public const STATUS_OVERDUE = 'overdue';
public const STATUS_CANCELLED = 'cancelled';
public const STATUSES = [
self::STATUS_PENDING => 'Pendente',
self::STATUS_PAID => 'Pago',
self::STATUS_PARTIAL => 'Parcial',
self::STATUS_OVERDUE => 'Atrasado',
self::STATUS_CANCELLED => 'Cancelado',
];
protected $fillable = [
'liability_account_id',
'installment_number',
'due_date',
'installment_amount',
'principal_amount',
'interest_amount',
'fee_amount',
'paid_amount',
'paid_date',
'status',
'reconciled_transaction_id',
'payment_account_id',
'notes',
];
protected $casts = [
'due_date' => 'date',
'paid_date' => 'date',
'installment_amount' => 'decimal:2',
'principal_amount' => 'decimal:2',
'interest_amount' => 'decimal:2',
'fee_amount' => 'decimal:2',
'paid_amount' => 'decimal:2',
];
protected $appends = ['is_overdue', 'days_until_due'];
/**
* Relação com o contrato passivo
*/
public function liabilityAccount(): BelongsTo
{
return $this->belongsTo(LiabilityAccount::class);
}
/**
* Relação com a conta usada para pagamento
*/
public function paymentAccount(): BelongsTo
{
return $this->belongsTo(Account::class, 'payment_account_id');
}
/**
* Verificar se está atrasado
*/
public function getIsOverdueAttribute(): bool
{
if ($this->status === self::STATUS_PAID) {
return false;
}
return $this->due_date->isPast();
}
/**
* Dias até o vencimento (negativo se atrasado)
*/
public function getDaysUntilDueAttribute(): int
{
return now()->startOfDay()->diffInDays($this->due_date, false);
}
/**
* Marcar como pago
*/
public function markAsPaid(?float $amount = null, ?\DateTime $paidDate = null, ?int $paymentAccountId = null): void
{
$this->paid_amount = $amount ?? $this->installment_amount;
$this->paid_date = $paidDate ?? now();
$this->payment_account_id = $paymentAccountId;
$this->status = self::STATUS_PAID;
$this->save();
// Recalcular totais do contrato
$this->liabilityAccount->recalculateTotals();
}
/**
* Atualizar status baseado na data de vencimento
*/
public function updateOverdueStatus(): void
{
if ($this->status === self::STATUS_PENDING && $this->is_overdue) {
$this->status = self::STATUS_OVERDUE;
$this->save();
}
}
/**
* Scope para parcelas pendentes
*/
public function scopePending($query)
{
return $query->where('status', self::STATUS_PENDING);
}
/**
* Scope para parcelas pagas
*/
public function scopePaid($query)
{
return $query->where('status', self::STATUS_PAID);
}
/**
* Scope para parcelas atrasadas
*/
public function scopeOverdue($query)
{
return $query->where('status', self::STATUS_OVERDUE)
->orWhere(function ($q) {
$q->where('status', self::STATUS_PENDING)
->where('due_date', '<', now()->startOfDay());
});
}
}