diff --git a/app/routes/investments.py b/app/routes/investments.py index 20635a7..56cf713 100644 --- a/app/routes/investments.py +++ b/app/routes/investments.py @@ -102,13 +102,15 @@ def sync_schwab(): import logging log = logging.getLogger(__name__) + # Use the active connection for ALL mapped accounts regardless of which + # connection_id was stored — accounts may still reference an old connection + # after a reconnect if the callback didn't update every record. connection = SchwabConnection.query.filter_by(is_active=True).first() if not connection: flash('No active Schwab connection. Connect at the Schwab page first.', 'warning') return redirect(url_for('investments.index')) accounts = SchwabAccount.query.filter( - SchwabAccount.connection_id == connection.id, SchwabAccount.pfm_account_id != None, SchwabAccount.is_active == True, ).all() @@ -117,19 +119,29 @@ def sync_schwab(): flash('No Schwab accounts mapped yet. Map them on the Schwab page first.', 'warning') return redirect(url_for('investments.index')) + # Patch every account to use the active connection before syncing + for sa in accounts: + sa.connection = connection + + ok_accounts, fail_accounts = [], [] total_pos = 0 for sa in accounts: try: _, pos = sync_account_snapshot(sa) total_pos += pos + ok_accounts.append(sa.account_name) except Exception as e: - log.error('[schwab] sync_schwab investments failed for %s: %s', sa.account_name, e, exc_info=True) - flash(f'Sync failed for {sa.account_name}: {e}', 'danger') + log.error('[schwab] sync_schwab failed for %s: %s', sa.account_name, e, exc_info=True) + fail_accounts.append(f'{sa.account_name} ({e})') - if total_pos: - flash(f'Synced {total_pos} holding(s) from Schwab.', 'success') - else: - flash('Sync complete — no positions found. Check System Logs for details.', 'info') + if ok_accounts: + flash(f'Synced {len(ok_accounts)} account(s)' + f'{f", {total_pos} position(s)" if total_pos else ""}.' + f' ({", ".join(ok_accounts)})', 'success') + if fail_accounts: + flash(f'Failed: {"; ".join(fail_accounts)}', 'danger') + if not ok_accounts and not fail_accounts: + flash('No mapped Schwab accounts found.', 'info') return redirect(url_for('investments.index')) diff --git a/app/routes/schwab.py b/app/routes/schwab.py index c6c7e19..eb9775f 100644 --- a/app/routes/schwab.py +++ b/app/routes/schwab.py @@ -282,6 +282,11 @@ def sync_snapshot(schwab_account_id): if not sa.pfm_account_id: flash('Map this account to a PFM account first.', 'warning') return redirect(url_for('schwab.index')) + # Always use the currently active connection — the stored connection_id on the + # account record may reference an older connection after a reconnect. + active_conn = SchwabConnection.query.filter_by(is_active=True).first() + if active_conn: + sa.connection = active_conn try: bal_updated, pos_synced = sync_account_snapshot(sa) flash(