'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('transaction_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); } }