05/31 Teller.io connection

This commit is contained in:
2026-05-31 22:40:02 -04:00
parent 67ed91d94c
commit 1d7ae3caf0
12 changed files with 1055 additions and 0 deletions
+2
View File
@@ -10,3 +10,5 @@ from app.models.investment import Investment, InvestmentTransaction
from app.models.net_worth_snapshot import NetWorthSnapshot
from app.models.ai_insight import AiInsight
from app.models.fx_rate import FxRate
from app.models.teller_enrollment import TellerEnrollment, TellerAccount
+53
View File
@@ -0,0 +1,53 @@
from app.extensions import db
from datetime import datetime
class TellerEnrollment(db.Model):
"""
Represents a Teller enrollment — one per connected bank institution.
An enrollment contains one or more accounts.
"""
__tablename__ = 'teller_enrollments'
id = db.Column(db.Integer, primary_key=True)
enrollment_id = db.Column(db.String(64), unique=True, nullable=False, index=True)
access_token = db.Column(db.String(128), nullable=False)
institution_name = db.Column(db.String(100), nullable=True)
user_id = db.Column(db.String(64), nullable=True) # Teller user ID
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('TellerAccount', back_populates='enrollment',
cascade='all, delete-orphan', lazy='dynamic')
def __repr__(self):
return f'<TellerEnrollment {self.institution_name} ({self.enrollment_id})>'
class TellerAccount(db.Model):
"""
Maps a Teller account to a PFM account.
Tracks the last synced transaction ID for incremental syncs.
"""
__tablename__ = 'teller_accounts'
id = db.Column(db.Integer, primary_key=True)
enrollment_id = db.Column(db.Integer, db.ForeignKey('teller_enrollments.id'), nullable=False)
teller_account_id = db.Column(db.String(64), unique=True, nullable=False, index=True)
pfm_account_id = db.Column(db.Integer, db.ForeignKey('accounts.id'), nullable=True)
account_name = db.Column(db.String(100), nullable=True)
account_type = db.Column(db.String(50), nullable=True) # depository / credit
account_subtype = db.Column(db.String(50), nullable=True) # checking / savings / credit_card
institution_name = db.Column(db.String(100), nullable=True)
last_sync_date = db.Column(db.Date, nullable=True) # date of last successful sync
last_teller_txn_id = db.Column(db.String(64), nullable=True) # for from_id pagination
is_active = db.Column(db.Boolean, default=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
enrollment = db.relationship('TellerEnrollment', back_populates='accounts')
pfm_account = db.relationship('Account')
def __repr__(self):
return f'<TellerAccount {self.account_name} → PFM #{self.pfm_account_id}>'