class EditMODClearanceApplicationsTests(DataTestClient):
    def setUp(self):
        super().setUp()
        self.application = self.create_mod_clearance_application(
            self.organisation, case_type=self.case_type)
        self.url = reverse("applications:application",
                           kwargs={"pk": self.application.id})
        self.data = {"name": "abc"}

    def test_edit_unsubmitted_application_name_success(self):
        updated_at = self.application.updated_at

        response = self.client.put(self.url, self.data,
                                   **self.exporter_headers)

        self.application.refresh_from_db()
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(self.application.name, self.data["name"])
        self.assertNotEqual(self.application.updated_at, updated_at)
        # Unsubmitted (draft) applications should not create audit entries when edited
        self.assertEqual(Audit.objects.count(), 0)

    @parameterized.expand(get_case_statuses(read_only=False))
    def test_edit_application_name_in_editable_status_success(
            self, editable_status):
        old_name = self.application.name
        self.submit_application(self.application)
        self.application.status = get_case_status_by_status(editable_status)
        self.application.save()
        updated_at = self.application.updated_at

        response = self.client.put(self.url, self.data,
                                   **self.exporter_headers)
        self.application.refresh_from_db()
        audit_qs = Audit.objects.all()
        audit_object = audit_qs.first()

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(self.application.name, self.data["name"])
        self.assertNotEqual(self.application.updated_at, updated_at)
        self.assertEqual(audit_qs.count(), 2)
        self.assertEqual(audit_object.payload, {
            "new_name": self.data["name"],
            "old_name": old_name
        })

    @parameterized.expand(get_case_statuses(read_only=True))
    def test_edit_application_name_in_read_only_status_failure(
            self, read_only_status):
        self.submit_application(self.application)
        self.application.status = get_case_status_by_status(read_only_status)
        self.application.save()

        response = self.client.put(self.url, self.data,
                                   **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Exemple #2
0
    def post(self, request, pk, good_pk):
        data = request.data
        application = self.get_object()

        if application.status.status in get_case_statuses(read_only=True):
            return JsonResponse(
                data={"errors": [strings.Applications.Generic.READ_ONLY]},
                status=status.HTTP_400_BAD_REQUEST,
            )

        data["good"] = good_pk
        data["application"] = pk
        data["user"] = request.user.pk

        serializer = GoodOnApplicationDocumentCreateSerializer(data=data)
        if serializer.is_valid():
            try:
                serializer.save()
            except Exception:
                return JsonResponse(
                    {"errors": {
                        "file": strings.Documents.UPLOAD_FAILURE
                    }},
                    status=status.HTTP_400_BAD_REQUEST)
            return JsonResponse({"documents": serializer.data},
                                status=status.HTTP_201_CREATED)

        delete_uploaded_document(data)
        return JsonResponse({"errors": serializer.errors},
                            status=status.HTTP_400_BAD_REQUEST)
    def delete(self, request, pk, ext_loc_pk):
        application = get_application(pk)
        if not is_case_status_draft(
                application.status.status
        ) and application.status.status in get_case_statuses(read_only=True):
            return JsonResponse(
                data={
                    "error":
                    f"Application status {application.status.status} is read-only."
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        if (not is_case_status_draft(application.status.status) and
                application.status.status != CaseStatusEnum.APPLICANT_EDITING):
            if ExternalLocationOnApplication.objects.filter(
                    application=application).count() == 1:
                return JsonResponse(
                    data={
                        "errors": {
                            "external_locations": [
                                "Go back and change your answer from ‘Change a site, or delete a good, "
                                "third party or country’ to ’Change something else’."
                            ]
                        }
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

        removed_locations = ExternalLocationOnApplication.objects.filter(
            application=application, external_location__pk=ext_loc_pk)

        if removed_locations:
            audit_trail_service.create(
                actor=request.user,
                verb=AuditType.REMOVED_EXTERNAL_LOCATIONS_FROM_APPLICATION,
                target=application.get_case(),
                payload={
                    "locations": [
                        location.external_location.name + " " +
                        location.external_location.country.name
                        if location.external_location.country else
                        location.external_location.name
                        for location in removed_locations
                    ]
                },
            )

        removed_locations.delete()

        return HttpResponse(status=status.HTTP_204_NO_CONTENT)
    def setUp(self):
        super().setUp()

        self.draft = self.create_draft_standard_application(self.organisation, "Draft")
        self.url_draft = reverse("applications:application_documents", kwargs={"pk": self.draft.id})
        self.test_filename = "dog.jpg"

        self.editable_case_statuses = get_case_statuses(read_only=False)
        self.read_only_case_statuses = get_case_statuses(read_only=True)

        self.data = {
            "name": self.test_filename,
            "s3_key": self.test_filename,
            "size": 476,
            "description": "banana cake 1",
        }

        self.data2 = {
            "name": self.test_filename + "2",
            "s3_key": self.test_filename,
            "size": 476,
            "description": "banana cake 2",
        }
Exemple #5
0
    def delete(self, request, obj_pk):
        good_on_application = self.get_object()
        application = good_on_application.application

        if application.status.status in get_case_statuses(read_only=True):
            return JsonResponse(
                data={"errors": [strings.Applications.Generic.READ_ONLY]},
                status=status.HTTP_400_BAD_REQUEST,
            )

        if good_on_application.application.organisation.id != get_request_user_organisation_id(
                request):
            return JsonResponse(
                data={
                    "errors": strings.Applications.Generic.INVALID_ORGANISATION
                },
                status=status.HTTP_403_FORBIDDEN,
            )

        if (good_on_application.good.status == GoodStatus.SUBMITTED
                and GoodOnApplication.objects.filter(
                    good=good_on_application.good).count() == 1):
            good_on_application.good.status = GoodStatus.DRAFT
            good_on_application.good.save()

        good_on_application.delete()

        # if the application no longer has goods with firearm details, remove the flag
        if (not application.goods.filter(
                good__firearm_details__isnull=False).exists() and
                application.flags.filter(id=SystemFlags.FIREARMS_ID).exists()):
            application.flags.remove(SystemFlags.FIREARMS_ID)

        audit_trail_service.create(
            actor=request.user,
            verb=AuditType.REMOVE_GOOD_FROM_APPLICATION,
            action_object=good_on_application.good,
            target=application.get_case(),
            payload={"good_name": good_on_application.good.description},
        )

        return JsonResponse(data={"status": "success"},
                            status=status.HTTP_200_OK)
class EditStandardApplicationTests(DataTestClient):
    def setUp(self):
        super().setUp()
        self.data = {"name": "new app name!"}

    def test_edit_unsubmitted_application_name_success(self):
        """ Test edit the application name of an unsubmitted application. An unsubmitted application
        has the 'draft' status.
        """
        application = self.create_draft_standard_application(self.organisation)

        url = reverse("applications:application",
                      kwargs={"pk": application.id})
        updated_at = application.updated_at

        response = self.client.put(url, self.data, **self.exporter_headers)

        application.refresh_from_db()
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(application.name, self.data["name"])
        self.assertGreater(application.updated_at, updated_at)
        # Unsubmitted (draft) applications should not create audit entries when edited
        self.assertEqual(Audit.objects.count(), 0)

    @parameterized.expand(get_case_statuses(read_only=False))
    def test_edit_application_name_in_editable_status_success(
            self, editable_status):
        old_name = "Old Name"
        application = self.create_draft_standard_application(
            self.organisation, reference_name=old_name)
        self.submit_application(application)
        application.status = get_case_status_by_status(editable_status)
        application.save()
        url = reverse("applications:application",
                      kwargs={"pk": application.id})
        updated_at = application.updated_at
        response = self.client.put(url, self.data, **self.exporter_headers)
        application.refresh_from_db()
        audit_qs = Audit.objects.all()
        audit_object = audit_qs.first()

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(application.name, self.data["name"])
        self.assertNotEqual(application.updated_at, updated_at)
        self.assertEqual(audit_qs.count(), 2)
        self.assertEqual(audit_object.payload, {
            "new_name": self.data["name"],
            "old_name": old_name
        })

    @parameterized.expand(get_case_statuses(read_only=True))
    def test_edit_application_name_in_read_only_status_failure(
            self, read_only_status):
        application = self.create_draft_standard_application(self.organisation)
        self.submit_application(application)
        application.status = get_case_status_by_status(read_only_status)
        application.save()
        url = reverse("applications:application",
                      kwargs={"pk": application.id})

        response = self.client.put(url, self.data, **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_edit_submitted_application_reference_number(self):
        """ Test successful editing of an application's reference number when the application's status
        is non read-only.
        """
        application = self.create_draft_standard_application(self.organisation)
        self.submit_application(application)
        application.status = get_case_status_by_status(
            CaseStatusEnum.APPLICANT_EDITING)
        application.save()
        url = reverse("applications:application",
                      kwargs={"pk": application.id})
        updated_at = application.updated_at
        audit_qs = Audit.objects.all()
        new_ref = "35236246"
        update_ref = "13124124"

        # Add ref
        data = {
            "reference_number_on_information_form": new_ref,
            "have_you_been_informed": "yes"
        }
        response = self.client.put(url, data, **self.exporter_headers)

        application.refresh_from_db()

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            application.reference_number_on_information_form,
            data["reference_number_on_information_form"],
        )
        self.assertNotEqual(application.updated_at, updated_at)

        # Check add audit
        self.assertEqual(audit_qs.count(), 2)
        self.assertEqual(AuditType(audit_qs.first().verb),
                         AuditType.UPDATE_APPLICATION_LETTER_REFERENCE)
        self.assertEqual(audit_qs.first().payload, {
            "old_ref_number": "no reference",
            "new_ref_number": new_ref
        })

        # Update ref
        data = {
            "reference_number_on_information_form": update_ref,
            "have_you_been_informed": "yes"
        }
        response = self.client.put(url, data, **self.exporter_headers)

        # Check update audit
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(audit_qs.count(), 3)
        self.assertEqual(AuditType(audit_qs.first().verb),
                         AuditType.UPDATE_APPLICATION_LETTER_REFERENCE)
        self.assertEqual(audit_qs.first().payload, {
            "old_ref_number": new_ref,
            "new_ref_number": update_ref
        })

        # Update ref with no reference
        data = {
            "reference_number_on_information_form": "",
            "have_you_been_informed": "yes"
        }
        response = self.client.put(url, data, **self.exporter_headers)

        # Check update
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(audit_qs.count(), 4)
        self.assertEqual(AuditType(audit_qs.first().verb),
                         AuditType.UPDATE_APPLICATION_LETTER_REFERENCE)
        self.assertEqual(audit_qs.first().payload, {
            "old_ref_number": update_ref,
            "new_ref_number": "no reference"
        })

        # Remove ref
        data = {
            "reference_number_on_information_form": "",
            "have_you_been_informed": "no"
        }
        response = self.client.put(url, data, **self.exporter_headers)

        # Check update
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(audit_qs.count(), 5)
        self.assertEqual(AuditType(audit_qs.first().verb),
                         AuditType.REMOVED_APPLICATION_LETTER_REFERENCE)
        self.assertEqual(audit_qs.first().payload,
                         {"old_ref_number": "no reference"})
class CountriesOnDraftApplicationTests(DataTestClient):

    COUNTRIES_COUNT = 10

    def setUp(self):
        super().setUp()
        self.draft = self.create_draft_open_application(self.organisation)

        self.url = reverse("applications:countries",
                           kwargs={"pk": self.draft.id})
        self.data = {
            "countries":
            Country.objects.all()[:self.COUNTRIES_COUNT].values_list("id",
                                                                     flat=True)
        }

    def test_add_countries_to_a_draft_success(self):
        response = self.client.post(self.url, self.data,
                                    **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        response = self.client.get(self.url, **self.exporter_headers).json()
        self.assertEqual(len(response["countries"]), self.COUNTRIES_COUNT)

    def test_add_no_countries_to_a_draft_failure(self):
        data = {"countries": []}

        response = self.client.post(self.url, data, **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_add_countries_to_a_submitted_application_failure(self):
        self.submit_application(self.draft)
        countries_on_app_before = CountryOnApplication.objects.filter(
            application=self.draft).count()

        response = self.client.post(self.url, self.data,
                                    **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            CountryOnApplication.objects.filter(
                application=self.draft).count(),
            countries_on_app_before,
        )

    def test_remove_countries_from_a_submitted_application_success(self):
        CountryOnApplication(application=self.draft,
                             country=get_country("US")).save()
        self.submit_application(self.draft)
        countries_on_app_before = CountryOnApplication.objects.filter(
            application=self.draft).count()
        data = {"countries": [get_country("FR").pk]}

        response = self.client.post(self.url, data, **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(
            CountryOnApplication.objects.filter(
                application=self.draft).count(),
            countries_on_app_before - 1,
        )

    def test_add_countries_to_a_draft_standard_application_failure(self):
        std_draft = self.create_draft_standard_application(self.organisation)
        pre_test_country_count = CountryOnApplication.objects.all().count()

        url = reverse("applications:countries", kwargs={"pk": std_draft.id})

        response = self.client.post(url, self.data, **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(CountryOnApplication.objects.all().count(),
                         pre_test_country_count)

    def test_add_countries_to_a_draft_failure(self):
        """ Test failure in adding a country that does not exist. """
        data = {"countries": ["1234"]}

        response = self.client.post(self.url, data, **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        response = self.client.get(self.url, **self.exporter_headers).json()
        self.assertEqual(len(response["countries"]), 1)

    def test_add_countries_to_another_orgs_draft_failure(self):
        """
        Ensure that a user cannot add countries to another organisation's draft
        """
        organisation_2, _ = self.create_organisation_with_exporter_user()
        self.draft = self.create_draft_open_application(organisation_2)
        self.url = reverse("applications:countries",
                           kwargs={"pk": self.draft.id})

        response = self.client.post(self.url, self.data,
                                    **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

        response = self.client.get(self.url, **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    @parameterized.expand(get_case_statuses(read_only=True))
    def test_add_countries_to_application_in_read_only_status_failure(
            self, read_only_status):
        application = self.create_draft_open_application(self.organisation)
        application.status = get_case_status_by_status(read_only_status)
        application.save()

        url = reverse("applications:countries", kwargs={"pk": application.id})
        response = self.client.post(url, self.data, **self.exporter_headers)

        # Default Open application already has a country added
        self.assertEqual(application.application_countries.count(), 1)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @parameterized.expand([
        CaseStatusEnum.RESUBMITTED,
        CaseStatusEnum.INITIAL_CHECKS,
        CaseStatusEnum.SUBMITTED,
    ])
    def test_add_countries_to_application_in_editable_status_failure(
            self, editable_status):
        """ Test failure in adding a country to an application in a minor editable status. Major editing
         status of APPLICANT_EDITING is removed from the case status list. """
        application = self.create_draft_open_application(self.organisation)
        application.status = get_case_status_by_status(editable_status)
        application.save()

        url = reverse("applications:countries", kwargs={"pk": application.id})
        response = self.client.post(url, self.data, **self.exporter_headers)

        # Default Open application already has a country added
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(application.application_countries.count(), 1)

    @parameterized.expand(get_case_statuses(read_only=False))
    def test_remove_countries_to_application_in_editable_status_success(
            self, editable_status):
        add_second_country_data = {
            "countries":
            Country.objects.filter(id__in=("GA", "FR")).values_list("id",
                                                                    flat=True)
        }

        delete_country_data = {
            "countries":
            Country.objects.filter(id="GA").values_list("id", flat=True)
        }

        application = self.create_draft_open_application(self.organisation)
        # Add second country, as cannot delete last remaining country
        url = reverse("applications:countries", kwargs={"pk": application.id})
        self.client.post(url, add_second_country_data, **self.exporter_headers)
        application.status = get_case_status_by_status(editable_status)
        application.save()

        response = self.client.post(url, delete_country_data,
                                    **self.exporter_headers)

        # Assert 'FR' country removed and 'GA' country remains
        self.assertEqual(application.application_countries.count(), 1)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(application.application_countries.first().country.id,
                         "GA")
Exemple #8
0
def add_sites_to_application(user: ExporterUser, new_sites: Union[QuerySet,
                                                                  List[Site]],
                             application: BaseApplication):
    """
    Add sites to an application, handle validation and audit
    """
    sites_on_application = SiteOnApplication.objects.filter(
        application=application)

    if not new_sites:
        raise ValidationError({"sites": ["Select at least one site"]})

    # Users don't specify their goods locations if they've already departed
    if getattr(application, "have_goods_departed", False):
        raise ValidationError(
            {"sites": [Applications.Generic.GOODS_ALREADY_DEPARTED]})

    # Sites can't be set if the case is in a read only state
    if application.status.status in get_case_statuses(read_only=True):
        raise ValidationError({
            "sites":
            [f"Application status {application.status.status} is read-only"]
        })

    # Transhipment and Trade Control applications can't have sites based in certain countries
    if application.case_type.id in [
            *CaseTypeEnum.trade_control_case_type_ids(), CaseTypeEnum.SITL.id
    ]:
        banned_sites = new_sites.filter(
            address__country_id__in=
            TRANSHIPMENT_AND_TRADE_CONTROL_BANNED_COUNTRIES).values_list(
                "address__country_id", flat=True)

        if banned_sites:
            raise ValidationError({
                "sites": [
                    ExternalLocations.Errors.COUNTRY_ON_APPLICATION %
                    (", ".join(banned_sites), application.case_type.reference)
                ]
            })

    # It's possible for users to modify sites as long as sites they add are in countries
    # already on the application
    if not application.is_major_editable():
        old_countries = sites_on_application.values_list(
            "site__address__country")
        difference = new_sites.exclude(address__country__in=old_countries)

        if difference:
            raise ValidationError({
                "sites":
                ["Sites have to be in the same country on minor edits"]
            })

    removed_sites_on_application = sites_on_application.exclude(
        site__id__in=new_sites)
    added_sites = new_sites.exclude(
        id__in=sites_on_application.values_list("site__id", flat=True))
    removed_locations = ExternalLocationOnApplication.objects.filter(
        application=application)

    _set_activity(
        user=user,
        application=application,
        removed_locations=removed_locations,
        removed_sites=removed_sites_on_application,
        added_sites=added_sites,
    )

    # Check if site has been removed and if it is no longer used on other applications set "is_used_on_application" to False
    # Only do this for minor/major edits
    if application.status.status != CaseStatusEnum.DRAFT:
        removed_site_ids = removed_sites_on_application.values_list("site_id",
                                                                    flat=True)
        if removed_site_ids:
            sites_still_on_other_applications = (
                SiteOnApplication.objects.exclude(
                    application=application).exclude(
                        application__status__status="draft").filter(
                            site__id__in=removed_site_ids))
            removed_sites_no_longer_on_other_applications = removed_sites_on_application.exclude(
                site__id__in=sites_still_on_other_applications.values_list(
                    "site_id", flat=True))

            removed_sites = Site.objects.filter(
                id__in=removed_sites_no_longer_on_other_applications.
                values_list("site_id", flat=True))
            removed_sites.update(is_used_on_application=False)

        # Set "is_used_on_application" to True for sites that have been added
        added_sites.update(is_used_on_application=True)

    # Save the new sites
    SiteOnApplication.objects.bulk_create([
        SiteOnApplication(site=site, application=application)
        for site in added_sites
    ])

    removed_sites_on_application.delete()
    removed_locations.delete()

    # Update application activity
    application.activity = TRADING
    application.save()
class SitesOnDraftTests(DataTestClient):
    def setUp(self):
        super().setUp()
        self.primary_site = self.organisation.primary_site
        self.application = self.create_draft_standard_application(
            self.organisation)

        self.url = reverse("applications:application_sites",
                           kwargs={"pk": self.application.id})

    def test_add_site_to_a_draft(self):
        data = {"sites": [self.primary_site.id]}

        response = self.client.post(self.url, data, **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.application = StandardApplication.objects.get(
            pk=self.application.id)
        self.assertEqual(self.application.activity, "Trading")

        url = reverse("applications:application_sites",
                      kwargs={"pk": self.application.id})
        response = self.client.get(url, **self.exporter_headers).json()
        self.assertEqual(len(response["sites"]), 1)

    def test_add_multiple_sites_to_a_draft(self):
        site_2 = SiteFactory(organisation=self.organisation)

        data = {"sites": [self.primary_site.id, site_2.id]}

        response = self.client.post(self.url, data, **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.application = StandardApplication.objects.get(
            pk=self.application.id)
        self.assertEqual(self.application.activity, "Trading")

        url = reverse("applications:application_sites",
                      kwargs={"pk": self.application.id})
        response = self.client.get(url, **self.exporter_headers)
        response_data = response.json()
        self.assertEqual(len(response_data["sites"]), 2)

    def test_user_cannot_add_another_organisations_site_to_a_draft(self):
        org2, _ = self.create_organisation_with_exporter_user()
        site_org2 = org2.primary_site

        data = {"sites": [site_org2.id]}

        url = reverse("applications:application_sites",
                      kwargs={"pk": self.application.id})
        response = self.client.post(url, data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            SiteOnApplication.objects.filter(
                application=self.application).count(), 1)

    def test_add_a_site_to_a_draft_deletes_existing_sites(self):
        url = reverse("applications:application_sites",
                      kwargs={"pk": self.application.id})
        response = self.client.get(url, **self.exporter_headers).json()

        site_id = response["sites"][0]["id"]
        self.assertEqual(len(response["sites"]), 1)

        # Post a new site to the draft, with the expectation that the existing site is deleted
        data = {"sites": [str(SiteFactory(organisation=self.organisation).id)]}

        url = reverse("applications:application_sites",
                      kwargs={"pk": self.application.id})
        response = self.client.post(url, data, **self.exporter_headers)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # Check that the new site has been added, and the old one deleted
        url = reverse("applications:application_sites",
                      kwargs={"pk": self.application.id})
        response = self.client.get(url, **self.exporter_headers).json()
        self.assertEqual(len(response["sites"]), 1)
        self.assertNotEqual(response["sites"][0]["id"], site_id)

    def test_adding_site_to_draft_deletes_external_locations(self):
        draft = self.application
        external_location = self.create_external_location(
            "test", self.organisation)
        url = reverse("applications:application_sites",
                      kwargs={"pk": self.application.id})
        data = {"external_locations": [external_location.id]}
        self.client.post(url, data, **self.exporter_headers)
        data = {"sites": [self.primary_site.id]}
        self.client.post(self.url, data, **self.exporter_headers)
        self.assertEqual(
            SiteOnApplication.objects.filter(application=draft).count(), 1)
        self.assertEqual(
            ExternalLocationOnApplication.objects.filter(
                application=draft).count(), 0)

    def test_add_site_to_a_submitted_application_success(self):
        site_to_add = SiteFactory(organisation=self.organisation)
        data = {"sites": [self.primary_site.id, site_to_add.id]}
        self.submit_application(self.application)

        response = self.client.post(self.url, data, **self.exporter_headers)
        self.application.refresh_from_db()

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(
            SiteOnApplication.objects.filter(
                application=self.application).count(), 2)

    def test_add_site_to_a_submitted_application_failure(self):
        """
        Cannot add additional site to a submitted application unless the additional site
        is located in a country that is already on the application
        """
        site_to_add = SiteFactory(organisation=self.organisation,
                                  address__country=get_country("PL"))
        data = {"sites": [self.primary_site.id, site_to_add.id]}
        self.submit_application(self.application)

        response = self.client.post(self.url, data, **self.exporter_headers)
        self.application.refresh_from_db()

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            SiteOnApplication.objects.filter(
                application=self.application).count(), 1)

    def test_adding_site_to_submitted_application_when_external_locations_already_on_application_failure(
        self, ):
        SiteOnApplication.objects.filter(application=self.application).delete()
        external_location = self.create_external_location(
            "storage facility", self.organisation)
        ExternalLocationOnApplication(
            application=self.application,
            external_location=external_location).save()

        self.submit_application(self.application)
        data = {"sites": [self.primary_site.id]}

        response = self.client.post(self.url, data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            SiteOnApplication.objects.filter(
                application=self.application).count(), 0)
        self.assertEqual(
            ExternalLocationOnApplication.objects.filter(
                application=self.application).count(),
            1,
        )

    @parameterized.expand(get_case_statuses(read_only=True))
    def test_add_site_to_application_in_read_only_status_failure(
            self, read_only_status):
        data = {"sites": [self.primary_site.id]}

        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(read_only_status)
        application.save()

        url = reverse("applications:application_sites",
                      kwargs={"pk": application.id})
        response = self.client.post(url, data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(application.application_sites.count(), 1)

    @parameterized.expand(get_case_statuses(read_only=False))
    def test_add_site_to_application_in_editable_status_success(
            self, editable_status):
        data = {"sites": [self.primary_site.id]}

        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(editable_status)
        application.save()

        url = reverse("applications:application_sites",
                      kwargs={"pk": application.id})
        response = self.client.post(url, data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(application.application_sites.count(), 1)

    @parameterized.expand([
        (CaseTypeEnum.SITL.id,
         DataTestClient.create_draft_standard_application),
        (CaseTypeEnum.SICL.id,
         DataTestClient.create_draft_standard_application),
        (CaseTypeEnum.OICL.id, DataTestClient.create_draft_open_application),
    ])
    def test_add_gb_sites_failure(self, case_type_id, create_function):
        """
        Assert that it isn't possible to add sites based in GB to transhipment & trade control applications
        """
        site = SiteFactory(organisation=self.organisation)
        transhipment = create_function(self,
                                       organisation=self.organisation,
                                       case_type_id=case_type_id)

        url = reverse("applications:application_sites",
                      kwargs={"pk": transhipment.id})
        data = {"sites": [site.id]}
        response = self.client.post(url, data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(transhipment.application_sites.count(), 1)
        self.assertEqual(
            response.json()["errors"]["sites"][0],
            ExternalLocations.Errors.COUNTRY_ON_APPLICATION %
            (site.address.country.id, transhipment.case_type.reference),
        )
        self.assertNotEqual(transhipment.application_sites.get().site.name,
                            site.name)
class DraftDocumentTests(DataTestClient):
    def setUp(self):
        super().setUp()

        self.draft = self.create_draft_standard_application(self.organisation, "Draft")
        self.url_draft = reverse("applications:application_documents", kwargs={"pk": self.draft.id})
        self.test_filename = "dog.jpg"

        self.editable_case_statuses = get_case_statuses(read_only=False)
        self.read_only_case_statuses = get_case_statuses(read_only=True)

        self.data = {
            "name": self.test_filename,
            "s3_key": self.test_filename,
            "size": 476,
            "description": "banana cake 1",
        }

        self.data2 = {
            "name": self.test_filename + "2",
            "s3_key": self.test_filename,
            "size": 476,
            "description": "banana cake 2",
        }

    @mock.patch("api.documents.tasks.scan_document_for_viruses.now")
    def test_upload_document_on_unsubmitted_application(self, mock_prepare_doc):
        """ Test success in adding a document to an unsubmitted application. """
        self.client.post(self.url_draft, data=self.data, **self.exporter_headers)

        response = self.client.get(self.url_draft, **self.exporter_headers)
        response_data = [
            {
                "name": document["name"],
                "s3_key": document["s3_key"],
                "size": document["size"],
                "description": document["description"],
            }
            for document in response.json()["documents"]
        ]

        self.assertEqual(len(response_data), 2)
        self.assertTrue(self.data in response_data)

    @mock.patch("api.documents.tasks.scan_document_for_viruses.now")
    def test_upload_multiple_documents_on_unsubmitted_application(self, mock_prepare_doc):
        """ Test success in adding multiple documents to an unsubmitted application. """
        data = [self.data, self.data2]
        self.client.post(self.url_draft, data=self.data, **self.exporter_headers)
        self.client.post(self.url_draft, data=self.data2, **self.exporter_headers)

        response = self.client.get(self.url_draft, **self.exporter_headers)
        response_data = [
            {
                "name": document["name"],
                "s3_key": document["s3_key"],
                "size": document["size"],
                "description": document["description"],
            }
            for document in response.json()["documents"]
        ]

        self.assertEqual(len(response_data), 3)
        for document in data:
            self.assertTrue(document in response_data)

    @mock.patch("api.documents.tasks.scan_document_for_viruses.now")
    @mock.patch("api.documents.models.Document.delete_s3")
    def test_delete_individual_draft_document(self, mock_delete_s3, mock_prepare_doc):
        """ Test success in deleting a document from an unsubmitted application. """
        self.client.post(self.url_draft, data=self.data, **self.exporter_headers)
        response = self.client.get(self.url_draft, **self.exporter_headers)

        url = reverse(
            "applications:application_document",
            kwargs={"pk": self.draft.id, "doc_pk": response.json()["documents"][0]["id"],},
        )

        self.client.delete(url, **self.exporter_headers)
        mock_delete_s3.assert_called_once()

        response = self.client.get(self.url_draft, **self.exporter_headers)
        self.assertEqual(len(response.json()["documents"]), 1)

    def test_get_individual_draft_document(self):
        """ Test success in downloading a document from an unsubmitted application. """
        application_document = self.draft.applicationdocument_set.first()
        url = reverse(
            "applications:application_document", kwargs={"pk": self.draft.id, "doc_pk": application_document.id},
        )

        response = self.client.get(url, **self.exporter_headers)
        self.assertEqual(response.json()["document"]["name"], application_document.name)
        self.assertEqual(response.json()["document"]["s3_key"], application_document.s3_key)
        self.assertEqual(response.json()["document"]["size"], application_document.size)

    @parameterized.expand(get_case_statuses(read_only=False))
    @mock.patch("api.documents.tasks.scan_document_for_viruses.now")
    def test_add_document_when_application_in_editable_state_success(self, editable_status, mock_prepare_doc):
        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(editable_status)
        application.save()

        url = reverse("applications:application_documents", kwargs={"pk": application.id})
        response = self.client.post(url, data=self.data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(application.applicationdocument_set.count(), 2)

    @parameterized.expand(get_case_statuses(read_only=False))
    @mock.patch("api.documents.tasks.scan_document_for_viruses.now")
    @mock.patch("api.documents.models.Document.delete_s3")
    def test_delete_document_when_application_in_editable_state_success(
        self, editable_status, mock_delete_s3, mock_prepare_doc
    ):
        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(editable_status)
        application.save()

        url = reverse(
            "applications:application_document",
            kwargs={"pk": application.id, "doc_pk": application.applicationdocument_set.first().id,},
        )

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(application.applicationdocument_set.count(), 0)

    @parameterized.expand(get_case_statuses(read_only=True))
    def test_add_document_when_application_in_read_only_state_failure(self, read_only_status):
        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(read_only_status)
        application.save()

        url = reverse("applications:application_documents", kwargs={"pk": application.id})
        response = self.client.post(url, data=self.data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(application.applicationdocument_set.count(), 1)

    @parameterized.expand(get_case_statuses(read_only=True))
    @mock.patch("api.documents.tasks.scan_document_for_viruses.now")
    @mock.patch("api.documents.models.Document.delete_s3")
    def test_delete_document_when_application_in_read_only_state_failure(
        self, read_only_status, mock_delete_s3, mock_prepare_doc
    ):
        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(read_only_status)
        application.save()

        url = reverse("applications:application_document", kwargs={"pk": application.id, "doc_pk": uuid.uuid4()},)
        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(application.applicationdocument_set.count(), 1)
Exemple #11
0
    def post(self, request, pk):
        """ Add countries to an open licence application. """
        application = get_application(pk)
        if application.goodstype_category in GoodsTypeCategory.IMMUTABLE_DESTINATIONS:
            raise BadRequestError(
                detail=
                "You cannot do this action for this type of open application")
        data = request.data
        country_ids = data.get("countries")

        # Validate that there are countries
        if not country_ids:
            return JsonResponse(
                data={
                    "errors": {
                        "countries": ["You have to pick at least one country"]
                    }
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        if not is_case_status_draft(
                application.status.status
        ) and application.status.status in get_case_statuses(read_only=True):
            return JsonResponse(
                data={
                    "errors": {
                        "external_locations": [
                            f"Application status {application.status.status} is read-only."
                        ]
                    }
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        else:
            previous_countries = CountryOnApplication.objects.filter(
                application=application)
            previous_country_ids = [
                str(previous_country_id) for previous_country_id in
                previous_countries.values_list("country__id", flat=True)
            ]
            new_countries = []

            if (is_case_status_draft(application.status.status)
                    or application.status.status
                    == CaseStatusEnum.APPLICANT_EDITING):
                new_countries = [
                    get_country(country_id) for country_id in country_ids
                    if country_id not in previous_country_ids
                ]
            else:
                for country_id in country_ids:
                    if previous_country_ids and country_id not in previous_country_ids:
                        return JsonResponse(
                            data={
                                "errors": {
                                    "countries": [
                                        "Go back and change your answer from ‘Change a site, or delete "
                                        "a good, third party or country’ to ’Change something else’."
                                    ]
                                }
                            },
                            status=status.HTTP_400_BAD_REQUEST,
                        )

            # Get countries to be removed
            removed_country_ids = list(
                set(previous_country_ids) - set(country_ids))
            removed_countries = previous_countries.filter(
                country__id__in=removed_country_ids)

            # Append new Countries to application (only in unsubmitted/applicant editing statuses)
            CountryOnApplication.objects.bulk_create([
                CountryOnApplication(country=country, application=application)
                for country in new_countries
            ])

            countries_data = CountrySerializer(new_countries, many=True).data

            case = Case.objects.get(id=application.id)

            if new_countries:
                audit_trail_service.create(
                    actor=request.user,
                    verb=AuditType.ADD_COUNTRIES_TO_APPLICATION,
                    target=case,
                    payload={
                        "countries":
                        [country.name for country in new_countries]
                    },
                )

            if removed_countries:
                audit_trail_service.create(
                    actor=request.user,
                    verb=AuditType.REMOVED_COUNTRIES_FROM_APPLICATION,
                    target=case,
                    payload={
                        "countries": [
                            country.country.name
                            for country in removed_countries
                        ]
                    },
                )

            removed_countries.delete()
            return JsonResponse(data={"countries": countries_data},
                                status=status.HTTP_201_CREATED)
class ExternalLocationsOnApplicationTests(DataTestClient):
    def setUp(self):
        super().setUp()
        self.application = self.create_draft_standard_application(
            self.organisation)
        self.external_location = self.create_external_location(
            "storage facility", self.organisation)
        self.url = reverse(
            "applications:application_external_locations",
            kwargs={"pk": self.application.id},
        )

    def test_add_external_location_to_an_unsubmitted_application(self):
        SiteOnApplication.objects.filter(application=self.application).delete()
        data = {"external_locations": [self.external_location.id]}

        response = self.client.post(self.url, data, **self.exporter_headers)
        self.application.refresh_from_db()

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(
            ExternalLocationOnApplication.objects.filter(
                application=self.application).count(),
            1,
        )
        self.assertEqual(self.application.activity, "Brokering")

    def test_adding_external_location_to_unsubmitted_application_removes_sites(
            self):
        data = {"external_locations": [self.external_location.id]}
        self.client.post(self.url, data, **self.exporter_headers)
        self.assertEqual(
            SiteOnApplication.objects.filter(
                application=self.application).count(), 0)
        self.assertEqual(
            ExternalLocationOnApplication.objects.filter(
                application=self.application).count(),
            1,
        )

    def test_add_external_location_to_a_submitted_application_success(self):
        SiteOnApplication.objects.filter(application=self.application).delete()
        ExternalLocationOnApplication(
            application=self.application,
            external_location=self.external_location).save()
        external_location_to_add = self.create_external_location(
            "storage facility 2", self.organisation)
        data = {
            "external_locations": [
                self.external_location.id,
                external_location_to_add.id,
            ]
        }
        self.submit_application(self.application)

        response = self.client.post(self.url, data, **self.exporter_headers)
        self.application.refresh_from_db()

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(
            ExternalLocationOnApplication.objects.filter(
                application=self.application).count(),
            2,
        )

    def test_add_external_location_to_a_submitted_application_failure(self):
        """
        Cannot add additional external locations to a submitted application unless the additional external location
        is located in a country that is already on the application
        """
        SiteOnApplication.objects.filter(application=self.application).delete()
        ExternalLocationOnApplication(
            application=self.application,
            external_location=self.external_location).save()
        external_location_to_add = self.create_external_location(
            "storage facility 2", self.organisation, "US")
        data = {
            "external_locations": [
                self.external_location.id,
                external_location_to_add.id,
            ]
        }
        self.submit_application(self.application)

        response = self.client.post(self.url, data, **self.exporter_headers)
        self.application.refresh_from_db()

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            ExternalLocationOnApplication.objects.filter(
                application=self.application).count(),
            1,
        )

    def test_adding_external_location_to_submitted_application_when_sites_already_on_application_failure(
        self, ):
        self.submit_application(self.application)
        data = {"external_locations": [self.external_location.id]}

        response = self.client.post(self.url, data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            SiteOnApplication.objects.filter(
                application=self.application).count(), 1)
        self.assertEqual(
            ExternalLocationOnApplication.objects.filter(
                application=self.application).count(),
            0,
        )

    def test_adding_no_external_locations_to_application_failure(self):
        data = {"external_locations": []}

        response = self.client.post(self.url, data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_removing_external_locations_success(self):
        url = reverse(
            "applications:application_remove_external_location",
            kwargs={
                "pk": self.application.id,
                "ext_loc_pk": self.external_location.id
            },
        )

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

    def test_removing_external_locations_failure(self):
        """ Test failure in removing an external location on a submitted, editable application that only has 1 external
        location added.
        """
        ExternalLocationOnApplication(
            application=self.application,
            external_location=self.external_location).save()
        self.submit_application(self.application)
        url = reverse(
            "applications:application_remove_external_location",
            kwargs={
                "pk": self.application.id,
                "ext_loc_pk": self.external_location.id
            },
        )

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @parameterized.expand(get_case_statuses(read_only=True))
    def test_remove_external_locations_from_application_in_read_only_status_failure(
            self, read_only_status):
        ExternalLocationOnApplication(
            application=self.application,
            external_location=self.external_location).save()
        url = reverse(
            "applications:application_remove_external_location",
            kwargs={
                "pk": self.application.id,
                "ext_loc_pk": self.external_location.id
            },
        )

        self.application.status = get_case_status_by_status(read_only_status)
        self.application.save()

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(self.application.external_application_sites.count(),
                         1)

    @parameterized.expand(get_case_statuses(read_only=False))
    def test_remove_external_locations_from_application_in_editable_status_success(
            self, editable_status):
        """ Test success in removing an external location from an application in an editable status that has
        more than one external location added.
        """
        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(editable_status)
        application.save()

        ExternalLocationOnApplication(
            application=application,
            external_location=self.external_location).save()
        second_external_location = self.create_external_location(
            "storage facility", self.organisation)
        ExternalLocationOnApplication(
            application=application,
            external_location=second_external_location).save()

        url = reverse(
            "applications:application_remove_external_location",
            kwargs={
                "pk": application.id,
                "ext_loc_pk": self.external_location.id
            },
        )

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(application.external_application_sites.count(), 1)

    @parameterized.expand(get_case_statuses(read_only=False))
    def test_add_external_locations_to_application_in_editable_status_success(
            self, editable_status):
        data = {"external_locations": [self.external_location.id]}

        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(editable_status)
        application.save()
        SiteOnApplication.objects.filter(application=application).delete()

        url = reverse("applications:application_external_locations",
                      kwargs={"pk": application.id})
        response = self.client.post(url, data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(application.external_application_sites.count(), 1)

    @parameterized.expand(get_case_statuses(read_only=True))
    def test_add_external_locations_to_application_in_read_only_status_failure(
            self, read_only_status):
        data = {"external_locations": [self.external_location.id]}

        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(read_only_status)
        application.save()

        url = reverse("applications:application_external_locations",
                      kwargs={"pk": application.id})
        response = self.client.post(url, data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(application.external_application_sites.count(), 0)

    @parameterized.expand([
        (CaseTypeEnum.SITL.id,
         DataTestClient.create_draft_standard_application),
        (CaseTypeEnum.SICL.id,
         DataTestClient.create_draft_standard_application),
        (CaseTypeEnum.OICL.id, DataTestClient.create_draft_open_application),
    ])
    def test_add_gb_external_locations_failure(self, case_type_id,
                                               create_function):
        """
        Assert that it isn't possible to add external locations based in GB to transhipment & trade control applications
        """
        external_location = self.create_external_location(
            "Hard to Find", self.organisation, "GB")
        transhipment = create_function(self,
                                       organisation=self.organisation,
                                       case_type_id=case_type_id)

        url = reverse("applications:application_external_locations",
                      kwargs={"pk": transhipment.id})
        data = {"external_locations": [external_location.id]}
        response = self.client.post(url, data, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(transhipment.application_sites.count(), 1)
        self.assertEqual(
            response.json()["errors"]["external_locations"][0],
            ExternalLocations.Errors.COUNTRY_ON_APPLICATION %
            (external_location.country.id, transhipment.case_type.reference),
        )
Exemple #13
0
class RemovingGoodsOffDraftsTests(DataTestClient):
    def test_remove_a_good_from_draft_success(self):
        """
        Given a standard application with a good
        And the good's status is SUBMITTED
        And there are no other applications with this good attached
        When I attempt to delete the good from the application
        Then the good_on_application is deleted
        And the good status is changed to DRAFT
        """
        draft = self.create_draft_standard_application(self.organisation)
        self.submit_application(
            draft
        )  # This will submit the application and set the good status to SUBMITTED

        url = reverse(
            "applications:good_on_application",
            kwargs={"obj_pk": self.good_on_application.id},
        )

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            GoodOnApplication.objects.filter(application=draft).count(), 0)
        self.assertEqual(self.good_on_application.good.status,
                         GoodStatus.DRAFT)

    def test_remove_a_good_from_draft_success_when_good_is_verified(self):
        """
        Given a standard application with a good
        And the good's status is VERIFIED
        And there are no other applications with this good attached
        When I attempt to delete the good from the application
        Then the good_on_application is deleted
        And the good status is not changed
        """
        draft = self.create_draft_standard_application(self.organisation)
        self.good_on_application.good.status = GoodStatus.VERIFIED
        self.good_on_application.good.save()

        url = reverse(
            "applications:good_on_application",
            kwargs={"obj_pk": self.good_on_application.id},
        )

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            GoodOnApplication.objects.filter(application=draft).count(), 0)
        self.assertEqual(self.good_on_application.good.status,
                         GoodStatus.VERIFIED)

    def test_remove_a_good_from_application_success_when_good_is_on_multiple_applications(
        self, ):
        """
        Given a standard application with a good
        And the good's status is VERIFIED
        And there are no other applications with this good attached
        When I attempt to delete the good from the application
        Then the good_on_application is deleted
        And the good status is not changed
        """
        application1 = self.create_draft_standard_application(
            self.organisation)
        self.submit_application(application1)
        good_on_application1 = GoodOnApplication.objects.get(
            application=application1)

        application2 = self.create_draft_standard_application(
            self.organisation)
        GoodOnApplication.objects.get(application=application2).delete()

        good_on_application2 = GoodOnApplication(
            good=good_on_application1.good,
            application=application2,
            quantity=10,
            unit=Units.NAR,
            value=500,
        )
        good_on_application2.save()

        url = reverse("applications:good_on_application",
                      kwargs={"obj_pk": good_on_application1.id})

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            GoodOnApplication.objects.filter(application=application1).count(),
            0)
        self.assertEqual(
            GoodOnApplication.objects.filter(application=application2).count(),
            1)
        self.assertEqual(
            Good.objects.get(pk=good_on_application2.good.pk).status,
            GoodStatus.SUBMITTED,
        )

    def test_remove_a_good_that_does_not_exist_from_draft(self):
        """
        Given a standard application with a good
        When I attempt to delete a good that doesn't exist
        Then the delete operation returns a not found response
        And no goods are deleted
        """
        draft = self.create_draft_standard_application(self.organisation)

        url = reverse(
            "applications:good_on_application",
            kwargs={"obj_pk": "7070dc05-0afa-482c-b4f7-ae0a8943e53c"},
        )  # Imaginary UUID

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
        self.assertEqual(
            GoodOnApplication.objects.filter(application=draft).count(), 1)

    def test_remove_a_good_from_draft_as_gov_user_failure(self):
        draft = self.create_draft_standard_application(self.organisation)

        url = reverse(
            "applications:good_on_application",
            kwargs={"obj_pk": self.good_on_application.id},
        )

        response = self.client.delete(url, **self.gov_headers)

        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
        self.assertEqual(
            GoodOnApplication.objects.filter(application=draft).count(), 1)

    def test_remove_goods_from_application_not_in_users_organisation_failure(
            self):
        self.create_draft_standard_application(self.organisation)
        url = reverse(
            "applications:good_on_application",
            kwargs={"obj_pk": self.good_on_application.id},
        )

        other_organisation, _ = self.create_organisation_with_exporter_user()
        permission_denied_user = UserOrganisationRelationship.objects.get(
            organisation=other_organisation).user
        permission_denied_user_headers = {
            "HTTP_EXPORTER_USER_TOKEN":
            user_to_token(permission_denied_user.baseuser_ptr),
            "HTTP_ORGANISATION_ID":
            str(other_organisation.id),
        }

        response = self.client.delete(url, **permission_denied_user_headers)

        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    @parameterized.expand(get_case_statuses(read_only=False))
    def test_delete_good_from_application_in_an_editable_status_success(
            self, editable_status):
        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(editable_status)
        application.save()
        url = reverse(
            "applications:good_on_application",
            kwargs={"obj_pk": self.good_on_application.id},
        )

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            GoodOnApplication.objects.filter(application=application).count(),
            0)

    @parameterized.expand(get_case_statuses(read_only=True))
    def test_delete_good_from_application_in_read_only_status_failure(
            self, read_only_status):
        application = self.create_draft_standard_application(self.organisation)
        application.status = get_case_status_by_status(read_only_status)
        application.save()
        url = reverse(
            "applications:good_on_application",
            kwargs={"obj_pk": self.good_on_application.id},
        )

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            GoodOnApplication.objects.filter(application=application).count(),
            1)

    def test_delete_firearm_good_from_application_removes_flag_from_case_success(
            self):
        application = self.create_draft_standard_application(self.organisation)
        goa = application.goods.first()
        firearm_derails = FirearmGoodDetails.objects.create(
            year_of_manufacture=timezone.now().year,
            has_identification_markings=True,
            is_covered_by_firearm_act_section_one_two_or_five=True,
        )
        goa.good.firearm_derails = firearm_derails
        goa.good.save()
        application.flags.add(SystemFlags.FIREARMS_ID)
        application.save()
        url = reverse("applications:good_on_application",
                      kwargs={"obj_pk": goa.id})

        response = self.client.delete(url, **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            GoodOnApplication.objects.filter(application=application).count(),
            0)
        self.assertFalse(
            application.flags.filter(id=SystemFlags.FIREARMS_ID).exists())