06/03 Optimize codes, fix Schwab Account sync error 2
This commit is contained in:
+41
-7
@@ -10,7 +10,8 @@ from app.models.account import Account
|
||||
from app.models.schwab_connection import SchwabConnection, SchwabAccount
|
||||
from app.services.schwab_service import (
|
||||
get_auth_url, exchange_code, _apply_token_data,
|
||||
get_account_number_hashes, get_accounts, sync_preview, import_transactions,
|
||||
get_account_number_hashes, get_accounts,
|
||||
sync_preview, import_transactions, sync_account_snapshot,
|
||||
ACCOUNT_TYPE_MAP,
|
||||
)
|
||||
|
||||
@@ -85,14 +86,24 @@ def callback():
|
||||
return redirect(url_for('schwab.index'))
|
||||
|
||||
for ra in raw_accounts:
|
||||
sec = ra.get('securitiesAccount', {})
|
||||
acct_num = sec.get('accountNumber', '')
|
||||
acct_hash = hash_map.get(acct_num, acct_num) # use hashValue, fall back to raw number
|
||||
sec = ra.get('securitiesAccount', {})
|
||||
acct_num = sec.get('accountNumber', '')
|
||||
acct_hash = hash_map.get(acct_num, acct_num)
|
||||
if not acct_hash:
|
||||
continue
|
||||
existing = SchwabAccount.query.filter_by(account_hash=acct_hash).first()
|
||||
if not existing:
|
||||
masked = '…' + acct_num[-4:] if len(acct_num) >= 4 else acct_num
|
||||
masked = '…' + acct_num[-4:] if len(acct_num) >= 4 else acct_num
|
||||
|
||||
# Try to find an existing record (by new hash or old raw number) so we
|
||||
# can update it in-place and preserve the pfm_account_id mapping.
|
||||
existing = (SchwabAccount.query.filter_by(account_hash=acct_hash).first() or
|
||||
SchwabAccount.query.filter_by(account_hash=acct_num).first() or
|
||||
SchwabAccount.query.filter_by(account_number_display=masked).first())
|
||||
|
||||
if existing:
|
||||
existing.connection = conn
|
||||
existing.account_hash = acct_hash
|
||||
existing.is_active = True
|
||||
else:
|
||||
db.session.add(SchwabAccount(
|
||||
connection=conn,
|
||||
account_hash=acct_hash,
|
||||
@@ -261,6 +272,29 @@ def full_resync(schwab_account_id):
|
||||
return redirect(url_for('schwab.index'))
|
||||
|
||||
|
||||
# ── Balance + position snapshot ───────────────────────────────────────────────
|
||||
|
||||
@schwab_bp.route('/snapshot/<int:schwab_account_id>', methods=['POST'])
|
||||
@login_required
|
||||
def sync_snapshot(schwab_account_id):
|
||||
"""Pull live balance and investment positions from Schwab and write to PFM."""
|
||||
sa = db.get_or_404(SchwabAccount, 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'))
|
||||
try:
|
||||
bal_updated, pos_synced = sync_account_snapshot(sa)
|
||||
flash(
|
||||
f'{sa.account_name}: balance updated'
|
||||
f'{f", {pos_synced} position(s) synced" if pos_synced else " (no positions found)"}.',
|
||||
'success',
|
||||
)
|
||||
except Exception as e:
|
||||
log.error('[schwab] sync_snapshot failed for id=%s: %s', schwab_account_id, e, exc_info=True)
|
||||
flash(f'Snapshot sync failed: {e}', 'danger')
|
||||
return redirect(url_for('schwab.index'))
|
||||
|
||||
|
||||
# ── Disconnect ────────────────────────────────────────────────────────────────
|
||||
|
||||
@schwab_bp.route('/disconnect', methods=['POST'])
|
||||
|
||||
Reference in New Issue
Block a user