diff --git a/app/main/forms.py b/app/main/forms.py index fc7f7549b..3ac908a59 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -684,6 +684,17 @@ class ServiceSwitchLettersForm(StripWhitespaceForm): ) +class ServicePostageForm(StripWhitespaceForm): + + postage = RadioField( + 'Choose your postage', + choices=[ + ('first', 'First class only'), + ('second', 'Second class only'), + ], + ) + + class BrandingStyle(RadioField): def post_validate(self, form, validation_stopped): diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index 5cf9390db..d25160b6d 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -43,6 +43,7 @@ from app.main.forms import ( ServiceEditInboundNumberForm, ServiceInboundNumberForm, ServiceLetterContactBlockForm, + ServicePostageForm, ServicePreviewBranding, ServiceReplyToEmailForm, ServiceSetBranding, @@ -649,6 +650,19 @@ def service_set_letters(service_id): ) +@main.route("/services//service-settings/set-postage", methods=['GET', 'POST']) +@login_required +@user_is_platform_admin +def service_set_postage(service_id): + form = ServicePostageForm(postage=current_service.postage) + + if form.validate_on_submit(): + service_api_client.update_service(service_id, postage=form.postage.data) + return redirect(url_for(".service_settings", service_id=service_id)) + + return render_template('views/service-settings/set-postage.html', form=form) + + @main.route("/services//service-settings/set-auth-type", methods=['GET']) @login_required @user_has_permissions('manage_service') diff --git a/app/navigation.py b/app/navigation.py index 1b9e556a5..36a126478 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -230,6 +230,7 @@ class HeaderNavigation(Navigation): 'service_set_international_sms', 'service_set_letter_contact_block', 'service_set_letters', + 'service_set_postage', 'service_set_reply_to_email', 'service_set_sms', 'service_set_sms_prefix', @@ -352,6 +353,7 @@ class MainNavigation(Navigation): 'service_set_international_sms', 'service_set_letter_contact_block', 'service_set_letters', + 'service_set_postage', 'service_set_reply_to_email', 'service_set_sms', 'service_set_sms_prefix', @@ -677,6 +679,7 @@ class CaseworkNavigation(Navigation): 'service_set_international_sms', 'service_set_letter_contact_block', 'service_set_letters', + 'service_set_postage', 'service_set_reply_to_email', 'service_set_sms', 'service_set_sms_prefix', @@ -905,6 +908,7 @@ class OrgNavigation(Navigation): 'service_set_international_sms', 'service_set_letter_contact_block', 'service_set_letters', + 'service_set_postage', 'service_set_reply_to_email', 'service_set_sms', 'service_set_sms_prefix', diff --git a/app/notify_client/models.py b/app/notify_client/models.py index 10a5eefad..03a97851c 100644 --- a/app/notify_client/models.py +++ b/app/notify_client/models.py @@ -280,6 +280,7 @@ class Service(dict): 'name', 'organisation_type', 'permissions', + 'postage', 'prefix_sms', 'research_mode', 'service_callback_api', diff --git a/app/notify_client/service_api_client.py b/app/notify_client/service_api_client.py index 73ac7b6f3..26a1fe79f 100644 --- a/app/notify_client/service_api_client.py +++ b/app/notify_client/service_api_client.py @@ -88,6 +88,7 @@ class ServiceAPIClient(NotifyAdminAPIClient): 'free_sms_fragment_limit', 'prefix_sms', 'contact_link', + 'postage', } if disallowed_attributes: raise TypeError('Not allowed to update service attributes: {}'.format( diff --git a/app/templates/views/service-settings.html b/app/templates/views/service-settings.html index ad6b64909..0314769af 100644 --- a/app/templates/views/service-settings.html +++ b/app/templates/views/service-settings.html @@ -235,6 +235,21 @@ )}} {% endcall %} + {% if current_user.platform_admin %} + {% call row() %} + {{ text_field('Postage') }} + {% set postage = {'first': 'First class only', 'second': 'Second class only'} %} + {{ text_field(postage[current_service.postage]) }} + {{ edit_field( + 'Change', + url_for('.service_set_postage', + service_id=current_service.id), + permissions=['manage_service'] + ) + }} + {% endcall %} + {% endif %} + {% endcall %} diff --git a/app/templates/views/service-settings/set-postage.html b/app/templates/views/service-settings/set-postage.html new file mode 100644 index 000000000..995b1fc3b --- /dev/null +++ b/app/templates/views/service-settings/set-postage.html @@ -0,0 +1,39 @@ +{% extends "withnav_template.html" %} +{% from "components/radios.html" import radios %} +{% from "components/page-footer.html" import page_footer %} + +{% block service_page_title %} + Postage +{% endblock %} + +{% block maincolumn_content %} + +
+
+

Postage

+

You can send letters by first or second class post.

+

+ See a list of postage prices. +

+

Delivery times

+

+ Letters sent before 5:30pm are dispatched the next working day (Monday to Friday). +

+

+ First class letters are delivered one day after they’re dispatched. Second class letters are delivered 2 days after they’re dispatched. +

+

+ Royal Mail delivers from Monday to Saturday, excluding bank holidays. +

+
+ {{ radios(form.postage) }} + {{ page_footer( + 'Save', + back_link=url_for('.service_settings', service_id=current_service.id), + back_link_text='Back to settings' + ) }} +
+
+
+ +{% endblock %} diff --git a/tests/__init__.py b/tests/__init__.py index 1d626d4cb..6f412363e 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -146,6 +146,7 @@ def service_json( organisation_type='central', prefix_sms=True, contact_link=None, + postage='second', ): if users is None: users = [] @@ -174,6 +175,7 @@ def service_json( 'inbound_api': inbound_api, 'service_callback_api': service_callback_api, 'prefix_sms': prefix_sms, + 'postage': postage, } diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index abace066a..cab7f38e8 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -89,6 +89,7 @@ def mock_get_service_settings_page_common( 'Label Value Action', 'Send letters Off Change', + 'Postage Second class only Change', 'Label Value Action', 'Organisation Org 1 Change', @@ -1849,6 +1850,38 @@ def test_set_letter_branding_saves( mock_update_service.assert_called_once_with(service_one['id'], dvla_organisation='500') +def test_set_postage_platform_admin_only( + logged_in_client, + service_one, +): + response = logged_in_client.get(url_for('main.service_set_postage', service_id=SERVICE_ONE_ID)) + assert response.status_code == 403 + + +def test_set_postage_prepopulates( + logged_in_platform_admin_client, + service_one, +): + response = logged_in_platform_admin_client.get(url_for('main.service_set_postage', service_id=SERVICE_ONE_ID)) + assert response.status_code == 200 + page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') + assert page.select('input[checked]')[0]['value'] == 'second' + + +def test_set_postage_saves( + logged_in_platform_admin_client, + service_one, + mock_update_service, +): + response = logged_in_platform_admin_client.post( + url_for('main.service_set_postage', service_id=SERVICE_ONE_ID), + data={'postage': 'first'} + ) + assert response.status_code == 302 + assert response.location == url_for('main.service_settings', service_id=SERVICE_ONE_ID, _external=True) + mock_update_service.assert_called_once_with(SERVICE_ONE_ID, postage='first') + + @pytest.mark.parametrize('current_branding, expected_values, expected_labels', [ (None, [ 'None', '1', '2', '3', '4', '5',