Exemple #1
0
    def put(self, request, pk):
        application = get_application(pk)
        if application.goodstype_category in GoodsTypeCategory.IMMUTABLE_GOODS:
            raise BadRequestError(
                detail=
                "You cannot do this action for this type of open application")

        data = request.data

        serialized_data, errors = self.validate_data(data)

        if errors:
            return JsonResponse(data={"errors": errors},
                                status=status.HTTP_400_BAD_REQUEST)

        countries = data.get("countries")
        serialized_contract_types = serialized_data.get("contract_types")

        contract_types = [",".join(serialized_contract_types)]

        qs = CountryOnApplication.objects.filter(country__in=countries,
                                                 application=application)

        qs.update(contract_types=contract_types,
                  other_contract_type_text=serialized_data.get(
                      "other_contract_type_text"))

        [
            Flag.objects.get(name=ContractType.get_flag_name(
                contract_type)).countries_on_applications.set(qs)
            for contract_type in serialized_contract_types
        ]
        return JsonResponse(data={"countries_set": "success"},
                            status=status.HTTP_200_OK)
Exemple #2
0
 def post(self, request, pk):
     """
     Upload additional document onto an application
     """
     application = get_application(pk)
     return upload_application_document(application, request.data,
                                        request.user)
    def put(self, request, pk):
        """ Update an application instance with route of goods data. """

        application = get_application(pk)
        serializer = get_application_update_serializer(application)
        case = application.get_case()
        data = request.data.copy()

        serializer = serializer(application,
                                data=data,
                                context=get_request_user_organisation(request),
                                partial=True)
        if not serializer.is_valid():
            return JsonResponse(data={"errors": serializer.errors},
                                status=status.HTTP_400_BAD_REQUEST)

        previous_answer = application.is_shipped_waybill_or_lading
        new_answer = str_to_bool(data.get("is_shipped_waybill_or_lading"))

        if previous_answer != new_answer:
            self.add_audit_entry(request, case, "is shipped waybill or lading",
                                 previous_answer, new_answer)

        if not new_answer:
            previous_details = application.non_waybill_or_lading_route_details
            new_details = data.get("non_waybill_or_lading_route_details")

            if previous_details != new_details:
                self.add_audit_entry(request, case,
                                     "non_waybill_or_lading_route_details",
                                     previous_details, new_details)

        serializer.save()
        return JsonResponse(data={}, status=status.HTTP_200_OK)
Exemple #4
0
        def inner(request, *args, **kwargs):
            application_id = _get_application_id(request, kwargs)
            application = get_application(application_id)

            party_type = request.request.data.get("type")

            if application.case_type.sub_type == CaseTypeSubTypeEnum.OPEN and party_type:
                if (
                    application.goodstype_category == GoodsTypeCategory.MILITARY
                    and party_type == PartyType.ULTIMATE_END_USER
                ):
                    pass
                elif (
                    application.goodstype_category == GoodsTypeCategory.CRYPTOGRAPHIC
                    and party_type == PartyType.THIRD_PARTY
                ):
                    pass
                elif party_type == PartyType.END_USER:
                    pass
                else:
                    return JsonResponse(
                        data={"errors": ["This type of party can not be added to this type of open application"]},
                        status=status.HTTP_400_BAD_REQUEST,
                    )

            return func(request, *args, **kwargs)
