mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-22 08:48:38 +00:00
First slice of the per-dwelling ASHP bundle costing (ADR-0025). Products is the rich catalogue collection over Product, owning the catalogue math: given a typed AshpCostInputs it sums the applicable Southern Housing rate lines (decommission + heat-pump band + fixed cylinder + full wet distribution) into a Cost with the separate 25% ASHP contingency. Pure -- no EpcPropertyData or calculator. Pinned exact (1e-9) against the real rate sheet. Reuse branch, decommission variants, fallbacks, band edges and radiator clamp follow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
39 lines
1.6 KiB
Python
39 lines
1.6 KiB
Python
"""Behaviour of `Products.ashp_bundle_cost` — the composite, per-dwelling ASHP
|
|
bundle cost (ADR-0025). Pure catalogue math: given a typed `AshpCostInputs` it
|
|
selects and sums the applicable Southern Housing rate lines (decommission +
|
|
heat pump + cylinder + distribution) into a `Cost`, carrying the separate ASHP
|
|
contingency. No EpcPropertyData / calculator — the dwelling interpretation that
|
|
produces the inputs lives in the modelling layer.
|
|
|
|
Costs are pinned against the real Southern Housing Group rate sheet, so the
|
|
totals are exact (delta <= 1e-9), mirroring the cascade-pin philosophy.
|
|
"""
|
|
|
|
from domain.modelling.products import (
|
|
AshpCostInputs,
|
|
AshpExistingSystem,
|
|
Products,
|
|
)
|
|
from domain.modelling.recommendation import Cost
|
|
|
|
|
|
def test_ashp_bundle_cost_composes_an_electric_storage_full_distribution_dwelling() -> None:
|
|
# Arrange — a small electric-storage dwelling: no reusable wet system, so a
|
|
# full new wet distribution is priced. 4 kW design heat loss (smallest pump
|
|
# band), 7 radiators.
|
|
products = Products()
|
|
inputs = AshpCostInputs(
|
|
existing_system=AshpExistingSystem.ELECTRIC_STORAGE,
|
|
is_small_property=True,
|
|
design_heat_loss_kw=4.0,
|
|
radiator_count=7,
|
|
has_reusable_wet_system=False,
|
|
)
|
|
|
|
# Act
|
|
cost: Cost = products.ashp_bundle_cost(inputs)
|
|
|
|
# Assert — decommission 570 + pump 9720 + cylinder 2382.60 + distribution
|
|
# (7 rads) 3618 = 16290.60, with the separate 25% ASHP contingency.
|
|
assert abs(cost.total - 16290.60) <= 1e-9
|
|
assert abs(cost.contingency_rate - 0.25) <= 1e-9
|