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)
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)
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)
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)
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")
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)
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)
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)
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)
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)
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)
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)
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)
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})
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)
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
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)