From f535e76ab3e8ae34bcb133046610c284481f2eb7 Mon Sep 17 00:00:00 2001 From: Matthew Holmes Date: Tue, 27 Feb 2024 16:34:29 +0000 Subject: [PATCH] ICMSLST-1190 Refactor COM application template code. Changes: - Create models to hold template data. - Remove old json column used to save template data - Add app specific sidebar links, will be used in CFS application template. --- pii-ner-exclude.txt | 3 + web/domains/case/export/forms.py | 26 ++--- web/domains/case/export/models.py | 42 ++++--- web/domains/case/export/views.py | 5 +- web/domains/cat/forms.py | 21 +++- web/domains/cat/models.py | 94 +++++++--------- web/domains/cat/views.py | 131 +++++++++++++++------- web/management/commands/add_dummy_data.py | 28 +---- web/migrations/0001_initial.py | 47 ++++++-- web/models/__init__.py | 10 +- web/templates/web/domains/cat/edit.html | 10 +- web/tests/domains/cat/test_models.py | 42 ------- web/tests/domains/cat/test_views.py | 69 +++--------- 13 files changed, 272 insertions(+), 256 deletions(-) diff --git a/pii-ner-exclude.txt b/pii-ner-exclude.txt index 26404c10c..703b4d482 100644 --- a/pii-ner-exclude.txt +++ b/pii-ner-exclude.txt @@ -3859,3 +3859,6 @@ the Supplementary Report Add New Supplementary Report jQuery "Check if the date +CertificateOfGoodManufacturingPracticeApplicationTemplate +TemplateCls +Application Type" diff --git a/web/domains/case/export/forms.py b/web/domains/case/export/forms.py index 0d18b1f07..d37f6e7a5 100644 --- a/web/domains/case/export/forms.py +++ b/web/domains/case/export/forms.py @@ -207,19 +207,6 @@ def __init__(self, *args, **kwargs): type_code=ExportApplicationType.Types.MANUFACTURE ).country_group.countries.filter(is_active=True) - -class EditCOMForm(OptionalFormMixin, PrepareCertManufactureFormBase): - """Form used when editing the application. - - All fields are optional to allow partial record saving. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # Moved from PrepareCertManufactureFormBase to EditCOMForm as it shouldn't - # be set when creating a COM template. - self.fields["contact"].queryset = application_contacts(self.instance) - def clean_is_pesticide_on_free_sale_uk(self): """Perform extra logic even thought this is the edit form where every field is optional""" @@ -241,6 +228,19 @@ def clean_is_manufacturer(self): return val +class EditCOMForm(OptionalFormMixin, PrepareCertManufactureFormBase): + """Form used when editing the application. + + All fields are optional to allow partial record saving. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Moved from PrepareCertManufactureFormBase to EditCOMForm as it shouldn't + # be set when creating a COM template. + self.fields["contact"].queryset = application_contacts(self.instance) + + class SubmitCOMForm(EditCOMForm): """Form used when submitting the application. diff --git a/web/domains/case/export/models.py b/web/domains/case/export/models.py index 7e7059c54..8aa374a59 100644 --- a/web/domains/case/export/models.py +++ b/web/domains/case/export/models.py @@ -62,17 +62,11 @@ def create_application_url(self) -> str: raise ValueError(f"Unknown Application Type: {self.type_code}") # /PS-IGNORE -class ExportApplication(ApplicationBase): +class ExportApplicationABC(models.Model): + """Base class for ExportApplication and the templates.""" + class Meta: - indexes = [ - models.Index(fields=["status"], name="EA_status_idx"), - BTreeIndex( - fields=["reference"], - name="EA_search_case_reference_idx", - opclasses=["text_pattern_ops"], - ), - models.Index(fields=["-submit_datetime"], name="EA_submit_datetime_idx"), - ] + abstract = True application_type = models.ForeignKey( "web.ExportApplicationType", on_delete=models.PROTECT, blank=False, null=False @@ -152,6 +146,19 @@ class Meta: def is_import_application(self) -> bool: return False + +class ExportApplication(ExportApplicationABC, ApplicationBase): + class Meta: + indexes = [ + models.Index(fields=["status"], name="EA_status_idx"), + BTreeIndex( + fields=["reference"], + name="EA_search_case_reference_idx", + opclasses=["text_pattern_ops"], + ), + models.Index(fields=["-submit_datetime"], name="EA_submit_datetime_idx"), + ] + def get_edit_view_name(self) -> str: if self.process_type == ProcessTypes.COM: return "export:com-edit" @@ -189,10 +196,9 @@ def application_approved(self): return self.decision == self.APPROVE -@final -class CertificateOfManufactureApplication(ExportApplication): - PROCESS_TYPE = ProcessTypes.COM - IS_FINAL = True +class CertificateOfManufactureApplicationABC(models.Model): + class Meta: + abstract = True is_pesticide_on_free_sale_uk = models.BooleanField(null=True) is_manufacturer = models.BooleanField(null=True) @@ -202,6 +208,14 @@ class CertificateOfManufactureApplication(ExportApplication): manufacturing_process = models.TextField(max_length=4000, blank=False, null=True) +@final +class CertificateOfManufactureApplication( # type: ignore[misc] + CertificateOfManufactureApplicationABC, ExportApplication +): + PROCESS_TYPE = ProcessTypes.COM + IS_FINAL = True + + @final class CertificateOfFreeSaleApplication(ExportApplication): PROCESS_TYPE = ProcessTypes.CFS diff --git a/web/domains/case/export/views.py b/web/domains/case/export/views.py index 9e924e4f9..509c133ee 100644 --- a/web/domains/case/export/views.py +++ b/web/domains/case/export/views.py @@ -239,8 +239,11 @@ def set_template_data( :param template: Application Template :param type_code: App type. """ + + # Get data that we can save in the real application + data = model_to_dict(template.com_template, exclude=["id", "template"]) form_class = form_class_for_application_type(type_code) - form = form_class(instance=application, data=template.form_data()) + form = form_class(instance=application, data=data) if form.is_valid(): form.save() diff --git a/web/domains/cat/forms.py b/web/domains/cat/forms.py index 392a18a97..64c8ddd56 100644 --- a/web/domains/cat/forms.py +++ b/web/domains/cat/forms.py @@ -1,7 +1,13 @@ import django_filters from django import forms -from web.models import CertificateApplicationTemplate, ExportApplicationType +from web.domains.case.export.forms import PrepareCertManufactureFormBase +from web.forms.mixins import OptionalFormMixin +from web.models import ( + CertificateApplicationTemplate, + CertificateOfManufactureApplicationTemplate, + ExportApplicationType, +) class CATFilter(django_filters.FilterSet): @@ -34,3 +40,16 @@ class Meta: model = CertificateApplicationTemplate fields = ("name", "description", "sharing") widgets = {"description": forms.Textarea({"rows": 4})} + + +class CertificateOfManufactureTemplateForm(OptionalFormMixin, PrepareCertManufactureFormBase): + class Meta: + _fields = PrepareCertManufactureFormBase.Meta.fields + _fields.pop(_fields.index("contact")) + fields = _fields + + help_texts = PrepareCertManufactureFormBase.Meta.help_texts + labels = PrepareCertManufactureFormBase.Meta.labels + widgets = PrepareCertManufactureFormBase.Meta.widgets + + model = CertificateOfManufactureApplicationTemplate diff --git a/web/domains/cat/models.py b/web/domains/cat/models.py index 1c7ae26e6..52d9d499a 100644 --- a/web/domains/cat/models.py +++ b/web/domains/cat/models.py @@ -1,10 +1,12 @@ -import copy -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from django.conf import settings -from django.core.serializers.json import DjangoJSONEncoder from django.db import models +from web.domains.case.export.models import ( + CertificateOfManufactureApplicationABC, + ExportApplicationABC, +) from web.models import ExportApplicationType from web.types import TypedTextChoices @@ -12,48 +14,20 @@ from web.models import User -def encode_model_or_queryset(o: models.Model | models.QuerySet | Any) -> Any: - match o: - case models.Model(): - return o.pk - case models.QuerySet(): - return [encode_model_or_queryset(instance) for instance in o] - case _: - return o - - -def encode_json_field_data(data: dict[str, Any]) -> dict[str, Any]: - """Serialize Model and QuerySet instances so that they can be encoded using DjangoJSONEncoder. - - Previously this was done via a custom DjangoQuerysetJSONEncoder but didn't work - after upgrading to Psycopg 3. - """ - - return {key: encode_model_or_queryset(value) for key, value in data.items()} - - -class CertificateApplicationTemplateManager(models.Manager): - """Custom manager to preserve behaviour that relied on old custom DjangoQuerysetJSONEncoder.""" - - def create(self, **kwargs): - data = kwargs.pop("data", {}) - valid_data = encode_json_field_data(data) - - return super().create(data=valid_data, **kwargs) - - class CertificateApplicationTemplate(models.Model): class SharingStatuses(TypedTextChoices): PRIVATE = ("private", "Private (do not share)") VIEW = ("view", "Share (view only)") EDIT = ("edit", "Share (allow edit)") - # Create manager to handle legacy behaviour that relied on old custom DjangoQuerysetJSONEncoder. - objects = CertificateApplicationTemplateManager() + name = models.CharField(verbose_name="Template Name", max_length=70) + + description = models.CharField(verbose_name="Template Description", max_length=500) - name = models.CharField( - verbose_name="Template Name", - max_length=70, + application_type = models.CharField( + verbose_name="Application Type", + max_length=3, + choices=ExportApplicationType.Types.choices, help_text=( "DIT does not issue Certificates of Free Sale for food, food supplements, pesticides" " and CE marked medical devices. Certificates of Manufacture are applicable only to" @@ -61,12 +35,6 @@ class SharingStatuses(TypedTextChoices): ), ) - description = models.CharField(verbose_name="Template Description", max_length=500) - - application_type = models.CharField( - verbose_name="Application Type", max_length=3, choices=ExportApplicationType.Types.choices - ) - sharing = models.CharField( max_length=7, choices=SharingStatuses.choices, @@ -80,11 +48,6 @@ class SharingStatuses(TypedTextChoices): created = models.DateTimeField(auto_now_add=True) last_updated = models.DateTimeField(auto_now=True) is_active = models.BooleanField(default=True) - data = models.JSONField(default=dict, encoder=DjangoJSONEncoder) - - def form_data(self) -> dict: - """Data to use as a Django form's data argument.""" - return copy.deepcopy(self.data) def user_can_view(self, user: "User") -> bool: # A template may have sensitive information so we check if the user @@ -95,7 +58,34 @@ def user_can_edit(self, user: "User") -> bool: # Whether the user can edit the template itself. return user == self.owner - def save(self, *args, **kwargs): - self.data = encode_json_field_data(self.data) - return super().save(*args, **kwargs) +class CertificateOfManufactureApplicationTemplate( # type: ignore[misc] + ExportApplicationABC, CertificateOfManufactureApplicationABC +): + # Relationships to ignore from ExportApplicationABC + application_type = None + last_updated_by = None + variation_requests = None + case_notes = None + further_information_requests = None + update_requests = None + case_emails = None + submitted_by = None + created_by = None + exporter = None + exporter_office = None + contact = None + agent = None + agent_office = None + case_owner = None + cleared_by = None + + template = models.OneToOneField( + "web.CertificateApplicationTemplate", on_delete=models.CASCADE, related_name="com_template" + ) + + +class CertificateOfFreeSaleApplicationTemplate: ... # noqa: E701 + + +class CertificateOfGoodManufacturingPracticeApplicationTemplate: ... # noqa: E701 diff --git a/web/domains/cat/views.py b/web/domains/cat/views.py index 7f07ca675..cb79544cb 100644 --- a/web/domains/cat/views.py +++ b/web/domains/cat/views.py @@ -13,12 +13,25 @@ from django_filters import FilterSet from django_filters.views import FilterView -from web.domains.case.export.forms import form_class_for_application_type -from web.models import CertificateApplicationTemplate, User +from web.models import ( + CertificateApplicationTemplate, + CertificateOfManufactureApplicationTemplate, + ExportApplicationType, + User, +) from web.permissions import Perms from web.types import AuthenticatedHttpRequest -from .forms import CATFilter, CreateCATForm, EditCATForm +from .forms import ( + CATFilter, + CertificateOfManufactureTemplateForm, + CreateCATForm, + EditCATForm, +) + +# TODO: Use these +# from web.models import CertificateOfFreeSaleApplicationTemplate, CertificateOfGoodManufacturingPracticeApplicationTemplate, + if TYPE_CHECKING: from django.db import QuerySet @@ -64,6 +77,21 @@ def create(request: AuthenticatedHttpRequest) -> HttpResponse: cat.owner = request.user cat.save() + match cat.application_type: + case ExportApplicationType.Types.FREE_SALE: + # TODO: Add real template + # TemplateCls = CertificateOfFreeSaleApplicationTemplate + template_cls = CertificateOfManufactureApplicationTemplate + + case ExportApplicationType.Types.MANUFACTURE: + template_cls = CertificateOfManufactureApplicationTemplate + + case ExportApplicationType.Types.GMP: + # TODO: Add real template + # TemplateCls = CertificateOfGoodManufacturingPracticeApplicationTemplate + template_cls = CertificateOfManufactureApplicationTemplate + + template_cls.objects.create(template=cat) messages.success(request, f"Template '{cat.name}' created.") return redirect(reverse("cat:list")) @@ -104,15 +132,15 @@ def dispatch(self, request: AuthenticatedHttpRequest, *args, **kwargs) -> HttpRe def has_permission(self) -> bool: return _has_permission(self.request.user) - def get_form_class(self) -> ModelForm: + def get_form_class(self) -> type[ModelForm]: if "step" in self.kwargs: return form_class_for_application_type(self.object.application_type) else: # This is the template's metadata form. return EditCATForm - def get_form(self) -> ModelForm: - form = super().get_form() + def get_form(self, form_class=None) -> ModelForm: + form = super().get_form(form_class) if self.read_only: for fname in form.fields: @@ -123,29 +151,43 @@ def get_form(self) -> ModelForm: def get_form_kwargs(self) -> dict[str, Any]: kwargs = super().get_form_kwargs() - if "step" not in self.kwargs: + if "step" in self.kwargs: + # TODO: Set correct instance based on step. + # The step will change the template / related table. + kwargs["instance"] = self.object.com_template + else: kwargs["instance"] = self.object return kwargs - def get_initial(self) -> dict[str, Any]: - if "step" in self.kwargs: - return self.object.form_data() - else: - return super().get_initial() - def get_context_data(self, **kwargs: Any) -> dict[str, Any]: + kwargs = { + "page_title": self.get_page_title(), + "application_type": self.object.get_application_type_display(), + "sidebar_links": self.get_sidebar_links(), + "read_only": self.read_only, + } + + return super().get_context_data(**kwargs) + + def form_valid(self, form: ModelForm) -> HttpResponse: + form.save() + messages.success(self.request, f"Template '{self.object.name}' updated.") + + return super().form_valid(form) + + def get_page_title(self): + action = "View" if self.read_only else "Edit" + page_title = f"{action} Certificate Application Template" + + return page_title + + def get_sidebar_links(self): type_ = self.object.application_type + url_name = "view" if self.read_only else "edit" type_display = self.object.get_application_type_display() - if self.read_only: - url_name = "view" - page_title = "View Certificate Application Template" - else: - url_name = "edit" - page_title = "Edit Certifcate Application Template" - - sidebar_links = [ + common_steps: list[tuple[str, str]] = [ (reverse(f"cat:{url_name}", kwargs={"cat_pk": self.object.pk}), "Template"), ( reverse( @@ -154,28 +196,33 @@ def get_context_data(self, **kwargs: Any) -> dict[str, Any]: f"{type_display} Application", ), ] - kwargs = { - "page_title": page_title, - "application_type": type_display, - "sidebar_links": sidebar_links, - "read_only": self.read_only, - } - return super().get_context_data(**kwargs) - - def form_valid(self, form: ModelForm) -> HttpResponse: - result = super().form_valid(form) - - if "step" in self.kwargs: - # The JSON field encoder handles querysets as a list of PKs. - self.object.data = form.cleaned_data - self.object.save() - else: - # This is the metadata form for the template itself. - form.save() - - messages.success(self.request, f"Template '{self.object.name}' updated.") - return result + match self.object.application_type: + case ExportApplicationType.Types.FREE_SALE: + app_specific: list[tuple[str, str]] = [] + case ExportApplicationType.Types.MANUFACTURE: + app_specific = [] + case ExportApplicationType.Types.GMP: + app_specific = [] + case _: + app_specific = [] + + return common_steps + app_specific + + +def form_class_for_application_type(type_code: str) -> type[ModelForm]: + types_forms: dict[Any, type[ModelForm]] = { + # TODO: Use correct form + ExportApplicationType.Types.FREE_SALE: CertificateOfManufactureTemplateForm, + # TODO: Use correct form + ExportApplicationType.Types.GMP: CertificateOfManufactureTemplateForm, + ExportApplicationType.Types.MANUFACTURE: CertificateOfManufactureTemplateForm, + } + + try: + return types_forms[type_code] + except KeyError: + raise NotImplementedError(f"Type not supported: {type_code}") class CATReadOnlyView(CATEditView): diff --git a/web/management/commands/add_dummy_data.py b/web/management/commands/add_dummy_data.py index ea653aa9a..335eef9fa 100644 --- a/web/management/commands/add_dummy_data.py +++ b/web/management/commands/add_dummy_data.py @@ -414,32 +414,8 @@ def create_superuser(self, username: str, password: str) -> User: def create_certificate_application_templates( owner: User, ) -> list[CertificateApplicationTemplate]: - data = { - "GMP": { - "is_responsible_person": "yes", - "responsible_person_name": f"{owner.first_name}", - "responsible_person_address": "Old Admiralty Building\nLondon\n", - }, - "COM": { - "product_name": "Acme Wonder Product", - "is_manufacturer": True, - }, - } - objs = [] - - for type_code, label in ExportApplicationType.Types.choices: - objs.append( - CertificateApplicationTemplate( - name=f"{label} template ({type_code})", - description=f"Description of {label} template", - application_type=type_code, - sharing=CertificateApplicationTemplate.SharingStatuses.PRIVATE, - data=data.get(type_code, {}), - owner=owner, - ) - ) - - return CertificateApplicationTemplate.objects.bulk_create(objs) + # TODO: Add Test templates after full refactor. + return [] def create_dummy_signature(user: User) -> None: diff --git a/web/migrations/0001_initial.py b/web/migrations/0001_initial.py index d7499029c..865145c7c 100644 --- a/web/migrations/0001_initial.py +++ b/web/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.10 on 2024-02-27 10:33 +# Generated by Django 4.2.10 on 2024-02-28 14:10 import uuid @@ -19,11 +19,12 @@ class Migration(migrations.Migration): + initial = True dependencies = [ - ("auth", "0012_alter_user_first_name_max_length"), ("contenttypes", "0002_remove_content_type_name"), + ("auth", "0012_alter_user_first_name_max_length"), ] operations = [ @@ -310,13 +311,28 @@ class Migration(migrations.Migration): ("created", models.DateTimeField(auto_now_add=True)), ("last_updated", models.DateTimeField(auto_now=True)), ("is_active", models.BooleanField(default=True)), + ], + ), + migrations.CreateModel( + name="CertificateOfManufactureApplicationTemplate", + fields=[ ( - "data", - models.JSONField( - default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder + "id", + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" ), ), + ("last_update_datetime", models.DateTimeField(auto_now=True)), + ("variation_no", models.IntegerField(default=0)), + ("is_pesticide_on_free_sale_uk", models.BooleanField(null=True)), + ("is_manufacturer", models.BooleanField(null=True)), + ("product_name", models.CharField(max_length=1000, null=True)), + ("chemical_name", models.CharField(max_length=500, null=True)), + ("manufacturing_process", models.TextField(max_length=4000, null=True)), ], + options={ + "abstract": False, + }, ), migrations.CreateModel( name="CFSProduct", @@ -3670,7 +3686,7 @@ class Migration(migrations.Migration): ("last_update_datetime", models.DateTimeField(auto_now=True)), ("variation_no", models.IntegerField(default=0)), ], - bases=("web.process",), + bases=("web.process", models.Model), ), migrations.CreateModel( name="FurtherInformationRequest", @@ -5261,6 +5277,23 @@ class Migration(migrations.Migration): to="web.cfsschedule", ), ), + migrations.AddField( + model_name="certificateofmanufactureapplicationtemplate", + name="countries", + field=models.ManyToManyField( + help_text="A certificate will be created for each country selected. You may select up to 40 countries. You cannot select the same country twice, you must submit a new application.", + to="web.country", + ), + ), + migrations.AddField( + model_name="certificateofmanufactureapplicationtemplate", + name="template", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="com_template", + to="web.certificateapplicationtemplate", + ), + ), migrations.AddField( model_name="certificateapplicationtemplate", name="owner", @@ -5536,7 +5569,7 @@ class Migration(migrations.Migration): options={ "abstract": False, }, - bases=("web.exportapplication",), + bases=("web.exportapplication", models.Model), ), migrations.CreateModel( name="DerogationsApplication", diff --git a/web/models/__init__.py b/web/models/__init__.py index be3028423..a98e99dd3 100644 --- a/web/models/__init__.py +++ b/web/models/__init__.py @@ -105,7 +105,12 @@ VariationRequest, WithdrawApplication, ) -from web.domains.cat.models import CertificateApplicationTemplate +from web.domains.cat.models import ( + CertificateApplicationTemplate, + CertificateOfFreeSaleApplicationTemplate, + CertificateOfGoodManufacturingPracticeApplicationTemplate, + CertificateOfManufactureApplicationTemplate, +) from web.domains.commodity.models import ( Commodity, CommodityGroup, @@ -172,8 +177,11 @@ "CaseNote", "CertificateApplicationTemplate", "CertificateOfFreeSaleApplication", + "CertificateOfFreeSaleApplicationTemplate", "CertificateOfGoodManufacturingPracticeApplication", + "CertificateOfGoodManufacturingPracticeApplicationTemplate", "CertificateOfManufactureApplication", + "CertificateOfManufactureApplicationTemplate", "ChecklistFirearmsOILApplication", "ChiefRequestResponseErrors", "ClauseQuantity", diff --git a/web/templates/web/domains/cat/edit.html b/web/templates/web/domains/cat/edit.html index 247c8f038..375d3a192 100644 --- a/web/templates/web/domains/cat/edit.html +++ b/web/templates/web/domains/cat/edit.html @@ -2,9 +2,13 @@ {% from "display/fields.html" import application_field %} {% block main_content_intro %} -
- TODO: ICMLST-1050 ICMSLST-1051 ICMSLST-1052 - Add div info box referenced in ICMLST-1030 -
+ {% if application_type|lower == "certificate of manufacture" %} +
+ 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 Manufacture and a legal + declaration in the form of a Schedule. +
+ {% endif %} {% endblock %} {% block extra_main_content_form %} diff --git a/web/tests/domains/cat/test_models.py b/web/tests/domains/cat/test_models.py index 9a1264af2..290f70ca7 100644 --- a/web/tests/domains/cat/test_models.py +++ b/web/tests/domains/cat/test_models.py @@ -5,14 +5,6 @@ @pytest.mark.django_db class TestCertificateApplicationTemplate: - def test_form_data_makes_a_copy(self): - original = {"foo": "bar"} - obj = CertificateApplicationTemplate(data=original) - data = obj.form_data() - data["foo"] = "qux" - - assert original == {"foo": "bar"} - def test_owner_user_can_view(self): alice = User.objects.create_user("alice") bob = User.objects.create_user("bob") @@ -28,37 +20,3 @@ def test_owner_user_can_edit(self): assert template.user_can_edit(bob) is False assert template.user_can_edit(alice) is True - - def test_json_serialization_of_models(self): - """Test that calling model.objects.create() preserves old logic.""" - - alice = User.objects.create_user("alice") - data = { - "alice": alice, - "objects": User.objects.filter(username="alice"), - } - template = CertificateApplicationTemplate.objects.create( - owner=alice, - data=data, - ) - template.refresh_from_db() - - assert template.form_data() == {"alice": alice.pk, "objects": [alice.pk]} - - def test_json_serialization_of_models_for_existing_template(self): - """Test that calling model.save() preserves old logic.""" - - alice = User.objects.create_user("alice") - template = CertificateApplicationTemplate.objects.create(owner=alice, data={}) - assert template.form_data() == {} - - data = { - "alice": alice, - "objects": User.objects.filter(username="alice"), - } - template.refresh_from_db() - template.data = data - template.save() - template.refresh_from_db() - - assert template.form_data() == {"alice": alice.pk, "objects": [alice.pk]} diff --git a/web/tests/domains/cat/test_views.py b/web/tests/domains/cat/test_views.py index 15c5c4573..c8003c6c1 100644 --- a/web/tests/domains/cat/test_views.py +++ b/web/tests/domains/cat/test_views.py @@ -3,7 +3,11 @@ from pytest_django.asserts import assertTemplateUsed from web.domains.cat.forms import CATFilter -from web.models import CertificateApplicationTemplate, ExportApplicationType +from web.models import ( + CertificateApplicationTemplate, + CertificateOfManufactureApplicationTemplate, + ExportApplicationType, +) from web.tests.auth import AuthTestCase @@ -81,6 +85,7 @@ def test_show_edit_form(self): name="CFS template", application_type=ExportApplicationType.Types.FREE_SALE, ) + CertificateOfManufactureApplicationTemplate.objects.create(template=cat) url = reverse("cat:edit", kwargs={"cat_pk": cat.pk}) response = self.exporter_client.get(url) @@ -94,6 +99,7 @@ def test_permission_denied(self): name="CFS template", application_type=ExportApplicationType.Types.FREE_SALE, ) + CertificateOfManufactureApplicationTemplate.objects.create(template=cat) url = reverse("cat:edit", kwargs={"cat_pk": cat.pk}) response = self.importer_client.get(url) @@ -108,65 +114,14 @@ def test_show_edit_step_form(self): name="CFS template", application_type=ExportApplicationType.Types.FREE_SALE, ) - url = reverse("cat:edit-step", kwargs={"cat_pk": cat.pk, "step": "cfs"}) - - response = self.exporter_client.get(url) - - assert response.status_code == 200 - assertTemplateUsed(response, "web/domains/cat/edit.html") - - def test_step_form_initial_data(self): - # Does the form for 1 step in a template display the choices from - # my saved application template? - initial_data = {"foo": "bar"} + CertificateOfManufactureApplicationTemplate.objects.create(template=cat) - cat = CertificateApplicationTemplate.objects.create( - owner=self.exporter_user, - name="CFS template", - application_type=ExportApplicationType.Types.FREE_SALE, - data=initial_data, - ) url = reverse("cat:edit-step", kwargs={"cat_pk": cat.pk, "step": "cfs"}) response = self.exporter_client.get(url) assert response.status_code == 200 - assert response.context["form"].initial == initial_data - - def test_submit_step_form_saves_data_in_application_template(self): - cat = CertificateApplicationTemplate.objects.create( - owner=self.exporter_user, - name="GMP template", - application_type=ExportApplicationType.Types.GMP, - data={}, - ) - url = reverse("cat:edit-step", kwargs={"cat_pk": cat.pk, "step": "gmp"}) - - response = self.exporter_client.post(url, {}) - - assert response.status_code == 302 - cat.refresh_from_db() - - expected = { - "brand_name": None, - "auditor_accredited": None, - "auditor_certified": None, - "contact": None, - "gmp_certificate_issued": None, - "is_manufacturer": None, - "is_responsible_person": None, - "manufacturer_address": None, - "manufacturer_address_entry_type": "", - "manufacturer_country": None, - "manufacturer_name": None, - "manufacturer_postcode": None, - "responsible_person_address": None, - "responsible_person_address_entry_type": "", - "responsible_person_country": None, - "responsible_person_name": None, - "responsible_person_postcode": None, - } - assert cat.data == expected + assertTemplateUsed(response, "web/domains/cat/edit.html") class TestCATArchiveView(AuthTestCase): @@ -176,6 +131,7 @@ def test_archive_a_template(self): name="GMP template", application_type=ExportApplicationType.Types.GMP, ) + CertificateOfManufactureApplicationTemplate.objects.create(template=cat) assert cat.is_active is True url = reverse("cat:archive", kwargs={"cat_pk": cat.pk}) @@ -194,6 +150,7 @@ def test_permission_denied(self): name="CFS template", application_type=ExportApplicationType.Types.FREE_SALE, ) + CertificateOfManufactureApplicationTemplate.objects.create(template=cat) url = reverse("cat:archive", kwargs={"cat_pk": cat.pk}) response = self.importer_client.get(url) @@ -209,6 +166,7 @@ def test_restore_a_template(self): application_type=ExportApplicationType.Types.GMP, is_active=False, ) + CertificateOfManufactureApplicationTemplate.objects.create(template=cat) assert cat.is_active is False url = reverse("cat:restore", kwargs={"cat_pk": cat.pk}) @@ -228,6 +186,7 @@ def test_permission_denied(self): application_type=ExportApplicationType.Types.FREE_SALE, is_active=False, ) + CertificateOfManufactureApplicationTemplate.objects.create(template=cat) url = reverse("cat:restore", kwargs={"cat_pk": cat.pk}) response = self.importer_client.get(url) @@ -242,6 +201,7 @@ def test_show_disabled_form_for_template(self): name="CFS template", application_type=ExportApplicationType.Types.FREE_SALE, ) + CertificateOfManufactureApplicationTemplate.objects.create(template=cat) url = reverse("cat:view", kwargs={"cat_pk": cat.pk}) response = self.exporter_client.get(url) @@ -255,6 +215,7 @@ def test_show_disabled_form_for_step(self): name="CFS template", application_type=ExportApplicationType.Types.FREE_SALE, ) + CertificateOfManufactureApplicationTemplate.objects.create(template=cat) url = reverse("cat:view-step", kwargs={"cat_pk": cat.pk, "step": "cfs"}) response = self.exporter_client.get(url)