UX-43: tariff prices take 5 decimals #194
@@ -3120,8 +3120,9 @@ configuration rather than "turn the price feature off and hope".
|
||||
On the add-on page, choose **Other time windows** under Settings, Tariff and
|
||||
prices, or in Setup step 4. Add one row per time window, with its start, end,
|
||||
days and price. The page names any overlap, gap or empty price before you can
|
||||
save. You only need the JSON below for days the page cannot choose, such as
|
||||
Monday and Wednesday only.
|
||||
save. Prices take five decimals: divide the c€/kWh on your bill by 100, so
|
||||
34.512 c€/kWh is 0.34512 €/kWh. You only need the JSON below for days the page
|
||||
cannot choose, such as Monday and Wednesday only.
|
||||
|
||||
It is one option, holding a JSON object, on one line:
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@
|
||||
const days = h("select", { class: "sel", "aria-label": say(P.days) });
|
||||
for (const [v, label] of f.days || []) days.append(h("option", { value: v, selected: v === row.days }, label));
|
||||
days.addEventListener("change", () => set("days", days.value));
|
||||
const price = h("input", { class: "num", type: "number", inputmode: "decimal", step: "0.01",
|
||||
const price = h("input", { class: "num", type: "number", inputmode: "decimal", step: String(f.step || 0.01),
|
||||
value: row.price == null ? "" : row.price, "aria-label": say(P.price) });
|
||||
price.addEventListener("input", () => set("price", price.value === "" || isNaN(+price.value) ? null : +price.value));
|
||||
const cell = (label, ...kids) => h("label", { class: "pf" }, h("span", { class: "tiny muted" }, label), ...kids);
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
"contract": {"name": "Your contract", "description": "How your supplier prices each kWh you take from the grid."},
|
||||
"region": {"name": "Region", "description": "Fills in grid costs, levies and VAT for the year shown, but not yet for Wallonia or Brussels, so check your bill."},
|
||||
"fallback": {"name": "Price when the feed is down", "description": "Used when the price source does not answer."},
|
||||
"fixed_price": {"name": "Price per kWh, all in", "description": "Energy, supplier costs, grid costs, levies and VAT together."},
|
||||
"day_price": {"name": "Day price, weekdays 07:00 to 22:00", "description": "All in, as on your bill."},
|
||||
"night_price": {"name": "Night and weekend price", "description": "All in, as on your bill."},
|
||||
"periods": {"name": "Time windows and prices", "description": "One price per kWh for each time window, all in, as on your bill."}
|
||||
"fixed_price": {"name": "Price per kWh, all in", "description": "Energy, supplier costs, grid costs, levies and VAT together: divide c€/kWh from the bill by 100, so 34.512 c€/kWh is 0.34512."},
|
||||
"day_price": {"name": "Day price, weekdays 07:00 to 22:00", "description": "All in, as on your bill: divide c€/kWh by 100, so 34.512 c€/kWh is 0.34512."},
|
||||
"night_price": {"name": "Night and weekend price", "description": "All in, as on your bill: divide c€/kWh by 100, so 34.512 c€/kWh is 0.34512."},
|
||||
"periods": {"name": "Time windows and prices", "description": "One price per kWh for each time window, all in, as on your bill: divide c€/kWh by 100, so 34.512 c€/kWh is 0.34512."}
|
||||
},
|
||||
"choices": {
|
||||
"contract": {"none": "No prices", "fixed": "Fixed price", "daynight": "Day and night", "dynamic": "Dynamic, hourly", "custom": "Other time windows"},
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
"contract": {"name": "Uw contract", "description": "Hoe uw leverancier elke kWh prijst die u van het net afneemt."},
|
||||
"region": {"name": "Regio", "description": "Vult nettarieven, heffingen en btw in voor het getoonde jaar, nog niet voor Wallonië of Brussel, dus kijk uw factuur na."},
|
||||
"fallback": {"name": "Prijs als de feed wegvalt", "description": "Gebruikt als de prijsbron niet antwoordt."},
|
||||
"fixed_price": {"name": "Prijs per kWh, alles inbegrepen", "description": "Energie, kosten van de leverancier, nettarieven, heffingen en btw samen."},
|
||||
"day_price": {"name": "Dagprijs, weekdagen 07:00 tot 22:00", "description": "Alles inbegrepen, zoals op uw factuur."},
|
||||
"night_price": {"name": "Nacht- en weekendprijs", "description": "Alles inbegrepen, zoals op uw factuur."},
|
||||
"periods": {"name": "Tijdvakken en prijzen", "description": "Eén prijs per kWh voor elk tijdvak, alles inbegrepen, zoals op uw factuur."}
|
||||
"fixed_price": {"name": "Prijs per kWh, alles inbegrepen", "description": "Energie, kosten van de leverancier, nettarieven, heffingen en btw samen: deel c€/kWh van de factuur door 100, dus 34,512 c€/kWh is 0,34512."},
|
||||
"day_price": {"name": "Dagprijs, weekdagen 07:00 tot 22:00", "description": "Alles inbegrepen, zoals op uw factuur: deel c€/kWh door 100, dus 34,512 c€/kWh is 0,34512."},
|
||||
"night_price": {"name": "Nacht- en weekendprijs", "description": "Alles inbegrepen, zoals op uw factuur: deel c€/kWh door 100, dus 34,512 c€/kWh is 0,34512."},
|
||||
"periods": {"name": "Tijdvakken en prijzen", "description": "Eén prijs per kWh voor elk tijdvak, alles inbegrepen, zoals op uw factuur: deel c€/kWh door 100, dus 34,512 c€/kWh is 0,34512."}
|
||||
},
|
||||
"choices": {
|
||||
"contract": {"none": "Geen prijzen", "fixed": "Vaste prijs", "daynight": "Dag en nacht", "dynamic": "Dynamisch, per uur", "custom": "Andere tijdvakken"},
|
||||
|
||||
@@ -164,13 +164,13 @@ GROUPS = (
|
||||
wizard=4),
|
||||
Field("price_export_formula", TEXT),
|
||||
Field("ui.fallback", SEGMENTED, show=_DYNAMIC, wizard=4),
|
||||
Field("ui.fixed_price", NUMBER, "€/kWh", step=0.01,
|
||||
Field("ui.fixed_price", NUMBER, "€/kWh", step=0.00001,
|
||||
show=(("ui.fallback", "==", "fixed"),), wizard=4),
|
||||
Field("ui.day_price", NUMBER, "€/kWh", step=0.01,
|
||||
Field("ui.day_price", NUMBER, "€/kWh", step=0.00001,
|
||||
show=(("ui.fallback", "==", "daynight"),), wizard=4),
|
||||
Field("ui.night_price", NUMBER, "€/kWh", step=0.01,
|
||||
Field("ui.night_price", NUMBER, "€/kWh", step=0.00001,
|
||||
show=(("ui.fallback", "==", "daynight"),), wizard=4),
|
||||
Field("ui.periods", PERIOD_LIST, "€/kWh", step=0.01,
|
||||
Field("ui.periods", PERIOD_LIST, "€/kWh", step=0.00001,
|
||||
show=(("ui.fallback", "==", "custom"),), wizard=4),
|
||||
)),
|
||||
Part("selling", (
|
||||
|
||||
@@ -327,6 +327,66 @@ check("days the editor has no choice for stay in the Configuration tab, and "
|
||||
["ui.periods"] is None and edit(dict(SITE, static_profile=_raw), gain=0.5)
|
||||
["static_profile"] == _raw)
|
||||
|
||||
print("\n8. UX-43: tariff prices take five decimals")
|
||||
from app import uilayout as _L # noqa: E402
|
||||
_PX = 0.34512
|
||||
_TARIFF = ("ui.fixed_price", "ui.day_price", "ui.night_price", "ui.periods")
|
||||
_steps = {k: _L.field(k).step for k in _TARIFF}
|
||||
check("the four tariff price fields step 0.00001 EUR/kWh",
|
||||
sorted(_steps) == sorted(_TARIFF)
|
||||
and all(v == 0.00001 for v in _steps.values()))
|
||||
_f5 = edit(DEFAULTS, ui__contract="fixed", ui__fixed_price=_PX)
|
||||
check("fixed price 0.34512 is saved exactly and read back exactly",
|
||||
'"eur_per_kwh": 0.34512}' in _f5["static_profile"]
|
||||
and U.options_to_ui(_f5)["ui.fixed_price"] == _PX
|
||||
and trip(_f5) == _f5)
|
||||
_d5 = edit(SITE, ui__contract="daynight", ui__day_price=_PX,
|
||||
ui__night_price=0.26789)
|
||||
check("day price 0.34512 and night price 0.26789 are saved and read back exactly",
|
||||
'"eur_per_kwh": 0.34512' in _d5["static_profile"]
|
||||
and '"eur_per_kwh": 0.26789' in _d5["static_profile"]
|
||||
and U.options_to_ui(_d5)["ui.day_price"] == _PX
|
||||
and U.options_to_ui(_d5)["ui.night_price"] == 0.26789
|
||||
and not validate_startup_config(_d5))
|
||||
_n5 = edit(SITE, ui__contract="daynight", ui__day_price=0.3, ui__night_price=_PX)
|
||||
check("night price 0.34512 alone is saved and read back exactly",
|
||||
U.options_to_ui(_n5)["ui.night_price"] == _PX)
|
||||
_r3 = rows(("00:00", "07:00", "mon-sun", 0.12345), ("07:00", "22:00", "mon-sun", _PX),
|
||||
("22:00", "24:00", "mon-sun", 0.05001))
|
||||
_p3 = periods(_r3)
|
||||
check("three windows with five-decimal prices save and read back exactly",
|
||||
[p.eur_per_kwh for p in parse_static_profile(_p3["static_profile"]).periods]
|
||||
== [0.12345, _PX, 0.05001]
|
||||
and [r["price"] for r in U.options_to_ui(_p3)["ui.periods"]]
|
||||
== [0.12345, _PX, 0.05001] and trip(_p3) == _p3
|
||||
and "e-" not in _p3["static_profile"])
|
||||
check("a two-decimal price still works", U.options_to_ui(
|
||||
edit(DEFAULTS, ui__contract="fixed", ui__fixed_price=0.31))
|
||||
["ui.fixed_price"] == 0.31)
|
||||
_old = dict(SITE, price_provider="off", static_profile=json.dumps({"periods": [
|
||||
{"name": "day", "from": "07:00", "to": "22:00", "days": "mon-fri",
|
||||
"eur_per_kwh": 0.34},
|
||||
{"name": "night", "from": "22:00", "to": "07:00", "days": "mon-fri",
|
||||
"eur_per_kwh": 0.26},
|
||||
{"name": "night", "from": "00:00", "to": "24:00", "days": "sat,sun",
|
||||
"eur_per_kwh": 0.26}]}))
|
||||
check("a stored profile with two-decimal prices is unchanged by load and save",
|
||||
trip(_old) == _old)
|
||||
_js = open(os.path.join(HERE, "app", "static", "settings.js"),
|
||||
encoding="utf-8").read()
|
||||
check("the window editor's price input takes its step from the field, not a "
|
||||
"hard-coded 0.01", 'step: "0.01"' not in _js
|
||||
and "step: String(f.step || 0.01)" in _js)
|
||||
for _lang in ("en", "nl"):
|
||||
with open(os.path.join(HERE, "app", "ui_text", f"{_lang}.json"),
|
||||
encoding="utf-8") as _fh:
|
||||
_flds = json.load(_fh)["fields"]
|
||||
_hint = "34.512" if _lang == "en" else "34,512"
|
||||
_eq = "0.34512" if _lang == "en" else "0,34512"
|
||||
check(f"[{_lang}] the c€/kWh hint sits on all four tariff price fields",
|
||||
all(_hint in _flds[k]["description"] and _eq in _flds[k]["description"]
|
||||
for k in ("fixed_price", "day_price", "night_price", "periods")))
|
||||
|
||||
print()
|
||||
if fails:
|
||||
print(f"{len(fails)} FAILED")
|
||||
|
||||
Reference in New Issue
Block a user