feat: Add profitability calculation schemas and service functions

- Introduced Pydantic schemas for profitability calculations in `schemas/calculations.py`.
- Implemented service functions for profitability calculations in `services/calculations.py`.
- Added new exception class `ProfitabilityValidationError` for handling validation errors.
- Created repositories for managing project and scenario profitability snapshots.
- Developed a utility script for verifying authenticated routes.
- Added a new HTML template for the profitability calculator interface.
- Implemented a script to fix user ID sequence in the database.
This commit is contained in:
2025-11-12 22:22:29 +01:00
parent 6d496a599e
commit b1a6df9f90
15 changed files with 1654 additions and 0 deletions

View File

@@ -19,6 +19,7 @@ from sqlalchemy.sql import func
from config.database import Base
from services.currency import normalise_currency
from .enums import ResourceType, ScenarioStatus, sql_enum
from .profitability_snapshot import ScenarioProfitability
if TYPE_CHECKING: # pragma: no cover
from .financial_input import FinancialInput
@@ -75,6 +76,13 @@ class Scenario(Base):
cascade="all, delete-orphan",
passive_deletes=True,
)
profitability_snapshots: Mapped[List["ScenarioProfitability"]] = relationship(
"ScenarioProfitability",
back_populates="scenario",
cascade="all, delete-orphan",
order_by=lambda: ScenarioProfitability.calculated_at.desc(),
passive_deletes=True,
)
@validates("currency")
def _normalise_currency(self, key: str, value: str | None) -> str | None:
@@ -83,3 +91,11 @@ class Scenario(Base):
def __repr__(self) -> str: # pragma: no cover
return f"Scenario(id={self.id!r}, name={self.name!r}, project_id={self.project_id!r})"
@property
def latest_profitability(self) -> "ScenarioProfitability | None":
"""Return the most recent profitability snapshot for this scenario."""
if not self.profitability_snapshots:
return None
return self.profitability_snapshots[0]