Files
double-entry-accounting/accounting/models.py
2025-05-08 16:12:33 +12:00

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')