You've already forked double-entry-accounting
106 lines
4.3 KiB
Python
106 lines
4.3 KiB
Python
import sqlalchemy as sa
|
|
from sqlalchemy.ext.declarative import declarative_base
|
|
from sqlalchemy.orm import sessionmaker, relationship
|
|
|
|
Base = declarative_base()
|
|
|
|
|
|
class Account(Base):
|
|
__tablename__ = 'accounts'
|
|
|
|
id = sa.Column(sa.Integer, primary_key=True)
|
|
name = sa.Column(sa.String(100), nullable=False)
|
|
account_type = sa.Column(sa.String(50), nullable=False) # Asset, Liability, Equity, Revenue, Expense
|
|
code = sa.Column(sa.String(20), unique=True, nullable=False)
|
|
parent_id = sa.Column(sa.Integer, sa.ForeignKey('accounts.id'))
|
|
balance = sa.Column(sa.Numeric(15, 2), default=0)
|
|
|
|
parent = relationship('Account', remote_side=[id])
|
|
entries = relationship('JournalEntryLine', back_populates='account')
|
|
|
|
def __repr__(self):
|
|
return f"<Account(code={self.code}, name={self.name}, type={self.account_type})>"
|
|
|
|
|
|
class JournalEntry(Base):
|
|
__tablename__ = 'journal_entries'
|
|
|
|
id = sa.Column(sa.Integer, primary_key=True)
|
|
date = sa.Column(sa.Date, nullable=False)
|
|
reference = sa.Column(sa.String(100))
|
|
description = sa.Column(sa.String(200))
|
|
created_at = sa.Column(sa.DateTime, server_default=sa.func.now())
|
|
|
|
lines = relationship('JournalEntryLine', back_populates='journal_entry')
|
|
|
|
|
|
class JournalEntryLine(Base):
|
|
__tablename__ = 'journal_entry_lines'
|
|
|
|
id = sa.Column(sa.Integer, primary_key=True)
|
|
journal_entry_id = sa.Column(sa.Integer, sa.ForeignKey('journal_entries.id'), nullable=False)
|
|
account_id = sa.Column(sa.Integer, sa.ForeignKey('accounts.id'), nullable=False)
|
|
amount = sa.Column(sa.Numeric(15, 2), nullable=False)
|
|
is_debit = sa.Column(sa.Boolean, nullable=False) # True for debit, False for credit
|
|
|
|
journal_entry = relationship('JournalEntry', back_populates='lines')
|
|
account = relationship('Account', back_populates='entries')
|
|
|
|
|
|
class BankAccount(Base):
|
|
__tablename__ = 'bank_accounts'
|
|
|
|
id = sa.Column(sa.Integer, primary_key=True)
|
|
name = sa.Column(sa.String(100), nullable=False)
|
|
account_number = sa.Column(sa.String(50))
|
|
bank_name = sa.Column(sa.String(100))
|
|
currency = sa.Column(sa.String(3), default='USD')
|
|
ledger_account_id = sa.Column(sa.Integer, sa.ForeignKey('accounts.id'))
|
|
|
|
ledger_account = relationship('Account')
|
|
transactions = relationship('BankTransaction', back_populates='bank_account')
|
|
|
|
|
|
class BankTransaction(Base):
|
|
__tablename__ = 'bank_transactions'
|
|
|
|
id = sa.Column(sa.Integer, primary_key=True)
|
|
bank_account_id = sa.Column(sa.Integer, sa.ForeignKey('bank_accounts.id'), nullable=False)
|
|
date = sa.Column(sa.Date, nullable=False)
|
|
amount = sa.Column(sa.Numeric(15, 2), nullable=False)
|
|
description = sa.Column(sa.String(200))
|
|
reference = sa.Column(sa.String(100))
|
|
status = sa.Column(sa.String(20), default='unreconciled') # unreconciled, reconciled
|
|
journal_entry_id = sa.Column(sa.Integer, sa.ForeignKey('journal_entries.id'))
|
|
|
|
bank_account = relationship('BankAccount', back_populates='transactions')
|
|
journal_entry = relationship('JournalEntry')
|
|
|
|
|
|
class ReconciliationReport(Base):
|
|
__tablename__ = 'reconciliation_reports'
|
|
|
|
id = sa.Column(sa.Integer, primary_key=True)
|
|
bank_account_id = sa.Column(sa.Integer, sa.ForeignKey('bank_accounts.id'), nullable=False)
|
|
start_date = sa.Column(sa.Date, nullable=False)
|
|
end_date = sa.Column(sa.Date, nullable=False)
|
|
created_at = sa.Column(sa.DateTime, server_default=sa.func.now())
|
|
status = sa.Column(sa.String(20), default='draft') # draft, completed
|
|
|
|
bank_account = relationship('BankAccount')
|
|
matches = relationship('ReconciliationMatch', back_populates='report')
|
|
|
|
|
|
class ReconciliationMatch(Base):
|
|
__tablename__ = 'reconciliation_matches'
|
|
|
|
id = sa.Column(sa.Integer, primary_key=True)
|
|
report_id = sa.Column(sa.Integer, sa.ForeignKey('reconciliation_reports.id'), nullable=False)
|
|
transaction_id = sa.Column(sa.Integer, sa.ForeignKey('bank_transactions.id'), nullable=False)
|
|
journal_entry_id = sa.Column(sa.Integer, sa.ForeignKey('journal_entries.id'), nullable=False)
|
|
match_score = sa.Column(sa.Numeric(5, 2)) # 0-100 score for match quality
|
|
notes = sa.Column(sa.String(200))
|
|
|
|
report = relationship('ReconciliationReport', back_populates='matches')
|
|
transaction = relationship('BankTransaction')
|
|
journal_entry = relationship('JournalEntry') |