from app.extensions import db from datetime import datetime class SchwabConnection(db.Model): """OAuth connection to Schwab. One per user (single-user app).""" __tablename__ = 'schwab_connections' id = db.Column(db.Integer, primary_key=True) access_token = db.Column(db.Text, nullable=False) refresh_token = db.Column(db.Text, nullable=False) token_expires_at = db.Column(db.DateTime, nullable=False) # UTC is_active = db.Column(db.Boolean, default=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) last_synced_at = db.Column(db.DateTime, nullable=True) accounts = db.relationship('SchwabAccount', back_populates='connection', cascade='all, delete-orphan', lazy='dynamic') @property def token_is_expired(self): return datetime.utcnow() >= self.token_expires_at def __repr__(self): return f'' class SchwabAccount(db.Model): """Maps one Schwab account (identified by its encrypted hash) to a PFM account.""" __tablename__ = 'schwab_accounts' id = db.Column(db.Integer, primary_key=True) connection_id = db.Column(db.Integer, db.ForeignKey('schwab_connections.id'), nullable=False) account_hash = db.Column(db.String(100), unique=True, nullable=False, index=True) account_number_display = db.Column(db.String(20), nullable=True) # masked, e.g. "…4321" account_type = db.Column(db.String(50), nullable=True) # CASH / MARGIN / etc. account_name = db.Column(db.String(100), nullable=True) # display label pfm_account_id = db.Column(db.Integer, db.ForeignKey('accounts.id'), nullable=True) last_sync_date = db.Column(db.Date, nullable=True) last_schwab_txn_id = db.Column(db.String(64), nullable=True) is_active = db.Column(db.Boolean, default=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) connection = db.relationship('SchwabConnection', back_populates='accounts') pfm_account = db.relationship('Account') def __repr__(self): return f''