From dca1a72326fff53611b3ea2fd1f7081a3a2fbe68 Mon Sep 17 00:00:00 2001 From: Tristan Escalada <355457+tescalada@users.noreply.github.com> Date: Mon, 20 Jul 2026 16:55:21 -0400 Subject: [PATCH 01/11] Add tariffs from the meter form via a modal Extract the tariff form fields into a shared partial included by both the standalone tariff page and a new modal-only template. Add GET|POST /tariff/add-modal, guarded by the tariff:add permission. GET returns the form fragment with no page chrome. A valid POST creates the tariff and returns its id and name as JSON; an invalid POST returns 400 and re-renders the fragment with inline field errors. On the customer meter form, the tariff select starts blank and carries an option that loads the modal form, submits it, and inserts the created tariff into the dropdown. --- sparkmeter/meter/meterform.py | 8 +- sparkmeter/meter/templates/meter-form.html | 198 ++++++++- sparkmeter/tariff/tariffview.py | 30 ++ sparkmeter/tariff/templates/tariff-form.html | 221 +--------- .../tariff/templates/tariff-modal-form.html | 54 +++ .../templates/tariff/_tariff-form-fields.html | 204 +++++++++ sparkmeter/tariff/tests/test_tariffviews.py | 46 ++ ...est_meterviews-MeterViewTest.test_add.page | 189 +++++++- ...-MeterViewTest.test_add_32_bit_serial.page | 189 +++++++- ...erViewTest.test_add_duplicated_serial.page | 192 ++++++++- ...rViewTest.test_add_empty_country_code.page | 197 ++++++++- ...rViewTest.test_add_empty_phone_number.page | 197 ++++++++- ...ews-MeterViewTest.test_add_from_cloud.page | 189 +++++++- ...iewTest.test_add_invalid_phone_number.page | 197 ++++++++- ...est_add_invalid_serial-invalid-serial.page | 192 ++++++++- ...MeterViewTest.test_add_invalid_serial.page | 197 ++++++++- ...iews-MeterViewTest.test_add_totalizer.page | 2 + ...iewTest.test_add_totalizer_from_cloud.page | 2 + ...-MeterViewTest.test_add_unknown_model.page | 192 ++++++++- ...omer_state_cloud-customer-state-cloud.page | 191 ++++++++- ...er_state_ground-customer-state-ground.page | 191 ++++++++- ...er_tariff_cloud-customer-tariff-cloud.page | 191 ++++++++- ...ews-MeterViewTest.test_edit_totalizer.page | 4 +- ...wTest.test_edit_with_tags-prepopulate.page | 191 ++++++++- ...ews-MeterViewTest.test_edit_with_tags.page | 191 ++++++++- ...terViewTest.test_unknown_server_error.page | 5 + ...t_tariffviews-TariffViewTest.test_add.page | 318 +++++++------- ...ffViewTest.test_add_form_int_outrange.page | 318 +++++++------- ...ews-TariffViewTest.test_add_modal_get.page | 403 ++++++++++++++++++ ...Test.test_add_with_invalid_blockrates.page | 318 +++++++------- ...ffViewTest.test_add_with_invalid_tous.page | 318 +++++++------- ...st.test_edit-edit-negative-post-error.page | 318 +++++++------- ...iffViewTest.test_edit-edit-post-error.page | 318 +++++++------- ..._tariffviews-TariffViewTest.test_edit.page | 316 +++++++------- ...s-TariffViewTest.test_error_blockrate.page | 318 +++++++------- ...iffViewTest.test_error_duplicate_name.page | 316 +++++++------- ...-TariffViewTest.test_error_empty_name.page | 316 +++++++------- ...fViewTest.test_error_enter_load_limit.page | 318 +++++++------- ...t.test_error_enter_monthly_plan_price.page | 318 +++++++------- ...t.test_error_existing_duplicate_names.page | 316 +++++++------- ...s-TariffViewTest.test_error_flat_rate.page | 318 +++++++------- ...ViewTest.test_error_low_balance_empty.page | 320 +++++++------- ...wTest.test_error_low_balance_negative.page | 320 +++++++------- ...iewTest.test_error_negative_flat_rate.page | 318 +++++++------- ...ewTest.test_error_negative_load_limit.page | 318 +++++++------- ...t.test_error_no_scheduled_load_limits.page | 320 +++++++------- ...fviews-TariffViewTest.test_error_tous.page | 320 +++++++------- 47 files changed, 7212 insertions(+), 3211 deletions(-) create mode 100644 sparkmeter/tariff/templates/tariff-modal-form.html create mode 100644 sparkmeter/tariff/templates/tariff/_tariff-form-fields.html create mode 100644 test-data/tariff/test_tariffviews-TariffViewTest.test_add_modal_get.page diff --git a/sparkmeter/meter/meterform.py b/sparkmeter/meter/meterform.py index 666bc54..69e2dba 100644 --- a/sparkmeter/meter/meterform.py +++ b/sparkmeter/meter/meterform.py @@ -82,7 +82,8 @@ class BaseMeterForm(BaseForm): _("Tariff"), query_factory=lambda: Tariff.query.filter().order_by("name"), get_label="name", - allow_blank=False, + allow_blank=True, + blank_text=_("Select a tariff"), ) customer_name = StringField(_("Name"), default="new customer") customer_code = StringField(_("Code")) @@ -151,6 +152,11 @@ def validate_customer_national_number(self, field): ) ) + def validate_tariff(self, field): + """Require a tariff for customer meters with a clear validation message.""" + if self.meter_type == Meter.TYPE_CUSTOMER and field.data is None: + raise ValidationError(_("Please select a tariff or add a new one.")) + def save(self, view): """Save content of meter form to database.""" if self.meter_type == Meter.TYPE_CUSTOMER and self.customer_national_number.data: diff --git a/sparkmeter/meter/templates/meter-form.html b/sparkmeter/meter/templates/meter-form.html index c5644ec..eee51f4 100644 --- a/sparkmeter/meter/templates/meter-form.html +++ b/sparkmeter/meter/templates/meter-form.html @@ -15,6 +15,193 @@ {%- if form.mode == 'edit' -%} {% block subtitle %}{{ _('Edit') }}{% endblock %} {%- endif -%} +{% block scripts %} + {{ super() }} + {% if meter_type == 'customer' %} + + {% endif %} +{% endblock scripts %} {% block breadcrumbs %} {% call breadcrumb(role='operator', url=url_for('ground.index')) %} @@ -47,6 +234,12 @@ {% call render_box(title, box_content_class=box_content_class) %}
{{- form.hidden_tag() -}} + {{ form_errors(form, hiddens='only') }} + {% if form.errors %} +
+ {{ _('Please correct the highlighted fields and try again.') }} +
+ {% endif %} {%- if form.mode == 'add' -%} {{ addon_form_field(form.serial, form_type="horizontal", horizontal_columns=('lg', 2, 10)) }} {%- endif -%} @@ -58,12 +251,15 @@ {%- if meter_type == 'customer' -%} -
+
{{ form.tariff.label(class="control-label col-lg-2") }}
{{ form.tariff(class="form-control") }}
+
+ {{ form_error(form.tariff) }} +
{%- endif -%}
diff --git a/sparkmeter/tariff/tariffview.py b/sparkmeter/tariff/tariffview.py index 797cf59..d452573 100644 --- a/sparkmeter/tariff/tariffview.py +++ b/sparkmeter/tariff/tariffview.py @@ -9,12 +9,14 @@ from flask.globals import request from flask.helpers import flash, url_for from flask.templating import render_template +from flask.wrappers import Response from flask_babel import lazy_gettext as _ from markupsafe import Markup from werkzeug.exceptions import abort from werkzeug.utils import redirect from sparkmeter.misc.htmlutils import build_link +from sparkmeter.misc.jsonutils import json_dumps, jsonify from sparkmeter.tariff.tariffdomain import Tariff from sparkmeter.tariff.tariffform import TariffForm from sparkmeter.tariff.tariffutils import add_tariff_from_form, update_tariff_from_form @@ -25,6 +27,15 @@ tariff = AuthBlueprint("tariff", __name__) +def render_modal_form(form, status=200): + """Render the tariff modal form with optional validation metadata.""" + body = render_template("tariff-modal-form.html", form=form) + response = Response(body, status=status) + if form.errors: + response.headers["X-Form-Errors"] = json_dumps(form.errors) + return response + + @tariff.route("/tariff/") @verify_permission("tariff", "view") def index(): @@ -60,6 +71,25 @@ def add(): return form.render(mode="add") +@tariff.route("/tariff/add-modal", methods=["GET", "POST"]) +@verify_permission("tariff", "add") +def add_modal(): + """Add tariff form rendered for the meter modal workflow.""" + form = TariffForm(request.form if request.method == "POST" else None) + if request.method == "POST": + tariff = add_tariff_from_form(form) + if tariff: + return jsonify( + message=_("Tariff created."), + tariff={ + "id": tariff.id, + "name": tariff.name, + }, + ) + return render_modal_form(form, status=http.client.BAD_REQUEST) + return render_modal_form(form) + + @tariff.route("/tariff//edit", methods=["GET", "POST"]) @verify_permission("tariff", "edit") def edit(tariff_id): diff --git a/sparkmeter/tariff/templates/tariff-form.html b/sparkmeter/tariff/templates/tariff-form.html index 7bff1d7..bd24f0c 100644 --- a/sparkmeter/tariff/templates/tariff-form.html +++ b/sparkmeter/tariff/templates/tariff-form.html @@ -51,230 +51,11 @@ {% endmacro %} {% block content %} -
-
{% call render_box(title, box_content_class="padded") %} - {{ form.hidden_tag() }} - - {#- Tariff.name|e #} -
- {{ form.name.label(class_="control-label col-lg-2") }} -
- {{ form.name(class_="form-control") }} -
-
- {{ form_tariff_error(form, 'name') }} - - {# tariff plan duration and start day #} -
- {{ form.plan_duration_and_start_day.label(class_="control-label col-lg-2") }} -
- {{ form.plan_duration_and_start_day(class_="form-control numeric no-negative") }} -
-
- {{ form_tariff_error(form, 'cycle_start_day_of_month', class_='form-group cycle-start-day-of-month') }} - - {#- radio for load limit type, active depending on form data #} -
- {{ form.load_limit_type.label(class_="control-label col-lg-2") }} -
- - -
-
- {{ form_tariff_error(form, 'load_limit_type') }} - - {#- flat load limit text input, only visible when radio is active #} -
- {{ form.flat_load_limit.label(class_="control-label col-lg-2") }} -
- {{ form.flat_load_limit(class_="form-control numeric no-negative") }} - {{ _('in watts', currency=config.CURRENCY) }} -
-
- {% set extra = '' %} - {% if form.data.load_limit_type != 'flat' %} - {% set extra = ' hide' %} - {% endif %} - {{ form_tariff_error(form, 'flat_load_limit', class_='form-group load_limit_type' + extra) }} - - {#- scheduled load limit text input, only visible when radio is active #} -
- -
- {% include "tariff-load-limits-list.html" %} -
-
- {% set extra = '' %} - {% if form.data.load_limit_type != 'scheduled' %} - {% set extra = ' hide' %} - {% endif %} - {{ form_tariff_error(form, 'load_limits', class_='form-group load-limits' + extra) }} - - {#- Low balance threshold #} -
- {{ form.low_balance_threshold.label(class_="control-label col-lg-2") }} -
- {{ form.low_balance_threshold(class_="form-control numeric") }} - {{ _('in %(currency)s', currency=config.CURRENCY) }} -
-
- {{ form_tariff_error(form, 'low_balance_threshold') }} - - {#- Monthly Plan, checkbox/iButton for enabling it #} -
- {{ form.plan_enabled.label(class_="control-label col-lg-2") }} -
-
- -
-
-
- {{ form_tariff_error(form, 'plan_enabled') }} - - {# Hide some fields when plan is disabled #} - {% set extra = '' %} - {% if not form.data.plan_enabled %} - {% set extra = ' hide' %} - {% endif %} - -
- {{ form.plan_fixed_fee.label(class_="control-label col-lg-2") }} -
- {{ form.plan_fixed_fee(class_="form-control numeric no-negative") }} - {{ _('in %(currency)s', currency=config.CURRENCY) }} -
-
- {{ form_tariff_error(form, 'plan_fixed_fee', class_='form-group plan-fixed-fee' + extra) }} - -
- {{ form.plan_price.label(class_="control-label col-lg-2") }} -
- {{ form.plan_price(class_="form-control numeric no-negative") }} - {{ _('in %(currency)s', currency=config.CURRENCY) }} -
-
- {{ form_tariff_error(form, 'plan_price', class_='form-group plan-price' + extra) }} - - - {#- radio for tariff type, active depending on form data #} -
- {{ form.tariff_type.label(class_="control-label col-lg-2") }} -
- - -
-
- {{ form_tariff_error(form, 'tariff_type') }} - - {#- flat price text input, only visible when radio is active #} -
- {{ form.flat_price.label(class_="control-label col-lg-2") }} -
- {{ form.flat_price(class_="form-control numeric no-negative") }} - {{ _('in %(currency)s per kWh', currency=config.CURRENCY) }} -
-
- {% set extra = '' %} - {% if form.data.tariff_type != 'flat' %} - {% set extra = ' hide' %} - {% endif %} - {{ form_tariff_error(form, 'flat_price', class_='form-group tariff_type' + extra) }} - - {#- blockrate table, only visible when radio is active #} -
- -
- {% include "tariff-blockrate-list.html" %} -
-
- {{ form_tariff_error(form, 'blockrates') }} - - {#- time of use, checkbox/iButton for enabling it #} -
- {{ form.tou_enabled.label(class_="control-label col-lg-2") }} -
-
- -
-
-
- {{ form_tariff_error(form, 'tou_enabled') }} - -
- -
- {% include "tariff-tou-list.html" %} -
-
- {% set extra = '' %} - {% if not form.data.tou_enabled %} - {% set extra = ' hide' %} - {% endif %} - {{ form_tariff_error(form, 'tous', class_='form-group tou' + extra) }} - - {#- daily energy limit, checkbox/iButton for enabling it #} -
- {{ form.daily_energy_limit_enabled.label(class_="control-label col-lg-2") }} -
-
- -
-
-
- {{ form_tariff_error(form, 'daily_energy_limit_enabled') }} - - {# daily energy limit reset hour #} -
- {{ form.daily_energy_limit_reset_hour.label(class_="control-label col-lg-2") }} -
- {{ form.daily_energy_limit_reset_hour(class_="form-control") }} -
-
- - {% if form.data.daily_energy_limit_enabled -%} - {{ form_tariff_error(form, 'daily_energy_limit_reset_hour', class_='form-group daily-energy-limit-reset-hour') }} - {%- endif %} - - {# daily energy limit value #} -
- {{ form.daily_energy_limit_value.label(class_="control-label col-lg-2") }} -
- {{ form.daily_energy_limit_value(class_="form-control numeric no-negative") }} - {{ _('in kWh') }} -
-
- {% if form.data.daily_energy_limit_enabled -%} - {{ form_tariff_error(form, 'daily_energy_limit_value', class_='form-group daily-energy-limit-reset-value') }} - {%- endif %} + {% include "tariff/_tariff-form-fields.html" %} {#- Save #}
diff --git a/sparkmeter/tariff/templates/tariff-modal-form.html b/sparkmeter/tariff/templates/tariff-modal-form.html new file mode 100644 index 0000000..b71fb1e --- /dev/null +++ b/sparkmeter/tariff/templates/tariff-modal-form.html @@ -0,0 +1,54 @@ +{%- from "_macros.html" import form_errors -%} + +{% macro form_tariff_error(form, field, class_=None) %} + {% if form.errors[field] %} +
+ + + {% for error in form.errors[field] %} + {{ error }} + {% endfor %} + +
+ {% endif %} +{% endmacro %} + + + + + {{ form_errors(form, hiddens='only') }} + {% include "tariff/_tariff-form-fields.html" %} + diff --git a/sparkmeter/tariff/templates/tariff/_tariff-form-fields.html b/sparkmeter/tariff/templates/tariff/_tariff-form-fields.html new file mode 100644 index 0000000..1fdd3d6 --- /dev/null +++ b/sparkmeter/tariff/templates/tariff/_tariff-form-fields.html @@ -0,0 +1,204 @@ +
+
+ +{{ form.hidden_tag() }} + +
+ {{ form.name.label(class_="control-label col-lg-2") }} +
+ {{ form.name(class_="form-control") }} +
+
+{{ form_tariff_error(form, 'name') }} + +
+ {{ form.plan_duration_and_start_day.label(class_="control-label col-lg-2") }} +
+ {{ form.plan_duration_and_start_day(class_="form-control numeric no-negative") }} +
+
+{{ form_tariff_error(form, 'cycle_start_day_of_month', class_='form-group cycle-start-day-of-month') }} + +
+ {{ form.load_limit_type.label(class_="control-label col-lg-2") }} +
+ + +
+
+{{ form_tariff_error(form, 'load_limit_type') }} + +
+ {{ form.flat_load_limit.label(class_="control-label col-lg-2") }} +
+ {{ form.flat_load_limit(class_="form-control numeric no-negative") }} + {{ _('in watts', currency=config.CURRENCY) }} +
+
+{% set extra = '' %} +{% if form.data.load_limit_type != 'flat' %} +{% set extra = ' hide' %} +{% endif %} +{{ form_tariff_error(form, 'flat_load_limit', class_='form-group load_limit_type' + extra) }} + +
+ +
+ {% include "tariff-load-limits-list.html" %} +
+
+{% set extra = '' %} +{% if form.data.load_limit_type != 'scheduled' %} +{% set extra = ' hide' %} +{% endif %} +{{ form_tariff_error(form, 'load_limits', class_='form-group load-limits' + extra) }} + +
+ {{ form.low_balance_threshold.label(class_="control-label col-lg-2") }} +
+ {{ form.low_balance_threshold(class_="form-control numeric") }} + {{ _('in %(currency)s', currency=config.CURRENCY) }} +
+
+{{ form_tariff_error(form, 'low_balance_threshold') }} + +
+ {{ form.plan_enabled.label(class_="control-label col-lg-2") }} +
+
+ +
+
+
+{{ form_tariff_error(form, 'plan_enabled') }} + +{% set extra = '' %} +{% if not form.data.plan_enabled %} +{% set extra = ' hide' %} +{% endif %} + +
+ {{ form.plan_fixed_fee.label(class_="control-label col-lg-2") }} +
+ {{ form.plan_fixed_fee(class_="form-control numeric no-negative") }} + {{ _('in %(currency)s', currency=config.CURRENCY) }} +
+
+{{ form_tariff_error(form, 'plan_fixed_fee', class_='form-group plan-fixed-fee' + extra) }} + +
+ {{ form.plan_price.label(class_="control-label col-lg-2") }} +
+ {{ form.plan_price(class_="form-control numeric no-negative") }} + {{ _('in %(currency)s', currency=config.CURRENCY) }} +
+
+{{ form_tariff_error(form, 'plan_price', class_='form-group plan-price' + extra) }} + +
+ {{ form.tariff_type.label(class_="control-label col-lg-2") }} +
+ + +
+
+{{ form_tariff_error(form, 'tariff_type') }} + +
+ {{ form.flat_price.label(class_="control-label col-lg-2") }} +
+ {{ form.flat_price(class_="form-control numeric no-negative") }} + {{ _('in %(currency)s per kWh', currency=config.CURRENCY) }} +
+
+{% set extra = '' %} +{% if form.data.tariff_type != 'flat' %} +{% set extra = ' hide' %} +{% endif %} +{{ form_tariff_error(form, 'flat_price', class_='form-group tariff_type' + extra) }} + +
+ +
+ {% include "tariff-blockrate-list.html" %} +
+
+{{ form_tariff_error(form, 'blockrates') }} + +
+ {{ form.tou_enabled.label(class_="control-label col-lg-2") }} +
+
+ +
+
+
+{{ form_tariff_error(form, 'tou_enabled') }} + +
+ +
+ {% include "tariff-tou-list.html" %} +
+
+{% set extra = '' %} +{% if not form.data.tou_enabled %} +{% set extra = ' hide' %} +{% endif %} +{{ form_tariff_error(form, 'tous', class_='form-group tou' + extra) }} + +
+ {{ form.daily_energy_limit_enabled.label(class_="control-label col-lg-2") }} +
+
+ +
+
+
+{{ form_tariff_error(form, 'daily_energy_limit_enabled') }} + +
+ {{ form.daily_energy_limit_reset_hour.label(class_="control-label col-lg-2") }} +
+ {{ form.daily_energy_limit_reset_hour(class_="form-control") }} +
+
+{% if form.data.daily_energy_limit_enabled -%} +{{ form_tariff_error(form, 'daily_energy_limit_reset_hour', class_='form-group daily-energy-limit-reset-hour') }} +{%- endif %} + +
+ {{ form.daily_energy_limit_value.label(class_="control-label col-lg-2") }} +
+ {{ form.daily_energy_limit_value(class_="form-control numeric no-negative") }} + {{ _('in kWh') }} +
+
+{% if form.data.daily_energy_limit_enabled -%} +{{ form_tariff_error(form, 'daily_energy_limit_value', class_='form-group daily-energy-limit-reset-value') }} +{%- endif %} diff --git a/sparkmeter/tariff/tests/test_tariffviews.py b/sparkmeter/tariff/tests/test_tariffviews.py index 828b9b0..75ad734 100644 --- a/sparkmeter/tariff/tests/test_tariffviews.py +++ b/sparkmeter/tariff/tests/test_tariffviews.py @@ -55,6 +55,52 @@ def test_add(self, client): response = client.get(path) self.verify_response(response) + def test_add_modal_get(self, client): + # GET renders the modal form with no validation errors (tariffview lines 78, 90, 32-33, 36). + path = "/tariff/add-modal" + + response = client.get(path) + assert response.status_code == http.client.OK + assert "X-Form-Errors" not in response.headers + self.verify_response(response) + + def test_add_modal_post_valid(self, client, config): + # A valid POST creates the tariff and returns JSON (tariffview lines 79-88). + path = "/tariff/add-modal" + data = dict( + name="MODAL TARIFF", + flat_load_limit=150, + plan_price=0, + cycle_start_day_of_month=1, + tariff_type="flat", + flat_price=4, + tous="", + ) + + config["HEROKU"] = False + response = client.post(path, data=data) + + assert response.status_code == http.client.OK + body = response.json() + assert body["message"] == "Tariff created." + + tariffs = Tariff.get_all() + assert len(tariffs) == 1 + assert body["tariff"]["name"] == "MODAL TARIFF" + assert body["tariff"]["id"] == str(tariffs[0].id) + + def test_add_modal_post_invalid(self, client): + # An invalid POST re-renders the modal form with the error header (tariffview lines 89, 34-35). + path = "/tariff/add-modal" + data = dict(name="", flat_load_limit=150, flat_price=4) + + response = client.post(path, data=data) + + assert response.status_code == http.client.BAD_REQUEST + assert "X-Form-Errors" in response.headers + assert "Please set a name for this tariff" in response.text + assert not Tariff.query.scalar() + def test_add_form(self, client, config): path = "/tariff/add" diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add.page b/test-data/meter/test_meterviews-MeterViewTest.test_add.page index 4140e36..0fc3e8d 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add.page @@ -29,6 +29,189 @@ + + @@ -206,6 +389,7 @@
+
@@ -227,8 +411,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_32_bit_serial.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_32_bit_serial.page index 4140e36..0fc3e8d 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_32_bit_serial.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_32_bit_serial.page @@ -29,6 +29,189 @@ + + @@ -206,6 +389,7 @@
+
@@ -227,8 +411,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_duplicated_serial.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_duplicated_serial.page index 613b330..518e914 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_duplicated_serial.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_duplicated_serial.page @@ -33,6 +33,189 @@ + + @@ -210,6 +393,10 @@
+
+ Please correct the highlighted fields and try again. +
+
@@ -238,8 +425,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_country_code.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_country_code.page index 81758d6..cc91b58 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_country_code.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_country_code.page @@ -12,7 +12,7 @@ < Set-Cookie: %% COOKIE %% < Set-Cookie: %% COOKIE %% < Vary: Cookie -< X-Form-Errors: {"state": ["Not a valid choice."],"tariff": ["Not a valid choice"]} +< X-Form-Errors: {"state": ["Not a valid choice."],"tariff": ["Please select a tariff or add a new one."]} < @@ -33,6 +33,189 @@ + + @@ -210,6 +393,10 @@
+
+ Please correct the highlighted fields and try again. +
+
@@ -228,11 +415,15 @@
-
+
- +
+
+
+

Please select a tariff or add a new one.

+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_phone_number.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_phone_number.page index e7d6b97..87c27e1 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_phone_number.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_phone_number.page @@ -12,7 +12,7 @@ < Set-Cookie: %% COOKIE %% < Set-Cookie: %% COOKIE %% < Vary: Cookie -< X-Form-Errors: {"state": ["Not a valid choice."],"tariff": ["Not a valid choice"]} +< X-Form-Errors: {"state": ["Not a valid choice."],"tariff": ["Please select a tariff or add a new one."]} < @@ -33,6 +33,189 @@ + + @@ -210,6 +393,10 @@
+
+ Please correct the highlighted fields and try again. +
+
@@ -228,11 +415,15 @@
-
+
- +
+
+
+

Please select a tariff or add a new one.

+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_from_cloud.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_from_cloud.page index eedfa9d..6911773 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_from_cloud.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_from_cloud.page @@ -29,6 +29,189 @@ + + @@ -206,6 +389,7 @@
+
@@ -227,8 +411,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_phone_number.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_phone_number.page index 71352a4..98b277e 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_phone_number.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_phone_number.page @@ -12,7 +12,7 @@ < Set-Cookie: %% COOKIE %% < Set-Cookie: %% COOKIE %% < Vary: Cookie -< X-Form-Errors: {"customer_national_number": ["1 is not a valid national phone number for Brazil"],"state": ["Not a valid choice."],"tariff": ["Not a valid choice"]} +< X-Form-Errors: {"customer_national_number": ["1 is not a valid national phone number for Brazil"],"state": ["Not a valid choice."],"tariff": ["Please select a tariff or add a new one."]} < @@ -33,6 +33,189 @@ + + @@ -210,6 +393,10 @@
+
+ Please correct the highlighted fields and try again. +
+
@@ -228,11 +415,15 @@
-
+
- +
+
+
+

Please select a tariff or add a new one.

+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial-invalid-serial.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial-invalid-serial.page index 8c01146..c5fc215 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial-invalid-serial.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial-invalid-serial.page @@ -33,6 +33,189 @@ + + @@ -210,6 +393,10 @@
+
+ Please correct the highlighted fields and try again. +
+
@@ -238,8 +425,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial.page index 11c5c37..cddb3c4 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial.page @@ -9,7 +9,7 @@ < HTTP/1.1 200 OK < Content-Type: text/html; charset=utf-8 -< X-Form-Errors: {"serial": ["Invalid meter serial, must look like \"SMXXX-XX-XXXXXXXX\"."],"state": ["Not a valid choice."],"tariff": ["Not a valid choice"]} +< X-Form-Errors: {"serial": ["Invalid meter serial, must look like \"SMXXX-XX-XXXXXXXX\"."],"state": ["Not a valid choice."],"tariff": ["Please select a tariff or add a new one."]} < @@ -30,6 +30,189 @@ + + @@ -207,6 +390,10 @@
+
+ Please correct the highlighted fields and try again. +
+
@@ -232,11 +419,15 @@
-
+
- +
+
+
+

Please select a tariff or add a new one.

+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer.page index 7ae9ec3..d0c0aa3 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer.page @@ -29,6 +29,7 @@ + @@ -206,6 +207,7 @@
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer_from_cloud.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer_from_cloud.page index cf901c9..387f84d 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer_from_cloud.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer_from_cloud.page @@ -29,6 +29,7 @@ + @@ -206,6 +207,7 @@
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_unknown_model.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_unknown_model.page index f8997c5..fd232f2 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_unknown_model.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_unknown_model.page @@ -33,6 +33,189 @@ + + @@ -210,6 +393,10 @@
+
+ Please correct the highlighted fields and try again. +
+
@@ -238,8 +425,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_cloud-customer-state-cloud.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_cloud-customer-state-cloud.page index 5f1c239..cdbffdc 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_cloud-customer-state-cloud.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_cloud-customer-state-cloud.page @@ -29,6 +29,189 @@ + + @@ -212,7 +395,8 @@ Edit Meter SM15R-01-00000001
-
+ +
@@ -220,8 +404,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_ground-customer-state-ground.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_ground-customer-state-ground.page index 5f1c239..cdbffdc 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_ground-customer-state-ground.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_ground-customer-state-ground.page @@ -29,6 +29,189 @@ + + @@ -212,7 +395,8 @@ Edit Meter SM15R-01-00000001
-
+ +
@@ -220,8 +404,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_tariff_cloud-customer-tariff-cloud.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_tariff_cloud-customer-tariff-cloud.page index 0cbb242..58782fe 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_tariff_cloud-customer-tariff-cloud.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_tariff_cloud-customer-tariff-cloud.page @@ -29,6 +29,189 @@ + + @@ -212,7 +395,8 @@ Edit Meter SM15R-01-00000001
-
+ +
@@ -220,8 +404,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_totalizer.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_totalizer.page index f5316f3..84a3e19 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_totalizer.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_totalizer.page @@ -29,6 +29,7 @@ + @@ -212,7 +213,8 @@ Edit Meter SM15R-01-10000001
-
+ +
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags-prepopulate.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags-prepopulate.page index a53ec3d..41614e6 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags-prepopulate.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags-prepopulate.page @@ -28,6 +28,189 @@ + + @@ -216,7 +399,8 @@ Edit Meter SM15R-01-00000001
-
+ +
@@ -224,8 +408,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags.page index fd62bce..bb51492 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags.page @@ -29,6 +29,189 @@ + + @@ -212,7 +395,8 @@ Edit Meter SM15R-01-00000001
-
+ +
@@ -220,8 +404,11 @@
- +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_unknown_server_error.page b/test-data/meter/test_meterviews-MeterViewTest.test_unknown_server_error.page index da31037..ede4209 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_unknown_server_error.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_unknown_server_error.page @@ -33,6 +33,7 @@ + @@ -210,6 +211,10 @@
+
+ Please correct the highlighted fields and try again. +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_add.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_add.page index d82de5f..d8b92b0 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_add.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_add.page @@ -194,14 +194,6 @@
-
-
@@ -210,16 +202,27 @@
- +
+
+ + -
- -
- -
-
-
+ + +
+ +
+ +
+
+
You must enter a tariff name @@ -227,40 +230,46 @@
-
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
+
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+
Must be higher than 0
-
- -
+ + +
+ +
@@ -318,67 +327,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -439,23 +458,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -513,37 +534,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_add_form_int_outrange.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_add_form_int_outrange.page index e43923a..cdf2143 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_add_form_int_outrange.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_add_form_int_outrange.page @@ -197,14 +197,6 @@
-
-
@@ -213,50 +205,67 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+
Load Limit must be less than or equal to 2147483647
-
- -
+ + +
+ +
@@ -314,67 +323,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -435,23 +454,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,37 +530,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_add_modal_get.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_add_modal_get.page new file mode 100644 index 0000000..86a4996 --- /dev/null +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_add_modal_get.page @@ -0,0 +1,403 @@ +> GET /tariff/add-modal HTTP/1.1 +> Cookie: session=%% SESSION %% +> Host: localhost +> User-Agent: Unittest/1.0 +> + +< HTTP/1.1 200 OK +< Content-Type: text/html; charset=utf-8 +< Set-Cookie: %% COOKIE %% +< Set-Cookie: %% COOKIE %% +< Vary: Cookie +< + + + + + +
+
+ + + + + + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
+
+ + + + + + + + + + + + +
StartEndLoad Limit in watts
+ +
+ + +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
+ + + + + + + + + + + + + + +
min total. energy (kWh)max total. energy (kWh)USD per kWh
+ +
+ + +
+
+ + +
+ +
+
+ +
+
+
+ + +
+ +
+ + + + + + + + + + + + + +
StartEndModifier
+ +
+ + +
+
+ + +
+ +
+
+ +
+
+
+ + +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
+ diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_add_with_invalid_blockrates.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_add_with_invalid_blockrates.page index 35dafa4..0bfddcc 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_add_with_invalid_blockrates.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_add_with_invalid_blockrates.page @@ -197,14 +197,6 @@
-
-
@@ -213,44 +205,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -308,67 +317,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -429,29 +448,31 @@ - - -
+
+ +
Block rates contain at least one gap, between 0 and 65535
-
- -
-
- -
-
-
- -
- -
+ +
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,37 +530,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_add_with_invalid_tous.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_add_with_invalid_tous.page index 130741d..b896f2a 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_add_with_invalid_tous.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_add_with_invalid_tous.page @@ -197,14 +197,6 @@
-
-
@@ -213,44 +205,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -308,67 +317,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -429,23 +448,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -503,43 +524,44 @@ - - -
+
+ +
The TOU period modifier must be a positive number.
-
- -
-
- -
-
-
- -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_edit-edit-negative-post-error.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_edit-edit-negative-post-error.page index 9746fd8..64ca680 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_edit-edit-negative-post-error.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_edit-edit-negative-post-error.page @@ -199,14 +199,6 @@
-
-
@@ -215,44 +207,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -310,73 +319,83 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+
Flat Rate cannot be negative
-
- -
+ + +
+ +
@@ -437,23 +456,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -511,37 +532,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_edit-edit-post-error.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_edit-edit-post-error.page index 70a55c7..e7df0b4 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_edit-edit-post-error.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_edit-edit-post-error.page @@ -199,14 +199,6 @@
-
-
@@ -215,44 +207,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -310,73 +319,83 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+
Please set a Flat Rate
-
- -
+ + +
+ +
@@ -437,23 +456,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -511,37 +532,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_edit.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_edit.page index eae6086..74106f6 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_edit.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_edit.page @@ -198,14 +198,6 @@
-
-
@@ -214,45 +206,62 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -310,67 +319,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -431,23 +450,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -505,37 +526,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_blockrate.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_blockrate.page index b93f730..3374010 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_blockrate.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_blockrate.page @@ -197,14 +197,6 @@
-
-
@@ -213,44 +205,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -308,67 +317,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -429,29 +448,31 @@ - - -
+
+ +
Please add some block rates.
-
- -
-
- -
-
-
- -
- -
+ +
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,37 +530,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_duplicate_name.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_duplicate_name.page index 49c541d..488f090 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_duplicate_name.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_duplicate_name.page @@ -194,14 +194,6 @@
-
-
@@ -210,15 +202,26 @@
- +
+
+ + -
- -
- -
-
-
+ + +
+ +
+ +
+
+
A tariff with the name "TARIFF" already exists @@ -226,34 +229,40 @@
-
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -311,67 +320,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -432,23 +451,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -506,37 +527,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_empty_name.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_empty_name.page index 1bf005a..42ccd71 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_empty_name.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_empty_name.page @@ -197,14 +197,6 @@
-
-
@@ -213,15 +205,26 @@
- +
+
+ + -
- -
- -
-
-
+ + +
+ +
+ +
+
+
Please set a name for this tariff @@ -229,34 +232,40 @@
-
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -314,67 +323,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -435,23 +454,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,37 +530,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_enter_load_limit.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_enter_load_limit.page index ceefb7c..8742026 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_enter_load_limit.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_enter_load_limit.page @@ -197,14 +197,6 @@
-
-
@@ -213,50 +205,67 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+
Please enter a Load Limit for this tariff
-
- -
+ + +
+ +
@@ -314,67 +323,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -435,23 +454,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,37 +530,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_enter_monthly_plan_price.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_enter_monthly_plan_price.page index fd1918d..4c9755c 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_enter_monthly_plan_price.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_enter_monthly_plan_price.page @@ -197,14 +197,6 @@
-
-
@@ -213,44 +205,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -308,73 +317,83 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+
Number must be at least 0.
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -435,23 +454,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,37 +530,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_existing_duplicate_names.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_existing_duplicate_names.page index 0f1f2aa..d56b3cb 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_existing_duplicate_names.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_existing_duplicate_names.page @@ -197,14 +197,6 @@
-
-
@@ -213,15 +205,26 @@
- +
+
+ + -
- -
- -
-
-
+ + +
+ +
+ +
+
+
A tariff with the name "TARIFF" already exists @@ -229,34 +232,40 @@
-
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -314,67 +323,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -435,23 +454,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,37 +530,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_flat_rate.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_flat_rate.page index 0189fd9..a19d19a 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_flat_rate.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_flat_rate.page @@ -197,14 +197,6 @@
-
-
@@ -213,44 +205,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -308,73 +317,83 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+
Please set a Flat Rate
-
- -
+ + +
+ +
@@ -435,23 +454,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,37 +530,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_low_balance_empty.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_low_balance_empty.page index be646ab..efcafc1 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_low_balance_empty.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_low_balance_empty.page @@ -197,14 +197,6 @@
-
-
@@ -213,44 +205,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -308,79 +317,89 @@ - - -
- -
- - in USD -
-
-
+
+ + + +
+ +
+ + in USD +
+
+
Low Balance cannot be empty.
-
- -
-
- -
-
-
- -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
+
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+
Please set a Flat Rate
-
- -
+ + +
+ +
@@ -441,23 +460,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -515,37 +536,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_low_balance_negative.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_low_balance_negative.page index b59e35a..f8298b3 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_low_balance_negative.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_low_balance_negative.page @@ -197,14 +197,6 @@
-
-
@@ -213,44 +205,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -308,79 +317,89 @@ - - -
- -
- - in USD -
-
-
+
+ + + +
+ +
+ + in USD +
+
+
Low Balance must be higher or equals to 0.
-
- -
-
- -
-
-
- -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
+
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+
Please set a Flat Rate
-
- -
+ + +
+ +
@@ -441,23 +460,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -515,37 +536,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_negative_flat_rate.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_negative_flat_rate.page index 9a51721..50c9d3d 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_negative_flat_rate.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_negative_flat_rate.page @@ -197,14 +197,6 @@
-
-
@@ -213,44 +205,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -308,73 +317,83 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+
Flat Rate cannot be negative
-
- -
+ + +
+ +
@@ -435,23 +454,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,37 +530,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_negative_load_limit.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_negative_load_limit.page index 2fcadba..28a8241 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_negative_load_limit.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_negative_load_limit.page @@ -197,14 +197,6 @@
-
-
@@ -213,50 +205,67 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+
Load Limits cannot be negative
-
- -
+ + +
+ +
@@ -314,67 +323,77 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
- -
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+ + +
+ +
@@ -435,23 +454,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,37 +530,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_no_scheduled_load_limits.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_no_scheduled_load_limits.page index bbc03f4..4d576d9 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_no_scheduled_load_limits.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_no_scheduled_load_limits.page @@ -197,14 +197,6 @@
-
-
@@ -213,44 +205,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -308,79 +317,89 @@ - - -
+
+ +
Please add some Load limit periods.
-
- -
- - in USD -
-
-
- -
-
- -
-
-
- -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+
Please set a Flat Rate
-
- -
+ + +
+ +
@@ -441,23 +460,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -515,37 +536,38 @@ - - -
- -
-
- -
-
-
- + + -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_tous.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_tous.page index 0a36f96..cbcdd79 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_error_tous.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_error_tous.page @@ -197,14 +197,6 @@
-
-
@@ -213,44 +205,61 @@
- +
+
+ + -
- -
- -
-
- + -
- -
- -
-
-
- -
- - -
-
-
- -
- - in watts -
-
-
- -
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in watts +
+
+ + +
+ +
@@ -308,73 +317,83 @@ - - -
- -
- - in USD -
-
-
- -
-
- -
-
-
- + + -
- -
- - in USD -
-
- - -
- -
- - in USD -
-
-
- -
- - -
-
-
- -
- - in USD per kWh -
-
-
+
+ +
+ + in USD +
+
+ + +
+ +
+
+ +
+
+
+ + + +
+ +
+ + in USD +
+
+ + +
+ +
+ + in USD +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + in USD per kWh +
+
+
Please set a Flat Rate
-
- -
+ + +
+ +
@@ -435,23 +454,25 @@ - - -
- -
-
- -
-
-
- + + + -
- -
+
+ +
+
+ +
+
+
+ + +
+ +
@@ -509,43 +530,44 @@ - - -
+
+ +
Please add some TOU periods.
-
- -
-
- -
-
-
- -
- -
- -
-
+
+ +
+
+ +
+
+
-
- -
- - in kWh -
-
+ +
+ +
+ +
+
+ +
+ +
+ + in kWh +
+
From 0627fa306771eaa20a5436071cf0f30454558c6b Mon Sep 17 00:00:00 2001 From: Tristan Escalada <355457+tescalada@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:26:02 -0400 Subject: [PATCH 02/11] Derive the test image version from the current commit in a worktree A worktree's .git is a file rather than a directory, so hatch-vcs cannot read it from the build context and the version was pinned to a bare 0.0.0. sparkmeter.__version__ derives git_version from the PEP 440 local segment, which 0.0.0 does not have, leaving it empty. The page tests scrub GIT_VERSION out of every snapshot with str.replace(), and replacing the empty string inserts the marker between every character, so every page test failed. --- scripts/run_coverage.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/run_coverage.sh b/scripts/run_coverage.sh index 0c822d1..ce3eb91 100644 --- a/scripts/run_coverage.sh +++ b/scripts/run_coverage.sh @@ -8,11 +8,18 @@ compare_branch="${DIFF_COVER_COMPARE_BRANCH:-origin/main}" fail_under="${DIFF_COVER_FAIL_UNDER:-90}" # A git worktree's .git is a file, not a directory, and is unreadable inside the -# build context, so hatch-vcs cannot derive the version. Supply a placeholder in -# that case; a normal checkout leaves it empty and reads .git as usual. +# build context, so hatch-vcs cannot derive the version. Build one from the +# current commit in that case; a normal checkout leaves it empty and reads .git +# as usual. +# +# The local segment (`+g`) is not optional. `sparkmeter.__version__` +# derives `git_version` from it and yields "" when it is absent, and the page +# tests scrub `GIT_VERSION` out of every snapshot with `str.replace()`. Replacing +# the empty string inserts the marker between every character of every snapshot, +# which fails the whole page-test suite. version="" if [ -f .git ]; then - version="0.0.0" + version="0.0.0+g$(git rev-parse --short HEAD)" fi docker compose -f docker-compose.test.yml build \ From 673cce30172c59307ffcbf95f3cc83d30b461b9e Mon Sep 17 00:00:00 2001 From: Tristan Escalada <355457+tescalada@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:31:30 -0400 Subject: [PATCH 03/11] Report tariff modal form errors through the shared X-Form-Errors builder The block rate, TOU and scheduled load limit validators store the raw ValueError rather than its message. render_modal_form serialized form.errors directly, and the JSON encoder has no branch for exceptions, so any of those three validation failures raised a TypeError and turned the 400 into a 500. BaseForm.render already coerced every error to str and logged the result. Move that into set_form_errors_header and use it from both, so the modal and the standalone page report errors identically. Build the modal form from request.form on GET as well, matching /tariff/add. With no formdata the JSON collection fields keep None, which renders as null in the params element and as an empty value in the hidden inputs, and posting an untouched modal back then fails to parse. Use http.client.OK for render_modal_form's default status, consistent with the rest of the module. --- sparkmeter/tariff/tariffview.py | 12 ++- sparkmeter/tariff/tests/test_tariffviews.py | 84 +++++++++++++++++-- sparkmeter/web/forms.py | 35 ++++++-- ...ews-TariffViewTest.test_add_modal_get.page | 12 +-- 4 files changed, 115 insertions(+), 28 deletions(-) diff --git a/sparkmeter/tariff/tariffview.py b/sparkmeter/tariff/tariffview.py index d452573..1c4594f 100644 --- a/sparkmeter/tariff/tariffview.py +++ b/sparkmeter/tariff/tariffview.py @@ -16,24 +16,22 @@ from werkzeug.utils import redirect from sparkmeter.misc.htmlutils import build_link -from sparkmeter.misc.jsonutils import json_dumps, jsonify +from sparkmeter.misc.jsonutils import jsonify from sparkmeter.tariff.tariffdomain import Tariff from sparkmeter.tariff.tariffform import TariffForm from sparkmeter.tariff.tariffutils import add_tariff_from_form, update_tariff_from_form from sparkmeter.web.blueprint import AuthBlueprint +from sparkmeter.web.forms import set_form_errors_header from sparkmeter.web.permission import verify_permission logger = logging.getLogger(__name__) tariff = AuthBlueprint("tariff", __name__) -def render_modal_form(form, status=200): +def render_modal_form(form, status=http.client.OK): """Render the tariff modal form with optional validation metadata.""" body = render_template("tariff-modal-form.html", form=form) - response = Response(body, status=status) - if form.errors: - response.headers["X-Form-Errors"] = json_dumps(form.errors) - return response + return set_form_errors_header(Response(body, status=status), form) @tariff.route("/tariff/") @@ -75,7 +73,7 @@ def add(): @verify_permission("tariff", "add") def add_modal(): """Add tariff form rendered for the meter modal workflow.""" - form = TariffForm(request.form if request.method == "POST" else None) + form = TariffForm(request.form) if request.method == "POST": tariff = add_tariff_from_form(form) if tariff: diff --git a/sparkmeter/tariff/tests/test_tariffviews.py b/sparkmeter/tariff/tests/test_tariffviews.py index 75ad734..d351070 100644 --- a/sparkmeter/tariff/tests/test_tariffviews.py +++ b/sparkmeter/tariff/tests/test_tariffviews.py @@ -13,10 +13,10 @@ from sparkmeter.event.eventdomain import Event from sparkmeter.meter.meterdomain import MeterConfig from sparkmeter.misc.htmlutils import build_link -from sparkmeter.misc.jsonutils import json_dumps +from sparkmeter.misc.jsonutils import json_dumps, json_loads from sparkmeter.tariff.tariffdomain import Tariff from sparkmeter.tests.base import WebViewTestCaseBase -from sparkmeter.tests.test_data_factory import MeterFactory, TariffFactory +from sparkmeter.tests.test_data_factory import MeterFactory, TariffFactory, VendorFactory @pytest.fixture(scope="module", autouse=True) @@ -56,7 +56,6 @@ def test_add(self, client): self.verify_response(response) def test_add_modal_get(self, client): - # GET renders the modal form with no validation errors (tariffview lines 78, 90, 32-33, 36). path = "/tariff/add-modal" response = client.get(path) @@ -64,8 +63,39 @@ def test_add_modal_get(self, client): assert "X-Form-Errors" not in response.headers self.verify_response(response) + def test_add_modal_get_renders_empty_collections(self, client): + """A freshly opened modal must match /tariff/add, which posts back cleanly. + + With no formdata the JSON fields keep ``None``, which renders as + ``null``/``""`` instead of ``[]`` and cannot be posted back. + """ + response = client.get("/tariff/add-modal") + standalone = client.get("/tariff/add") + + for attribute in ('data-blockrates="[]"', 'data-tous="[]"', 'data-load-limits="[]"'): + assert attribute in response.text + assert attribute in standalone.text + + def test_add_modal_untouched_post_is_parseable(self, client): + """Submitting an untouched modal must not post unparseable collections.""" + data = dict(name="", blockrates="[]", tous="[]", load_limits="[]") + + response = client.post("/tariff/add-modal", data=data) + + assert response.status_code == http.client.BAD_REQUEST + errors = json_loads(response.headers["X-Form-Errors"]) + assert "blockrates" not in errors + assert "tous" not in errors + assert "load_limits" not in errors + + def test_add_modal_forbidden_without_permission(self, client, vendor_role): + """The modal endpoint is behind the same tariff:add permission as /tariff/add.""" + client.login_as(VendorFactory(roles=[vendor_role])) + + assert client.get("/tariff/add-modal").status_code == http.client.NOT_FOUND + assert client.post("/tariff/add-modal", data={}).status_code == http.client.NOT_FOUND + def test_add_modal_post_valid(self, client, config): - # A valid POST creates the tariff and returns JSON (tariffview lines 79-88). path = "/tariff/add-modal" data = dict( name="MODAL TARIFF", @@ -90,17 +120,59 @@ def test_add_modal_post_valid(self, client, config): assert body["tariff"]["id"] == str(tariffs[0].id) def test_add_modal_post_invalid(self, client): - # An invalid POST re-renders the modal form with the error header (tariffview lines 89, 34-35). path = "/tariff/add-modal" data = dict(name="", flat_load_limit=150, flat_price=4) response = client.post(path, data=data) assert response.status_code == http.client.BAD_REQUEST - assert "X-Form-Errors" in response.headers + errors = json_loads(response.headers["X-Form-Errors"]) + assert errors["name"] == ["Please set a name for this tariff"] assert "Please set a name for this tariff" in response.text assert not Tariff.query.scalar() + @pytest.mark.parametrize( + "field, data, message", + [ + ( + "blockrates", + dict( + tariff_type=Tariff.TYPE_BLOCKRATE, + blockrates=json_dumps([{"lower": "1", "upper": "20", "value": "1"}]), + ), + "Block rates contain at least one gap, between 0 and 65535", + ), + ( + "tous", + dict( + tou_enabled=True, + tous=json_dumps([{"start": "00:00", "end": "12:00", "value": -100}]), + ), + "The TOU period modifier must be a positive number.", + ), + ( + "load_limits", + dict(load_limit_type=Tariff.LOAD_LIMIT_TYPE_SCHEDULED, load_limits=json_dumps([])), + "Please add some Load limit periods.", + ), + ], + ) + def test_add_modal_post_collection_error(self, client, field, data, message): + """These validators store the raw exception, which is not JSON serializable. + + Reporting them used to raise a TypeError out of the error header and + turn the response into a 500. + """ + path = "/tariff/add-modal" + data = dict(data, name="TARIFF", flat_load_limit=150, flat_price=4) + + response = client.post(path, data=data) + + assert response.status_code == http.client.BAD_REQUEST + errors = json_loads(response.headers["X-Form-Errors"]) + assert errors[field] == [message] + assert not Tariff.query.scalar() + def test_add_form(self, client, config): path = "/tariff/add" diff --git a/sparkmeter/web/forms.py b/sparkmeter/web/forms.py index 84b02cd..17144c3 100644 --- a/sparkmeter/web/forms.py +++ b/sparkmeter/web/forms.py @@ -39,6 +39,31 @@ def getall(self, key): return [self[key]] +def set_form_errors_header(response, form): + """Attach a form's validation errors to a response as ``X-Form-Errors``. + + This is for development, and especially so that unittests can show a nicer + error when there is a form error. + + Every error is coerced to ``str``: validators are free to store exception + instances rather than messages, and those are not JSON serializable. + + :param response: the response to annotate. + :param form: the form whose errors should be reported. + :return: the same response, for convenience. + :rtype: Response + """ + if not form.errors: + return response + + error_dict = {} + for name, errors in list(form.errors.items()): + error_dict[name] = list(map(str, errors)) + response.headers["X-Form-Errors"] = json_dumps(error_dict) + logger.warning("{} errors: {} {}".format(type(form).__name__, error_dict, form.data)) + return response + + class BaseForm(FlaskForm): """Base form, used by all other forms in the application.""" @@ -102,15 +127,7 @@ def render(self, **context): :rtype: Response """ body = render_template(self.template_filename, form=self, **context) - response = Response(body) - if self.errors: - error_dict = {} - for name, errors in list(self.errors.items()): - error_dict[name] = list(map(str, errors)) - response.headers["X-Form-Errors"] = json_dumps(error_dict) - logger.warning("{} errors: {} {}".format(type(self).__name__, error_dict, self.data)) - - return response + return set_form_errors_header(Response(body), self) def flatten_json(form, json, parent_key="", separator="-", skip_unknown_keys=True): # pragma: nocoverage diff --git a/test-data/tariff/test_tariffviews-TariffViewTest.test_add_modal_get.page b/test-data/tariff/test_tariffviews-TariffViewTest.test_add_modal_get.page index 86a4996..da516c3 100644 --- a/test-data/tariff/test_tariffviews-TariffViewTest.test_add_modal_get.page +++ b/test-data/tariff/test_tariffviews-TariffViewTest.test_add_modal_get.page @@ -49,18 +49,18 @@
- - - + + +
From 615d40ee4f33507ed284973213daae73b8b9f365 Mon Sep 17 00:00:00 2001 From: Tristan Escalada <355457+tescalada@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:37:33 -0400 Subject: [PATCH 04/11] Move the tariff modal behavior into a page module The behavior lived in a ~190 line inline - {% endif %} -{% endblock scripts %} {% block breadcrumbs %} {% call breadcrumb(role='operator', url=url_for('ground.index')) %} @@ -251,6 +65,25 @@
{%- if meter_type == 'customer' -%} + {#- The modal's behavior lives in meter/js/meter-tariff-modal.js; its + configuration and user-facing strings are carried here. `forceescape` + is required: flask-babel's LazyString defines `__html__`, so a + translated string is otherwise emitted without escaping and a quote + or an angle bracket in a translation would break the attribute. -#} +
+
{{ form.tariff.label(class="control-label col-lg-2") }}
diff --git a/sparkmeter/meter/tests/test_meterviews.py b/sparkmeter/meter/tests/test_meterviews.py index a5b76de..8cf6a65 100644 --- a/sparkmeter/meter/tests/test_meterviews.py +++ b/sparkmeter/meter/tests/test_meterviews.py @@ -244,6 +244,47 @@ def test_add_duplicated_serial(self, client): assert "Meter serial SM15R-01-0000007B already exists." in response.text self.verify_response(response) + def test_add_customer_meter_tariff_select(self, client): + """The select starts blank and offers the modal, which drives the form's markup.""" + TariffFactory(name="TARIFF") + self.session.commit() + + response = client.get("/meter/add-meter") + + # QuerySelectField(allow_blank=True) renders the blank option with this + # value; the modal's JavaScript restores the select to it. + assert '' in response.text + assert 'data-add-new-value="__add_new__"' in response.text + assert 'data-add-new-label="<Add New>"' in response.text + + def test_add_customer_meter_without_tariff(self, client): + """A customer meter needs a tariff, and says so in the field's error markup.""" + data = { + "serial": "SM15R-01-0000007B", + "state": 0, + } + + response = client.post("/meter/add-meter", data=data) + + assert response.status_code == http.client.OK + assert "Please select a tariff or add a new one." in response.text + assert "has-error" in response.text + assert not list(self.ground.get_meters()) + + def test_add_customer_meter_with_add_new_sentinel(self, client): + """The add-new option is a client-side sentinel, never a submittable tariff.""" + data = { + "serial": "SM15R-01-0000007B", + "state": 0, + "tariff": "__add_new__", + } + + response = client.post("/meter/add-meter", data=data) + + assert response.status_code == http.client.OK + assert "No tariff was created. Please select a tariff or add a new one." in response.text + assert not list(self.ground.get_meters()) + def test_add_unknown_model(self, client): tariff = TariffFactory() self.session.commit() diff --git a/sparkmeter/tariff/js/tariff-form.js b/sparkmeter/tariff/js/tariff-form.js index e9b6c9a..7fe0d23 100644 --- a/sparkmeter/tariff/js/tariff-form.js +++ b/sparkmeter/tariff/js/tariff-form.js @@ -11,16 +11,23 @@ function TariffForm() { exports.TariffForm = TariffForm; +// Namespace for the delegated handlers below, so that re-initializing the form +// -- which the tariff modal does every time it renders the fragment -- rebinds +// them instead of stacking a second copy on `document`. +var EVENTS = '.tariffform'; + TariffForm.prototype = { _init: function() { - $(document).on('change', 'input:radio[id^="tariff_type"]', function(event) { + $(document).off(EVENTS); + + $(document).on('change' + EVENTS, 'input:radio[id^="tariff_type"]', function(event) { $("div.tariff_type").addClass("hide"); $("div.tariff_type." + $(this).val()).removeClass("hide"); $("input#tariff_type[value='flat']").attr('checked', $(this).val() === 'flat'); $("input#tariff_type[value='blockrate']").attr('checked', $(this).val() === 'blockrate'); }); - $(document).on('change', 'input:radio[id^="load_limit_type"]', function(event) { + $(document).on('change' + EVENTS, 'input:radio[id^="load_limit_type"]', function(event) { $("div.load_limit_type").addClass("hide"); $("div.load_limit_type." + $(this).val()).removeClass("hide"); $("input#load_limit_type[value='flat']").attr('checked', $(this).val() === 'flat'); @@ -32,7 +39,7 @@ TariffForm.prototype = { } }); - $(document).on('change', 'input:checkbox[id^="tou_enabled"]', function(event) { + $(document).on('change' + EVENTS, 'input:checkbox[id^="tou_enabled"]', function(event) { if (this.checked) { $(".tou").removeClass("hide"); } else { @@ -40,7 +47,7 @@ TariffForm.prototype = { } }); - $(document).on('change', 'input:checkbox[id^="plan_enabled"]', function(event) { + $(document).on('change' + EVENTS, 'input:checkbox[id^="plan_enabled"]', function(event) { if (this.checked) { $(".plan-price").removeClass("hide"); $(".plan-fixed-fee").removeClass("hide"); @@ -50,7 +57,7 @@ TariffForm.prototype = { } }); - $(document).on('change', 'input:checkbox[id^="daily_energy_limit_enabled"]', function(event) { + $(document).on('change' + EVENTS, 'input:checkbox[id^="daily_energy_limit_enabled"]', function(event) { if (this.checked) { $(".daily-energy-limit-reset-hour").removeClass("hide"); $(".daily-energy-limit-value").removeClass("hide"); diff --git a/sparkmeter/tariff/templates/tariff-form.html b/sparkmeter/tariff/templates/tariff-form.html index bd24f0c..4cfdb1e 100644 --- a/sparkmeter/tariff/templates/tariff-form.html +++ b/sparkmeter/tariff/templates/tariff-form.html @@ -37,19 +37,6 @@ {% endblock breadcrumbs %} -{% macro form_tariff_error(form, field, class_=None) %} - {% if form.errors[field] %} -
- - - {% for error in form.errors[field] %} - {{ error }} - {% endfor %} - -
- {% endif %} -{% endmacro %} - {% block content %}
diff --git a/sparkmeter/tariff/templates/tariff-modal-form.html b/sparkmeter/tariff/templates/tariff-modal-form.html index b71fb1e..d300e18 100644 --- a/sparkmeter/tariff/templates/tariff-modal-form.html +++ b/sparkmeter/tariff/templates/tariff-modal-form.html @@ -1,53 +1,5 @@ {%- from "_macros.html" import form_errors -%} -{% macro form_tariff_error(form, field, class_=None) %} - {% if form.errors[field] %} -
- - - {% for error in form.errors[field] %} - {{ error }} - {% endfor %} - -
- {% endif %} -{% endmacro %} - - - {{ form_errors(form, hiddens='only') }} {% include "tariff/_tariff-form-fields.html" %} diff --git a/sparkmeter/tariff/templates/tariff/_tariff-form-fields.html b/sparkmeter/tariff/templates/tariff/_tariff-form-fields.html index 1fdd3d6..bcea382 100644 --- a/sparkmeter/tariff/templates/tariff/_tariff-form-fields.html +++ b/sparkmeter/tariff/templates/tariff/_tariff-form-fields.html @@ -1,3 +1,16 @@ +{% macro form_tariff_error(form, field, class_=None) %} + {% if form.errors[field] %} +
+ + + {% for error in form.errors[field] %} + {{ error }} + {% endfor %} + +
+ {% endif %} +{% endmacro %} +
- - @@ -233,7 +50,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_32_bit_serial.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_32_bit_serial.page index 0fc3e8d..abb8f61 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_32_bit_serial.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_32_bit_serial.page @@ -29,189 +29,6 @@ - - @@ -233,7 +50,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_duplicated_serial.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_duplicated_serial.page index 518e914..e48496a 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_duplicated_serial.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_duplicated_serial.page @@ -33,189 +33,6 @@ - - @@ -237,7 +54,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_country_code.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_country_code.page index cc91b58..ebbc860 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_country_code.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_country_code.page @@ -33,189 +33,6 @@ - - @@ -237,7 +54,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_phone_number.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_phone_number.page index 87c27e1..ed3ca53 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_phone_number.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_empty_phone_number.page @@ -33,189 +33,6 @@ - - @@ -237,7 +54,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_from_cloud.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_from_cloud.page index 6911773..1ee1f00 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_from_cloud.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_from_cloud.page @@ -29,189 +29,6 @@ - - @@ -233,7 +50,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_phone_number.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_phone_number.page index 98b277e..f9f47ef 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_phone_number.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_phone_number.page @@ -33,189 +33,6 @@ - - @@ -237,7 +54,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial-invalid-serial.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial-invalid-serial.page index c5fc215..eae472e 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial-invalid-serial.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial-invalid-serial.page @@ -33,189 +33,6 @@ - - @@ -237,7 +54,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial.page index cddb3c4..03edcf5 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_invalid_serial.page @@ -30,189 +30,6 @@ - - @@ -234,7 +51,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer.page b/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer.page index d0c0aa3..9e52a23 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_add_totalizer.page @@ -29,7 +29,6 @@ - @@ -51,7 +50,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_cloud-customer-state-cloud.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_cloud-customer-state-cloud.page index cdbffdc..ea27690 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_cloud-customer-state-cloud.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_cloud-customer-state-cloud.page @@ -29,189 +29,6 @@ - - @@ -233,7 +50,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_ground-customer-state-ground.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_ground-customer-state-ground.page index cdbffdc..ea27690 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_ground-customer-state-ground.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_state_ground-customer-state-ground.page @@ -29,189 +29,6 @@ - - @@ -233,7 +50,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_tariff_cloud-customer-tariff-cloud.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_tariff_cloud-customer-tariff-cloud.page index 58782fe..6ee394a 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_tariff_cloud-customer-tariff-cloud.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_customer_tariff_cloud-customer-tariff-cloud.page @@ -29,189 +29,6 @@ - - @@ -233,7 +50,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_totalizer.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_totalizer.page index 84a3e19..897127c 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_totalizer.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_totalizer.page @@ -29,7 +29,6 @@ - @@ -51,7 +50,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags.page b/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags.page index bb51492..41b3b26 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_edit_with_tags.page @@ -29,189 +29,6 @@ - - @@ -233,7 +50,7 @@ - +
+
+
+
diff --git a/test-data/meter/test_meterviews-MeterViewTest.test_unknown_server_error.page b/test-data/meter/test_meterviews-MeterViewTest.test_unknown_server_error.page index ede4209..7d37cdb 100644 --- a/test-data/meter/test_meterviews-MeterViewTest.test_unknown_server_error.page +++ b/test-data/meter/test_meterviews-MeterViewTest.test_unknown_server_error.page @@ -33,7 +33,6 @@ - @@ -55,7 +54,7 @@ - +
+
+
- #meter-tariff-modal .modal-dialog { - width: 900px; - max-width: calc(100vw - 40px); - } - - #meter-tariff-modal .control-label.col-lg-2 { - width: 18%; - } - - #meter-tariff-modal .input-group.col-lg-3, - #meter-tariff-modal .col-md-5 { - width: 52%; - } - - #meter-tariff-modal .input-group.col-lg-10, - #meter-tariff-modal .btn-group.col-lg-10 { - width: 70%; - } - - #meter-tariff-modal .input-group .form-control { - min-width: 0; - } - - @media (max-width: 991px) { - #meter-tariff-modal .control-label.col-lg-2, - #meter-tariff-modal .input-group.col-lg-3, - #meter-tariff-modal .input-group.col-lg-10, - #meter-tariff-modal .btn-group.col-lg-10, - #meter-tariff-modal .col-md-5 { - width: 100%; - } - } - - +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Date: Mon, 20 Jul 2026 18:20:59 -0400 Subject: [PATCH 05/11] Render the tariff modal's flash messages as text base.flash builds its alert with jQuery's .html(), so the message the server returns in the add-modal JSON reached the page as markup. The inline implementation the module replaced used .text(). Add base.flashText, which builds the same alert from .text(), and have the tariff modal use it for all four of its messages. base.flash is shared by the rest of the application and keeps its behavior. --- assets/javascripts/base.js | 15 ++++++++++++--- assets/javascripts/base.spec.js | 21 +++++++++++++++++++++ sparkmeter/meter/js/meter-tariff-modal.js | 8 ++++---- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/assets/javascripts/base.js b/assets/javascripts/base.js index a7a6d94..5a106fb 100644 --- a/assets/javascripts/base.js +++ b/assets/javascripts/base.js @@ -16,9 +16,7 @@ function format_currency(number) { } exports.format_currency = format_currency; -function flash(msg, category, delay) { - var flash = $('
'); - flash.html(msg); +function showAlert(flash, category, delay) { flash.addClass('alert'); flash.hide(); if (category) { @@ -30,8 +28,19 @@ function flash(msg, category, delay) { flash.delay(delay).fadeOut('slow'); } } + +function flash(msg, category, delay) { + showAlert($('
').html(msg), category, delay); +} exports.flash = flash; +// Same alert as flash(), for a message that is not markup -- notably one that +// came back from the server, which must not be able to inject elements. +function flashText(msg, category, delay) { + showAlert($('
').text(msg), category, delay); +} +exports.flashText = flashText; + var _pageLoaders = {}; function registerPageLoader(pageName, loader) { diff --git a/assets/javascripts/base.spec.js b/assets/javascripts/base.spec.js index 0e48e20..38a0996 100644 --- a/assets/javascripts/base.spec.js +++ b/assets/javascripts/base.spec.js @@ -45,6 +45,27 @@ describe('base', function() { base.flash("testing", "category", 1000); expect($(".alerts").html()).toMatchSnapshot(); }); + test('should render its message as markup', function() { + base.flash("bold"); + expect($(".alerts b").length).toBe(1); + }); + }); + + describe('flashText', function() { + test('should add a div to .alerts', function() { + base.flashText("testing"); + expect($(".alerts").html()).toBe( + '
testing
'); + }); + test('should add an alert-category class', function() { + base.flashText("testing", "category", 1000); + expect($(".alerts div").hasClass('alert-category')).toBe(true); + }); + test('should render its message as text', function() { + base.flashText("bold"); + expect($(".alerts b").length).toBe(0); + expect($(".alerts").text()).toBe("bold"); + }); }); describe('getMetaItemProps', function() { diff --git a/sparkmeter/meter/js/meter-tariff-modal.js b/sparkmeter/meter/js/meter-tariff-modal.js index e411b38..2fbcc00 100644 --- a/sparkmeter/meter/js/meter-tariff-modal.js +++ b/sparkmeter/meter/js/meter-tariff-modal.js @@ -191,7 +191,7 @@ MeterTariffModal.prototype = { self.modal.modal('show'); }) .fail(function() { - base.flash(self.text('load-error'), 'danger'); + base.flashText(self.text('load-error'), 'danger'); self.restoreTariffSelection(); }); }, @@ -277,7 +277,7 @@ MeterTariffModal.prototype = { self.previousValue = String(data.tariff.id); self.select.val(self.previousValue); self.modal.modal('hide'); - base.flash(data.message || self.text('created'), 'success'); + base.flashText(data.message || self.text('created'), 'success'); }).fail(function(xhr) { if (!self.claimResponse(requestId)) { return; @@ -288,7 +288,7 @@ MeterTariffModal.prototype = { } return; } - base.flash(self.text('save-error'), 'danger'); + base.flashText(self.text('save-error'), 'danger'); }); }, @@ -320,7 +320,7 @@ MeterTariffModal.prototype = { sessionExpired: function() { this.modal.modal('hide'); this.restoreTariffSelection(); - base.flash(this.text('session-expired'), 'danger'); + base.flashText(this.text('session-expired'), 'danger'); }, addTariffOption: function(value, label) { From dabb32989b91920a840e79674763fae13d69561a Mon Sep 17 00:00:00 2001 From: Tristan Escalada <355457+tescalada@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:21:12 -0400 Subject: [PATCH 06/11] Restore the tariff modal dialog's width below 992px The