progress
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Float, Text, Index
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Date, Float, Boolean, Text, Index, ForeignKey, Enum
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.models.base import BaseModel
|
||||
import enum
|
||||
|
||||
|
||||
class BillingBatch(BaseModel):
|
||||
@@ -45,3 +48,174 @@ class BillingBatchFile(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
class StatementStatus(str, enum.Enum):
|
||||
"""Statement status enumeration"""
|
||||
DRAFT = "draft"
|
||||
PENDING_APPROVAL = "pending_approval"
|
||||
APPROVED = "approved"
|
||||
SENT = "sent"
|
||||
PAID = "paid"
|
||||
CANCELLED = "cancelled"
|
||||
|
||||
|
||||
class StatementTemplate(BaseModel):
|
||||
"""
|
||||
Templates for billing statement generation
|
||||
Allows customization of statement format, footer text, etc.
|
||||
"""
|
||||
__tablename__ = "statement_templates"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
name = Column(String(100), nullable=False, unique=True)
|
||||
description = Column(Text)
|
||||
|
||||
# Template content
|
||||
header_template = Column(Text) # HTML/Jinja2 template for header
|
||||
footer_template = Column(Text) # HTML/Jinja2 template for footer
|
||||
css_styles = Column(Text) # Custom CSS for statement styling
|
||||
|
||||
# Template settings
|
||||
is_default = Column(Boolean, default=False)
|
||||
is_active = Column(Boolean, default=True)
|
||||
|
||||
# Metadata
|
||||
created_at = Column(DateTime, default=func.now())
|
||||
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
|
||||
created_by = Column(String(50))
|
||||
|
||||
# Relationships
|
||||
statements = relationship("BillingStatement", back_populates="template")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<StatementTemplate(name='{self.name}', default={self.is_default})>"
|
||||
|
||||
|
||||
class BillingStatement(BaseModel):
|
||||
"""
|
||||
Generated billing statements for files/clients
|
||||
Tracks statement metadata, status, and generation details
|
||||
"""
|
||||
__tablename__ = "billing_statements"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
statement_number = Column(String(50), unique=True, nullable=False) # Unique statement identifier
|
||||
|
||||
# File/Client reference
|
||||
file_no = Column(String(45), ForeignKey("files.file_no"), nullable=False)
|
||||
customer_id = Column(String(45), ForeignKey("rolodex.id")) # Optional direct customer reference
|
||||
|
||||
# Statement period
|
||||
period_start = Column(Date, nullable=False)
|
||||
period_end = Column(Date, nullable=False)
|
||||
statement_date = Column(Date, nullable=False, default=func.current_date())
|
||||
due_date = Column(Date)
|
||||
|
||||
# Financial totals
|
||||
previous_balance = Column(Float, default=0.0)
|
||||
current_charges = Column(Float, default=0.0)
|
||||
payments_credits = Column(Float, default=0.0)
|
||||
total_due = Column(Float, nullable=False)
|
||||
|
||||
# Trust account information
|
||||
trust_balance = Column(Float, default=0.0)
|
||||
trust_applied = Column(Float, default=0.0)
|
||||
|
||||
# Statement details
|
||||
status = Column(Enum(StatementStatus), default=StatementStatus.DRAFT)
|
||||
template_id = Column(Integer, ForeignKey("statement_templates.id"))
|
||||
|
||||
# Generated content
|
||||
html_content = Column(Text) # Generated HTML content
|
||||
pdf_path = Column(String(500)) # Path to generated PDF file
|
||||
|
||||
# Billing metadata
|
||||
billed_transaction_count = Column(Integer, default=0)
|
||||
approved_by = Column(String(50)) # User who approved the statement
|
||||
approved_at = Column(DateTime)
|
||||
sent_by = Column(String(50)) # User who sent the statement
|
||||
sent_at = Column(DateTime)
|
||||
|
||||
# Metadata
|
||||
created_at = Column(DateTime, default=func.now())
|
||||
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
|
||||
created_by = Column(String(50))
|
||||
|
||||
# Notes and customization
|
||||
custom_footer = Column(Text) # Override template footer for this statement
|
||||
internal_notes = Column(Text) # Internal notes not shown to client
|
||||
|
||||
# Relationships
|
||||
file = relationship("File", back_populates="billing_statements")
|
||||
customer = relationship("Rolodex", back_populates="billing_statements")
|
||||
template = relationship("StatementTemplate", back_populates="statements")
|
||||
statement_items = relationship("BillingStatementItem", back_populates="statement", cascade="all, delete-orphan")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<BillingStatement(number='{self.statement_number}', file_no='{self.file_no}', total={self.total_due})>"
|
||||
|
||||
|
||||
class BillingStatementItem(BaseModel):
|
||||
"""
|
||||
Individual line items on a billing statement
|
||||
Links to ledger entries that were included in the statement
|
||||
"""
|
||||
__tablename__ = "billing_statement_items"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
statement_id = Column(Integer, ForeignKey("billing_statements.id"), nullable=False)
|
||||
ledger_id = Column(Integer, ForeignKey("ledger.id"), nullable=False)
|
||||
|
||||
# Item display details (cached from ledger for statement consistency)
|
||||
date = Column(Date, nullable=False)
|
||||
description = Column(Text)
|
||||
quantity = Column(Float, default=0.0)
|
||||
rate = Column(Float, default=0.0)
|
||||
amount = Column(Float, nullable=False)
|
||||
|
||||
# Item categorization
|
||||
item_category = Column(String(50)) # fees, costs, payments, adjustments
|
||||
|
||||
# Metadata
|
||||
created_at = Column(DateTime, default=func.now())
|
||||
|
||||
# Relationships
|
||||
statement = relationship("BillingStatement", back_populates="statement_items")
|
||||
ledger_entry = relationship("Ledger")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<BillingStatementItem(statement_id={self.statement_id}, amount={self.amount})>"
|
||||
|
||||
|
||||
class StatementPayment(BaseModel):
|
||||
"""
|
||||
Payments applied to billing statements
|
||||
Tracks payment history and application
|
||||
"""
|
||||
__tablename__ = "statement_payments"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
statement_id = Column(Integer, ForeignKey("billing_statements.id"), nullable=False)
|
||||
|
||||
# Payment details
|
||||
payment_date = Column(Date, nullable=False)
|
||||
payment_amount = Column(Float, nullable=False)
|
||||
payment_method = Column(String(50)) # check, credit_card, trust_transfer, etc.
|
||||
reference_number = Column(String(100)) # check number, transaction ID, etc.
|
||||
|
||||
# Application details
|
||||
applied_to_fees = Column(Float, default=0.0)
|
||||
applied_to_costs = Column(Float, default=0.0)
|
||||
applied_to_trust = Column(Float, default=0.0)
|
||||
|
||||
# Metadata
|
||||
created_at = Column(DateTime, default=func.now())
|
||||
created_by = Column(String(50))
|
||||
notes = Column(Text)
|
||||
|
||||
# Relationships
|
||||
statement = relationship("BillingStatement")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<StatementPayment(statement_id={self.statement_id}, amount={self.payment_amount})>"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user