external_account_id) { return; } $performance = $client->getPerformance($account->external_account_id); $portfolios = $performance['portfolios'] ?? []; $netAmounts = $performance['net_amounts'] ?? []; if (empty($portfolios)) { Log::warning('No portfolio data from Indexa Capital', [ 'account_id' => $account->id, 'external_account_id' => $account->external_account_id, ]); return; } $sinceDate = null; if (! $isFirstSync) { $lastBalanceDate = $account->balances()->max('balance_date'); if ($lastBalanceDate) { $sinceDate = $lastBalanceDate; } } $accountCurrency = strtoupper($account->currency_code); $userCurrency = strtoupper($account->user->currency_code); $count = 0; foreach ($portfolios as $entry) { $date = $entry['date'] ?? null; $value = $entry['total_amount'] ?? null; if ($date === null || $value === null) { continue; } if ($sinceDate !== null && $date < $sinceDate) { continue; } $balanceCents = (int) round(floatval($value) * 100); $investedAmountCents = $this->calculateInvestedAmount($entry, $netAmounts, $accountCurrency, $userCurrency, $date); $account->balances()->updateOrCreate( ['balance_date' => $date], [ 'balance' => $balanceCents, ...($investedAmountCents !== null ? ['invested_amount' => $investedAmountCents] : []), ], ); $count++; } Log::info('Synced Indexa Capital balances', [ 'account_id' => $account->id, 'days_synced' => $count, ...($sinceDate ? ['since_date' => $sinceDate] : []), ]); } /** * Calculate invested amount from the net_amounts data, converted to the user's currency. * * Uses net_amounts (cumulative net inflows keyed by YYYYMMDD) which represents * the actual money invested (inflows - outflows - tax_outflows), matching * what Indexa Capital shows as "investment" on their dashboard. * * Falls back to total_amount - return if net_amounts is unavailable. * * @param array $entry * @param array $netAmounts */ private function calculateInvestedAmount(array $entry, array $netAmounts, string $accountCurrency, string $userCurrency, string $date): ?int { $entryDate = $entry['date'] ?? null; $amount = null; if ($entryDate !== null && ! empty($netAmounts)) { $dateKey = str_replace('-', '', $entryDate); if (isset($netAmounts[$dateKey])) { $amount = floatval($netAmounts[$dateKey]); } } if ($amount === null) { $totalAmount = $entry['total_amount'] ?? null; $returnValue = $entry['return'] ?? null; if ($totalAmount !== null && $returnValue !== null) { $amount = floatval($totalAmount) - floatval($returnValue); } } if ($amount === null) { return null; } if (strcasecmp($accountCurrency, $userCurrency) !== 0) { $amount = $this->currencyConverter->convert($accountCurrency, $userCurrency, $amount, $date); } return (int) round($amount * 100); } }