mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
Classify the landlord Age column into a construction-age-band category 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fc591c6550
commit
cb6a335382
3 changed files with 114 additions and 0 deletions
|
|
@ -8,6 +8,7 @@ from applications.landlord_description_overrides.landlord_description_overrides_
|
||||||
LandlordDescriptionOverridesTriggerBody,
|
LandlordDescriptionOverridesTriggerBody,
|
||||||
)
|
)
|
||||||
from domain.epc.built_form_type import BuiltFormType
|
from domain.epc.built_form_type import BuiltFormType
|
||||||
|
from domain.epc.construction_age_band import ConstructionAgeBand
|
||||||
from domain.epc.glazing_type import GlazingType
|
from domain.epc.glazing_type import GlazingType
|
||||||
from domain.epc.main_fuel_type import MainFuelType
|
from domain.epc.main_fuel_type import MainFuelType
|
||||||
from domain.epc.property_type import PropertyType
|
from domain.epc.property_type import PropertyType
|
||||||
|
|
@ -26,6 +27,9 @@ from infrastructure.postgres.engine import commit_scope, make_engine, make_sessi
|
||||||
from infrastructure.postgres.landlord_built_form_type_override_table import (
|
from infrastructure.postgres.landlord_built_form_type_override_table import (
|
||||||
LandlordBuiltFormTypeOverrideRow,
|
LandlordBuiltFormTypeOverrideRow,
|
||||||
)
|
)
|
||||||
|
from infrastructure.postgres.landlord_construction_age_band_override_table import (
|
||||||
|
LandlordConstructionAgeBandOverrideRow,
|
||||||
|
)
|
||||||
from infrastructure.postgres.landlord_glazing_override_table import (
|
from infrastructure.postgres.landlord_glazing_override_table import (
|
||||||
LandlordGlazingOverrideRow,
|
LandlordGlazingOverrideRow,
|
||||||
)
|
)
|
||||||
|
|
@ -130,6 +134,16 @@ def _build_columns(
|
||||||
session, LandlordGlazingOverrideRow
|
session, LandlordGlazingOverrideRow
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
"construction_age_band": lambda src: ClassifiableColumn(
|
||||||
|
name="construction_age_band",
|
||||||
|
source_column=src,
|
||||||
|
classifier=ChatGptColumnClassifier(
|
||||||
|
chat_gpt, ConstructionAgeBand, ConstructionAgeBand.UNKNOWN
|
||||||
|
),
|
||||||
|
repo=LandlordOverridesRepository[ConstructionAgeBand](
|
||||||
|
session, LandlordConstructionAgeBandOverrideRow
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
columns: list[ClassifiableColumn[Any]] = []
|
columns: list[ClassifiableColumn[Any]] = []
|
||||||
|
|
|
||||||
31
domain/epc/construction_age_band.py
Normal file
31
domain/epc/construction_age_band.py
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class ConstructionAgeBand(Enum):
|
||||||
|
"""A landlord-supplied construction age band, as resolved by the
|
||||||
|
landlord-description-overrides context.
|
||||||
|
|
||||||
|
Each member's value is the RdSAP England-&-Wales age-band **letter code**
|
||||||
|
(A..M) the calculator's U-value cascades read from
|
||||||
|
`SapBuildingPart.construction_age_band` — the same representation the gov-EPC
|
||||||
|
API lodges. The construction-age-band Simulation Overlay
|
||||||
|
(``domain/epc/property_overlays/construction_age_band_overlay.py``) sets the
|
||||||
|
letter directly, so these values MUST stay the bare letter codes. Member
|
||||||
|
names carry the year ranges for readability. ``UNKNOWN`` covers values the
|
||||||
|
classifier cannot resolve (it leaves the lodged cert's age band untouched).
|
||||||
|
"""
|
||||||
|
|
||||||
|
A_BEFORE_1900 = "A"
|
||||||
|
B_1900_1929 = "B"
|
||||||
|
C_1930_1949 = "C"
|
||||||
|
D_1950_1966 = "D"
|
||||||
|
E_1967_1975 = "E"
|
||||||
|
F_1976_1982 = "F"
|
||||||
|
G_1983_1990 = "G"
|
||||||
|
H_1991_1995 = "H"
|
||||||
|
I_1996_2002 = "I"
|
||||||
|
J_2003_2006 = "J"
|
||||||
|
K_2007_2011 = "K"
|
||||||
|
L_2012_2022 = "L"
|
||||||
|
M_2023_ONWARDS = "M"
|
||||||
|
UNKNOWN = "Unknown"
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
"""SQLModel mirror of the ``landlord_construction_age_band_overrides`` Drizzle table.
|
||||||
|
|
||||||
|
The schema source of truth lives in the ``assessment-model`` TS repo
|
||||||
|
(`src/app/db/schema/landlord_overrides.ts`). The migrations are owned there;
|
||||||
|
this row class only mirrors the columns so the Python lambda can read/write.
|
||||||
|
See ADR-0003. Shape mirrors ``LandlordWallTypeOverrideRow`` -- the only
|
||||||
|
differences are the table name, the ``construction_age_band`` pgEnum on
|
||||||
|
``value``, and the unique-constraint name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from typing import ClassVar
|
||||||
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
|
from sqlalchemy import BigInteger, Column, UniqueConstraint
|
||||||
|
from sqlalchemy import Enum as SAEnum
|
||||||
|
from sqlmodel import Field, SQLModel
|
||||||
|
|
||||||
|
from domain.epc.construction_age_band import ConstructionAgeBand
|
||||||
|
from infrastructure.postgres.landlord_override_enums import override_source_sa_enum
|
||||||
|
|
||||||
|
|
||||||
|
class LandlordConstructionAgeBandOverrideRow(SQLModel, table=True):
|
||||||
|
__tablename__: ClassVar[str] = "landlord_construction_age_band_overrides" # pyright: ignore[reportIncompatibleVariableOverride]
|
||||||
|
__table_args__: ClassVar[tuple[UniqueConstraint, ...]] = ( # pyright: ignore[reportIncompatibleVariableOverride]
|
||||||
|
UniqueConstraint(
|
||||||
|
"portfolio_id",
|
||||||
|
"description",
|
||||||
|
name="landlord_construction_age_band_overrides_portfolio_description_unique",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
id: UUID = Field(default_factory=uuid4, primary_key=True)
|
||||||
|
|
||||||
|
# bigint to match the Drizzle ``portfolio_id`` FK; SQLModel's default int
|
||||||
|
# mapping is 32-bit Integer and would overflow once portfolio IDs exceed
|
||||||
|
# 2^31. The FK to ``portfolio.id`` is enforced by the Drizzle migration,
|
||||||
|
# not declared here -- the ``portfolio`` table is not modelled in Python.
|
||||||
|
portfolio_id: int = Field(
|
||||||
|
sa_column=Column(BigInteger, nullable=False, index=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
description: str = Field(nullable=False)
|
||||||
|
|
||||||
|
value: ConstructionAgeBand = Field(
|
||||||
|
sa_column=Column(
|
||||||
|
SAEnum(
|
||||||
|
ConstructionAgeBand,
|
||||||
|
name="construction_age_band",
|
||||||
|
values_callable=lambda cls: [m.value for m in cls], # pyright: ignore[reportUnknownLambdaType, reportUnknownMemberType, reportUnknownVariableType]
|
||||||
|
),
|
||||||
|
nullable=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Shared SAEnum -- see ``landlord_override_enums`` for why this single
|
||||||
|
# instance is reused by every ``landlord_*_overrides`` row class.
|
||||||
|
source: str = Field(
|
||||||
|
sa_column=Column(override_source_sa_enum, nullable=False),
|
||||||
|
)
|
||||||
|
|
||||||
|
created_at: datetime = Field(
|
||||||
|
default_factory=lambda: datetime.now(timezone.utc),
|
||||||
|
nullable=False,
|
||||||
|
)
|
||||||
|
updated_at: datetime = Field(
|
||||||
|
default_factory=lambda: datetime.now(timezone.utc),
|
||||||
|
nullable=False,
|
||||||
|
)
|
||||||
Loading…
Add table
Reference in a new issue