Files
delphi-database/app/models/pensions.py
2025-08-14 19:16:28 -05:00

259 lines
8.4 KiB
Python

"""
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 (legacy vesting fields)
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.
vests_on = Column(Date) # Legacy SCHEDULE.csv Vests_On
vests_at = Column(Float, default=0.0) # Legacy SCHEDULE.csv Vests_At (percent)
# 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
# Legacy MARRIAGE.csv fields
married_from = Column(Date)
married_to = Column(Date)
married_years = Column(Float, default=0.0)
service_from = Column(Date)
service_to = Column(Date)
service_years = Column(Float, default=0.0)
marital_percent = Column(Float, default=0.0)
# 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
# Legacy DEATH.csv fields
lump1 = Column(Float, default=0.0)
lump2 = Column(Float, default=0.0)
growth1 = Column(Float, default=0.0)
growth2 = Column(Float, default=0.0)
disc1 = Column(Float, default=0.0)
disc2 = Column(Float, default=0.0)
# 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
# Rich typed columns reflecting legacy LIFETABL.csv headers
# LE_* = Life Expectancy, NA_* = Number Alive/Survivors
le_aa = Column(Float)
na_aa = Column(Float)
le_am = Column(Float)
na_am = Column(Float)
le_af = Column(Float)
na_af = Column(Float)
le_wa = Column(Float)
na_wa = Column(Float)
le_wm = Column(Float)
na_wm = Column(Float)
le_wf = Column(Float)
na_wf = Column(Float)
le_ba = Column(Float)
na_ba = Column(Float)
le_bm = Column(Float)
na_bm = Column(Float)
le_bf = Column(Float)
na_bf = Column(Float)
le_ha = Column(Float)
na_ha = Column(Float)
le_hm = Column(Float)
na_hm = Column(Float)
le_hf = Column(Float)
na_hf = Column(Float)
# Optional metadata retained for future variations
table_year = Column(Integer) # Year/version of table if known
table_type = Column(String(45)) # Source/type of table (optional)
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)
month = Column(Integer, nullable=False)
# Rich typed NA_* columns reflecting legacy NUMBERAL.csv headers
na_aa = Column(Float)
na_am = Column(Float)
na_af = Column(Float)
na_wa = Column(Float)
na_wm = Column(Float)
na_wf = Column(Float)
na_ba = Column(Float)
na_bm = Column(Float)
na_bf = Column(Float)
na_ha = Column(Float)
na_hm = Column(Float)
na_hf = Column(Float)
# Optional metadata retained for future variations
table_type = Column(String(45))
description = Column(Text)
class PensionResult(BaseModel):
"""
Computed pension results summary
Corresponds to RESULTS table in legacy system
"""
__tablename__ = "pension_results"
id = Column(Integer, primary_key=True, autoincrement=True)
# Optional linkage if present in future exports
file_no = Column(String(45))
version = Column(String(10))
# Columns observed in legacy RESULTS.csv header
accrued = Column(Float)
start_age = Column(Integer)
cola = Column(Float)
withdrawal = Column(String(45))
pre_dr = Column(Float)
post_dr = Column(Float)
tax_rate = Column(Float)
age = Column(Integer)
years_from = Column(Float)
life_exp = Column(Float)
ev_monthly = Column(Float)
payments = Column(Float)
pay_out = Column(Float)
fund_value = Column(Float)
pv = Column(Float)
mortality = Column(Float)
pv_am = Column(Float)
pv_amt = Column(Float)
pv_pre_db = Column(Float)
pv_annuity = Column(Float)
wv_at = Column(Float)
pv_plan = Column(Float)
years_married = Column(Float)
years_service = Column(Float)
marr_per = Column(Float)
marr_amt = Column(Float)