- 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
170 lines
4.2 KiB
PHP
Executable File
170 lines
4.2 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Carbon\Carbon;
|
|
|
|
class FinancialGoal extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $fillable = [
|
|
'user_id',
|
|
'name',
|
|
'description',
|
|
'icon',
|
|
'color',
|
|
'target_amount',
|
|
'current_amount',
|
|
'currency',
|
|
'target_date',
|
|
'start_date',
|
|
'monthly_contribution',
|
|
'status',
|
|
'completed_at',
|
|
'priority',
|
|
];
|
|
|
|
protected $casts = [
|
|
'target_amount' => 'decimal:2',
|
|
'current_amount' => 'decimal:2',
|
|
'monthly_contribution' => 'decimal:2',
|
|
'target_date' => 'date',
|
|
'start_date' => 'date',
|
|
'completed_at' => 'date',
|
|
];
|
|
|
|
protected $appends = [
|
|
'progress_percentage',
|
|
'remaining_amount',
|
|
'months_remaining',
|
|
'required_monthly_saving',
|
|
'is_on_track',
|
|
'status_label',
|
|
];
|
|
|
|
// ============================================
|
|
// Relaciones
|
|
// ============================================
|
|
|
|
public function user()
|
|
{
|
|
return $this->belongsTo(User::class);
|
|
}
|
|
|
|
public function contributions()
|
|
{
|
|
return $this->hasMany(GoalContribution::class);
|
|
}
|
|
|
|
// ============================================
|
|
// Accessors
|
|
// ============================================
|
|
|
|
public function getProgressPercentageAttribute()
|
|
{
|
|
if ($this->target_amount <= 0) return 0;
|
|
return min(100, round(($this->current_amount / $this->target_amount) * 100, 1));
|
|
}
|
|
|
|
public function getRemainingAmountAttribute()
|
|
{
|
|
return max(0, $this->target_amount - $this->current_amount);
|
|
}
|
|
|
|
public function getMonthsRemainingAttribute()
|
|
{
|
|
if (!$this->target_date) return null;
|
|
|
|
$now = Carbon::now();
|
|
$target = Carbon::parse($this->target_date);
|
|
|
|
if ($target->isPast()) return 0;
|
|
|
|
return $now->diffInMonths($target);
|
|
}
|
|
|
|
public function getRequiredMonthlySavingAttribute()
|
|
{
|
|
if (!$this->months_remaining || $this->months_remaining <= 0) {
|
|
return $this->remaining_amount;
|
|
}
|
|
|
|
return round($this->remaining_amount / $this->months_remaining, 2);
|
|
}
|
|
|
|
public function getIsOnTrackAttribute()
|
|
{
|
|
if (!$this->monthly_contribution || !$this->required_monthly_saving) {
|
|
return null;
|
|
}
|
|
|
|
return $this->monthly_contribution >= $this->required_monthly_saving;
|
|
}
|
|
|
|
public function getStatusLabelAttribute()
|
|
{
|
|
return match($this->status) {
|
|
'active' => 'En progreso',
|
|
'completed' => 'Completada',
|
|
'paused' => 'Pausada',
|
|
'cancelled' => 'Cancelada',
|
|
default => $this->status,
|
|
};
|
|
}
|
|
|
|
// ============================================
|
|
// Methods
|
|
// ============================================
|
|
|
|
public function addContribution($amount, $date = null, $transactionId = null, $notes = null)
|
|
{
|
|
$contribution = $this->contributions()->create([
|
|
'amount' => $amount,
|
|
'contribution_date' => $date ?? now(),
|
|
'transaction_id' => $transactionId,
|
|
'notes' => $notes,
|
|
]);
|
|
|
|
$this->current_amount += $amount;
|
|
|
|
// Verificar si se completó la meta
|
|
if ($this->current_amount >= $this->target_amount) {
|
|
$this->status = 'completed';
|
|
$this->completed_at = now();
|
|
}
|
|
|
|
$this->save();
|
|
|
|
return $contribution;
|
|
}
|
|
|
|
public function markAsCompleted()
|
|
{
|
|
$this->status = 'completed';
|
|
$this->completed_at = now();
|
|
$this->save();
|
|
}
|
|
|
|
// ============================================
|
|
// Scopes
|
|
// ============================================
|
|
|
|
public function scopeActive($query)
|
|
{
|
|
return $query->where('status', 'active');
|
|
}
|
|
|
|
public function scopeCompleted($query)
|
|
{
|
|
return $query->where('status', 'completed');
|
|
}
|
|
|
|
public function scopeForUser($query, $userId)
|
|
{
|
|
return $query->where('user_id', $userId);
|
|
}
|
|
}
|