Files
mortgage-simulator/app/models.py
T
Mateusz Gruszczyński 4bdb20d9f5 changes3
2026-06-03 13:48:15 +02:00

102 lines
3.3 KiB
Python

from __future__ import annotations
from datetime import date
from enum import Enum
from typing import Literal
from pydantic import BaseModel, Field
class InstallmentType(str, Enum):
equal = "equal"
decreasing = "decreasing"
class OverpaymentEffect(str, Enum):
shorten = "shorten"
lower_payment = "lower_payment"
class GraceType(str, Enum):
none = "none"
interest_only = "interest_only"
full = "full"
class RateChange(BaseModel):
month: int = Field(ge=1, description="Miesiac od startu kredytu")
annual_rate: float = Field(ge=0, le=30, description="Roczne oprocentowanie procentowo")
class Overpayment(BaseModel):
month: int = Field(ge=1)
amount: float = Field(gt=0)
repeat: Literal["once", "monthly", "yearly"] = "once"
until_month: int | None = Field(default=None, ge=1)
commission_percent: float = Field(default=0, ge=0, le=20, description="Prowizja od nadplaty w procentach")
commission_until_month: int | None = Field(default=None, ge=1, description="Ostatni miesiac naliczania prowizji od nadplaty")
class HistoricalMonth(BaseModel):
month: int = Field(ge=1)
annual_rate: float | None = Field(default=None, ge=0, le=30)
grace_type: GraceType = GraceType.none
overpayment: float = Field(default=0, ge=0)
overpayment_commission_percent: float = Field(default=0, ge=0, le=20)
note: str = ""
class SimulationRequest(BaseModel):
principal: float = Field(gt=0)
years: int = Field(default=25, ge=1, le=50)
term_months: int | None = Field(default=None, ge=1, le=600, description="Okres kredytu w miesiacach")
margin: float = Field(ge=0, le=20, default=2.0)
base_rate: float = Field(ge=0, le=30, default=5.75)
installment_type: InstallmentType = InstallmentType.equal
overpayment_effect: OverpaymentEffect = OverpaymentEffect.shorten
loan_start_date: date = Field(default_factory=date.today)
due_day: int = Field(default=5, ge=1, le=28, description="Dzien splaty raty")
move_due_date_to_business_day: bool = True
overpayment_protection_months: int | None = Field(default=None, ge=1, description="Okres ochronny prowizji od nadplat w miesiacach")
overpayment_protection_commission_percent: float = Field(default=0, ge=0, le=20, description="Domyslna prowizja od nadplat w okresie ochronnym")
rate_changes: list[RateChange] = Field(default_factory=list)
overpayments: list[Overpayment] = Field(default_factory=list)
historical_months: list[HistoricalMonth] = Field(default_factory=list)
class ScheduleRow(BaseModel):
month: int
due_date: str
days: int
rate: float
payment: float
principal_part: float
interest_part: float
overpayment: float
overpayment_fee: float
remaining: float
grace_type: GraceType = GraceType.none
cumulative_interest: float
cumulative_cost: float
cumulative_overpayment: float
class Summary(BaseModel):
months: int
total_paid: float
total_interest: float
total_overpayment: float
total_overpayment_fees: float
interest_saved: float
months_saved: int
baseline_interest: float
baseline_months: int
average_payment: float
max_payment: float
payoff_date: str | None = None
class SimulationResponse(BaseModel):
schedule: list[ScheduleRow]
baseline_schedule: list[ScheduleRow] = Field(default_factory=list)
summary: Summary