session('show_encryption_prompt', false), 'netWorthEvolution' => Inertia::defer(fn () => $this->getNetWorthEvolution($request), 'dashboard'), 'topCategories' => Inertia::defer(fn () => $this->getTopCategories($request), 'dashboard'), 'cashflowSummary' => Inertia::defer(fn () => $this->getCashflowSummary($request), 'dashboard'), ]); } private function getNetWorthEvolution(Request $request): array { $user = $request->user(); $now = Carbon::now(); $start = $now->copy()->subMonths(12); $end = $now->copy(); $accounts = $user->activeSpace()->accounts() ->with(['bank:id,name,logo', 'realEstateDetail:account_id,linked_loan_account_id']) ->orderBy('position') ->orderBy('name') ->get(); return $this->accountMetricsService->getNetWorthEvolution($user->currency_code, $accounts, $start, $end); } private function getTopCategories(Request $request): array { $user = $request->user(); $now = Carbon::now(); $from = $now->copy()->subDays(30); $to = $now->copy(); $period = new PeriodComparator($from, $to); $previousPeriod = $period->previous(); $spaceId = $user->activeSpace()->id; $currentSpending = $this->categorySpendingService->forPeriod($spaceId, $period->from, $period->to); $previousSpending = $this->categorySpendingService->forPeriod($spaceId, $previousPeriod->from, $previousPeriod->to); $totalAmount = $currentSpending->sum('amount'); return $currentSpending ->sortByDesc('amount') ->take(10) ->map(function ($item) use ($previousSpending, $totalAmount) { $previousAmount = $previousSpending->firstWhere('category_id', $item['category_id'])['amount'] ?? 0; return [ 'category' => $item['category'], 'category_id' => $item['category_id'], 'amount' => $item['amount'], 'previous_amount' => $previousAmount, 'total_amount' => $totalAmount, 'has_children' => $item['has_children'], 'is_direct' => $item['is_direct'], ]; }) ->values() ->all(); } private function getCashflowSummary(Request $request): array { $user = $request->user(); $now = Carbon::now(); $from = $now->copy()->startOfMonth(); $to = $now->copy()->endOfMonth(); $period = new PeriodComparator($from, $to); $previousPeriod = $period->previous(); $spaceId = $user->activeSpace()->id; return [ 'current' => $this->calculateCashflowSummary($spaceId, $period->from, $period->to), 'previous' => $this->calculateCashflowSummary($spaceId, $previousPeriod->from, $previousPeriod->to), ]; } private function calculateCashflowSummary(string $spaceId, Carbon $from, Carbon $to): array { $income = max(0, $this->getTransactionSum($spaceId, $from, $to, CategoryType::Income)); $expense = max(0, -$this->getTransactionSum($spaceId, $from, $to, CategoryType::Expense)); return CashflowSummaryService::summarize($income, $expense); } private function getTransactionSum(string $spaceId, Carbon $from, Carbon $to, CategoryType $type): int { return Transaction::query() ->where('transactions.space_id', $spaceId) ->whereBetween('transactions.transaction_date', [$from, $to]) ->where(function ($q) use ($type) { $q->whereExists(function ($sub) use ($type) { $sub->select(DB::raw(1)) ->from('categories') ->whereColumn('categories.id', 'transactions.category_id') ->where('categories.type', $type); }) ->orWhere(function ($q) use ($type) { $q->whereNull('transactions.category_id') ->where('transactions.amount', $type === CategoryType::Income ? '>' : '<', 0); }); }) ->sum('transactions.amount'); } }