diff --git a/core/validators.py b/core/validators.py index ba26e665b5..ba7e246c35 100644 --- a/core/validators.py +++ b/core/validators.py @@ -4,11 +4,14 @@ from ukpostcodeutils import validation from core.helpers import clam_av_client +from regex import PHONE_NUMBER_REGEX + +PHONE_INVALID_MESSAGE = 'Enter a valid UK telephone number' def is_valid_uk_postcode(value): if not validation.is_valid_postcode(value.replace(' ', '').upper()): - raise ValidationError(_('Please enter a UK postcode')) + raise ValidationError(_('Enter a valid UK postcode')) def validate_file_infection(file): @@ -22,3 +25,10 @@ def validate_file_infection(file): raise ValidationError('Rejected: uploaded file did not pass security scan') file.seek(0) + + +def is_valid_uk_phone_number(phone_number): + if not PHONE_NUMBER_REGEX.match(phone_number): + raise ValidationError(_(PHONE_INVALID_MESSAGE)) + else: + return diff --git a/export_academy/forms.py b/export_academy/forms.py index 1b212b8134..6a23b15597 100644 --- a/export_academy/forms.py +++ b/export_academy/forms.py @@ -4,7 +4,6 @@ DateTimeField, HiddenInput, PasswordInput, - ValidationError, widgets as django_widgets, ) from django.forms.widgets import ChoiceWidget @@ -14,9 +13,8 @@ from wagtail.admin.forms import WagtailAdminModelForm from contact import constants -from core.validators import is_valid_uk_postcode +from core.validators import is_valid_uk_phone_number, is_valid_uk_postcode from directory_constants.choices import COUNTRY_CHOICES -from regex import PHONE_NUMBER_REGEX COUNTRIES = COUNTRY_CHOICES.copy() COUNTRIES.insert(0, ('', 'Select a country')) @@ -39,7 +37,8 @@ def to_python(self, value): return super().to_python(value) -PHONE_ERROR_MESSAGE = 'Please enter a valid UK phone number' +PHONE_REQUIRED_MESSAGE = 'Enter your telephone number' +PHONE_INVALID_MESSAGE = 'Enter a valid UK telephone number' class PersonalDetails(forms.Form): @@ -48,7 +47,7 @@ class PersonalDetails(forms.Form): min_length=2, max_length=50, error_messages={ - 'required': _('Enter your name'), + 'required': _('Enter your first name'), }, widget=django_widgets.TextInput(attrs={'class': 'govuk-input great-text-input'}), ) @@ -57,20 +56,17 @@ class PersonalDetails(forms.Form): min_length=2, max_length=50, error_messages={ - 'required': _('Enter your family name'), + 'required': _('Enter your last name'), }, widget=django_widgets.TextInput(attrs={'class': 'govuk-input great-text-input'}), ) phone_number = forms.CharField( label='UK telephone number', - min_length=8, - max_length=16, help_text='This can be a landline or mobile number', + validators=[is_valid_uk_phone_number], error_messages={ - 'max_length': PHONE_ERROR_MESSAGE, - 'min_length': PHONE_ERROR_MESSAGE, - 'invalid': PHONE_ERROR_MESSAGE, - 'required': PHONE_ERROR_MESSAGE, + 'invalid': PHONE_INVALID_MESSAGE, + 'required': PHONE_REQUIRED_MESSAGE, }, widget=django_widgets.TextInput(attrs={'class': 'govuk-input great-text-input'}), ) @@ -83,14 +79,6 @@ class PersonalDetails(forms.Form): widget=django_widgets.TextInput(attrs={'class': 'govuk-input great-text-input'}), ) - def clean_phone_number(self): - phone_number = self.cleaned_data['phone_number'].replace(' ', '') - if phone_number == '': - return phone_number - if not PHONE_NUMBER_REGEX.match(phone_number): - raise ValidationError(PHONE_ERROR_MESSAGE) - return phone_number - @property def serialized_data(self): data = super().serialized_data @@ -113,14 +101,14 @@ class ExportExperience(forms.Form): ('I do not have a product for export', 'I do not have a product for export'), ), widget=forms.RadioSelect(attrs={'id': 'hiring-select'}), - error_messages={'required': _('Please answer this question')}, + error_messages={'required': _('Choose one option about your export experience')}, ) sector = forms.ChoiceField( label='What is your sector?', help_text='Select at least one sector that applies to you', choices=constants.INDUSTRY_CHOICES, - error_messages={'required': _('Please answer this question')}, + error_messages={'required': _('Choose a sector')}, widget=django_widgets.Select(attrs={'class': 'govuk-select great-select'}), ) @@ -128,7 +116,6 @@ class ExportExperience(forms.Form): label='', help_text='Select an additional sector (optional)', choices=constants.INDUSTRY_CHOICES, - error_messages={'required': _('Please answer this question')}, required=False, widget=django_widgets.Select(attrs={'class': 'govuk-select great-select'}), ) @@ -137,7 +124,6 @@ class ExportExperience(forms.Form): label='', help_text='Select an additional sector (optional)', choices=constants.INDUSTRY_CHOICES, - error_messages={'required': _('Please answer this question')}, required=False, widget=django_widgets.Select(attrs={'class': 'govuk-select great-select'}), ) @@ -151,7 +137,7 @@ class ExportExperience(forms.Form): ("I don't know", "I don't know"), ), widget=forms.RadioSelect, - error_messages={'required': _('Please answer this question')}, + error_messages={'required': _('Choose one option about what you export')}, ) @property @@ -180,7 +166,7 @@ class BusinessDetails(forms.Form): business_postcode = forms.CharField( label='Business unit postcode', max_length=8, - error_messages={'required': 'Enter your business postcode', 'invalid': 'Please enter a UK postcode'}, + error_messages={'required': 'Enter your business postcode', 'invalid': 'Enter a valid UK postcode'}, validators=[is_valid_uk_postcode], widget=django_widgets.TextInput(attrs={'class': 'govuk-input great-text-input govuk-!-width-one-half'}), ) @@ -196,7 +182,7 @@ class BusinessDetails(forms.Form): ("I'd prefer not to say", "I'd prefer not to say"), ), widget=forms.RadioSelect, - error_messages={'required': _('Please answer this question')}, + error_messages={'required': _('Enter a turnover amount')}, ) employee_count = forms.ChoiceField( @@ -209,7 +195,7 @@ class BusinessDetails(forms.Form): ('prefer not to say', "I'd prefer not to say"), ), widget=forms.RadioSelect, - error_messages={'required': _('Please answer this question')}, + error_messages={'required': _('Choose number of employees')}, ) @property @@ -220,9 +206,9 @@ def serialized_data(self): class MarketingSources(forms.Form): marketing_sources = forms.ChoiceField( - label=_('How did you hear about the Export Academy?'), + label='', choices=constants.MARKETING_SOURCES_CHOICES, - error_messages={'required': _('Please answer this question')}, + error_messages={'required': _('Tell us how you heard about the UK Export Academy')}, widget=django_widgets.Select(attrs={'class': 'govuk-select great-select'}), ) diff --git a/export_academy/templates/export_academy/registration_form_confirm.html b/export_academy/templates/export_academy/registration_form_confirm.html index 5e397539f1..ca1aa2cdb9 100755 --- a/export_academy/templates/export_academy/registration_form_confirm.html +++ b/export_academy/templates/export_academy/registration_form_confirm.html @@ -149,17 +149,17 @@

