170 lines
4.4 KiB
PHP
170 lines
4.4 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 RecurringTemplate extends Model
|
|
{
|
|
use HasFactory, SoftDeletes;
|
|
|
|
protected $fillable = [
|
|
'user_id',
|
|
'source_transaction_id',
|
|
'name',
|
|
'description',
|
|
'frequency',
|
|
'frequency_interval',
|
|
'day_of_month',
|
|
'day_of_week',
|
|
'start_date',
|
|
'end_date',
|
|
'max_occurrences',
|
|
'account_id',
|
|
'category_id',
|
|
'cost_center_id',
|
|
'type',
|
|
'planned_amount',
|
|
'transaction_description',
|
|
'notes',
|
|
'is_active',
|
|
'last_generated_date',
|
|
'occurrences_generated',
|
|
];
|
|
|
|
protected $casts = [
|
|
'start_date' => 'date',
|
|
'end_date' => 'date',
|
|
'last_generated_date' => 'date',
|
|
'planned_amount' => 'decimal:2',
|
|
'is_active' => 'boolean',
|
|
'frequency_interval' => 'integer',
|
|
'day_of_month' => 'integer',
|
|
'day_of_week' => 'integer',
|
|
'max_occurrences' => 'integer',
|
|
'occurrences_generated' => 'integer',
|
|
];
|
|
|
|
/**
|
|
* Frequências disponíveis
|
|
*/
|
|
public const FREQUENCIES = [
|
|
'daily' => ['label' => 'Diária', 'days' => 1],
|
|
'weekly' => ['label' => 'Semanal', 'days' => 7],
|
|
'biweekly' => ['label' => 'Quinzenal', 'days' => 14],
|
|
'monthly' => ['label' => 'Mensal', 'months' => 1],
|
|
'bimonthly' => ['label' => 'Bimestral', 'months' => 2],
|
|
'quarterly' => ['label' => 'Trimestral', 'months' => 3],
|
|
'semiannual' => ['label' => 'Semestral', 'months' => 6],
|
|
'annual' => ['label' => 'Anual', 'months' => 12],
|
|
];
|
|
|
|
// ============================================
|
|
// Relacionamentos
|
|
// ============================================
|
|
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class);
|
|
}
|
|
|
|
public function sourceTransaction(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Transaction::class, 'source_transaction_id');
|
|
}
|
|
|
|
public function account(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Account::class);
|
|
}
|
|
|
|
public function category(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Category::class);
|
|
}
|
|
|
|
public function costCenter(): BelongsTo
|
|
{
|
|
return $this->belongsTo(CostCenter::class);
|
|
}
|
|
|
|
public function instances(): HasMany
|
|
{
|
|
return $this->hasMany(RecurringInstance::class);
|
|
}
|
|
|
|
public function pendingInstances(): HasMany
|
|
{
|
|
return $this->hasMany(RecurringInstance::class)->where('status', 'pending');
|
|
}
|
|
|
|
public function paidInstances(): HasMany
|
|
{
|
|
return $this->hasMany(RecurringInstance::class)->where('status', 'paid');
|
|
}
|
|
|
|
// ============================================
|
|
// Métodos de Negócio
|
|
// ============================================
|
|
|
|
/**
|
|
* Verifica se pode gerar mais instâncias
|
|
*/
|
|
public function canGenerateMore(): bool
|
|
{
|
|
if (!$this->is_active) {
|
|
return false;
|
|
}
|
|
|
|
// Verificar limite de ocorrências
|
|
if ($this->max_occurrences !== null && $this->occurrences_generated >= $this->max_occurrences) {
|
|
return false;
|
|
}
|
|
|
|
// Verificar data fim
|
|
if ($this->end_date !== null && now()->startOfDay()->gt($this->end_date)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Retorna a frequência formatada para exibição
|
|
*/
|
|
public function getFrequencyLabelAttribute(): string
|
|
{
|
|
$freq = self::FREQUENCIES[$this->frequency] ?? null;
|
|
if (!$freq) {
|
|
return $this->frequency;
|
|
}
|
|
|
|
$label = $freq['label'];
|
|
if ($this->frequency_interval > 1) {
|
|
$label = "A cada {$this->frequency_interval} " . strtolower($label);
|
|
}
|
|
|
|
return $label;
|
|
}
|
|
|
|
/**
|
|
* Retorna quantas instâncias pendentes existem
|
|
*/
|
|
public function getPendingCountAttribute(): int
|
|
{
|
|
return $this->pendingInstances()->count();
|
|
}
|
|
|
|
/**
|
|
* Retorna o total pago até agora
|
|
*/
|
|
public function getTotalPaidAttribute(): float
|
|
{
|
|
return (float) $this->paidInstances()->sum('paid_amount');
|
|
}
|
|
}
|