06/03 Optimize codes, fix Schwab Account sync errors
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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'})
|
||||||
|
|||||||
Reference in New Issue
Block a user