Exemple #5
0
    def delete(self, request, pk, party_pk):
        """
        Removes a party from application.
        """
        application = get_application(pk)

        try:
            poa = application.active_parties.all().get(party__pk=party_pk)
        except PartyOnApplication.DoesNotExist:
            return HttpResponse(status=status.HTTP_404_NOT_FOUND)

        if not application.party_is_editable(poa.party):
            return JsonResponse(
                data={"errors": [strings.Applications.Generic.INVALID_OPERATION_FOR_READ_ONLY_CASE_ERROR]},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Delete party
        application.delete_party(poa)

        # Audit
        audit_trail_service.create(
            actor=request.user,
            verb=AuditType.REMOVE_PARTY,
            target=application.get_case(),
            payload={"party_type": poa.party.type.replace("_", " "), "party_name": poa.party.name,},
        )

        return JsonResponse(data={"party": PartySerializer(poa.party).data}, status=status.HTTP_200_OK)
Exemple #6
0
    def delete(self, request, pk, goodstype_pk):
        """
        Deletes a goodstype
        """
        application = get_application(pk)
        if (hasattr(application, "goodstype_category")
                and application.goodstype_category
                in GoodsTypeCategory.IMMUTABLE_GOODS):
            raise BadRequestError(
                detail=
                "You cannot do this action for this type of open application")
        goods_type = get_goods_type(goodstype_pk)
        if application.case_type.sub_type == CaseTypeSubTypeEnum.HMRC:
            delete_goods_type_document_if_exists(goods_type)
        goods_type.delete()

        audit_trail_service.create(
            actor=request.user,
            verb=AuditType.REMOVE_GOOD_TYPE_FROM_APPLICATION,
            action_object=goods_type,
            target=Case.objects.get(id=application.id),
            payload={"good_type_name": goods_type.description},
        )

        return JsonResponse(data={}, status=status.HTTP_200_OK)
    def get_queryset(self):
        request_data = dict(self.request.GET)
        # Assemble the supplied filters, ready to be used in querysets below
        params = {
            f"{key}__contains": value[0]
            for key, value in request_data.items()
            if key not in ["page", "party_type"]
        }
        # Rename country to country__name for filter
        if "country__contains" in params:
            params["country__name__contains"] = params.pop("country__contains")

        application_id = self.kwargs["pk"]
        application = get_application(application_id)

        uncopied_parties = self.get_uncopied_parties(application.organisation,
                                                     params)
        newest_copied_parties = self.get_newest_copied_parties(
            application.organisation, params)

        # Exclude the UK if end user on standard transhipment
        if application.case_type.id == CaseTypeEnum.SITL.id:
            if "end_user" in request_data["party_type"]:
                uncopied_parties = uncopied_parties.exclude(country__id="GB")
                newest_copied_parties = newest_copied_parties.exclude(
                    country__id="GB")

        return uncopied_parties.union(newest_copied_parties).order_by("name")
Exemple #8
0
    def post(self, request, pk):
        """
        Post a goodstype
        """
        application = get_application(pk)
        if (hasattr(application, "goodstype_category")
                and application.goodstype_category
                in GoodsTypeCategory.IMMUTABLE_GOODS):
            raise BadRequestError(
                detail=
                "You cannot do this action for this type of open application")
        request.data["application"] = application
        serializer = GoodsTypeSerializer(data=request.data)

        if serializer.is_valid(raise_exception=True):
            serializer.save()

            audit_trail_service.create(
                actor=request.user,
                verb=AuditType.ADD_GOOD_TYPE_TO_APPLICATION,
                action_object=serializer.instance,
                target=application.get_case(),
                payload={"good_type_name": serializer.instance.description},
            )

            return JsonResponse(data={"good": serializer.data},
                                status=status.HTTP_201_CREATED)
Exemple #9
0
    def post(self, request, pk):
        application = get_application(pk)
        sites = Site.objects.filter(
            organisation_id=get_request_user_organisation_id(request),
            id__in=request.data.get("sites", []))
        add_sites_to_application(request.user, sites, application)

        return JsonResponse(data={"sites": {}}, status=status.HTTP_201_CREATED)
Exemple #10
0
    def put(self, request, pk):
        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

        for good, countries in data.items():
            good = get_goods_type(good)

            # Validate that at least one country has been selected per good
            if not countries:
                return JsonResponse(
                    {"errors": "Select at least one country for each good"},
                    status=status.HTTP_400_BAD_REQUEST)

            # Validate that the countries given are valid countries
            if not Country.objects.filter(
                    pk__in=countries).count() == len(countries):
                return HttpResponse(status=status.HTTP_404_NOT_FOUND)

            initial_countries = list(good.countries.all())
            good.countries.set(countries)
            removed_countries = [
                country.name for country in initial_countries
                if country not in good.countries.all()
            ]
            added_countries = [
                country.name for country in good.countries.all()
                if country not in initial_countries
            ]

            if removed_countries:
                audit_trail_service.create(
                    actor=request.user,
                    verb=AuditType.REMOVED_COUNTRIES_FROM_GOOD,
                    action_object=good,
                    target=Case.objects.get(id=application.id),
                    payload={
                        "good_type_name": good.description,
                        "countries": ", ".join(removed_countries),
                    },
                )

            if added_countries:
                audit_trail_service.create(
                    actor=request.user,
                    verb=AuditType.ASSIGNED_COUNTRIES_TO_GOOD,
                    action_object=good,
                    target=Case.objects.get(id=application.id),
                    payload={
                        "good_type_name": good.description,
                        "countries": ", ".join(added_countries),
                    },
                )

        return JsonResponse(data=data, status=status.HTTP_200_OK)
    def put(self, request, pk):
        application = get_application(pk)
        serializer = get_application_end_use_details_update_serializer(application)
        serializer = serializer(application, data=request.data, partial=True)

        if not serializer.is_valid():
            return JsonResponse(data={"errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)

        save_and_audit_end_use_details(request, application, serializer)
        return JsonResponse(data=serializer.validated_data, status=status.HTTP_200_OK)
Exemple #12
0
 def get_export_type(self, instance):
     instance = get_application(instance.pk)
     if hasattr(instance, "export_type"):
         return {
             "key":
             instance.export_type,
             "value":
             get_value_from_enum(instance.export_type,
                                 ApplicationExportType),
         }
    def get(self, request, pk):
        """
        Retrieve default duration for an application.
        """
        application = get_application(pk)

        duration = get_default_duration(application)

        return JsonResponse(data={"licence_duration": duration},
                            status=status.HTTP_200_OK)
Exemple #14
0
    def put(self, request, pk):
        application = get_application(pk)
        serializer = get_temp_export_details_update_serializer(
            application.export_type)
        serializer = serializer(application, data=request.data, partial=True)

        if serializer.is_valid(raise_exception=True):
            save_and_audit_temporary_export_details(request, application,
                                                    serializer)
            return JsonResponse(data=serializer.validated_data,
                                status=status.HTTP_200_OK)
Exemple #15
0
    def get(self, request, pk):
        """
        View all additional documents on an application
        """
        application = get_application(pk)
        documents = ApplicationDocumentSerializer(
            ApplicationDocument.objects.filter(application_id=pk),
            many=True).data

        return JsonResponse({
            "documents": documents,
            "editable": application.is_major_editable()
        })
    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)
Exemple #17
0
    def get(self, request, pk, goodstype_pk):
        """
        Gets a goodstype
        """
        application = get_application(pk)
        goods_type = get_goods_type(goodstype_pk)
        default_countries = Country.objects.filter(
            countries_on_application__application=application)

        goods_type_data = GoodsTypeViewSerializer(
            goods_type, default_countries=default_countries).data

        return JsonResponse(data={"good": goods_type_data},
                            status=status.HTTP_200_OK)
Exemple #18
0
 def get(self, request, pk):
     application = get_application(pk)
     countries = [
         country for country in (CountryOnApplication.objects.filter(
             application_id=pk).prefetch_related(
                 "country_id", "country__name").values(
                     "contract_types", "other_contract_type_text",
                     "country_id", "country__name"))
     ]
     return JsonResponse(data={
         "countries": countries,
         "status": application.status.status
     },
                         status=status.HTTP_200_OK)
Exemple #19
0
    def get(self, request, pk):
        """
        Get parties for an application
        """
        application = get_application(pk)

        application_parties = application.active_parties.all().filter(deleted_at__isnull=True).select_related("party")

        if "type" in request.GET:
            application_parties = application_parties.filter(party__type=request.GET["type"])

        parties_data = PartySerializer([p.party for p in application_parties], many=True).data

        key = PartyType.api_key_name(request.GET["type"]) if "type" in request.GET else "parties"

        return JsonResponse(data={key: parties_data})
Exemple #20
0
    def update(self, instance, validated_data):
        """
        Update and return an existing `Application` instance, given the validated data.
        """
        instance.name = validated_data.get("name", instance.name)
        instance.status = validated_data.get("status", instance.status)
        instance.clearance_level = validated_data.get("clearance_level",
                                                      instance.clearance_level)

        # Remove any previous denial reasons
        if validated_data.get("status") == get_case_status_by_status(
                CaseStatusEnum.FINALISED):
            ApplicationDenialReason.objects.filter(
                application=get_application(instance.id)).delete()
            instance.last_closed_at = timezone.now()

        instance = super().update(instance, validated_data)
        return instance
    def post(self, request, pk):
        application = get_application(pk)
        data = request.data
        location_ids = data.get("external_locations")

        errors = self._validate_request(application, location_ids)
        if errors:
            return JsonResponse(data={"errors": errors},
                                status=status.HTTP_400_BAD_REQUEST)

        previous_locations = ExternalLocationOnApplication.objects.filter(
            application=application)
        previous_location_ids = [
            str(previous_location_id) for previous_location_id in
            previous_locations.values_list("external_location__id", flat=True)
        ]

        new_locations, errors = self._get_new_locations(
            application, get_request_user_organisation(request), location_ids,
            previous_locations, previous_location_ids)
        if errors:
            return JsonResponse(data={"errors": errors},
                                status=status.HTTP_400_BAD_REQUEST)

        # Update activity
        application.activity = self.BROKERING
        application.save()

        external_locations, errors = self._set_locations_and_sites(
            data.get("method"),
            previous_location_ids,
            location_ids,
            previous_locations,
            new_locations,
            application,
            request.user,
        )
        if errors:
            return JsonResponse(data={"errors": errors},
                                status=status.HTTP_400_BAD_REQUEST)

        return JsonResponse(data={"external_locations": external_locations},
                            status=status.HTTP_201_CREATED)
    def get(self, request, pk):
        """
        Retrieve an application instance
        """
        application = get_application(pk)
        serializer = get_application_view_serializer(application)
        data = serializer(
            application,
            context={
                "user_type": request.user.type,
                "exporter_user": request.user.exporteruser,
                "organisation_id": get_request_user_organisation_id(request),
            },
        ).data

        if application.case_type.sub_type == CaseTypeSubTypeEnum.OPEN:
            data["destinations"] = get_destinations(
                application.id, user_type=request.user.type)

        return JsonResponse(data=data, status=status.HTTP_200_OK)
    def delete(self, request, pk):
        """
        Deleting an application should only be allowed for draft applications
        """
        application = get_application(pk)

        if not is_case_status_draft(application.status.status):
            return JsonResponse(
                data={
                    "errors":
                    strings.Applications.Generic.
                    DELETE_SUBMITTED_APPLICATION_ERROR
                },
                status=status.HTTP_400_BAD_REQUEST,
            )
        application.delete()
        return JsonResponse(data={
            "status":
            strings.Applications.Generic.DELETE_DRAFT_APPLICATION
        },
                            status=status.HTTP_200_OK)
Exemple #24
0
    def get_data(self, instance):
        from api.licences.serializers.open_general_licences import OpenGeneralLicenceCaseSerializer
        from api.applications.helpers import get_application_view_serializer

        if instance.case_type.type == CaseTypeTypeEnum.REGISTRATION:
            return OpenGeneralLicenceCaseSerializer(
                get_open_general_export_licence_case(instance.id)).data
        elif instance.case_type.type == CaseTypeTypeEnum.APPLICATION:
            application = get_application(instance.id)
            serializer = get_application_view_serializer(application)
            return serializer(application).data
        elif instance.case_type.type == CaseTypeTypeEnum.QUERY:
            return QueryViewSerializer(instance.query, read_only=True).data
        elif instance.case_type.sub_type == CaseTypeSubTypeEnum.COMP_SITE:
            compliance = ComplianceSiteCase.objects.get(id=instance.id)
            return ComplianceSiteViewSerializer(compliance,
                                                context={
                                                    "team": self.team
                                                }).data
        elif instance.case_type.sub_type == CaseTypeSubTypeEnum.COMP_VISIT:
            compliance = ComplianceVisitCase.objects.get(id=instance.id)
            return ComplianceVisitSerializer(compliance).data
Exemple #25
0
    def post(self, request, pk):
        """
        Add a party to an application
        """
        application = get_application(pk)

        data = request.data
        data["organisation"] = get_request_user_organisation_id(request)

        serializer = PartySerializer(data=data, application_type=application.case_type.sub_type)

        if serializer.is_valid(raise_exception=True):
            if str_to_bool(data.get("validate_only", False)):
                return JsonResponse(data={data["type"]: serializer.initial_data}, status=status.HTTP_200_OK)

            # Save party and add to application
            serializer.save()

            try:
                party, removed_party = application.add_party(serializer.instance)
            except ApplicationException as exc:
                return JsonResponse(data={"errors": exc.data}, status=status.HTTP_400_BAD_REQUEST)

            # Audit
            if removed_party:
                audit_trail_service.create(
                    actor=request.user,
                    verb=AuditType.REMOVE_PARTY,
                    target=application.get_case(),
                    payload={"party_type": removed_party.type.replace("_", " "), "party_name": removed_party.name},
                )
            audit_trail_service.create(
                actor=request.user,
                verb=AuditType.ADD_PARTY,
                target=application.get_case(),
                payload={"party_type": party.type.replace("_", " "), "party_name": party.name},
            )

            return JsonResponse(data={party.type: serializer.data}, status=status.HTTP_201_CREATED)
    def put(self, request, pk):
        """
        Update an application instance
        """
        application = get_application(pk)
        serializer = get_application_update_serializer(application)
        case = application.get_case()
        data = request.data.copy()
        serializer = serializer(application,
                                data=data,
                                context=get_request_user_organisation(request),
                                partial=True)

        # Prevent minor edits of the clearance level
        if not application.is_major_editable() and request.data.get(
                "clearance_level"):
            return JsonResponse(
                data={
                    "errors": {
                        "clearance_level": [
                            strings.Applications.Generic.
                            NOT_POSSIBLE_ON_MINOR_EDIT
                        ]
                    }
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Prevent minor edits of the f680 clearance types
        if not application.is_major_editable() and request.data.get("types"):
            return JsonResponse(
                data={
                    "errors": {
                        "types": [
                            strings.Applications.Generic.
                            NOT_POSSIBLE_ON_MINOR_EDIT
                        ]
                    }
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Prevent minor edits of additional_information
        if not application.is_major_editable() and any([
                request.data.get(field)
                for field in constants.F680.ADDITIONAL_INFORMATION_FIELDS
        ]):
            return JsonResponse(
                data={
                    "errors": {
                        "Additional details": [
                            strings.Applications.Generic.
                            NOT_POSSIBLE_ON_MINOR_EDIT
                        ]
                    }
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        if not serializer.is_valid():
            return JsonResponse(data={"errors": serializer.errors},
                                status=status.HTTP_400_BAD_REQUEST)

        if application.case_type.sub_type == CaseTypeSubTypeEnum.HMRC:
            serializer.save()
            return JsonResponse(data={}, status=status.HTTP_200_OK)

        # Audit block
        if request.data.get("name"):
            old_name = application.name

            serializer.save()

            audit_trail_service.create(
                actor=request.user.exporteruser,
                verb=AuditType.UPDATED_APPLICATION_NAME,
                target=case,
                payload={
                    "old_name": old_name,
                    "new_name": serializer.data.get("name")
                },
            )
            return JsonResponse(data={}, status=status.HTTP_200_OK)

        if request.data.get("clearance_level"):
            serializer.save()
            return JsonResponse(data={}, status=status.HTTP_200_OK)

        # Audit block
        if application.case_type.sub_type == CaseTypeSubTypeEnum.F680:
            if request.data.get("types"):
                old_types = [
                    F680ClearanceTypeEnum.get_text(type)
                    for type in application.types.values_list("name",
                                                              flat=True)
                ]
                new_types = [
                    F680ClearanceTypeEnum.get_text(type)
                    for type in request.data.get("types")
                ]
                serializer.save()

                if set(old_types) != set(new_types):
                    audit_trail_service.create(
                        actor=request.user,
                        verb=AuditType.UPDATE_APPLICATION_F680_CLEARANCE_TYPES,
                        target=case,
                        payload={
                            "old_types": old_types,
                            "new_types": new_types
                        },
                    )
                return JsonResponse(data={}, status=status.HTTP_200_OK)
            else:
                serializer.save()

        if application.case_type.sub_type == CaseTypeSubTypeEnum.STANDARD:
            save_and_audit_have_you_been_informed_ref(request, application,
                                                      serializer)

        return JsonResponse(data={}, status=status.HTTP_200_OK)
    def put(self, request, pk):
        """
        Submit a draft application which will set its submitted_at datetime and status before creating a case
        Depending on the application subtype, this will also submit the declaration of the licence
        """
        application = get_application(pk)
        old_status = application.status.status

        if application.case_type.sub_type != CaseTypeSubTypeEnum.HMRC:
            assert_user_has_permission(
                request.user.exporteruser,
                ExporterPermissions.SUBMIT_LICENCE_APPLICATION,
                application.organisation)

        errors = validate_application_ready_for_submission(application)
        if errors:
            return JsonResponse(data={"errors": errors},
                                status=status.HTTP_400_BAD_REQUEST)

        # Queries are completed directly when submit is clicked on the task list
        # HMRC are completed when submit is clicked on the summary page (page after task list)
        # Applications are completed when submit is clicked on the declaration page (page after summary page)

        if application.case_type.sub_type in [
                CaseTypeSubTypeEnum.EUA, CaseTypeSubTypeEnum.GOODS
        ] or (CaseTypeSubTypeEnum.HMRC and request.data.get("submit_hmrc")):
            application.submitted_by = request.user.exporteruser
            create_submitted_audit(request, application, old_status)
            submit_application(application)
            if request.data.get("submit_hmrc"):
                auto_generate_case_document(
                    "application_form", application,
                    AutoGeneratedDocuments.APPLICATION_FORM)

        elif application.case_type.sub_type in [
                CaseTypeSubTypeEnum.STANDARD,
                CaseTypeSubTypeEnum.OPEN,
                CaseTypeSubTypeEnum.F680,
                CaseTypeSubTypeEnum.GIFTING,
                CaseTypeSubTypeEnum.EXHIBITION,
        ]:
            if request.data.get("submit_declaration"):
                errors = _validate_agree_to_declaration(request, errors)
                if errors:
                    return JsonResponse(data={"errors": errors},
                                        status=status.HTTP_400_BAD_REQUEST)

                # If a valid declaration is provided, save the application
                application.submitted_by = request.user.exporteruser
                application.agreed_to_foi = request.data.get("agreed_to_foi")
                application.foi_reason = request.data.get("foi_reason", "")
                submit_application(application)

                if application.case_type.sub_type in [
                        CaseTypeSubTypeEnum.STANDARD, CaseTypeSubTypeEnum.OPEN
                ]:
                    set_case_flags_on_submitted_standard_or_open_application(
                        application)

                add_goods_flags_to_submitted_application(application)
                apply_flagging_rules_to_case(application)
                create_submitted_audit(request, application, old_status)
                auto_generate_case_document(
                    "application_form", application,
                    AutoGeneratedDocuments.APPLICATION_FORM)
                run_routing_rules(application)

                # Set the sites on this application as used so their name/site records located at are no longer editable
                sites_on_application = SiteOnApplication.objects.filter(
                    application=application)
                Site.objects.filter(id__in=sites_on_application.values_list(
                    "site_id", flat=True)).update(is_used_on_application=True)

        if application.case_type.sub_type in [
                CaseTypeSubTypeEnum.STANDARD,
                CaseTypeSubTypeEnum.OPEN,
                CaseTypeSubTypeEnum.HMRC,
        ]:
            if UUID(SystemFlags.ENFORCEMENT_CHECK_REQUIRED
                    ) not in application.flags.values_list("id", flat=True):
                application.flags.add(SystemFlags.ENFORCEMENT_CHECK_REQUIRED)

        # If the user hasn't visited the optional goods to country mapping page, then no goods to country mappings will
        # have been saved before this point. So save mappings for all goods to all countries, which is the default
        if (application.case_type.sub_type == CaseTypeSubTypeEnum.OPEN
                and GoodsType.objects.filter(application=application,
                                             countries__isnull=True).exists()):
            countries_on_application = CountryOnApplication.objects.filter(
                application=application).values_list("country", flat=True)

            for goods_type in GoodsType.objects.filter(application=application,
                                                       countries__isnull=True):
                goods_type.countries.set(countries_on_application)

        # Serialize for the response message
        serializer = get_application_view_serializer(application)
        serializer = serializer(application,
                                context={"user_type": request.user.type})

        application_data = serializer.data

        if application.case_type.sub_type == CaseTypeSubTypeEnum.OPEN:
            application_data["destinations"] = get_destinations(
                application.id, user_type=request.user.type)

        data = {
            "application": {
                "reference_code": application.reference_code,
                **application_data
            }
        }

        if application.reference_code:
            data["reference_code"] = application.reference_code

        return JsonResponse(data=data, status=status.HTTP_200_OK)
    def put(self, request, pk):
        application = get_application(pk)
        is_licence_application = application.case_type.sub_type != CaseTypeSubTypeEnum.EXHIBITION

        data = deepcopy(request.data)

        if data["status"] == CaseStatusEnum.FINALISED:
            return JsonResponse(
                data={
                    "errors": [
                        strings.Applications.Generic.Finalise.Error.
                        SET_FINALISED
                    ]
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        if not can_set_status(application, data["status"]):
            raise ValidationError({"status": [strings.Statuses.BAD_STATUS]})

        if hasattr(request.user, "exporteruser"):
            if get_request_user_organisation_id(
                    request) != application.organisation.id:
                raise PermissionDenied()

            if not can_status_be_set_by_exporter_user(
                    application.status.status, data["status"]):
                return JsonResponse(
                    data={
                        "errors": [
                            strings.Applications.Generic.Finalise.Error.
                            EXPORTER_SET_STATUS
                        ]
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )
        else:
            if not can_status_be_set_by_gov_user(
                    request.user.govuser, application.status.status,
                    data["status"], is_licence_application):
                return JsonResponse(
                    data={
                        "errors": [
                            strings.Applications.Generic.Finalise.Error.
                            GOV_SET_STATUS
                        ]
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

        update_licence_status(application, data["status"])

        case_status = get_case_status_by_status(data["status"])
        data["status"] = str(case_status.pk)
        old_status = application.status

        serializer = get_application_update_serializer(application)
        serializer = serializer(application, data=data, partial=True)

        if not serializer.is_valid():
            return JsonResponse(data={"errors": serializer.errors},
                                status=status.HTTP_400_BAD_REQUEST)

        application = serializer.save()

        if CaseStatusEnum.is_terminal(
                old_status.status) and not CaseStatusEnum.is_terminal(
                    application.status.status):
            # we reapply flagging rules if the status is reopened from a terminal state
            apply_flagging_rules_to_case(application)

        audit_trail_service.create(
            actor=request.user,
            verb=AuditType.UPDATED_STATUS,
            target=application.get_case(),
            payload={
                "status": {
                    "new": CaseStatusEnum.get_text(case_status.status),
                    "old": CaseStatusEnum.get_text(old_status.status),
                },
                "additional_text": data.get("note"),
            },
        )

        # Case routing rules
        if old_status != application.status:
            run_routing_rules(case=application, keep_status=True)

        if CaseStatusEnum.is_terminal(application.status.status):
            gov_notify_service.send_email(
                email_address=application.submitted_by.email,
                template_type=TemplateType.APPLICATION_STATUS,
                data=ApplicationStatusEmailData(
                    case_reference=application.reference_code,
                    application_reference=application.name,
                    link=
                    f"{settings.EXPORTER_BASE_URL}/applications/{application.id}",
                ),
            )

        data = get_application_view_serializer(application)(
            application, context={
                "user_type": request.user.type
            }).data

        if application.case_type.sub_type == CaseTypeSubTypeEnum.OPEN:
            data["destinations"] = get_destinations(
                application.id, user_type=request.user.type)

        return JsonResponse(
            data={"data": data},
            status=status.HTTP_200_OK,
        )
    def put(self, request, pk):
        """
        Finalise an application
        """
        application = get_application(pk)

        # Check permissions
        is_mod_clearance = application.case_type.sub_type in CaseTypeSubTypeEnum.mod
        if not can_status_be_set_by_gov_user(
                request.user.govuser, application.status.status,
                CaseStatusEnum.FINALISED, is_mod_clearance):
            return JsonResponse(
                data={
                    "errors": [
                        strings.Applications.Generic.Finalise.Error.
                        SET_FINALISED
                    ]
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        licence_data = request.data.copy()

        action = licence_data.get("action")
        if not action:
            return JsonResponse(
                data={
                    "errors":
                    [strings.Applications.Finalise.Error.NO_ACTION_GIVEN]
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Refusals & NLRs
        if action in [AdviceType.REFUSE, AdviceType.NO_LICENCE_REQUIRED]:
            return JsonResponse(data={"application": str(application.id)},
                                status=status.HTTP_200_OK)

        # Approvals & Provisos
        else:
            # Check if any blocking flags are on the case
            blocking_flags = (get_flags(application.get_case()).filter(
                status=FlagStatuses.ACTIVE,
                blocks_approval=True).order_by("name").values_list("name",
                                                                   flat=True))
            if blocking_flags:
                raise PermissionDenied([
                    f"{strings.Applications.Finalise.Error.BLOCKING_FLAGS}{','.join(list(blocking_flags))}"
                ])

            try:
                active_licence = Licence.objects.get_active_licence(
                    application)
                default_licence_duration = active_licence.duration
            except Licence.DoesNotExist:
                default_licence_duration = get_default_duration(application)

            licence_data["duration"] = licence_data.get(
                "duration", default_licence_duration)

            # Check change default duration permission
            if licence_data[
                    "duration"] != default_licence_duration and not request.user.govuser.has_permission(
                        GovPermissions.MANAGE_LICENCE_DURATION):
                raise PermissionDenied([
                    strings.Applications.Finalise.Error.SET_DURATION_PERMISSION
                ])

            # Validate date
            try:
                start_date = timezone.datetime(year=int(licence_data["year"]),
                                               month=int(
                                                   licence_data["month"]),
                                               day=int(licence_data["day"]))
            except (KeyError, ValueError):
                raise ParseError({
                    "start_date":
                    [strings.Applications.Finalise.Error.INVALID_DATE]
                })

            # Delete existing draft if one exists
            try:
                licence = Licence.objects.get_draft_licence(application)
            except Licence.DoesNotExist:
                licence = None

            licence_data["start_date"] = start_date.strftime("%Y-%m-%d")

            if licence:
                # Update Draft Licence object
                licence_serializer = LicenceCreateSerializer(instance=licence,
                                                             data=licence_data,
                                                             partial=True)
            else:
                # Create Draft Licence object
                licence_data["case"] = application.id
                licence_data["status"] = LicenceStatus.DRAFT
                licence_data["reference_code"] = get_licence_reference_code(
                    application.reference_code)
                licence_serializer = LicenceCreateSerializer(data=licence_data)

            if not licence_serializer.is_valid():
                raise ParseError(licence_serializer.errors)

            licence = licence_serializer.save()

            # Delete draft licence document that may now be invalid
            GeneratedCaseDocument.objects.filter(
                case_id=pk,
                advice_type=AdviceType.APPROVE,
                visible_to_exporter=False).delete()

            # Only validate & save GoodsOnLicence (quantities & values) for Standard applications
            if application.case_type.sub_type == CaseTypeSubTypeEnum.STANDARD:
                errors = validate_and_create_goods_on_licence(
                    pk, licence.id, request.data)
                if errors:
                    raise ParseError(errors)

            return JsonResponse(data=LicenceCreateSerializer(licence).data,
                                status=status.HTTP_200_OK)
    def post(self, request, pk):
        """
        Copy an application
        In this function we get the application and remove it's relation to itself on the database, which allows for us
        keep most of the data in relation to the application intact.
        """
        self.old_application_id = pk
        old_application = get_application(pk)

        data = request.data

        serializer = GenericApplicationCopySerializer(
            data=data, context={"application_type": old_application.case_type})

        if not serializer.is_valid():
            return JsonResponse(data={"errors": serializer.errors},
                                status=status.HTTP_400_BAD_REQUEST)

        # Deepcopy so new_application is not a pointer to old_application
        # (if not deepcopied, any changes done on one applies to the other)
        self.new_application = deepcopy(old_application)

        if self.new_application.case_type.sub_type == CaseTypeSubTypeEnum.F680:
            for field in constants.F680.ADDITIONAL_INFORMATION_FIELDS:
                setattr(self.new_application, field, None)

        # Clear references to parent objects, and current application instance object
        self.strip_id_for_application_copy()

        # Replace the reference and have you been informed (if required) with users answer. Also sets some defaults
        self.new_application.name = request.data["name"]
        if (self.new_application.case_type.sub_type
                == CaseTypeSubTypeEnum.STANDARD and
                not self.new_application.case_type.id == CaseTypeEnum.SICL.id):
            self.new_application.have_you_been_informed = request.data.get(
                "have_you_been_informed")
            self.new_application.reference_number_on_information_form = request.data.get(
                "reference_number_on_information_form")
        self.new_application.status = get_case_status_by_status(
            CaseStatusEnum.DRAFT)
        self.new_application.copy_of_id = self.old_application_id

        # Remove SLA data
        self.new_application.sla_days = 0
        self.new_application.sla_remaining_days = get_application_target_sla(
            self.new_application.case_type.sub_type)
        self.new_application.last_closed_at = None
        self.new_application.sla_updated_at = None

        # Remove data that should not be copied
        self.remove_data_from_application_copy()

        # Need to save here to create the pk/id for relationships
        self.new_application.save()

        # Create new foreign key connection using data from old application (this is for tables pointing to the case)
        self.create_foreign_relations_for_new_application()
        self.duplicate_goodstypes_for_new_application()

        # Get all parties connected to the application and produce a copy (and replace reference for each one)
        self.duplicate_parties_on_new_application()

        # Get all f680 clearance types
        self.duplicate_f680_clearance_types()

        # Remove usage & licenced quantity/ value
        self.new_application.goods_type.update(usage=0)

        # Save
        self.new_application.created_at = now()
        self.new_application.save()
        return JsonResponse(data={"data": self.new_application.id},
                            status=status.HTTP_201_CREATED)