webmoney/backend/app/Models/FinancialGoal.php
marcoitaloesp-ai 854e90e23c
v1.32.0 - Financial Planning Suite: Health Score, Goals, Budgets & Reports
NEW FEATURES:
- Financial Health: Score 0-100, 6 metrics, insights, recommendations
- Goals: Create/edit savings goals, contributions, progress tracking
- Budgets: Monthly category limits, usage alerts, year summary
- Reports: 7 tabs with charts (category, evolution, projection, etc.)

BACKEND:
- New models: FinancialGoal, GoalContribution, Budget
- New controllers: FinancialHealthController, FinancialGoalController, BudgetController, ReportController
- New migrations: financial_goals, goal_contributions, budgets

FRONTEND:
- New pages: FinancialHealth.jsx, Goals.jsx, Budgets.jsx, Reports.jsx
- New services: financialHealthService, financialGoalService, budgetService, reportService
- Navigation: New 'Planning' group in sidebar

Chart.js integration for all visualizations
2025-12-14 16:31:45 +00:00

170 lines
4.2 KiB
PHP

<?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);
}
}