diff --git a/app/main/forms.py b/app/main/forms.py index 928674651..0ab44e1ff 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -173,6 +173,52 @@ class SMSCode(StringField): return super().__call__(type='tel', pattern='[0-9]*', **kwargs) +class ForgivingIntegerField(StringField): + + POSTGRES_MAX_INT = 2147483647 + + def process_formdata(self, valuelist): + + if valuelist: + + valuelist[0] = valuelist[0].replace(',', '') + + try: + valuelist[0] = int(valuelist[0]) + except ValueError: + pass + + if valuelist[0] == '': + valuelist[0] = 0 + + return super().process_formdata(valuelist) + + def pre_validate(self, form): + + if self.data: + error = None + try: + if int(self.data) > self.POSTGRES_MAX_INT: + error = 'Must be less than {:,.0f}'.format(self.POSTGRES_MAX_INT) + except ValueError: + error = 'Must be a whole number' + + if error: + raise ValidationError(error) + + return super().pre_validate(form) + + def __call__(self, **kwargs): + + try: + value = int(self.data) + value = '{:,.0f}'.format(value) + except (ValueError, TypeError): + value = self.data if self.data is not None else '' + + return super().__call__(value=value, **kwargs) + + def organisation_type(): return RadioField( 'Who runs this service?', @@ -594,17 +640,15 @@ class Triage(StripWhitespaceForm): class EstimateUsageForm(StripWhitespaceForm): - volume_email = StringField( + + volume_email = ForgivingIntegerField( 'How many emails do you expect to send in the next year?', - validators=[DataRequired(message='Can’t be empty')] ) - volume_sms = StringField( + volume_sms = ForgivingIntegerField( 'How many text messages do you expect to send in the next year?', - validators=[DataRequired(message='Can’t be empty')] ) - volume_letter = StringField( + volume_letter = ForgivingIntegerField( 'How many letters do you expect to send in the next year?', - validators=[DataRequired(message='Can’t be empty')] ) consent_to_research = RadioField( 'Can we contact you when we’re doing user research?', @@ -615,6 +659,16 @@ class EstimateUsageForm(StripWhitespaceForm): validators=[DataRequired()] ) + at_least_one_volume_filled = True + + def validate(self, *args, **kwargs): + + if self.volume_email.data == self.volume_sms.data == self.volume_letter.data == 0: + self.at_least_one_volume_filled = False + return False + + return super().validate(*args, **kwargs) + class ProviderForm(StripWhitespaceForm): priority = IntegerField('Priority', [validators.NumberRange(min=1, max=100, message="Must be between 1 and 100")]) diff --git a/app/templates/views/service-settings/estimate-usage.html b/app/templates/views/service-settings/estimate-usage.html index f2eb74a99..c22b7142f 100644 --- a/app/templates/views/service-settings/estimate-usage.html +++ b/app/templates/views/service-settings/estimate-usage.html @@ -1,4 +1,5 @@ {% extends "withnav_template.html" %} +{% from "components/banner.html" import banner_wrapper %} {% from "components/form.html" import form_wrapper %} {% from "components/page-footer.html" import page_footer %} {% from "components/radios.html" import radios %} @@ -11,8 +12,17 @@ {% block maincolumn_content %}
- {% call form_wrapper() %} + {% if not form.at_least_one_volume_filled %} + {% call banner_wrapper(type='dangerous') %} +

+ no things supplied +

+

Tell us some things

+ {% endcall %} + {% else %}

Estimate usage

+ {% endif %} + {% call form_wrapper() %}
{{ textbox(form.volume_email, width='1-2', hint='For example, 1,000,000') }} {{ textbox(form.volume_sms, width='1-2', hint='For example, 500,000') }} diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index 116d3a4ba..1eb68e16a 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -833,7 +833,7 @@ def test_non_gov_user_is_told_they_cant_go_live( ), ( (('email', 1234), ('sms', 0), ('letter', 999)), - ('1234', '0', '999'), + ('1,234', '0', '999'), ), )) def test_should_show_estimate_volumes( @@ -890,9 +890,9 @@ def test_should_show_persist_estimated_volumes( 'main.estimate_usage', service_id=SERVICE_ONE_ID, _data={ - 'volume_email': '1234', - 'volume_sms': '0', - 'volume_letter': '9876', + 'volume_email': '1,234,567', + 'volume_sms': '', + 'volume_letter': '098', 'consent_to_research': consent_to_research, }, _expected_status=302, @@ -904,9 +904,9 @@ def test_should_show_persist_estimated_volumes( ) mock_update_service.assert_called_once_with( SERVICE_ONE_ID, - volume_email='1234', - volume_sms='0', - volume_letter='9876', + volume_email=1234567, + volume_sms=0, + volume_letter=98, consent_to_research=expected_persisted_consent_to_research, ) @@ -914,15 +914,15 @@ def test_should_show_persist_estimated_volumes( @pytest.mark.parametrize('data, error_selector, expected_error_message', ( ( { - 'volume_email': '', - 'volume_sms': '0', + 'volume_email': '1234', + 'volume_sms': '2147483648', 'volume_letter': '9876', 'consent_to_research': 'yes', }, - 'label[for=volume_email]', + 'label[for=volume_sms]', ( - 'How many emails do you expect to send in the next year? For example, 1,000,000 ' - 'Can’t be empty' + 'How many text messages do you expect to send in the next year? For example, 500,000 ' + 'Must be less than 2,147,483,647' ) ), ( @@ -949,8 +949,28 @@ def test_should_error_if_bad_estimations_given( _data=data, _expected_status=200, ) - assert normalize_spaces(page.select_one(error_selector).text) == ( - expected_error_message + assert normalize_spaces(page.select_one(error_selector).text) == expected_error_message + assert mock_update_service.called is False + + +def test_should_error_if_all_volumes_zero( + client_request, + mock_update_service, +): + page = client_request.post( + 'main.estimate_usage', + service_id=SERVICE_ONE_ID, + _data={ + 'volume_email': '', + 'volume_sms': '0', + 'volume_letter': '0,000', + 'consent_to_research': 'yes', + }, + _expected_status=200, + ) + assert normalize_spaces(page.select_one('.banner-dangerous').text) == ( + 'no things supplied ' + 'Tell us some things' ) assert mock_update_service.called is False