From cf8c8b325e48a4ddc74080e369368ab9a72c1f9d Mon Sep 17 00:00:00 2001 From: Michael Lockwood Date: Mon, 23 Dec 2024 12:15:23 +0000 Subject: [PATCH] ECIL-342 CPTPP country group, banner for CFS apps and submit validation --- pii-ner-exclude.txt | 6 + web/domains/case/export/forms.py | 28 + web/domains/case/export/views.py | 15 +- web/domains/country/managers.py | 3 + web/domains/country/types.py | 1 + web/domains/country/utils.py | 26 + .../commands/fixtures/country_groups.json | 2669 +++++++++-------- .../0050_alter_countrygroup_name.py | 47 + web/static/web/js/pages/cfs-schedule-edit.js | 55 +- .../web/domains/case/export/cfs-edit.html | 8 +- .../cfs/edit-schedule-form-content.html | 12 + web/tests/domains/case/export/test_forms.py | 20 +- web/tests/domains/country/test_utils.py | 16 + 13 files changed, 1562 insertions(+), 1344 deletions(-) create mode 100644 web/domains/country/utils.py create mode 100644 web/migrations/0050_alter_countrygroup_name.py create mode 100644 web/tests/domains/country/test_utils.py diff --git a/pii-ner-exclude.txt b/pii-ner-exclude.txt index 3d380e48e..84921174c 100644 --- a/pii-ner-exclude.txt +++ b/pii-ner-exclude.txt @@ -5214,3 +5214,9 @@ eml gif jpeg jpg +CPTPP +Progressive Agreement for Trans-Pacific Partnership +Comprehensive and Progressive Agreement for Trans-Pacific Partnership +checkIsEUCosmeticsRegulation(legislations +Trans-Pacific Partnership +CPTTP diff --git a/web/domains/case/export/forms.py b/web/domains/case/export/forms.py index aa91ed1d1..78565fe60 100644 --- a/web/domains/case/export/forms.py +++ b/web/domains/case/export/forms.py @@ -14,6 +14,10 @@ import web.forms.widgets as icms_widgets from web.domains.case.forms import application_contacts +from web.domains.country.utils import ( + get_cptpp_countries_list, + get_selected_cptpp_countries, +) from web.domains.file.utils import ICMSFileField from web.forms.mixins import OptionalFormMixin from web.forms.widgets import ICMSModelSelect2Widget @@ -353,6 +357,30 @@ class SubmitCFSForm(EditCFSFormBase): All fields are fully validated to ensure form is correct. """ + def clean(self) -> dict[str, Any]: + cleaned_data: dict[str, Any] = super().clean() + + # Check that cosmetics aren't being exported to countries within the CPTPP + # This may want to be moved to the schedule level rather than the application level + has_cosmetics = self.instance.schedules.filter( + legislations__is_eu_cosmetics_regulation=True + ).exists() + + cptpp_selected = get_selected_cptpp_countries(cleaned_data["countries"]) + + if has_cosmetics and cptpp_selected.exists(): + cptpp_countries_list = get_cptpp_countries_list() + self.add_error( + "countries", + ( + f"This application is not necessary. A Certificate of Free Sale (CFS) for cosmetic " + f"products is no longer required for {cptpp_countries_list} due to the UK’s accession to " + f"the Comprehensive and Progressive Agreement for Trans-Pacific Partnership (CPTPP)." + ), + ) + + return cleaned_data + class CFSScheduleFormBase(forms.ModelForm): class Meta: diff --git a/web/domains/case/export/views.py b/web/domains/case/export/views.py index 0e3d88fae..da4ed248d 100644 --- a/web/domains/case/export/views.py +++ b/web/domains/case/export/views.py @@ -1,5 +1,6 @@ from typing import NamedTuple +from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.mixins import PermissionRequiredMixin @@ -26,6 +27,10 @@ view_application_file, ) from web.domains.cat.utils import template_in_user_templates +from web.domains.country.utils import ( + get_cptpp_countries_list, + get_selected_cptpp_countries_list, +) from web.domains.file.utils import create_file_model from web.flow.models import ProcessTypes from web.models import ( @@ -362,6 +367,7 @@ def edit_cfs(request: AuthenticatedHttpRequest, *, application_pk: int) -> HttpR "form": form, "schedules": schedules, "case_type": "export", + "cptpp_countries_list": get_cptpp_countries_list(), } return render(request, "web/domains/case/export/cfs-edit.html", context) @@ -426,13 +432,14 @@ def cfs_edit_schedule( else: form = EditCFSScheduleForm(**form_kwargs) - schedule_legislations = schedule.legislations.filter(is_active=True) - show_schedule_statements_is_responsible_person = ( get_show_schedule_statements_is_responsible_person(schedule) ) + schedule_legislations = schedule.legislations.filter(is_active=True) + has_cosmetics = schedule_legislations.filter(is_eu_cosmetics_regulation=True).exists() legislation_config = get_csf_schedule_legislation_config() + cptpp_countries_list = get_selected_cptpp_countries_list(application.countries.all()) context = { "page_title": "Edit Schedule", @@ -460,6 +467,9 @@ def cfs_edit_schedule( "export:cfs-schedule-manage-products", kwargs={"application_pk": application.pk, "schedule_pk": schedule.pk}, ), + "show_cptpp_warning": has_cosmetics and cptpp_countries_list, + "cptpp_countries_list": cptpp_countries_list, + "ilb_contact_email": settings.ILB_CONTACT_EMAIL, } return render(request, "web/domains/case/export/cfs-edit-schedule.html", context) @@ -845,6 +855,7 @@ def _get_cfs_errors(application: CertificateOfFreeSaleApplication) -> Applicatio # Check that the schedule has products if legislation has been set schedule_legislations = schedule.legislations.filter(is_active=True) + if schedule_legislations.exists() and not schedule.products.exists(): product_page_errors = PageErrors( page_name=f"Schedule {idx} - Product", diff --git a/web/domains/country/managers.py b/web/domains/country/managers.py index 3afbb31f4..b8bc8711a 100644 --- a/web/domains/country/managers.py +++ b/web/domains/country/managers.py @@ -169,3 +169,6 @@ def get_eu_countries(self) -> QuerySet["Country"]: def get_non_eu_countries(self) -> QuerySet["Country"]: return self._get_country_group_countries(CountryGroupName.NON_EU) + + def get_cptpp_countries(self) -> QuerySet["Country"]: + return self._get_country_group_countries(CountryGroupName.CPTPP) diff --git a/web/domains/country/types.py b/web/domains/country/types.py index ea2cecb4a..e73574866 100644 --- a/web/domains/country/types.py +++ b/web/domains/country/types.py @@ -29,6 +29,7 @@ class CountryGroupName(TypedTextChoices): # EU = "EU", "All EU countries" NON_EU = "NON_EU", "Non EU Single Countries" + CPTPP = "CPTPP", "Comprehensive and Progressive Agreement for Trans-Pacific Partnership" # # Inactive Import Applications diff --git a/web/domains/country/utils.py b/web/domains/country/utils.py new file mode 100644 index 000000000..320ef0a5c --- /dev/null +++ b/web/domains/country/utils.py @@ -0,0 +1,26 @@ +from django.db.models import QuerySet + +from .models import Country + + +def comma_separator(sequence: list) -> str: + if not sequence: + return "" + if len(sequence) == 1: + return sequence[0] + return "{} and {}".format(", ".join(sequence[:-1]), sequence[-1]) + + +def get_cptpp_countries_list() -> str: + cptpp = Country.util.get_cptpp_countries().values_list("name", flat=True) + return comma_separator(list(cptpp)) + + +def get_selected_cptpp_countries(countries: QuerySet["Country"]) -> QuerySet["Country"]: + country_pks = countries.values_list("pk", flat=True) + return Country.util.get_cptpp_countries().filter(pk__in=country_pks) + + +def get_selected_cptpp_countries_list(countries: QuerySet["Country"]) -> str: + selected_countries = get_selected_cptpp_countries(countries) + return comma_separator(list(selected_countries.values_list("name", flat=True))) diff --git a/web/management/commands/fixtures/country_groups.json b/web/management/commands/fixtures/country_groups.json index 526edcb82..44cea95b3 100644 --- a/web/management/commands/fixtures/country_groups.json +++ b/web/management/commands/fixtures/country_groups.json @@ -1,1327 +1,1346 @@ [ -{ - "model": "web.countrygroup", - "pk": 1, - "fields": { - "name": "CFS", - "comments": "Added Maldives 22/11/16\nAdded Zambia 14/03/2017\nAdded Aruba 10/05/2017\nAdded Mali 21/09/2018\nAdded Rwanda 27/09/18\nAdded Uganda 26/02/19\n", - "countries": [ - 1, - 2, - 3, - 4, - 7, - 8, - 176, - 11, - 12, - 13, - 14, - 15, - 16, - 169, - 167, - 18, - 19, - 160, - 20, - 21, - 22, - 23, - 24, - 26, - 27, - 28, - 29, - 30, - 31, - 33, - 34, - 162, - 35, - 37, - 40, - 41, - 42, - 43, - 163, - 44, - 46, - 47, - 48, - 51, - 159, - 52, - 54, - 57, - 58, - 60, - 170, - 61, - 62, - 63, - 66, - 67, - 68, - 69, - 71, - 73, - 74, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83, - 84, - 86, - 173, - 87, - 91, - 92, - 93, - 94, - 174, - 178, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 164, - 110, - 165, - 112, - 113, - 114, - 161, - 115, - 116, - 119, - 120, - 122, - 179, - 123, - 124, - 171, - 125, - 172, - 126, - 128, - 129, - 130, - 132, - 166, - 168, - 133, - 135, - 136, - 137, - 138, - 139, - 140, - 141, - 142, - 143, - 144, - 180, - 146, - 147, - 149, - 145, - 150, - 151, - 152, - 153, - 175, - 154 - ] + { + "model": "web.countrygroup", + "pk": 1, + "fields": { + "name": "CFS", + "comments": "Added Maldives 22/11/16\nAdded Zambia 14/03/2017\nAdded Aruba 10/05/2017\nAdded Mali 21/09/2018\nAdded Rwanda 27/09/18\nAdded Uganda 26/02/19\n", + "countries": [ + 1, + 2, + 3, + 4, + 7, + 8, + 176, + 11, + 12, + 13, + 14, + 15, + 16, + 169, + 167, + 18, + 19, + 160, + 20, + 21, + 22, + 23, + 24, + 26, + 27, + 28, + 29, + 30, + 31, + 33, + 34, + 162, + 35, + 37, + 40, + 41, + 42, + 43, + 163, + 44, + 46, + 47, + 48, + 51, + 159, + 52, + 54, + 57, + 58, + 60, + 170, + 61, + 62, + 63, + 66, + 67, + 68, + 69, + 71, + 73, + 74, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 86, + 173, + 87, + 91, + 92, + 93, + 94, + 174, + 178, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 164, + 110, + 165, + 112, + 113, + 114, + 161, + 115, + 116, + 119, + 120, + 122, + 179, + 123, + 124, + 171, + 125, + 172, + 126, + 128, + 129, + 130, + 132, + 166, + 168, + 133, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 180, + 146, + 147, + 149, + 145, + 150, + 151, + 152, + 153, + 175, + 154 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 2, + "fields": { + "name": "CFS_COM", + "comments": "", + "countries": [ + 1, + 2, + 3, + 4, + 7, + 8, + 176, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 169, + 167, + 18, + 19, + 160, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 33, + 34, + 162, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 163, + 44, + 45, + 46, + 158, + 47, + 48, + 49, + 50, + 51, + 159, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 170, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 173, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 174, + 178, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 164, + 110, + 111, + 165, + 112, + 113, + 114, + 177, + 161, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 179, + 123, + 124, + 171, + 125, + 172, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 166, + 168, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 156, + 157, + 141, + 142, + 143, + 144, + 180, + 146, + 147, + 148, + 149, + 145, + 150, + 151, + 152, + 153, + 175, + 154 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 3, + "fields": { + "name": "COM", + "comments": "", + "countries": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 11, + 12, + 13, + 14, + 15, + 16, + 167, + 18, + 19, + 160, + 20, + 21, + 22, + 23, + 24, + 26, + 27, + 28, + 29, + 30, + 31, + 33, + 34, + 162, + 35, + 37, + 40, + 41, + 42, + 43, + 163, + 44, + 46, + 47, + 48, + 51, + 159, + 52, + 54, + 55, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 65, + 66, + 67, + 68, + 69, + 71, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 86, + 87, + 88, + 91, + 92, + 93, + 94, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 109, + 164, + 110, + 111, + 165, + 112, + 113, + 114, + 161, + 115, + 116, + 119, + 120, + 122, + 123, + 124, + 125, + 126, + 128, + 129, + 130, + 132, + 133, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 146, + 147, + 149, + 145, + 150, + 151, + 152, + 153, + 154 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 4, + "fields": { + "name": "DEROGATION_COO", + "comments": "", + "countries": [ + 68, + 122, + 129, + 136 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 5, + "fields": { + "name": "FA_DFL_IC", + "comments": "", + "countries": [ + 10, + 17, + 25, + 36, + 38, + 39, + 45, + 49, + 50, + 53, + 56, + 64, + 70, + 72, + 85, + 89, + 90, + 95, + 108, + 117, + 118, + 121, + 127, + 131, + 134, + 156, + 157, + 148 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 6, + "fields": { + "name": "FA_OIL_COC", + "comments": "", + "countries": [ + 5 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 7, + "fields": { + "name": "FA_OIL_COO", + "comments": "", + "countries": [ + 5 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 8, + "fields": { + "name": "FA_SIL_COC", + "comments": "Removed 'any EU country' 29/08/19\nPotential for breach of sanctions - removed Any Country and Any non-EU Country. 14/12/15\nSanctions - Removed Iran,North Korea,Libya and Syria.\nRemoved UK.\nRemoved Russian Federation. 01/08/14\nAdded Bolivia,Costa Rica,El Salvador,Nicaragua,Occupied Palestinian Territories,Paraguay - 28/04/15", + "countries": [ + 1, + 2, + 3, + 4, + 5, + 32, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 160, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 33, + 34, + 162, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 163, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 159, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 164, + 110, + 111, + 165, + 112, + 113, + 114, + 161, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 137, + 138, + 139, + 140, + 156, + 157, + 141, + 142, + 143, + 144, + 146, + 147, + 149, + 145, + 150, + 151, + 152, + 153, + 154 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 9, + "fields": { + "name": "FA_SIL_COO", + "comments": "Removed 'any EU country' 29/08/19\nPotential for breach of sanctions - removed Any Country and Any non-EU Country. 15/12/15\nSanctions - Removed Iran,North Korea,Libya and Syria.\nRemoved Russian Federation 01/08/14.\nAdded Bolivia,Costa Rica,El Salvador,Nicaragua,Occupied Palestinian Territories,Paraguay - 28/04/15\n", + "countries": [ + 1, + 2, + 3, + 4, + 5, + 32, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 160, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 33, + 34, + 162, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 163, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 159, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 164, + 110, + 111, + 165, + 112, + 113, + 114, + 161, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 137, + 138, + 139, + 140, + 156, + 157, + 141, + 142, + 143, + 144, + 146, + 147, + 148, + 149, + 145, + 150, + 151, + 152, + 153, + 154 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 10, + "fields": { + "name": "GMP", + "comments": "", + "countries": [ + 30 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 11, + "fields": { + "name": "IRON_COO", + "comments": "", + "countries": [ + 77 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 12, + "fields": { + "name": "NON_EU", + "comments": "", + "countries": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 11, + 12, + 13, + 14, + 15, + 16, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 26, + 27, + 28, + 29, + 30, + 31, + 33, + 34, + 35, + 37, + 40, + 41, + 42, + 43, + 44, + 46, + 47, + 48, + 51, + 52, + 54, + 55, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 65, + 66, + 67, + 68, + 69, + 71, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 86, + 87, + 88, + 91, + 92, + 93, + 94, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 109, + 110, + 111, + 112, + 113, + 114, + 177, + 115, + 116, + 119, + 120, + 122, + 123, + 124, + 125, + 126, + 128, + 129, + 130, + 132, + 133, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 146, + 147, + 149, + 145, + 150, + 151, + 152, + 153, + 154 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 13, + "fields": { + "name": "OPT_COO", + "comments": "", + "countries": [ + 16 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 14, + "fields": { + "name": "OPT_TEMP_EXPORT_COO", + "comments": "", + "countries": [ + 32 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 15, + "fields": { + "name": "SANCTIONS", + "comments": "", + "countries": [ + 16, + 68, + 79, + 87, + 122, + 129, + 136 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 16, + "fields": { + "name": "TEXTILES_COO", + "comments": "Belarus removed 03/07/17", + "countries": [ + 16, + 79 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 17, + "fields": { + "name": "WOOD_COO", + "comments": "", + "countries": [ + 122 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 18, + "fields": { + "name": "EU", + "comments": "All EU countries", + "countries": [ + 32, + 10, + 17, + 25, + 36, + 38, + 39, + 45, + 49, + 50, + 53, + 56, + 64, + 70, + 72, + 85, + 89, + 90, + 95, + 108, + 117, + 118, + 121, + 127, + 131, + 134, + 156, + 157 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 19, + "fields": { + "name": "SANCTIONS_COC_COO", + "comments": "", + "countries": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 169, + 167, + 18, + 19, + 160, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 33, + 34, + 162, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 163, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 170, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 174, + 95, + 96, + 97, + 98, + 99, + 100, + 182, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 164, + 110, + 111, + 165, + 112, + 113, + 114, + 177, + 161, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 179, + 123, + 124, + 171, + 125, + 172, + 126, + 127, + 129, + 130, + 131, + 132, + 166, + 168, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 156, + 157, + 141, + 142, + 143, + 144, + 180, + 146, + 147, + 148, + 149, + 145, + 150, + 151, + 152, + 153, + 175, + 154 + ] + } + }, + { + "model": "web.countrygroup", + "pk": 20, + "fields": { + "name": "CPTPP", + "comments": "All CPTPP countries", + "countries": [ + 9, + 24, + 29, + 74, + 94, + 109, + 115, + 126, + 152 + ] + } } -}, -{ - "model": "web.countrygroup", - "pk": 2, - "fields": { - "name": "CFS_COM", - "comments": "", - "countries": [ - 1, - 2, - 3, - 4, - 7, - 8, - 176, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 169, - 167, - 18, - 19, - 160, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 33, - 34, - 162, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 163, - 44, - 45, - 46, - 158, - 47, - 48, - 49, - 50, - 51, - 159, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 170, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83, - 84, - 85, - 86, - 173, - 87, - 88, - 89, - 90, - 91, - 92, - 93, - 94, - 174, - 178, - 95, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 164, - 110, - 111, - 165, - 112, - 113, - 114, - 177, - 161, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 122, - 179, - 123, - 124, - 171, - 125, - 172, - 126, - 127, - 128, - 129, - 130, - 131, - 132, - 166, - 168, - 133, - 134, - 135, - 136, - 137, - 138, - 139, - 140, - 156, - 157, - 141, - 142, - 143, - 144, - 180, - 146, - 147, - 148, - 149, - 145, - 150, - 151, - 152, - 153, - 175, - 154 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 3, - "fields": { - "name": "COM", - "comments": "", - "countries": [ - 1, - 2, - 3, - 4, - 7, - 8, - 9, - 11, - 12, - 13, - 14, - 15, - 16, - 167, - 18, - 19, - 160, - 20, - 21, - 22, - 23, - 24, - 26, - 27, - 28, - 29, - 30, - 31, - 33, - 34, - 162, - 35, - 37, - 40, - 41, - 42, - 43, - 163, - 44, - 46, - 47, - 48, - 51, - 159, - 52, - 54, - 55, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 65, - 66, - 67, - 68, - 69, - 71, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83, - 84, - 86, - 87, - 88, - 91, - 92, - 93, - 94, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 109, - 164, - 110, - 111, - 165, - 112, - 113, - 114, - 161, - 115, - 116, - 119, - 120, - 122, - 123, - 124, - 125, - 126, - 128, - 129, - 130, - 132, - 133, - 135, - 136, - 137, - 138, - 139, - 140, - 141, - 142, - 143, - 144, - 146, - 147, - 149, - 145, - 150, - 151, - 152, - 153, - 154 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 4, - "fields": { - "name": "DEROGATION_COO", - "comments": "", - "countries": [ - 68, - 122, - 129, - 136 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 5, - "fields": { - "name": "FA_DFL_IC", - "comments": "", - "countries": [ - 10, - 17, - 25, - 36, - 38, - 39, - 45, - 49, - 50, - 53, - 56, - 64, - 70, - 72, - 85, - 89, - 90, - 95, - 108, - 117, - 118, - 121, - 127, - 131, - 134, - 156, - 157, - 148 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 6, - "fields": { - "name": "FA_OIL_COC", - "comments": "", - "countries": [ - 5 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 7, - "fields": { - "name": "FA_OIL_COO", - "comments": "", - "countries": [ - 5 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 8, - "fields": { - "name": "FA_SIL_COC", - "comments": "Removed 'any EU country' 29/08/19\nPotential for breach of sanctions - removed Any Country and Any non-EU Country. 14/12/15\nSanctions - Removed Iran,North Korea,Libya and Syria.\nRemoved UK.\nRemoved Russian Federation. 01/08/14\nAdded Bolivia,Costa Rica,El Salvador,Nicaragua,Occupied Palestinian Territories,Paraguay - 28/04/15", - "countries": [ - 1, - 2, - 3, - 4, - 5, - 32, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 160, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 33, - 34, - 162, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 163, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 159, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 80, - 81, - 82, - 83, - 84, - 85, - 86, - 88, - 89, - 90, - 91, - 92, - 93, - 94, - 95, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 164, - 110, - 111, - 165, - 112, - 113, - 114, - 161, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 123, - 124, - 125, - 126, - 127, - 128, - 129, - 130, - 131, - 132, - 133, - 134, - 135, - 137, - 138, - 139, - 140, - 156, - 157, - 141, - 142, - 143, - 144, - 146, - 147, - 149, - 145, - 150, - 151, - 152, - 153, - 154 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 9, - "fields": { - "name": "FA_SIL_COO", - "comments": "Removed 'any EU country' 29/08/19\nPotential for breach of sanctions - removed Any Country and Any non-EU Country. 15/12/15\nSanctions - Removed Iran,North Korea,Libya and Syria.\nRemoved Russian Federation 01/08/14.\nAdded Bolivia,Costa Rica,El Salvador,Nicaragua,Occupied Palestinian Territories,Paraguay - 28/04/15\n", - "countries": [ - 1, - 2, - 3, - 4, - 5, - 32, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 160, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 33, - 34, - 162, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 163, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 159, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 80, - 81, - 82, - 83, - 84, - 85, - 86, - 88, - 89, - 90, - 91, - 92, - 93, - 94, - 95, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 164, - 110, - 111, - 165, - 112, - 113, - 114, - 161, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 123, - 124, - 125, - 126, - 127, - 128, - 129, - 130, - 131, - 132, - 133, - 134, - 135, - 137, - 138, - 139, - 140, - 156, - 157, - 141, - 142, - 143, - 144, - 146, - 147, - 148, - 149, - 145, - 150, - 151, - 152, - 153, - 154 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 10, - "fields": { - "name": "GMP", - "comments": "", - "countries": [ - 30 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 11, - "fields": { - "name": "IRON_COO", - "comments": "", - "countries": [ - 77 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 12, - "fields": { - "name": "NON_EU", - "comments": "", - "countries": [ - 1, - 2, - 3, - 4, - 7, - 8, - 9, - 11, - 12, - 13, - 14, - 15, - 16, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 26, - 27, - 28, - 29, - 30, - 31, - 33, - 34, - 35, - 37, - 40, - 41, - 42, - 43, - 44, - 46, - 47, - 48, - 51, - 52, - 54, - 55, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 65, - 66, - 67, - 68, - 69, - 71, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83, - 84, - 86, - 87, - 88, - 91, - 92, - 93, - 94, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 109, - 110, - 111, - 112, - 113, - 114, - 177, - 115, - 116, - 119, - 120, - 122, - 123, - 124, - 125, - 126, - 128, - 129, - 130, - 132, - 133, - 135, - 136, - 137, - 138, - 139, - 140, - 141, - 142, - 143, - 144, - 146, - 147, - 149, - 145, - 150, - 151, - 152, - 153, - 154 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 13, - "fields": { - "name": "OPT_COO", - "comments": "", - "countries": [ - 16 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 14, - "fields": { - "name": "OPT_TEMP_EXPORT_COO", - "comments": "", - "countries": [ - 32 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 15, - "fields": { - "name": "SANCTIONS", - "comments": "", - "countries": [ - 16, - 68, - 79, - 87, - 122, - 129, - 136 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 16, - "fields": { - "name": "TEXTILES_COO", - "comments": "Belarus removed 03/07/17", - "countries": [ - 16, - 79 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 17, - "fields": { - "name": "WOOD_COO", - "comments": "", - "countries": [ - 122 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 18, - "fields": { - "name": "EU", - "comments": "All EU countries", - "countries": [ - 32, - 10, - 17, - 25, - 36, - 38, - 39, - 45, - 49, - 50, - 53, - 56, - 64, - 70, - 72, - 85, - 89, - 90, - 95, - 108, - 117, - 118, - 121, - 127, - 131, - 134, - 156, - 157 - ] - } -}, -{ - "model": "web.countrygroup", - "pk": 19, - "fields": { - "name": "SANCTIONS_COC_COO", - "comments": "", - "countries": [ - 1, - 2, - 3, - 4, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 169, - 167, - 18, - 19, - 160, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 33, - 34, - 162, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 163, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 170, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83, - 84, - 85, - 86, - 87, - 88, - 89, - 90, - 91, - 92, - 93, - 94, - 174, - 95, - 96, - 97, - 98, - 99, - 100, - 182, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 164, - 110, - 111, - 165, - 112, - 113, - 114, - 177, - 161, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 122, - 179, - 123, - 124, - 171, - 125, - 172, - 126, - 127, - 129, - 130, - 131, - 132, - 166, - 168, - 133, - 134, - 135, - 136, - 137, - 138, - 139, - 140, - 156, - 157, - 141, - 142, - 143, - 144, - 180, - 146, - 147, - 148, - 149, - 145, - 150, - 151, - 152, - 153, - 175, - 154 - ] - } -} -] +] \ No newline at end of file diff --git a/web/migrations/0050_alter_countrygroup_name.py b/web/migrations/0050_alter_countrygroup_name.py new file mode 100644 index 000000000..b96f2511b --- /dev/null +++ b/web/migrations/0050_alter_countrygroup_name.py @@ -0,0 +1,47 @@ +# Generated by Django 5.1.4 on 2024-12-20 09:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("web", "0049_file_clam_av_results"), + ] + + operations = [ + migrations.AlterField( + model_name="countrygroup", + name="name", + field=models.CharField( + choices=[ + ("CFS", "Certificate of Free Sale Countries"), + ("CFS_COM", "Certificate of Free Sale Country of Manufacture Countries"), + ("COM", "Certificate of Manufacture Countries"), + ("GMP", "Goods Manufacturing Practice Countries"), + ("FA_DFL_IC", "Firearms and Ammunition (Deactivated) Issuing Countries"), + ("FA_OIL_COC", "Firearms and Ammunition (OIL) COCs"), + ("FA_OIL_COO", "Firearms and Ammunition (OIL) COOs"), + ("FA_SIL_COC", "Firearms and Ammunition (SIL) COCs"), + ("FA_SIL_COO", "Firearms and Ammunition (SIL) COOs"), + ("SANCTIONS_COC_COO", "Adhoc application countries"), + ("SANCTIONS", "Sanctions and adhoc licence countries"), + ("WOOD_COO", "Wood (Quota) COOs"), + ("EU", "All EU countries"), + ("NON_EU", "Non EU Single Countries"), + ( + "CPTPP", + "Comprehensive and Progressive Agreement for Trans-Pacific Partnership", + ), + ("DEROGATION_COO", "Derogation from Sanctions COOs"), + ("IRON_COO", "Iron and Steel (Quota) COOs"), + ("OPT_COO", "OPT COOs"), + ("OPT_TEMP_EXPORT_COO", "OPT Temp Export COOs"), + ("TEXTILES_COO", "Textile COOs"), + ], + max_length=255, + unique=True, + verbose_name="Group Name", + ), + ), + ] diff --git a/web/static/web/js/pages/cfs-schedule-edit.js b/web/static/web/js/pages/cfs-schedule-edit.js index ce6a28f96..7763248a9 100644 --- a/web/static/web/js/pages/cfs-schedule-edit.js +++ b/web/static/web/js/pages/cfs-schedule-edit.js @@ -58,6 +58,7 @@ class EditScheduleEventHandler { const selectedLegislations = this.legislationSelect2.val(); const isExportOnly = getIsExportOnlyValue(); + updateCPTPPWarning(selectedLegislations, this.legislationConfig); updateIsResponsiblePerson(selectedLegislations, isExportOnly, this.legislationConfig); showIsBiocidalClaim(selectedLegislations, this.legislationConfig); } @@ -70,7 +71,7 @@ class EditScheduleEventHandler { // other event handlers can run const new_change_event = new Event("change"); - if (goodsOnUKMarket){ + if (goodsOnUKMarket) { document.querySelector(`input[type=radio][name="goods_export_only"][value="no"]`).checked = true document.querySelector(`input[type=radio][name="goods_export_only"][value="no"]`).dispatchEvent(new_change_event) } else { @@ -94,7 +95,7 @@ class EditScheduleEventHandler { } -function setEndUse (value) { +function setEndUse(value) { const endUse = document.querySelector('#final-product-end-use-wrapper'); endUse.style.display = value === "yes" ? "block" : "none"; } @@ -109,14 +110,14 @@ function getRadioElements(radioName) { } function getCheckedRadioValue(radioName) { - const selectedRadio = document.querySelector(`input[type=radio][name=${radioName}]:checked`); - let value = ""; + const selectedRadio = document.querySelector(`input[type=radio][name=${radioName}]:checked`); + let value = ""; - if (selectedRadio !== null) { - value = selectedRadio.value; - } + if (selectedRadio !== null) { + value = selectedRadio.value; + } - return value; + return value; } @@ -136,27 +137,51 @@ function updateIsResponsiblePerson(legislations, exportOnly, config) { /** - * Return true if responsible person statement should be shown. + * Either show or hide the cptpp warning depending on the config. * * @param {Array.} legislations List of selected legislations - * @param {string} exportOnly value of export only field * @param {Object.} config */ -function showResponsiblePersonStatement(legislations, exportOnly, config) { - let isEUCosmeticsRegulation = false; +function updateCPTPPWarning(legislations, config) { + const isEUCosmeticsRegulation = checkIsEUCosmeticsRegulation(legislations, config); + const wrapper = document.querySelector("#cptpp-warning-wrapper") + + if (wrapper) { + wrapper.style.display = isEUCosmeticsRegulation ? "block" : "none"; + } +} + +/** + * Return true if isEUCosmeticsRegulation in legislations. + * + * @param {Array.} legislations List of selected legislations + * @param {Object.} config + */ +function checkIsEUCosmeticsRegulation(legislations, config) { for (const legislation of legislations) { if (config.hasOwnProperty(legislation)) { let legislationConfig = config[legislation]; if (legislationConfig.isEUCosmeticsRegulation) { - isEUCosmeticsRegulation = true; - - break; + return true; } } } + return false; +} + + +/** + * Return true if responsible person statement should be shown. + * + * @param {Array.} legislations List of selected legislations + * @param {string} exportOnly value of export only field + * @param {Object.} config + */ +function showResponsiblePersonStatement(legislations, exportOnly, config) { + const isEUCosmeticsRegulation = checkIsEUCosmeticsRegulation(legislations, config); const notExportOnly = exportOnly === "no"; return isEUCosmeticsRegulation && notExportOnly; diff --git a/web/templates/web/domains/case/export/cfs-edit.html b/web/templates/web/domains/case/export/cfs-edit.html index 2ec80be66..9dbc6237f 100644 --- a/web/templates/web/domains/case/export/cfs-edit.html +++ b/web/templates/web/domains/case/export/cfs-edit.html @@ -15,7 +15,7 @@
This form is in respect of the Exporting Company. Please provide all the information requested. The information will be used to create a Certificate - of Free Sale and a legal declaration in the form of a Schedule. You must save your information then select + of Free Sale and a legal declaration in the form of a Schedule. You must save your information then select another section to move through the application.
@@ -23,6 +23,12 @@ {% include "partial/case/application-contact-details.html" %}

Countries

+ {% if cptpp_countries_list %} +
+ Please note that Certificates of Free Sale (CFS) for cosmetic products are no longer required for {{ cptpp_countries_list }} following UK accession to + CPTPP +
+ {% endif %} {{ fields.field(form.countries) }} {% endblock %} diff --git a/web/templates/web/domains/case/export/partials/cfs/edit-schedule-form-content.html b/web/templates/web/domains/case/export/partials/cfs/edit-schedule-form-content.html index 83a79b51d..9cc3f13eb 100644 --- a/web/templates/web/domains/case/export/partials/cfs/edit-schedule-form-content.html +++ b/web/templates/web/domains/case/export/partials/cfs/edit-schedule-form-content.html @@ -2,6 +2,18 @@ {{ fields.field(form.exporter_status, tooltip_msg_id="manufacturer-guidance-tooltip") }} {{ fields.field(form.brand_name_holder) }} {{ fields.field(form.legislations) }} +{% if cptpp_countries_list %} +
+

+ A Certificate of Free Sale (CFS) for cosmetic products is no longer required for {{ cptpp_countries_list }} + due to the UK’s accession to the Comprehensive and Progressive Agreement for Trans-Pacific Partnership (CPTPP). +

+

+ Please contact {{ ilb_contact_email }} if you encounter any problems or are + still being asked by any of the CPTPP countries to provide a CFS for cosmetics. +

+
+{% endif %} diff --git a/web/tests/domains/case/export/test_forms.py b/web/tests/domains/case/export/test_forms.py index ed58cab6a..ef01975d1 100644 --- a/web/tests/domains/case/export/test_forms.py +++ b/web/tests/domains/case/export/test_forms.py @@ -9,11 +9,12 @@ EditCFSScheduleForm, EditCOMForm, EditGMPForm, + SubmitCFSForm, SubmitCFSScheduleForm, SubmitGMPForm, ) from web.forms.widgets import RadioSelectInline -from web.models import ProductLegislation +from web.models import Country, ProductLegislation from web.models.shared import AddressEntryType, YesNoChoices @@ -140,6 +141,23 @@ def test_submit_cfs_schedule_form_biocidal_claim_required(cfs_app_in_progress): assert form.errors["biocidal_claim"][0] == "This field is required." +@pytest.mark.django_db +def test_submit_cfs_form_cptpp_cosmetics(cfs_app_in_progress): + """Tests that the biocidal_claim field is required when one of the legislations is biocidal.""" + app = cfs_app_in_progress + country = Country.util.get_cptpp_countries().last() + app.countries.add(country) + + app_schedule = app.schedules.get() + app_schedule.legislations.add( + ProductLegislation.objects.filter(is_eu_cosmetics_regulation=True)[0] + ) + + form = SubmitCFSForm(data={"countries": app.countries.all()}, instance=app) + assert not form.is_valid() + assert "This application is not necessary." in form.errors["countries"][0] + + @pytest.mark.django_db def test_edit_com_form_radio_select_widgets(com_app_in_progress): """Tests that the is_pesticide_on_free_sale_uk and is_manufacturer fields are rendered as diff --git a/web/tests/domains/country/test_utils.py b/web/tests/domains/country/test_utils.py new file mode 100644 index 000000000..ffdacce04 --- /dev/null +++ b/web/tests/domains/country/test_utils.py @@ -0,0 +1,16 @@ +import pytest + +from web.domains.country.utils import comma_separator + + +@pytest.mark.parametrize( + "data,expected", + [ + (["a"], "a"), + (["a", "b"], "a and b"), + (["a", "b", "c"], "a, b and c"), + ([], ""), + ], +) +def test_comma_separator(data, expected): + assert comma_separator(data) == expected