mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
fix(product): deterministic catalogue pick by ordering get() by id
ProductPostgresRepository.get took .first() with no ORDER BY, so when a measure type has several active material rows (the live catalogue holds 74 solar_pv, 5 high_heat_retention_storage_heaters) the chosen row — hence the cost and material_id — depended on the database's physical row order. Order by id so a re-seed prices the same product every time. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
7942a8101a
commit
62e1d4b813
2 changed files with 43 additions and 1 deletions
|
|
@ -17,11 +17,16 @@ class ProductPostgresRepository(ProductRepository):
|
|||
self._session = session
|
||||
|
||||
def get(self, measure_type: str) -> Product:
|
||||
# The live catalogue holds many active rows per type; order by id so the
|
||||
# pick is deterministic (a re-seed prices the same) rather than relying
|
||||
# on the database's physical row order.
|
||||
row: MaterialRow | None = self._session.exec(
|
||||
select(MaterialRow).where(
|
||||
select(MaterialRow)
|
||||
.where(
|
||||
col(MaterialRow.type) == measure_type,
|
||||
col(MaterialRow.is_active).is_(True),
|
||||
)
|
||||
.order_by(col(MaterialRow.id))
|
||||
).first()
|
||||
if row is None:
|
||||
raise ValueError(f"no active product for measure type {measure_type!r}")
|
||||
|
|
|
|||
|
|
@ -42,6 +42,43 @@ def test_get_maps_active_material_to_product_with_contingency(
|
|||
assert abs(product.contingency_rate - 0.10) <= 1e-9
|
||||
|
||||
|
||||
def test_get_picks_the_lowest_id_when_several_active_rows_share_a_type(
|
||||
db_engine: Engine,
|
||||
) -> None:
|
||||
# Arrange — the live catalogue holds many active rows per type (e.g. 74
|
||||
# solar_pv); the choice must be deterministic so a re-run prices the same.
|
||||
with Session(db_engine) as session:
|
||||
session.add_all(
|
||||
[
|
||||
MaterialRow(
|
||||
id=7,
|
||||
type="solar_pv",
|
||||
total_cost=99.0,
|
||||
cost_unit="gbp_per_unit",
|
||||
is_active=True,
|
||||
description="Solar PV (higher id)",
|
||||
),
|
||||
MaterialRow(
|
||||
id=3,
|
||||
type="solar_pv",
|
||||
total_cost=42.0,
|
||||
cost_unit="gbp_per_unit",
|
||||
is_active=True,
|
||||
description="Solar PV (lowest id)",
|
||||
),
|
||||
]
|
||||
)
|
||||
session.commit()
|
||||
|
||||
# Act
|
||||
with Session(db_engine) as session:
|
||||
product: Product = ProductPostgresRepository(session).get("solar_pv")
|
||||
|
||||
# Assert — the lowest-id active row wins, deterministically.
|
||||
assert product.id == 3
|
||||
assert abs(product.unit_cost_per_m2 - 42.0) <= 1e-9
|
||||
|
||||
|
||||
def test_get_raises_when_only_an_inactive_product_exists(db_engine: Engine) -> None:
|
||||
# Arrange
|
||||
with Session(db_engine) as session:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue