import uuid from datetime import date, datetime from decimal import Decimal from sqlalchemy import Boolean, Date, DateTime, ForeignKey, Integer, LargeBinary, Numeric, String from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from app.db.base import Base class PensionMetadata(Base): __tablename__ = "pension_metadata" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) account_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("accounts.id", ondelete="CASCADE"), nullable=False, unique=True, index=True) pension_type: Mapped[str] = mapped_column(String(20), nullable=False) # workplace_dc|workplace_db|sipp|lisa provider_name_enc: Mapped[bytes | None] = mapped_column("provider_name", LargeBinary, nullable=True) scheme_name_enc: Mapped[bytes | None] = mapped_column("scheme_name", LargeBinary, nullable=True) member_reference_enc: Mapped[bytes | None] = mapped_column("member_reference", LargeBinary, nullable=True) dob: Mapped[date | None] = mapped_column(Date, nullable=True) target_retirement_age: Mapped[int | None] = mapped_column(Integer, nullable=True) assumed_growth_rate: Mapped[Decimal | None] = mapped_column(Numeric(5, 4), nullable=True) # e.g. 0.0500 created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) account: Mapped["Account"] = relationship(lazy="noload") # type: ignore[name-defined] contributions: Mapped[list["PensionContribution"]] = relationship(back_populates="pension", lazy="noload", cascade="all, delete-orphan") class PensionContribution(Base): __tablename__ = "pension_contributions" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) pension_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("pension_metadata.id", ondelete="CASCADE"), nullable=False, index=True) contribution_date: Mapped[date] = mapped_column(Date, nullable=False, index=True) tax_year: Mapped[int] = mapped_column(Integer, nullable=False, index=True) # year ending 5 Apr, e.g. 2026 member_amount: Mapped[Decimal] = mapped_column(Numeric(14, 2), nullable=False) employer_amount: Mapped[Decimal] = mapped_column(Numeric(14, 2), nullable=False, default=0) relief_type: Mapped[str] = mapped_column(String(20), nullable=False) # relief_at_source|net_pay|salary_sacrifice|none gross_amount: Mapped[Decimal] = mapped_column(Numeric(14, 2), nullable=False) relief_amount: Mapped[Decimal] = mapped_column(Numeric(14, 2), nullable=False, default=0) notes_enc: Mapped[bytes | None] = mapped_column("notes", LargeBinary, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) pension: Mapped["PensionMetadata"] = relationship(back_populates="contributions", lazy="noload") class StatePensionRecord(Base): __tablename__ = "state_pension_records" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, unique=True, index=True) qualifying_years: Mapped[int] = mapped_column(Integer, nullable=False) checked_date: Mapped[date | None] = mapped_column(Date, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)