06/03 Optimize app

This commit is contained in:
2026-06-03 16:06:30 -04:00
parent 4af31a611e
commit ec1c0fc7c1
14 changed files with 447 additions and 12 deletions
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""
Schwab daily auto-sync — balance, positions, and transactions.
Add to crontab (crontab -e):
# Sync Schwab every day at 7 AM
0 7 * * * /home/pfm/venv/bin/python /home/pfm/web/scripts/sync_schwab.py >> /home/pfm/web/logs/sync_schwab.log 2>&1
Or run manually:
python scripts/sync_schwab.py
"""
import sys
import os
import logging
from datetime import datetime
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from app import create_app
from app.extensions import db
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s|%(levelname)s|%(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
)
log = logging.getLogger(__name__)
app = create_app()
with app.app_context():
from app.models.schwab_connection import SchwabConnection, SchwabAccount
from app.services.schwab_service import (
sync_account_snapshot, sync_preview, import_transactions,
)
connection = SchwabConnection.query.filter_by(is_active=True).first()
if not connection:
log.warning('[sync_schwab] No active Schwab connection — skipping.')
sys.exit(0)
# Warn if refresh token is close to expiry
if connection.refresh_token_expires_at:
days_left = (connection.refresh_token_expires_at - datetime.utcnow()).days
if days_left <= 2:
log.warning('[sync_schwab] Schwab refresh token expires in %d day(s)! '
'Log in and reconnect at /schwab/connect.', days_left)
accounts = SchwabAccount.query.filter(
SchwabAccount.pfm_account_id != None,
SchwabAccount.is_active == True,
).all()
if not accounts:
log.warning('[sync_schwab] No mapped Schwab accounts found.')
sys.exit(0)
log.info('[sync_schwab] Syncing %d account(s)…', len(accounts))
for sa in accounts:
sa.connection = connection # always use active connection
# ── 1. Balance + positions ────────────────────────────────────────────
try:
bal_updated, pos_synced = sync_account_snapshot(sa)
log.info('[sync_schwab] %s — balance updated=%s positions=%d',
sa.account_name, bal_updated, pos_synced)
except Exception as e:
log.error('[sync_schwab] snapshot failed for %s: %s', sa.account_name, e,
exc_info=True)
# ── 2. New transactions ───────────────────────────────────────────────
try:
preview = sync_preview(sa)
if preview:
imported, skipped = import_transactions(preview, sa)
log.info('[sync_schwab] %s — transactions: imported=%d skipped=%d',
sa.account_name, imported, skipped)
else:
log.info('[sync_schwab] %s — no new transactions.', sa.account_name)
except Exception as e:
log.error('[sync_schwab] transaction sync failed for %s: %s',
sa.account_name, e, exc_info=True)
log.info('[sync_schwab] Done.')