maybe good

This commit is contained in:
HotSwapp
2025-08-08 15:55:15 -05:00
parent ab6f163c15
commit b257a06787
80 changed files with 19739 additions and 0 deletions

31
app/models/__init__.py Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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}')>"