M8-T05: bind electricity costs to source bindings
This commit is contained in:
+12
-11
@@ -430,9 +430,7 @@ def test_prices_tibber_limit_caps_results(energy_client):
|
||||
|
||||
start = (datetime.now(UTC) - timedelta(hours=3)).isoformat()
|
||||
end = (datetime.now(UTC) + timedelta(hours=2)).isoformat()
|
||||
resp = client.get(
|
||||
"/api/energy/prices", params={"start": start, "end": end, "limit": 2}
|
||||
)
|
||||
resp = client.get("/api/energy/prices", params={"start": start, "end": end, "limit": 2})
|
||||
assert resp.status_code == 200
|
||||
body = resp.json()
|
||||
assert len(body["points"]) <= 2
|
||||
@@ -508,9 +506,16 @@ def test_costs_schema_fields_present(energy_client):
|
||||
item = resp.json()["items"][0]
|
||||
for field in (
|
||||
"period_start",
|
||||
"d1_kwh", "d2_kwh", "r1_kwh", "r2_kwh",
|
||||
"import_cost", "export_revenue", "net_cost",
|
||||
"currency", "degraded",
|
||||
"d1_kwh",
|
||||
"d2_kwh",
|
||||
"r1_kwh",
|
||||
"r2_kwh",
|
||||
"import_cost",
|
||||
"export_revenue",
|
||||
"net_cost",
|
||||
"currency",
|
||||
"degraded",
|
||||
"source_binding_id",
|
||||
):
|
||||
assert field in item, f"Missing field: {field}"
|
||||
|
||||
@@ -556,9 +561,7 @@ def test_summary_returns_correct_structure(energy_client):
|
||||
|
||||
start = (datetime.now(UTC) - timedelta(hours=3)).isoformat()
|
||||
end = datetime.now(UTC).isoformat()
|
||||
resp = client.get(
|
||||
"/api/energy/costs/summary", params={"start": start, "end": end}
|
||||
)
|
||||
resp = client.get("/api/energy/costs/summary", params={"start": start, "end": end})
|
||||
assert resp.status_code == 200
|
||||
body = resp.json()
|
||||
for field in (
|
||||
@@ -903,5 +906,3 @@ def test_tibber_test_token_not_in_response(energy_client):
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert secret_token not in resp.text
|
||||
|
||||
|
||||
|
||||
+855
-243
File diff suppressed because it is too large
Load Diff
@@ -1097,6 +1097,9 @@ def test_import_cost_total_includes_standing_charges(energy_db) -> None:
|
||||
from app.services import timezone as _tz_mod
|
||||
|
||||
now_utc = datetime.now(timezone.utc)
|
||||
# Keep the dynamic test date, but settle it at a deterministic business time
|
||||
# beyond the local 01:05 fixed-fee/credit cutoff.
|
||||
settled_local_now = now_utc.replace(hour=12, minute=0, second=0, microsecond=0)
|
||||
# D2 anchor = meter.started_at = 10 UTC days ago at midnight
|
||||
meter_started_at = now_utc.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=10)
|
||||
effective_from = meter_started_at # contract also starts at the same time
|
||||
@@ -1123,7 +1126,10 @@ def test_import_cost_total_includes_standing_charges(energy_db) -> None:
|
||||
|
||||
with Session(energy_db) as session:
|
||||
# Pin to UTC so local days = UTC days (deterministic on any CI host).
|
||||
with patch.object(_tz_mod, "local_tz", return_value=ZoneInfo("UTC")):
|
||||
with (
|
||||
patch.object(_tz_mod, "local_tz", return_value=ZoneInfo("UTC")),
|
||||
patch("app.services.energy_cost.local_now", return_value=settled_local_now),
|
||||
):
|
||||
catalog = build_catalog(session)
|
||||
import_entry = next(
|
||||
e for e in catalog if e.entity.key == "energy.import_cost_total"
|
||||
@@ -1163,6 +1169,9 @@ def test_export_revenue_total_includes_tax_credit(energy_db) -> None:
|
||||
from app.services import timezone as _tz_mod
|
||||
|
||||
now_utc = datetime.now(timezone.utc)
|
||||
# Keep the dynamic test date, but settle it at a deterministic business time
|
||||
# beyond the local 01:05 fixed-fee/credit cutoff.
|
||||
settled_local_now = now_utc.replace(hour=12, minute=0, second=0, microsecond=0)
|
||||
meter_started_at = now_utc.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=4)
|
||||
effective_from = meter_started_at
|
||||
|
||||
@@ -1186,7 +1195,10 @@ def test_export_revenue_total_includes_tax_credit(energy_db) -> None:
|
||||
session.commit()
|
||||
|
||||
with Session(energy_db) as session:
|
||||
with patch.object(_tz_mod, "local_tz", return_value=ZoneInfo("UTC")):
|
||||
with (
|
||||
patch.object(_tz_mod, "local_tz", return_value=ZoneInfo("UTC")),
|
||||
patch("app.services.energy_cost.local_now", return_value=settled_local_now),
|
||||
):
|
||||
catalog = build_catalog(session)
|
||||
export_entry = next(
|
||||
e for e in catalog if e.entity.key == "energy.export_revenue_total"
|
||||
@@ -1945,6 +1957,9 @@ def test_cumulative_anchor_is_meter_started_at(energy_db) -> None:
|
||||
from app.services import timezone as _tz_mod
|
||||
|
||||
now_utc = datetime.now(timezone.utc)
|
||||
# Keep the dynamic test date, but settle it at a deterministic business time
|
||||
# beyond the local 01:05 fixed-fee/credit cutoff.
|
||||
settled_local_now = now_utc.replace(hour=12, minute=0, second=0, microsecond=0)
|
||||
midnight_today = now_utc.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
# Contract starts 180 days ago (far before the meter)
|
||||
@@ -1966,7 +1981,10 @@ def test_cumulative_anchor_is_meter_started_at(energy_db) -> None:
|
||||
session.commit()
|
||||
|
||||
with Session(energy_db) as session:
|
||||
with patch.object(_tz_mod, "local_tz", return_value=ZoneInfo("UTC")):
|
||||
with (
|
||||
patch.object(_tz_mod, "local_tz", return_value=ZoneInfo("UTC")),
|
||||
patch("app.services.energy_cost.local_now", return_value=settled_local_now),
|
||||
):
|
||||
catalog = build_catalog(session)
|
||||
import_entry = next(
|
||||
e for e in catalog if e.entity.key == "energy.import_cost_total"
|
||||
@@ -2089,6 +2107,9 @@ def test_cumulative_resets_after_meter_swap(energy_db) -> None:
|
||||
from app.services import timezone as _tz_mod
|
||||
|
||||
now_utc = datetime.now(timezone.utc)
|
||||
# Keep the dynamic test date, but settle it at a deterministic business time
|
||||
# beyond the local 01:05 fixed-fee/credit cutoff.
|
||||
settled_local_now = now_utc.replace(hour=12, minute=0, second=0, microsecond=0)
|
||||
midnight_today = now_utc.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
old_meter_start = midnight_today - timedelta(days=30)
|
||||
@@ -2145,7 +2166,10 @@ def test_cumulative_resets_after_meter_swap(energy_db) -> None:
|
||||
session.commit()
|
||||
|
||||
with Session(energy_db) as session:
|
||||
with patch.object(_tz_mod, "local_tz", return_value=ZoneInfo("UTC")):
|
||||
with (
|
||||
patch.object(_tz_mod, "local_tz", return_value=ZoneInfo("UTC")),
|
||||
patch("app.services.energy_cost.local_now", return_value=settled_local_now),
|
||||
):
|
||||
catalog = build_catalog(session)
|
||||
import_entry = next(
|
||||
e for e in catalog if e.entity.key == "energy.import_cost_total"
|
||||
@@ -2194,6 +2218,9 @@ def test_daily_getters_unaffected_by_d2_meter_anchor(energy_db) -> None:
|
||||
from app.services import timezone as _tz_mod
|
||||
|
||||
now_utc = datetime.now(timezone.utc)
|
||||
# Keep the dynamic test date, but settle it at a deterministic business time
|
||||
# beyond the local 01:05 fixed-fee/credit cutoff.
|
||||
settled_local_now = now_utc.replace(hour=12, minute=0, second=0, microsecond=0)
|
||||
# Period 1h ago — in today's UTC window
|
||||
t0 = now_utc.replace(minute=0, second=0, microsecond=0) - timedelta(hours=1)
|
||||
if t0.date() < now_utc.date():
|
||||
@@ -2226,7 +2253,10 @@ def test_daily_getters_unaffected_by_d2_meter_anchor(energy_db) -> None:
|
||||
session.commit()
|
||||
|
||||
with Session(energy_db) as session:
|
||||
with patch.object(_tz_mod, "local_tz", return_value=ZoneInfo("UTC")):
|
||||
with (
|
||||
patch.object(_tz_mod, "local_tz", return_value=ZoneInfo("UTC")),
|
||||
patch("app.services.energy_cost.local_now", return_value=settled_local_now),
|
||||
):
|
||||
catalog = build_catalog(session)
|
||||
import_today_entry = next(
|
||||
e for e in catalog if e.entity.key == "energy.import_cost_today"
|
||||
|
||||
Reference in New Issue
Block a user