webmoney/backend/app/Models/Budget.php
marcoitaloesp-ai 604302ada4
fix: Change transaction_type to type in controllers and models
- FinancialHealthController: Fix column name in queries
- ReportController: Fix column name in queries
- Budget model: Fix getSpentAmountAttribute query
2025-12-14 16:36:31 +00:00

165 lines
4.3 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class Budget extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'category_id',
'name',
'amount',
'currency',
'year',
'month',
'period_type',
'is_active',
'notes',
];
protected $casts = [
'amount' => 'decimal:2',
'is_active' => 'boolean',
];
protected $appends = [
'spent_amount',
'remaining_amount',
'usage_percentage',
'is_exceeded',
'period_label',
];
// ============================================
// Relaciones
// ============================================
public function user()
{
return $this->belongsTo(User::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
// ============================================
// Accessors
// ============================================
public function getSpentAmountAttribute()
{
// Calcular el gasto real de las transacciones
$query = Transaction::where('user_id', $this->user_id)
->where('type', 'debit')
->whereYear('transaction_date', $this->year);
if ($this->period_type === 'monthly' && $this->month) {
$query->whereMonth('transaction_date', $this->month);
}
if ($this->category_id) {
// Incluir subcategorías
$categoryIds = [$this->category_id];
$subcategories = Category::where('parent_id', $this->category_id)->pluck('id')->toArray();
$categoryIds = array_merge($categoryIds, $subcategories);
$query->whereIn('category_id', $categoryIds);
}
return abs($query->sum('amount'));
}
public function getRemainingAmountAttribute()
{
return $this->amount - $this->spent_amount;
}
public function getUsagePercentageAttribute()
{
if ($this->amount <= 0) return 0;
return round(($this->spent_amount / $this->amount) * 100, 1);
}
public function getIsExceededAttribute()
{
return $this->spent_amount > $this->amount;
}
public function getPeriodLabelAttribute()
{
if ($this->period_type === 'yearly') {
return $this->year;
}
$months = [
1 => 'Enero', 2 => 'Febrero', 3 => 'Marzo', 4 => 'Abril',
5 => 'Mayo', 6 => 'Junio', 7 => 'Julio', 8 => 'Agosto',
9 => 'Septiembre', 10 => 'Octubre', 11 => 'Noviembre', 12 => 'Diciembre'
];
return ($months[$this->month] ?? '') . ' ' . $this->year;
}
// ============================================
// Methods
// ============================================
public static function copyToNextMonth($userId, $fromYear, $fromMonth)
{
$nextMonth = $fromMonth === 12 ? 1 : $fromMonth + 1;
$nextYear = $fromMonth === 12 ? $fromYear + 1 : $fromYear;
$budgets = self::where('user_id', $userId)
->where('year', $fromYear)
->where('month', $fromMonth)
->where('is_active', true)
->get();
foreach ($budgets as $budget) {
self::firstOrCreate([
'user_id' => $userId,
'category_id' => $budget->category_id,
'year' => $nextYear,
'month' => $nextMonth,
], [
'name' => $budget->name,
'amount' => $budget->amount,
'currency' => $budget->currency,
'period_type' => 'monthly',
'is_active' => true,
]);
}
}
// ============================================
// Scopes
// ============================================
public function scopeActive($query)
{
return $query->where('is_active', true);
}
public function scopeForPeriod($query, $year, $month = null)
{
$query->where('year', $year);
if ($month) {
$query->where('month', $month);
}
return $query;
}
public function scopeForUser($query, $userId)
{
return $query->where('user_id', $userId);
}
}