77 lines
3.2 KiB
Python
77 lines
3.2 KiB
Python
from app.extensions import db
|
|
from app.utils.crypto import EncryptedText
|
|
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(EncryptedText, 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}>'
|
|
|
|
|
|
class TellerSyncPreview(db.Model):
|
|
"""
|
|
Temporary server-side storage for sync preview data.
|
|
Replaces cookie-based session storage which has a 4 KB limit —
|
|
large accounts (100+ transactions) exceeded that limit and caused
|
|
silent data loss on the confirm step.
|
|
One row per teller_account_id; overwritten on each new sync preview.
|
|
"""
|
|
__tablename__ = 'teller_sync_previews'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
teller_account_id = db.Column(
|
|
db.Integer, db.ForeignKey('teller_accounts.id'),
|
|
nullable=False, unique=True, index=True,
|
|
)
|
|
data_json = db.Column(db.Text, nullable=False)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
def __repr__(self):
|
|
return f'<TellerSyncPreview account_id={self.teller_account_id}>'
|