maybe good
This commit is contained in:
31
app/models/__init__.py
Normal file
31
app/models/__init__.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Import all models for easy access
|
||||
"""
|
||||
from .base import BaseModel
|
||||
from .user import User
|
||||
from .rolodex import Rolodex, Phone
|
||||
from .files import File
|
||||
from .ledger import Ledger
|
||||
from .qdro import QDRO
|
||||
from .audit import AuditLog, LoginAttempt
|
||||
from .additional import Deposit, Payment, FileNote, FormVariable, ReportVariable
|
||||
from .pensions import (
|
||||
Pension, PensionSchedule, MarriageHistory, DeathBenefit,
|
||||
SeparationAgreement, LifeTable, NumberTable
|
||||
)
|
||||
from .lookups import (
|
||||
Employee, FileType, FileStatus, TransactionType, TransactionCode,
|
||||
State, GroupLookup, Footer, PlanInfo, FormIndex, FormList,
|
||||
PrinterSetup, SystemSetup
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"BaseModel", "User", "Rolodex", "Phone", "File", "Ledger", "QDRO",
|
||||
"AuditLog", "LoginAttempt",
|
||||
"Deposit", "Payment", "FileNote", "FormVariable", "ReportVariable",
|
||||
"Pension", "PensionSchedule", "MarriageHistory", "DeathBenefit",
|
||||
"SeparationAgreement", "LifeTable", "NumberTable",
|
||||
"Employee", "FileType", "FileStatus", "TransactionType", "TransactionCode",
|
||||
"State", "GroupLookup", "Footer", "PlanInfo", "FormIndex", "FormList",
|
||||
"PrinterSetup", "SystemSetup"
|
||||
]
|
||||
98
app/models/additional.py
Normal file
98
app/models/additional.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""
|
||||
Additional models for complete legacy system coverage
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Text, Date, Float, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class Deposit(BaseModel):
|
||||
"""
|
||||
Daily bank deposit summaries
|
||||
Corresponds to DEPOSITS table in legacy system
|
||||
"""
|
||||
__tablename__ = "deposits"
|
||||
|
||||
deposit_date = Column(Date, primary_key=True, index=True)
|
||||
total = Column(Float, nullable=False, default=0.0)
|
||||
notes = Column(Text)
|
||||
|
||||
# Relationships
|
||||
payments = relationship("Payment", back_populates="deposit", cascade="all, delete-orphan")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Deposit(date='{self.deposit_date}', total=${self.total})>"
|
||||
|
||||
|
||||
class Payment(BaseModel):
|
||||
"""
|
||||
Individual payments within deposits
|
||||
Corresponds to PAYMENTS table in legacy system
|
||||
"""
|
||||
__tablename__ = "payments"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
deposit_date = Column(Date, ForeignKey("deposits.deposit_date"), nullable=False)
|
||||
file_no = Column(String(45), ForeignKey("files.file_no"), nullable=True)
|
||||
client_id = Column(String(80), ForeignKey("rolodex.id"), nullable=True)
|
||||
regarding = Column(Text)
|
||||
amount = Column(Float, nullable=False, default=0.0)
|
||||
note = Column(Text)
|
||||
|
||||
# Relationships
|
||||
deposit = relationship("Deposit", back_populates="payments")
|
||||
file = relationship("File", back_populates="payments")
|
||||
client = relationship("Rolodex", back_populates="payments")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Payment(id={self.id}, amount=${self.amount}, file='{self.file_no}')>"
|
||||
|
||||
|
||||
class FileNote(BaseModel):
|
||||
"""
|
||||
Case file notes and memos
|
||||
Corresponds to FILENOTS table in legacy system
|
||||
"""
|
||||
__tablename__ = "file_notes"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
file_no = Column(String(45), ForeignKey("files.file_no"), nullable=False, index=True)
|
||||
memo_date = Column(Date, nullable=False, index=True)
|
||||
memo_note = Column(Text, nullable=False)
|
||||
|
||||
# Relationships
|
||||
file = relationship("File", back_populates="notes")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<FileNote(id={self.id}, file='{self.file_no}', date='{self.memo_date}')>"
|
||||
|
||||
|
||||
class FormVariable(BaseModel):
|
||||
"""
|
||||
Document template variables for form generation
|
||||
Corresponds to FVARLKUP table in legacy system
|
||||
"""
|
||||
__tablename__ = "form_variables"
|
||||
|
||||
identifier = Column(String(100), primary_key=True, index=True)
|
||||
query = Column(String(500), nullable=False)
|
||||
response = Column(Text)
|
||||
active = Column(Integer, default=1) # Legacy system uses integer for boolean
|
||||
|
||||
def __repr__(self):
|
||||
return f"<FormVariable(identifier='{self.identifier}')>"
|
||||
|
||||
|
||||
class ReportVariable(BaseModel):
|
||||
"""
|
||||
Report template variables for report generation
|
||||
Corresponds to RVARLKUP table in legacy system
|
||||
"""
|
||||
__tablename__ = "report_variables"
|
||||
|
||||
identifier = Column(String(100), primary_key=True, index=True)
|
||||
query = Column(String(500), nullable=False)
|
||||
active = Column(Integer, default=1) # Legacy system uses integer for boolean
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ReportVariable(identifier='{self.identifier}')>"
|
||||
49
app/models/audit.py
Normal file
49
app/models/audit.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""
|
||||
Audit logging models
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, JSON
|
||||
from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class AuditLog(BaseModel):
|
||||
"""
|
||||
Audit log for tracking user actions and system events
|
||||
"""
|
||||
__tablename__ = "audit_logs"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=True) # Nullable for system events
|
||||
username = Column(String(100), nullable=True) # Store username for deleted users
|
||||
action = Column(String(100), nullable=False) # Action performed (CREATE, UPDATE, DELETE, LOGIN, etc.)
|
||||
resource_type = Column(String(50), nullable=False) # Type of resource (USER, CUSTOMER, FILE, etc.)
|
||||
resource_id = Column(String(100), nullable=True) # ID of the affected resource
|
||||
details = Column(JSON, nullable=True) # Additional details as JSON
|
||||
ip_address = Column(String(45), nullable=True) # IPv4/IPv6 address
|
||||
user_agent = Column(Text, nullable=True) # Browser/client information
|
||||
timestamp = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
|
||||
# Relationships
|
||||
user = relationship("User", back_populates="audit_logs")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AuditLog(id={self.id}, user='{self.username}', action='{self.action}', resource='{self.resource_type}')>"
|
||||
|
||||
|
||||
class LoginAttempt(BaseModel):
|
||||
"""
|
||||
Track login attempts for security monitoring
|
||||
"""
|
||||
__tablename__ = "login_attempts"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True, index=True)
|
||||
username = Column(String(100), nullable=False, index=True)
|
||||
ip_address = Column(String(45), nullable=False)
|
||||
user_agent = Column(Text, nullable=True)
|
||||
success = Column(Integer, default=0) # 1 for success, 0 for failure
|
||||
timestamp = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
failure_reason = Column(String(200), nullable=True) # Reason for failure
|
||||
|
||||
def __repr__(self):
|
||||
return f"<LoginAttempt(username='{self.username}', success={bool(self.success)}, timestamp='{self.timestamp}')>"
|
||||
17
app/models/base.py
Normal file
17
app/models/base.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""
|
||||
Base model with common fields
|
||||
"""
|
||||
from sqlalchemy import Column, DateTime, String
|
||||
from sqlalchemy.sql import func
|
||||
from app.database.base import Base
|
||||
|
||||
|
||||
class TimestampMixin:
|
||||
"""Mixin for created_at and updated_at timestamps"""
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
|
||||
class BaseModel(Base, TimestampMixin):
|
||||
"""Base model class"""
|
||||
__abstract__ = True
|
||||
67
app/models/files.py
Normal file
67
app/models/files.py
Normal file
@@ -0,0 +1,67 @@
|
||||
"""
|
||||
File Cabinet models based on legacy FILCABNT.SC analysis
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Date, Text, Float, ForeignKey, Boolean
|
||||
from sqlalchemy.orm import relationship
|
||||
from decimal import Decimal
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class File(BaseModel):
|
||||
"""
|
||||
Client files/cases with financial tracking
|
||||
Corresponds to FILES table in legacy system
|
||||
"""
|
||||
__tablename__ = "files"
|
||||
|
||||
file_no = Column(String(45), primary_key=True, index=True) # Unique file number
|
||||
id = Column(String(80), ForeignKey("rolodex.id"), nullable=False) # File owner ID
|
||||
regarding = Column(Text) # Description of matter
|
||||
empl_num = Column(String(10), nullable=False) # Assigned attorney/employee
|
||||
file_type = Column(String(45), nullable=False) # Area of law
|
||||
|
||||
# Dates
|
||||
opened = Column(Date, nullable=False) # Date file opened
|
||||
closed = Column(Date) # Date file closed
|
||||
|
||||
# Status and billing
|
||||
status = Column(String(45), nullable=False) # ACTIVE, INACTIVE, FOLLOW UP, etc.
|
||||
footer_code = Column(String(45)) # Statement footer code
|
||||
opposing = Column(String(80)) # Opposing attorney ID
|
||||
rate_per_hour = Column(Float, nullable=False) # Hourly billing rate
|
||||
|
||||
# Account balances - previously billed
|
||||
trust_bal_p = Column(Float, default=0.0) # Trust account balance (billed)
|
||||
hours_p = Column(Float, default=0.0) # Hours (billed)
|
||||
hourly_fees_p = Column(Float, default=0.0) # Hourly fees (billed)
|
||||
flat_fees_p = Column(Float, default=0.0) # Flat fees (billed)
|
||||
disbursements_p = Column(Float, default=0.0) # Disbursements (billed)
|
||||
credit_bal_p = Column(Float, default=0.0) # Credit balance (billed)
|
||||
total_charges_p = Column(Float, default=0.0) # Total charges (billed)
|
||||
amount_owing_p = Column(Float, default=0.0) # Amount owing (billed)
|
||||
|
||||
# Account balances - current totals
|
||||
trust_bal = Column(Float, default=0.0) # Trust account balance (total)
|
||||
hours = Column(Float, default=0.0) # Total hours
|
||||
hourly_fees = Column(Float, default=0.0) # Total hourly fees
|
||||
flat_fees = Column(Float, default=0.0) # Total flat fees
|
||||
disbursements = Column(Float, default=0.0) # Total disbursements
|
||||
credit_bal = Column(Float, default=0.0) # Total credit balance
|
||||
total_charges = Column(Float, default=0.0) # Total charges
|
||||
amount_owing = Column(Float, default=0.0) # Total amount owing
|
||||
transferable = Column(Float, default=0.0) # Amount transferable from trust
|
||||
|
||||
# Notes
|
||||
memo = Column(Text) # File notes
|
||||
|
||||
# Relationships
|
||||
owner = relationship("Rolodex", back_populates="files")
|
||||
ledger_entries = relationship("Ledger", back_populates="file", cascade="all, delete-orphan")
|
||||
qdros = relationship("QDRO", back_populates="file", cascade="all, delete-orphan")
|
||||
pensions = relationship("Pension", back_populates="file", cascade="all, delete-orphan")
|
||||
pension_schedules = relationship("PensionSchedule", back_populates="file", cascade="all, delete-orphan")
|
||||
marriage_history = relationship("MarriageHistory", back_populates="file", cascade="all, delete-orphan")
|
||||
death_benefits = relationship("DeathBenefit", back_populates="file", cascade="all, delete-orphan")
|
||||
separation_agreements = relationship("SeparationAgreement", back_populates="file", cascade="all, delete-orphan")
|
||||
payments = relationship("Payment", back_populates="file", cascade="all, delete-orphan")
|
||||
notes = relationship("FileNote", back_populates="file", cascade="all, delete-orphan")
|
||||
40
app/models/ledger.py
Normal file
40
app/models/ledger.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
Ledger models based on legacy LEDGER.SC analysis
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Date, Float, Boolean, Text, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class Ledger(BaseModel):
|
||||
"""
|
||||
Financial transactions per case
|
||||
Corresponds to LEDGER table in legacy system
|
||||
"""
|
||||
__tablename__ = "ledger"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
file_no = Column(String(45), ForeignKey("files.file_no"), nullable=False)
|
||||
item_no = Column(Integer, nullable=False, default=1) # Item number within file
|
||||
|
||||
# Transaction details
|
||||
date = Column(Date, nullable=False) # Transaction date
|
||||
t_code = Column(String(10), nullable=False) # Transaction code (PMT, FEE, etc.)
|
||||
t_type = Column(String(1), nullable=False) # Transaction type (1-5)
|
||||
t_type_l = Column(String(1)) # Transaction type letter (C=Credit, D=Debit, etc.)
|
||||
|
||||
# Employee and billing
|
||||
empl_num = Column(String(10), nullable=False) # Employee number
|
||||
quantity = Column(Float, default=0.0) # Number of billable units (hours)
|
||||
rate = Column(Float, default=0.0) # Rate per unit
|
||||
amount = Column(Float, nullable=False) # Dollar amount
|
||||
billed = Column(String(1), default="N") # Y/N - has been billed
|
||||
|
||||
# Description
|
||||
note = Column(Text) # Additional notes for transaction
|
||||
|
||||
# Relationships
|
||||
file = relationship("File", back_populates="ledger_entries")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Ledger(file_no='{self.file_no}', amount={self.amount}, date='{self.date}')>"
|
||||
228
app/models/lookups.py
Normal file
228
app/models/lookups.py
Normal file
@@ -0,0 +1,228 @@
|
||||
"""
|
||||
Lookup table models based on legacy system analysis
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Text, Boolean, Float
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class Employee(BaseModel):
|
||||
"""
|
||||
Employee/Staff information
|
||||
Corresponds to EMPLOYEE table in legacy system
|
||||
"""
|
||||
__tablename__ = "employees"
|
||||
|
||||
empl_num = Column(String(10), primary_key=True, index=True) # Employee number
|
||||
first_name = Column(String(50)) # First name
|
||||
last_name = Column(String(100), nullable=False) # Last name
|
||||
title = Column(String(100)) # Job title
|
||||
initials = Column(String(10)) # Initials for billing
|
||||
rate_per_hour = Column(Float, default=0.0) # Default hourly rate
|
||||
active = Column(Boolean, default=True) # Is employee active
|
||||
email = Column(String(100)) # Email address
|
||||
phone = Column(String(20)) # Phone number
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Employee(empl_num='{self.empl_num}', name='{self.first_name} {self.last_name}')>"
|
||||
|
||||
|
||||
class FileType(BaseModel):
|
||||
"""
|
||||
File/Case types (areas of law)
|
||||
Corresponds to FILETYPE table in legacy system
|
||||
"""
|
||||
__tablename__ = "file_types"
|
||||
|
||||
type_code = Column(String(45), primary_key=True, index=True) # Type code
|
||||
description = Column(String(200), nullable=False) # Description
|
||||
default_rate = Column(Float, default=0.0) # Default hourly rate
|
||||
active = Column(Boolean, default=True) # Is type active
|
||||
|
||||
def __repr__(self):
|
||||
return f"<FileType(code='{self.type_code}', description='{self.description}')>"
|
||||
|
||||
|
||||
class FileStatus(BaseModel):
|
||||
"""
|
||||
File status codes
|
||||
Corresponds to FILESTAT table in legacy system
|
||||
"""
|
||||
__tablename__ = "file_statuses"
|
||||
|
||||
status_code = Column(String(45), primary_key=True, index=True) # Status code
|
||||
description = Column(String(200), nullable=False) # Description
|
||||
active = Column(Boolean, default=True) # Is status active
|
||||
sort_order = Column(Integer, default=0) # Display order
|
||||
|
||||
def __repr__(self):
|
||||
return f"<FileStatus(code='{self.status_code}', description='{self.description}')>"
|
||||
|
||||
|
||||
class TransactionType(BaseModel):
|
||||
"""
|
||||
Transaction types for ledger entries
|
||||
Corresponds to TRNSTYPE table in legacy system
|
||||
"""
|
||||
__tablename__ = "transaction_types"
|
||||
|
||||
t_type = Column(String(1), primary_key=True, index=True) # Transaction type code
|
||||
description = Column(String(100), nullable=False) # Description
|
||||
debit_credit = Column(String(1)) # D=Debit, C=Credit
|
||||
active = Column(Boolean, default=True) # Is type active
|
||||
|
||||
def __repr__(self):
|
||||
return f"<TransactionType(type='{self.t_type}', description='{self.description}')>"
|
||||
|
||||
|
||||
class TransactionCode(BaseModel):
|
||||
"""
|
||||
Transaction codes for ledger entries
|
||||
Corresponds to TRNSLKUP table in legacy system
|
||||
"""
|
||||
__tablename__ = "transaction_codes"
|
||||
|
||||
t_code = Column(String(10), primary_key=True, index=True) # Transaction code
|
||||
description = Column(String(200), nullable=False) # Description
|
||||
t_type = Column(String(1)) # Associated transaction type
|
||||
default_rate = Column(Float, default=0.0) # Default rate
|
||||
active = Column(Boolean, default=True) # Is code active
|
||||
|
||||
def __repr__(self):
|
||||
return f"<TransactionCode(code='{self.t_code}', description='{self.description}')>"
|
||||
|
||||
|
||||
class State(BaseModel):
|
||||
"""
|
||||
US States and territories
|
||||
Corresponds to STATES table in legacy system
|
||||
"""
|
||||
__tablename__ = "states"
|
||||
|
||||
abbreviation = Column(String(2), primary_key=True, index=True) # State abbreviation
|
||||
name = Column(String(100), nullable=False) # Full state name
|
||||
active = Column(Boolean, default=True) # Is state active for selection
|
||||
|
||||
def __repr__(self):
|
||||
return f"<State(abbrev='{self.abbreviation}', name='{self.name}')>"
|
||||
|
||||
|
||||
class GroupLookup(BaseModel):
|
||||
"""
|
||||
Customer group categories
|
||||
Corresponds to GRUPLKUP table in legacy system
|
||||
"""
|
||||
__tablename__ = "group_lookups"
|
||||
|
||||
group_code = Column(String(45), primary_key=True, index=True) # Group code
|
||||
description = Column(String(200), nullable=False) # Description
|
||||
active = Column(Boolean, default=True) # Is group active
|
||||
|
||||
def __repr__(self):
|
||||
return f"<GroupLookup(code='{self.group_code}', description='{self.description}')>"
|
||||
|
||||
|
||||
class Footer(BaseModel):
|
||||
"""
|
||||
Statement footer templates
|
||||
Corresponds to FOOTERS table in legacy system
|
||||
"""
|
||||
__tablename__ = "footers"
|
||||
|
||||
footer_code = Column(String(45), primary_key=True, index=True) # Footer code
|
||||
content = Column(Text) # Footer content/template
|
||||
description = Column(String(200)) # Description
|
||||
active = Column(Boolean, default=True) # Is footer active
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Footer(code='{self.footer_code}', description='{self.description}')>"
|
||||
|
||||
|
||||
class PlanInfo(BaseModel):
|
||||
"""
|
||||
Retirement plan information
|
||||
Corresponds to PLANINFO table in legacy system
|
||||
"""
|
||||
__tablename__ = "plan_info"
|
||||
|
||||
plan_id = Column(String(45), primary_key=True, index=True) # Plan identifier
|
||||
plan_name = Column(String(200), nullable=False) # Plan name
|
||||
plan_type = Column(String(45)) # Type of plan (401k, pension, etc.)
|
||||
sponsor = Column(String(200)) # Plan sponsor
|
||||
administrator = Column(String(200)) # Plan administrator
|
||||
address1 = Column(String(100)) # Address line 1
|
||||
address2 = Column(String(100)) # Address line 2
|
||||
city = Column(String(50)) # City
|
||||
state = Column(String(2)) # State abbreviation
|
||||
zip_code = Column(String(10)) # ZIP code
|
||||
phone = Column(String(20)) # Phone number
|
||||
active = Column(Boolean, default=True) # Is plan active
|
||||
notes = Column(Text) # Additional notes
|
||||
|
||||
def __repr__(self):
|
||||
return f"<PlanInfo(id='{self.plan_id}', name='{self.plan_name}')>"
|
||||
|
||||
|
||||
class FormIndex(BaseModel):
|
||||
"""
|
||||
Form templates index
|
||||
Corresponds to FORM_INX table in legacy system
|
||||
"""
|
||||
__tablename__ = "form_index"
|
||||
|
||||
form_id = Column(String(45), primary_key=True, index=True) # Form identifier
|
||||
form_name = Column(String(200), nullable=False) # Form name
|
||||
category = Column(String(45)) # Form category
|
||||
active = Column(Boolean, default=True) # Is form active
|
||||
|
||||
def __repr__(self):
|
||||
return f"<FormIndex(id='{self.form_id}', name='{self.form_name}')>"
|
||||
|
||||
|
||||
class FormList(BaseModel):
|
||||
"""
|
||||
Form template content
|
||||
Corresponds to FORM_LST table in legacy system
|
||||
"""
|
||||
__tablename__ = "form_list"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
form_id = Column(String(45), nullable=False) # Form identifier
|
||||
line_number = Column(Integer, nullable=False) # Line number in form
|
||||
content = Column(Text) # Line content
|
||||
|
||||
def __repr__(self):
|
||||
return f"<FormList(form_id='{self.form_id}', line={self.line_number})>"
|
||||
|
||||
|
||||
class PrinterSetup(BaseModel):
|
||||
"""
|
||||
Printer configuration
|
||||
Corresponds to PRINTERS table in legacy system
|
||||
"""
|
||||
__tablename__ = "printers"
|
||||
|
||||
printer_name = Column(String(100), primary_key=True, index=True) # Printer name
|
||||
description = Column(String(200)) # Description
|
||||
driver = Column(String(100)) # Print driver
|
||||
port = Column(String(20)) # Port/connection
|
||||
default_printer = Column(Boolean, default=False) # Is default printer
|
||||
active = Column(Boolean, default=True) # Is printer active
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Printer(name='{self.printer_name}', description='{self.description}')>"
|
||||
|
||||
|
||||
class SystemSetup(BaseModel):
|
||||
"""
|
||||
System configuration settings
|
||||
Corresponds to SETUP table in legacy system
|
||||
"""
|
||||
__tablename__ = "system_setup"
|
||||
|
||||
setting_key = Column(String(100), primary_key=True, index=True) # Setting key
|
||||
setting_value = Column(Text) # Setting value
|
||||
description = Column(String(200)) # Description of setting
|
||||
setting_type = Column(String(20), default="STRING") # DATA type (STRING, INTEGER, FLOAT, BOOLEAN)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<SystemSetup(key='{self.setting_key}', value='{self.setting_value}')>"
|
||||
158
app/models/pensions.py
Normal file
158
app/models/pensions.py
Normal file
@@ -0,0 +1,158 @@
|
||||
"""
|
||||
Pension calculation models based on legacy PENSION.SC analysis
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Date, Text, Float, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class Pension(BaseModel):
|
||||
"""
|
||||
Pension calculation data
|
||||
Corresponds to PENSIONS table in legacy system
|
||||
"""
|
||||
__tablename__ = "pensions"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
file_no = Column(String(45), ForeignKey("files.file_no"), nullable=False)
|
||||
version = Column(String(10), default="01") # Version number
|
||||
plan_id = Column(String(45)) # Plan identifier
|
||||
plan_name = Column(String(200)) # Name of pension plan
|
||||
|
||||
# Participant information
|
||||
title = Column(String(10)) # Mr., Mrs., Ms., etc.
|
||||
first = Column(String(50)) # First name
|
||||
last = Column(String(100)) # Last name
|
||||
birth = Column(Date) # Date of birth
|
||||
race = Column(String(1)) # Race code
|
||||
sex = Column(String(1)) # M/F
|
||||
|
||||
# Pension calculation data
|
||||
info = Column(Text) # Additional pension information
|
||||
valu = Column(Float, default=0.0) # Pension valuation
|
||||
accrued = Column(Float, default=0.0) # Accrued benefit
|
||||
vested_per = Column(Float, default=0.0) # Vested percentage
|
||||
start_age = Column(Integer) # Starting age for benefits
|
||||
|
||||
# Cost of living and withdrawal details
|
||||
cola = Column(Float, default=0.0) # Cost of living adjustment
|
||||
max_cola = Column(Float, default=0.0) # Maximum COLA
|
||||
withdrawal = Column(String(45)) # Withdrawal method
|
||||
pre_dr = Column(Float, default=0.0) # Pre-retirement discount rate
|
||||
post_dr = Column(Float, default=0.0) # Post-retirement discount rate
|
||||
tax_rate = Column(Float, default=0.0) # Tax rate
|
||||
|
||||
# Relationships
|
||||
file = relationship("File", back_populates="pensions")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Pension(file_no='{self.file_no}', plan_name='{self.plan_name}')>"
|
||||
|
||||
|
||||
class PensionSchedule(BaseModel):
|
||||
"""
|
||||
Pension payment schedules
|
||||
Corresponds to SCHEDULE table in legacy system
|
||||
"""
|
||||
__tablename__ = "pension_schedules"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
file_no = Column(String(45), ForeignKey("files.file_no"), nullable=False)
|
||||
version = Column(String(10), default="01")
|
||||
|
||||
# Schedule details
|
||||
start_date = Column(Date) # Start date for payments
|
||||
end_date = Column(Date) # End date for payments
|
||||
payment_amount = Column(Float, default=0.0) # Payment amount
|
||||
frequency = Column(String(20)) # Monthly, quarterly, etc.
|
||||
|
||||
# Relationships
|
||||
file = relationship("File", back_populates="pension_schedules")
|
||||
|
||||
|
||||
class MarriageHistory(BaseModel):
|
||||
"""
|
||||
Marriage/divorce history for pension calculations
|
||||
Corresponds to MARRIAGE table in legacy system
|
||||
"""
|
||||
__tablename__ = "marriage_history"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
file_no = Column(String(45), ForeignKey("files.file_no"), nullable=False)
|
||||
|
||||
# Marriage details
|
||||
marriage_date = Column(Date) # Date of marriage
|
||||
divorce_date = Column(Date) # Date of divorce/separation
|
||||
spouse_name = Column(String(100)) # Spouse name
|
||||
notes = Column(Text) # Additional notes
|
||||
|
||||
# Relationships
|
||||
file = relationship("File", back_populates="marriage_history")
|
||||
|
||||
|
||||
class DeathBenefit(BaseModel):
|
||||
"""
|
||||
Death benefit information
|
||||
Corresponds to DEATH table in legacy system
|
||||
"""
|
||||
__tablename__ = "death_benefits"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
file_no = Column(String(45), ForeignKey("files.file_no"), nullable=False)
|
||||
|
||||
# Death benefit details
|
||||
beneficiary_name = Column(String(100)) # Beneficiary name
|
||||
benefit_amount = Column(Float, default=0.0) # Benefit amount
|
||||
benefit_type = Column(String(45)) # Type of death benefit
|
||||
notes = Column(Text) # Additional notes
|
||||
|
||||
# Relationships
|
||||
file = relationship("File", back_populates="death_benefits")
|
||||
|
||||
|
||||
class SeparationAgreement(BaseModel):
|
||||
"""
|
||||
Separation agreement details
|
||||
Corresponds to SEPARATE table in legacy system
|
||||
"""
|
||||
__tablename__ = "separation_agreements"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
file_no = Column(String(45), ForeignKey("files.file_no"), nullable=False)
|
||||
|
||||
# Agreement details
|
||||
agreement_date = Column(Date) # Date of agreement
|
||||
terms = Column(Text) # Terms of separation
|
||||
notes = Column(Text) # Additional notes
|
||||
|
||||
# Relationships
|
||||
file = relationship("File", back_populates="separation_agreements")
|
||||
|
||||
|
||||
class LifeTable(BaseModel):
|
||||
"""
|
||||
Life expectancy tables for actuarial calculations
|
||||
Corresponds to LIFETABL table in legacy system
|
||||
"""
|
||||
__tablename__ = "life_tables"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
age = Column(Integer, nullable=False) # Age
|
||||
male_expectancy = Column(Float) # Male life expectancy
|
||||
female_expectancy = Column(Float) # Female life expectancy
|
||||
table_year = Column(Integer) # Year of table (e.g., 2023)
|
||||
table_type = Column(String(45)) # Type of table
|
||||
|
||||
|
||||
class NumberTable(BaseModel):
|
||||
"""
|
||||
Numerical tables for calculations
|
||||
Corresponds to NUMBERAL table in legacy system
|
||||
"""
|
||||
__tablename__ = "number_tables"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
table_type = Column(String(45), nullable=False) # Type of table
|
||||
key_value = Column(String(45), nullable=False) # Key identifier
|
||||
numeric_value = Column(Float) # Numeric value
|
||||
description = Column(Text) # Description
|
||||
66
app/models/qdro.py
Normal file
66
app/models/qdro.py
Normal file
@@ -0,0 +1,66 @@
|
||||
"""
|
||||
QDRO models based on legacy QDRO.SC analysis
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Date, Text, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class QDRO(BaseModel):
|
||||
"""
|
||||
Legal documents (QDROs - Qualified Domestic Relations Orders)
|
||||
Corresponds to QDROS table in legacy system
|
||||
"""
|
||||
__tablename__ = "qdros"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
file_no = Column(String(45), ForeignKey("files.file_no"), nullable=False)
|
||||
version = Column(String(10), default="01") # Version of QDRO
|
||||
plan_id = Column(String(45)) # Plan identifier
|
||||
|
||||
# CSV fields from legacy system
|
||||
field1 = Column(String(100)) # ^1 field
|
||||
field2 = Column(String(100)) # ^2 field
|
||||
part = Column(String(100)) # ^Part field
|
||||
altp = Column(String(100)) # ^AltP field
|
||||
pet = Column(String(100)) # ^Pet field (Petitioner)
|
||||
res = Column(String(100)) # ^Res field (Respondent)
|
||||
|
||||
# Case information
|
||||
case_type = Column(String(45)) # Case type
|
||||
case_code = Column(String(45)) # Case code
|
||||
section = Column(String(45)) # Court section
|
||||
case_number = Column(String(100)) # Case number
|
||||
|
||||
# Dates
|
||||
judgment_date = Column(Date) # Judgment date
|
||||
valuation_date = Column(Date) # Valuation date
|
||||
married_on = Column(Date) # Marriage date
|
||||
|
||||
# Award information
|
||||
percent_awarded = Column(String(100)) # Percent awarded (can be formula)
|
||||
|
||||
# Venue information
|
||||
ven_city = Column(String(50)) # Venue city
|
||||
ven_cnty = Column(String(50)) # Venue county
|
||||
ven_st = Column(String(2)) # Venue state
|
||||
|
||||
# Document status dates
|
||||
draft_out = Column(Date) # Draft sent out date
|
||||
draft_apr = Column(Date) # Draft approved date
|
||||
final_out = Column(Date) # Final sent out date
|
||||
|
||||
# Court information
|
||||
judge = Column(String(100)) # Judge name
|
||||
form_name = Column(String(200)) # Form/template name
|
||||
|
||||
# Additional fields
|
||||
status = Column(String(45), default="DRAFT") # DRAFT, APPROVED, FILED, etc.
|
||||
content = Column(Text) # Document content/template
|
||||
notes = Column(Text) # Additional notes
|
||||
|
||||
# Relationships
|
||||
file = relationship("File", back_populates="qdros")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<QDRO(file_no='{self.file_no}', version='{self.version}', case_number='{self.case_number}')>"
|
||||
63
app/models/rolodex.py
Normal file
63
app/models/rolodex.py
Normal file
@@ -0,0 +1,63 @@
|
||||
"""
|
||||
Rolodex (Customer/Client) models based on legacy ROLODEX.SC analysis
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Date, Text, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class Rolodex(BaseModel):
|
||||
"""
|
||||
Customer/Client information table
|
||||
Corresponds to ROLODEX table in legacy system
|
||||
"""
|
||||
__tablename__ = "rolodex"
|
||||
|
||||
id = Column(String(80), primary_key=True, index=True) # Unique key from legacy
|
||||
last = Column(String(80), nullable=False, index=True) # Last name or company
|
||||
first = Column(String(45)) # First name
|
||||
middle = Column(String(45)) # Middle name or initial
|
||||
prefix = Column(String(45)) # Title like Mr., Ms., Dr.
|
||||
suffix = Column(String(45)) # Jr., Sr., M.D., etc.
|
||||
title = Column(String(45)) # Official title/position
|
||||
group = Column(String(45)) # Client, opposing counsel, personal, etc.
|
||||
|
||||
# Address fields
|
||||
a1 = Column(String(45)) # Address line 1 or firm name
|
||||
a2 = Column(String(45)) # Address line 2
|
||||
a3 = Column(String(45)) # Address line 3
|
||||
city = Column(String(80)) # City
|
||||
abrev = Column(String(45)) # State abbreviation
|
||||
zip = Column(String(45)) # Zip code
|
||||
|
||||
# Contact info
|
||||
email = Column(String(100)) # Email address
|
||||
|
||||
# Personal info
|
||||
dob = Column(Date) # Date of birth
|
||||
ss_number = Column(String(20)) # Social Security Number
|
||||
legal_status = Column(String(45)) # Petitioner/Respondent, etc.
|
||||
|
||||
# Notes
|
||||
memo = Column(Text) # Notes for this rolodex entry
|
||||
|
||||
# Relationships
|
||||
phone_numbers = relationship("Phone", back_populates="rolodex_entry", cascade="all, delete-orphan")
|
||||
files = relationship("File", back_populates="owner")
|
||||
payments = relationship("Payment", back_populates="client")
|
||||
|
||||
|
||||
class Phone(BaseModel):
|
||||
"""
|
||||
Phone numbers linked to rolodex entries
|
||||
Corresponds to PHONE table in legacy system
|
||||
"""
|
||||
__tablename__ = "phone"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
rolodex_id = Column(String(80), ForeignKey("rolodex.id"), nullable=False)
|
||||
location = Column(String(45)) # Office, Home, Mobile, etc.
|
||||
phone = Column(String(45), nullable=False) # Phone number
|
||||
|
||||
# Relationships
|
||||
rolodex_entry = relationship("Rolodex", back_populates="phone_numbers")
|
||||
37
app/models/user.py
Normal file
37
app/models/user.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""
|
||||
User authentication models
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Boolean, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
"""
|
||||
User authentication and authorization
|
||||
"""
|
||||
__tablename__ = "users"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
username = Column(String(50), unique=True, nullable=False, index=True)
|
||||
email = Column(String(100), unique=True, nullable=False, index=True)
|
||||
hashed_password = Column(String(100), nullable=False)
|
||||
first_name = Column(String(50))
|
||||
last_name = Column(String(50))
|
||||
full_name = Column(String(100)) # Keep for backward compatibility
|
||||
|
||||
# Authorization
|
||||
is_active = Column(Boolean, default=True)
|
||||
is_admin = Column(Boolean, default=False)
|
||||
|
||||
# Activity tracking
|
||||
last_login = Column(DateTime(timezone=True))
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
# Relationships
|
||||
audit_logs = relationship("AuditLog", back_populates="user")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<User(username='{self.username}', email='{self.email}')>"
|
||||
Reference in New Issue
Block a user