06/03 Optimize codes, fix Schwab Account sync errors

This commit is contained in:
2026-06-03 13:26:32 -04:00
parent e8601c59df
commit 56608ed220
2 changed files with 18 additions and 5 deletions
+6 -4
View File
@@ -10,7 +10,7 @@ from app.models.account import Account
from app.models.schwab_connection import SchwabConnection, SchwabAccount from app.models.schwab_connection import SchwabConnection, SchwabAccount
from app.services.schwab_service import ( from app.services.schwab_service import (
get_auth_url, exchange_code, _apply_token_data, get_auth_url, exchange_code, _apply_token_data,
get_accounts, sync_preview, import_transactions, get_account_number_hashes, get_accounts, sync_preview, import_transactions,
ACCOUNT_TYPE_MAP, ACCOUNT_TYPE_MAP,
) )
@@ -74,8 +74,9 @@ def callback():
db.session.add(conn) db.session.add(conn)
db.session.flush() db.session.flush()
# Fetch accounts and store them # Fetch account hash mapping first (hashValue is required for all API paths)
try: try:
hash_map = get_account_number_hashes(conn)
raw_accounts = get_accounts(conn) raw_accounts = get_accounts(conn)
except Exception as e: except Exception as e:
log.error('[schwab] get_accounts failed: %s', e, exc_info=True) log.error('[schwab] get_accounts failed: %s', e, exc_info=True)
@@ -85,12 +86,13 @@ def callback():
for ra in raw_accounts: for ra in raw_accounts:
sec = ra.get('securitiesAccount', {}) sec = ra.get('securitiesAccount', {})
acct_hash = sec.get('accountNumber', '') acct_num = sec.get('accountNumber', '')
acct_hash = hash_map.get(acct_num, acct_num) # use hashValue, fall back to raw number
if not acct_hash: if not acct_hash:
continue continue
existing = SchwabAccount.query.filter_by(account_hash=acct_hash).first() existing = SchwabAccount.query.filter_by(account_hash=acct_hash).first()
if not existing: if not existing:
masked = '' + acct_hash[-4:] if len(acct_hash) >= 4 else acct_hash masked = '' + acct_num[-4:] if len(acct_num) >= 4 else acct_num
db.session.add(SchwabAccount( db.session.add(SchwabAccount(
connection=conn, connection=conn,
account_hash=acct_hash, account_hash=acct_hash,
+11
View File
@@ -163,6 +163,17 @@ def _raise_for_status(resp, context=''):
# ── Public API helpers ──────────────────────────────────────────────────────── # ── Public API helpers ────────────────────────────────────────────────────────
def get_account_number_hashes(connection):
"""
Return {accountNumber: hashValue} mapping.
Schwab requires the hashValue (encrypted account number) in all endpoint paths.
"""
data = _authed_get(connection, '/trader/v1/accounts/accountNumbers')
mapping = {item['accountNumber']: item['hashValue'] for item in data}
log.info('[schwab] get_account_number_hashes: %d account(s)', len(mapping))
return mapping
def get_accounts(connection): def get_accounts(connection):
"""Return list of Schwab account dicts.""" """Return list of Schwab account dicts."""
data = _authed_get(connection, '/trader/v1/accounts', params={'fields': 'positions'}) data = _authed_get(connection, '/trader/v1/accounts', params={'fields': 'positions'})