About your business

-

And finally...

+

How did you hear about the UK Export Academy?

- ChangeFinally + ChangeHow did you hear about the UK Export Academy?
-
How you heard of us
+
Tell us how you heard about the UK Export Academy
{{ form_data.marketing_sources }}
diff --git a/export_academy/views.py b/export_academy/views.py index 4b78953532..74195e4f51 100644 --- a/export_academy/views.py +++ b/export_academy/views.py @@ -352,8 +352,8 @@ def get_context_data(self, **kwargs): back_url=back_url, step_text='Step 4 of 4', landing_page=ExportAcademyHomePage.objects.first(), - title='And finally...', - current_page_breadcrumb='And finally...', + title='How did you hear about the UK Export Academy?', + current_page_breadcrumb='How did you hear about the UK Export Academy?', ) def get_success_url(self): diff --git a/requirements.txt b/requirements.txt index d567f72abf..a04ff49555 100644 --- a/requirements.txt +++ b/requirements.txt @@ -51,7 +51,7 @@ celery[redis]==5.2.7 # via # -r requirements.in # django-celery-beat -certifi==2023.11.17 +certifi==2024.2.2 # via # elastic-apm # elasticsearch diff --git a/requirements_test.txt b/requirements_test.txt index 2d1d2c7967..e9f16c70ff 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -80,7 +80,7 @@ celery[redis]==5.2.7 # via # -r requirements.in # django-celery-beat -certifi==2023.11.17 +certifi==2024.2.2 # via # elastic-apm # elasticsearch @@ -580,7 +580,7 @@ pytest-cov==4.1.0 # pytest-codecov pytest-django==4.8.0 # via -r requirements_test.in -pytest-sugar==0.9.7 +pytest-sugar==1.0.0 # via -r requirements_test.in pytest-xdist==3.5.0 # via -r requirements_test.in diff --git a/tests/unit/core/test_validators.py b/tests/unit/core/test_validators.py index e5722db76c..0da597c369 100644 --- a/tests/unit/core/test_validators.py +++ b/tests/unit/core/test_validators.py @@ -4,7 +4,11 @@ from django.forms import ValidationError from django.test import override_settings -from core.validators import is_valid_uk_postcode, validate_file_infection +from core.validators import ( + is_valid_uk_phone_number, + is_valid_uk_postcode, + validate_file_infection, +) from tests.helpers import create_response @@ -55,3 +59,21 @@ def test_validate_file_infection_negative_scan(mock_clam_av_client_scan): pytest.fail('Should not raise a validator error.') assert file.seek.call_count == 1 + + +@pytest.mark.parametrize( + 'phone_number, raise_expected', + ( + ('07508236677', False), + ('90201', True), + ('phone_number', True), + ), +) +def test_is_valid_uk_phone_number(phone_number, raise_expected): + try: + is_valid_uk_phone_number(phone_number) + if raise_expected: + assert False, f'Excepted {phone_number} to fail validation. It did not' + except ValidationError: + if not raise_expected: + assert False, f'Excepted {phone_number} to pass validation. It did not' diff --git a/tests/unit/export_academy/test_forms.py b/tests/unit/export_academy/test_forms.py index 1713090b58..ef4acb2b4f 100644 --- a/tests/unit/export_academy/test_forms.py +++ b/tests/unit/export_academy/test_forms.py @@ -37,9 +37,9 @@ }, ), { - 'first_name': 'Enter your name', - 'phone_number': 'Please enter a valid UK phone number', - 'last_name': 'Enter your family name', + 'first_name': 'Enter your first name', + 'phone_number': 'Enter your telephone number', + 'last_name': 'Enter your last name', 'job_title': 'Enter your job title', }, ), @@ -59,9 +59,9 @@ }, ), { - 'export_experience': 'Please answer this question', - 'sector': 'Please answer this question', - 'export_product': 'Please answer this question', + 'export_experience': 'Choose one option about your export experience', + 'sector': 'Choose a sector', + 'export_product': 'Choose one option about what you export', }, ), ( @@ -87,8 +87,8 @@ 'business_name': 'Enter your business name', 'business_address_line_1': 'Enter the first line of your business address', 'business_postcode': 'Enter your business postcode', - 'annual_turnover': 'Please answer this question', - 'employee_count': 'Please answer this question', + 'annual_turnover': 'Enter a turnover amount', + 'employee_count': 'Choose number of employees', }, ), ( @@ -103,7 +103,7 @@ }, ), { - 'marketing_sources': 'Please answer this question', + 'marketing_sources': 'Tell us how you heard about the UK Export Academy', }, ), ( diff --git a/tests/unit/export_academy/test_views.py b/tests/unit/export_academy/test_views.py index cd68789c5b..bac56fec91 100644 --- a/tests/unit/export_academy/test_views.py +++ b/tests/unit/export_academy/test_views.py @@ -270,10 +270,10 @@ def test_booking_success_view( }, reverse('export_academy:registration-experience'), { - 'first_name': 'Enter your name', - 'last_name': 'Enter your family name', + 'first_name': 'Enter your first name', + 'last_name': 'Enter your last name', 'job_title': 'Enter your job title', - 'phone_number': 'Please enter a valid UK phone number', + 'phone_number': 'Enter your telephone number', }, ), ( @@ -285,9 +285,9 @@ def test_booking_success_view( }, reverse('export_academy:registration-business'), { - 'export_experience': 'Please answer this question', - 'sector': 'Please answer this question', - 'export_product': 'Please answer this question', + 'export_experience': 'Choose one option about your export experience', + 'sector': 'Choose a sector', + 'export_product': 'Choose one option about what you export', }, ), ( @@ -304,8 +304,8 @@ def test_booking_success_view( 'business_name': 'Enter your business name', 'business_address_line_1': 'Enter the first line of your business address', 'business_postcode': 'Enter your business postcode', - 'annual_turnover': 'Please answer this question', - 'employee_count': 'Please answer this question', + 'annual_turnover': 'Enter a turnover amount', + 'employee_count': 'Choose number of employees', }, ), ( @@ -315,7 +315,7 @@ def test_booking_success_view( }, reverse('export_academy:registration-confirm'), { - 'marketing_sources': 'Please answer this question', + 'marketing_sources': 'Tell us how you heard about the UK Export Academy', }, ), ),