Exemple #1
0
        def inner(request, *args, **kwargs):
            application_status = _get_application(request, kwargs).values_list("status__status", flat=True)[0]

            if is_editable and application_status in CaseStatusEnum.read_only_statuses():
                return JsonResponse(
                    data={
                        "errors": {
                            "non_field_errors": [
                                strings.Applications.Generic.INVALID_OPERATION_FOR_READ_ONLY_CASE_ERROR
                            ]
                        }
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            if is_major_editable and application_status not in CaseStatusEnum.major_editable_statuses():
                return JsonResponse(
                    data={
                        "errors": {
                            "non_field_errors": [
                                strings.Applications.Generic.INVALID_OPERATION_FOR_NON_DRAFT_OR_MAJOR_EDIT_CASE_ERROR
                            ]
                        }
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            return func(request, *args, **kwargs)
Exemple #2
0
    def submit_application(application: BaseApplication,
                           user: ExporterUser = None):
        if not user:
            user = UserOrganisationRelationship.objects.filter(
                organisation_id=application.organisation_id).first().user

        application.submitted_at = timezone.localtime()
        application.sla_remaining_days = get_application_target_sla(
            application.case_type.sub_type)
        application.status = get_case_status_by_status(
            CaseStatusEnum.SUBMITTED)
        application.save()

        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)

        audit_trail_service.create(
            actor=user.baseuser_ptr,
            verb=AuditType.UPDATED_STATUS,
            target=application.get_case(),
            payload={
                "status": {
                    "new": CaseStatusEnum.get_text(CaseStatusEnum.SUBMITTED),
                    "old": CaseStatusEnum.get_text(CaseStatusEnum.DRAFT),
                }
            },
        )

        return application
def get_case_statuses(read_only):
    """ Get a list of the case statuses that are read-only. """
    if read_only:
        return CaseStatusEnum.read_only_statuses()
    else:
        return [
            status for status, value in CaseStatusEnum.choices
            if not CaseStatusEnum.is_read_only(status)
        ]
    def test_standard_application_declaration_submit_success(self, upload_bytes_file_func, html_to_pdf_func):
        upload_bytes_file_func.return_value = None
        html_to_pdf_func.return_value = None

        self.draft.agreed_to_foi = True
        self.draft.save()
        self.assertEqual(self.draft.status.status, CaseStatusEnum.DRAFT)

        data = {
            "submit_declaration": "True",
            "agreed_to_declaration": "True",
            "agreed_to_foi": "False",
            "foi_reason": "Lorem ipsum",
        }

        url = reverse("applications:application_submit", kwargs={"pk": self.draft.id})
        response = self.client.put(url, data, **self.exporter_headers)

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

        case = Case.objects.get(id=self.draft.id)
        self.assertIsNotNone(case.submitted_at)
        self.assertNotEqual(case.status.status, CaseStatusEnum.DRAFT)
        self.assertFalse(case.status.is_terminal)
        self.assertEqual(case.baseapplication.agreed_to_foi, False)
        self.assertEqual(case.baseapplication.foi_reason, "Lorem ipsum")
        self.assertEqual(case.submitted_by, self.exporter_user)
        self.assertTrue(UUID(SystemFlags.ENFORCEMENT_CHECK_REQUIRED) in case.flags.values_list("id", flat=True))

        for good_on_application in GoodOnApplication.objects.filter(application=case):
            self.assertEqual(good_on_application.good.status, GoodStatus.SUBMITTED)

        case_status_audits = Audit.objects.filter(target_object_id=case.id, verb=AuditType.UPDATED_STATUS).values_list(
            "payload", flat=True
        )
        self.assertIn(
            {
                "status": {
                    "new": CaseStatusEnum.get_text(CaseStatusEnum.SUBMITTED),
                    "old": CaseStatusEnum.get_text(CaseStatusEnum.DRAFT),
                }
            },
            case_status_audits,
        )
        # Asserting that the 'Application Form' has been autogenerated on submission of the application
        html_to_pdf_func.assert_called_once()
        upload_bytes_file_func.assert_called_once()
        self.assertEqual(
            CaseDocument.objects.filter(
                name__contains=AutoGeneratedDocuments.APPLICATION_FORM,
                type=CaseDocumentState.AUTO_GENERATED,
                safe=True,
                case=case,
                visible_to_exporter=False,
            ).count(),
            1,
        )
Exemple #5
0
    def change_status(self,
                      user,
                      status: CaseStatus,
                      note: Optional[str] = ""):
        """
        Sets the status for the case, runs validation on various parameters,
        creates audit entries and also runs flagging and automation rules
        """
        from api.cases.helpers import can_set_status
        from api.audit_trail import service as audit_trail_service
        from api.applications.libraries.application_helpers import can_status_be_set_by_gov_user
        from api.workflow.automation import run_routing_rules
        from api.workflow.flagging_rules_automation import apply_flagging_rules_to_case
        from api.licences.helpers import update_licence_status

        old_status = self.status.status

        # Only allow the final decision if the user has the MANAGE_FINAL_ADVICE permission
        if status.status == CaseStatusEnum.FINALISED:
            assert_user_has_permission(
                user.govuser, GovPermissions.MANAGE_LICENCE_FINAL_ADVICE)

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

        if not can_status_be_set_by_gov_user(
                user.govuser, old_status, status.status, is_mod=False):
            raise ValidationError({"status": ["Status cannot be set by user"]})

        self.status = status
        self.save()

        # Update licence status if applicable case status change
        update_licence_status(self, status.status)

        if CaseStatusEnum.is_terminal(
                old_status) and not CaseStatusEnum.is_terminal(
                    self.status.status):
            apply_flagging_rules_to_case(self)

        audit_trail_service.create(
            actor=user,
            verb=AuditType.UPDATED_STATUS,
            target=self,
            payload={
                "status": {
                    "new": CaseStatusEnum.get_text(self.status.status),
                    "old": old_status
                },
                "additional_text": note,
            },
        )

        if old_status != self.status.status:
            run_routing_rules(case=self, keep_status=True)
Exemple #6
0
def create_submitted_audit(request: Request, application: HmrcQuery,
                           old_status: str) -> None:
    audit_trail_service.create(
        actor=request.user,
        verb=AuditType.UPDATED_STATUS,
        target=application.get_case(),
        payload={
            "status": {
                "new": CaseStatusEnum.get_text(CaseStatusEnum.SUBMITTED),
                "old": CaseStatusEnum.get_text(old_status),
            }
        },
        ignore_case_status=True,
        send_notification=False,
    )
    def test_gov_set_status_for_all_except_applicant_editing_and_finalised_success(self, case_status):
        if case_status == CaseStatusEnum.REVOKED:
            self.standard_application.licences.add(
                self.create_licence(self.standard_application, status=LicenceStatus.ISSUED)
            )

        data = {"status": case_status}

        with mock.patch("gov_notify.service.client") as mock_notify_client:
            response = self.client.put(self.url, data=data, **self.gov_headers)

        self.standard_application.refresh_from_db()

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(self.standard_application.status, get_case_status_by_status(case_status))

        if CaseStatusEnum.is_terminal(case_status):
            mock_notify_client.send_email.assert_called_with(
                email_address=self.standard_application.submitted_by.email,
                template_id=TemplateType.APPLICATION_STATUS.template_id,
                data={
                    "case_reference": self.standard_application.reference_code,
                    "application_reference": self.standard_application.name,
                    "link": f"{settings.EXPORTER_BASE_URL}/applications/{self.standard_application.pk}",
                },
            )
Exemple #8
0
    def put(self, request, pk):
        """ Respond to a control list classification."""
        assert_user_has_permission(request.user.govuser, constants.GovPermissions.RESPOND_PV_GRADING)

        query = get_exporter_query(pk)
        if CaseStatusEnum.is_terminal(query.status.status):
            return JsonResponse(
                data={"errors": [strings.Applications.Generic.TERMINAL_CASE_CANNOT_PERFORM_OPERATION_ERROR]},
                status=status.HTTP_400_BAD_REQUEST,
            )

        data = request.data

        pv_grading_good_serializer = PVGradingResponseSerializer(data=data)

        if pv_grading_good_serializer.is_valid():
            if not str_to_bool(data.get("validate_only")):
                pv_grading = pv_grading_good_serializer.save()
                self.update_query_and_good(query, data, pv_grading)
                self.generate_audit_trail(request.user, query)

                # Send a notification to the user
                for user_relationship in UserOrganisationRelationship.objects.filter(organisation=query.organisation):
                    user_relationship.send_notification(content_object=query, case=query)

                return JsonResponse(
                    data={"pv_grading_query": pv_grading_good_serializer.data}, status=status.HTTP_200_OK,
                )

            return JsonResponse(data={"pv_grading_query": data}, status=status.HTTP_200_OK)

        return JsonResponse(data={"errors": pv_grading_good_serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
Exemple #9
0
def can_status_be_set_by_gov_user(user: GovUser, original_status: str,
                                  new_status: str, is_mod: bool) -> bool:
    """
    Check that a status can be set by a gov user. Gov users can not set a case's status to
    `Applicant editing`. They also cannot set a case's status to `Finalised` or open a closed case
    without additional permissions.
    """
    if new_status == CaseStatusEnum.APPLICANT_EDITING:
        return False

    elif CaseStatusEnum.is_terminal(
            original_status) and not assert_user_has_permission(
                user, GovPermissions.REOPEN_CLOSED_CASES):
        return False

    if new_status == CaseStatusEnum.FINALISED:
        if is_mod:
            if not assert_user_has_permission(
                    user, GovPermissions.MANAGE_CLEARANCE_FINAL_ADVICE):
                return False
        else:
            if not assert_user_has_permission(
                    user, GovPermissions.MANAGE_LICENCE_FINAL_ADVICE):
                return False
    return True
    def test_exporter_set_application_status_surrendered_success(self, mock_notify_client):
        self.standard_application.status = get_case_status_by_status(CaseStatusEnum.FINALISED)
        self.standard_application.save()
        self.create_licence(self.standard_application, status=LicenceStatus.ISSUED)
        surrendered_status = get_case_status_by_status("surrendered")

        data = {"status": CaseStatusEnum.SURRENDERED}
        response = self.client.put(self.url, data=data, **self.exporter_headers)
        response_data = response.json()["data"]

        self.standard_application.refresh_from_db()

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            response_data["status"],
            {"key": surrendered_status.status, "value": CaseStatusEnum.get_text(surrendered_status.status)},
        )
        self.assertEqual(self.standard_application.status, get_case_status_by_status(CaseStatusEnum.SURRENDERED))
        mock_notify_client.send_email.assert_called_with(
            email_address=self.standard_application.submitted_by.email,
            template_id=TemplateType.APPLICATION_STATUS.template_id,
            data={
                "case_reference": self.standard_application.reference_code,
                "application_reference": self.standard_application.name,
                "link": f"{settings.EXPORTER_BASE_URL}/applications/{self.standard_application.pk}",
            },
        )
Exemple #11
0
    def test_rules_rerun_when_no_rules_are_applied_then_case_status_is_changed_and_audited(
            self):
        self.routing_rule_1.delete()
        self.case.queues.set([self.other_queue.id])

        response = self.client.put(self.url, {}, **self.gov_headers)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.case.refresh_from_db()

        # Case has been removed from queues
        self.assertEqual(self.case.queues.count(), 0)

        # Assert case status changed to all applicable statuses in correct order (ignoring initial submission status)
        exclude_payload = {
            "status": {
                "new": CaseStatusEnum.get_text(CaseStatusEnum.SUBMITTED),
                "old": CaseStatusEnum.get_text(CaseStatusEnum.DRAFT),
            }
        }

        actual_status_changes = (Audit.objects.filter(
            target_object_id=self.case.id,
            verb=AuditType.UPDATED_STATUS).exclude(
                payload=exclude_payload).order_by("created_at"))

        applicable_status_changes = CaseStatus.objects.filter(
            workflow_sequence__isnull=False,
            workflow_sequence__gt=CaseStatus.objects.get(
                status=CaseStatusEnum.SUBMITTED).workflow_sequence,
            workflow_sequence__lte=CaseStatus.objects.get(
                status=CaseStatusEnum.UNDER_FINAL_REVIEW).workflow_sequence,
        ).order_by("workflow_sequence")

        self.assertEqual(actual_status_changes.count(),
                         applicable_status_changes.count())

        for index in range(len(applicable_status_changes)):
            self.assertEqual(
                actual_status_changes[index].payload["status"]["new"],
                CaseStatusEnum.get_text(
                    applicable_status_changes[index].status),
            )

        # Assert the case status was finally set to Under Final Review (the last applicable status)
        self.assertEqual(self.case.status.status,
                         CaseStatusEnum.UNDER_FINAL_REVIEW)
Exemple #12
0
def can_status_be_set_by_exporter_user(original_status: str,
                                       new_status: str) -> bool:
    """ Check that a status can be set by an exporter user. Exporter users cannot withdraw an application
    that is already in a terminal state and they cannot set an application to `Applicant editing` if the
    application is read only.
    """
    if new_status == CaseStatusEnum.WITHDRAWN:
        if CaseStatusEnum.is_terminal(original_status):
            return False
    elif new_status == CaseStatusEnum.SURRENDERED:
        if original_status != CaseStatusEnum.FINALISED:
            return False
    elif CaseStatusEnum.is_read_only(
            original_status) or new_status != CaseStatusEnum.APPLICANT_EDITING:
        return False

    return True
    def test_exp_set_application_status_to_submitted_when_previously_applicant_editing_success(
        self, upload_bytes_file_func, html_to_pdf_func
    ):
        upload_bytes_file_func.return_value = None
        html_to_pdf_func.return_value = None

        standard_application = self.create_draft_standard_application(self.organisation)
        self.submit_application(standard_application)
        standard_application.status = get_case_status_by_status(CaseStatusEnum.APPLICANT_EDITING)
        standard_application.save()
        previous_submitted_at = standard_application.submitted_at

        data = {"submit_declaration": True, "agreed_to_declaration": True, "agreed_to_foi": True, "foi_reason": ""}

        url = reverse("applications:application_submit", kwargs={"pk": standard_application.id})

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

        standard_application.refresh_from_db()
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertNotEqual(
            standard_application.status.status, CaseStatusEnum.APPLICANT_EDITING,
        )
        self.assertFalse(standard_application.status.is_terminal)
        self.assertNotEqual(standard_application.submitted_at, previous_submitted_at)
        self.assertEqual(standard_application.agreed_to_foi, True)

        case_status_audits = Audit.objects.filter(
            target_object_id=standard_application.id, verb=AuditType.UPDATED_STATUS
        ).values_list("payload", flat=True)
        self.assertIn(
            {
                "status": {
                    "new": CaseStatusEnum.get_text(CaseStatusEnum.SUBMITTED),
                    "old": CaseStatusEnum.get_text(CaseStatusEnum.APPLICANT_EDITING),
                }
            },
            case_status_audits,
        )
        html_to_pdf_func.assert_called_once()
        upload_bytes_file_func.assert_called_once()
    def test_application_in_state_major_editable_success(self):
        application = self.create_standard_application_case(self.organisation)
        application.status = CaseStatus.objects.get(
            status=CaseStatusEnum.major_editable_statuses()[0])
        application.save()

        @application_in_state(is_major_editable=True)
        def a_view(request, *args, **kwargs):
            return HttpResponse()

        resp = a_view(request=None, pk=application.pk)
        self.assertEqual(resp.status_code, status.HTTP_200_OK)
Exemple #15
0
    def save(self, *args, **kwargs):
        if CaseStatusEnum.is_terminal(self.status.status):
            self.case_officer = None
            if self.pk:
                self.queues.clear()
            CaseAssignment.objects.filter(case=self).delete()

        if not self.reference_code and self.status != get_case_status_by_status(
                CaseStatusEnum.DRAFT):
            self.reference_code = generate_reference_code(self)

        super(Case, self).save(*args, **kwargs)
class CaseNotesExporterCreateTests(DataTestClient):
    def setUp(self):
        super().setUp()
        self.standard_application = self.create_draft_standard_application(
            self.organisation)
        self.case = self.submit_application(self.standard_application)
        self.url = reverse("cases:case_notes", kwargs={"pk": self.case.id})
        self.data = {"text": "Days of brutalism"}

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

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(CaseNote.objects.count(), 1)
        self.assertEqual(CaseNote.objects.get().text, self.data.get("text"))
        self.assertEqual(CaseNote.objects.get().is_visible_to_exporter, True)

    @parameterized.expand([
        [{}],  # Empty data
        [{
            "text": ""
        }],  # Empty text field
        [{
            "text": "🍌"
        }],  # Less than two character minimum
        [{
            "text": "🍌" * 2201
        }],  # More than two thousand, two hundred character maximum
    ])
    def test_create_case_note_failure(self, data):
        response = self.client.post(self.url,
                                    data=data,
                                    **self.exporter_headers)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(CaseNote.objects.count(), 0)

    @parameterized.expand(CaseStatusEnum.terminal_statuses())
    def test_create_case_note_case_terminal_state_failure_exporter_user(
            self, terminal_status):
        self.standard_application.status = get_case_status_by_status(
            terminal_status)
        self.standard_application.save()

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

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
    def test_application_in_state_editable_failure(self):
        application = self.create_standard_application_case(self.organisation)
        application_status = CaseStatusEnum.read_only_statuses()[0]
        application.status = CaseStatus.objects.get(status=application_status)
        application.save()

        @application_in_state(is_editable=True)
        def a_view(request, *args, **kwargs):
            return HttpResponse()

        resp = a_view(request=None, pk=application.pk)
        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertTrue(strings.Applications.Generic.
                        INVALID_OPERATION_FOR_READ_ONLY_CASE_ERROR in
                        resp.content.decode("utf-8"))
Exemple #18
0
def convert_status(status):
    converted = CaseStatusEnum.get_value(status)
    return converted if converted else status
Exemple #19
0
    def put(self, request, pk):
        """ Respond to a control list classification."""
        assert_user_has_permission(request.user.govuser, constants.GovPermissions.REVIEW_GOODS)

        query = get_exporter_query(pk)
        if CaseStatusEnum.is_terminal(query.status.status):
            return JsonResponse(
                data={"errors": [strings.Applications.Generic.TERMINAL_CASE_CANNOT_PERFORM_OPERATION_ERROR]},
                status=status.HTTP_400_BAD_REQUEST,
            )

        data = request.data

        clc_good_serializer = ClcControlGoodSerializer(query.good, data=data)

        if clc_good_serializer.is_valid():
            if not str_to_bool(data.get("validate_only")):
                previous_control_list_entries = list(
                    query.good.control_list_entries.values_list("rating", flat=True)
                ) or [strings.Goods.GOOD_NO_CONTROL_CODE]

                clc_good_serializer.save()
                query.clc_responded = True
                query.save()

                if clc_good_serializer.validated_data.get("control_list_entries"):
                    values = clc_good_serializer.validated_data["control_list_entries"]
                    new_control_list_entries = [clc.rating for clc in values]
                else:
                    new_control_list_entries = [strings.Goods.GOOD_NO_CONTROL_CODE]

                if new_control_list_entries != previous_control_list_entries:
                    audit_trail_service.create(
                        actor=request.user,
                        verb=AuditType.GOOD_REVIEWED,
                        action_object=query.good,
                        target=query.get_case(),
                        payload={
                            "good_name": query.good.description,
                            "old_control_list_entry": previous_control_list_entries,
                            "new_control_list_entry": new_control_list_entries,
                        },
                    )

                flag = Flag.objects.get(id=SystemFlags.GOOD_CLC_QUERY_ID)
                query.good.flags.remove(flag)
                query.good.status = GoodStatus.VERIFIED
                query.good.save()
                apply_flagging_rules_to_case(query)

                audit_trail_service.create(
                    actor=request.user, verb=AuditType.CLC_RESPONSE, action_object=query.good, target=query.get_case(),
                )

                # Send a notification to the user
                for user_relationship in UserOrganisationRelationship.objects.filter(organisation=query.organisation):
                    user_relationship.send_notification(content_object=query, case=query)

                return JsonResponse(
                    data={"control_list_classification_query": clc_good_serializer.data}, status=status.HTTP_200_OK
                )

            return JsonResponse(data={"control_list_classification_query": data}, status=status.HTTP_200_OK)

        return JsonResponse(data={"errors": clc_good_serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
Exemple #20
0
 def get_status(self, instance):
     return {
         "key": instance.status.status,
         "value": CaseStatusEnum.get_text(instance.status.status)
     }
Exemple #21
0
 def is_editable(self):
     return not CaseStatusEnum.is_read_only(self.status.status)
class CreateCaseAdviceTests(DataTestClient):
    def setUp(self):
        super().setUp()
        self.standard_application = self.create_draft_standard_application(
            self.organisation)
        self.good = self.standard_application.goods.first().good
        self.standard_case = self.submit_application(self.standard_application)

        team_2 = Team(name="2")
        team_3 = Team(name="3")

        team_2.save()
        team_3.save()

        role = Role(name="team_level")
        role.permissions.set([
            constants.GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name,
            constants.GovPermissions.MANAGE_TEAM_ADVICE.name,
            constants.GovPermissions.MANAGE_TEAM_CONFIRM_OWN_ADVICE.name,
            constants.GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name,
            constants.GovPermissions.MANAGE_TEAM_ADVICE.name,
        ])
        role.save()

        self.gov_user.role = role
        self.gov_user.save()

        self.gov_user_2 = GovUserFactory(baseuser_ptr__email="*****@*****.**",
                                         team=team_2,
                                         role=role)
        self.gov_user_3 = GovUserFactory(baseuser_ptr__email="*****@*****.**",
                                         team=team_3,
                                         role=role)

        self.standard_case_url = reverse("cases:case_final_advice",
                                         kwargs={"pk": self.standard_case.id})

    def test_advice_is_concatenated_when_final_advice_first_created(self):
        """
        Final advice is created on first call
        """
        self.create_advice(self.gov_user, self.standard_case, "end_user",
                           AdviceType.PROVISO, AdviceLevel.TEAM)
        self.create_advice(self.gov_user_2, self.standard_case, "end_user",
                           AdviceType.PROVISO, AdviceLevel.TEAM)
        self.create_advice(self.gov_user, self.standard_case, "good",
                           AdviceType.NO_LICENCE_REQUIRED, AdviceLevel.TEAM)
        self.create_advice(self.gov_user_2, self.standard_case, "good",
                           AdviceType.NO_LICENCE_REQUIRED, AdviceLevel.TEAM)

        response = self.client.get(self.standard_case_url, **self.gov_headers)
        response_data = response.json()["advice"]

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response_data), 6)

        end_user, good = None, None
        for data in response_data:
            if data.get("end_user"):
                end_user = data.get("type").get("key")
            elif data.get("good"):
                good = data.get("type").get("key")

        self.assertEqual(end_user, AdviceType.PROVISO)
        self.assertEqual(good, AdviceType.NO_LICENCE_REQUIRED)

    def test_create_conflicting_final_advice_shows_all_fields(self):
        """
        The type should show conflicting if there are conflicting types in the advice on a single object
        """
        self.create_advice(self.gov_user, self.standard_case, "good",
                           AdviceType.NO_LICENCE_REQUIRED, AdviceLevel.TEAM)
        self.create_advice(self.gov_user_2, self.standard_case, "good",
                           AdviceType.REFUSE, AdviceLevel.TEAM)
        self.create_advice(self.gov_user_3, self.standard_case, "good",
                           AdviceType.PROVISO, AdviceLevel.TEAM)

        response = self.client.get(self.standard_case_url, **self.gov_headers)
        response_data = response.json()["advice"][0]

        self.assertEqual(response_data.get("type").get("key"), "conflicting")
        self.assertEqual(response_data.get("proviso"), "I am easy to proviso")
        self.assertCountEqual(["1a", "1b", "1c"],
                              response_data["denial_reasons"])

    def test_create_final_advice_same_advice_type_different_pv_gradings(self):
        """
        Same advice types, different pv gradings
        """
        inputs = [
            (self.gov_user, PvGrading.UK_OFFICIAL),
            (self.gov_user_2, PvGrading.UK_OFFICIAL_SENSITIVE),
            (self.gov_user_3, PvGrading.NATO_CONFIDENTIAL),
        ]
        for user, pv_grading in inputs:
            self.create_advice(user, self.standard_case, "good",
                               AdviceType.PROVISO, AdviceLevel.TEAM,
                               pv_grading)

        response = self.client.get(self.standard_case_url, **self.gov_headers)
        response_data = response.json()["advice"]

        self.assertEqual(response_data[0].get("type").get("key"), "proviso")
        self.assertEqual(response_data[0].get("proviso"),
                         "I am easy to proviso")
        pv_gradings = Advice.objects.get(
            id=response_data[0]["id"]).collated_pv_grading
        self.assertIn("\n-------\n", pv_gradings)
        for _, pv_grading in inputs:
            self.assertIn(PvGrading.to_str(pv_grading), pv_gradings)

    def test_create_final_advice_same_advice_type_same_pv_gradings(self):
        """
        Same advice types, same pv gradings
        """
        pv_grading = PvGrading.OCCAR_CONFIDENTIAL
        inputs = [self.gov_user, self.gov_user_2, self.gov_user_3]
        for user in inputs:
            self.create_advice(user, self.standard_case, "good",
                               AdviceType.PROVISO, AdviceLevel.TEAM,
                               pv_grading)

        response = self.client.get(self.standard_case_url, **self.gov_headers)
        response_data = response.json()["advice"]

        self.assertEqual(response_data[0].get("type").get("key"), "proviso")
        self.assertEqual(response_data[0].get("proviso"),
                         "I am easy to proviso")
        pv_gradings = Advice.objects.get(
            id=response_data[0]["id"]).collated_pv_grading
        self.assertNotIn("\n-------\n", pv_gradings)
        self.assertIn(PvGrading.to_str(pv_grading), pv_gradings)

    def test_create_conflicting_final_advice_different_advice_type_same_pv_gradings(
            self):
        """
        Different advice types, same pv gradings
        """
        pv_grading = PvGrading.UK_OFFICIAL
        inputs = [
            (self.gov_user, AdviceType.PROVISO),
            (self.gov_user_2, AdviceType.REFUSE),
            (self.gov_user_3, AdviceType.APPROVE),
        ]
        for user, advice_type in inputs:
            self.create_advice(user, self.standard_case, "good", advice_type,
                               AdviceLevel.TEAM, pv_grading)

        response = self.client.get(self.standard_case_url, **self.gov_headers)
        response_data = response.json()["advice"]

        self.assertEqual(response_data[0].get("type").get("key"),
                         "conflicting")
        pv_gradings = Advice.objects.get(
            id=response_data[0]["id"]).collated_pv_grading
        self.assertNotIn("\n-------\n", pv_gradings)
        self.assertIn(PvGrading.to_str(pv_grading), pv_gradings)

    def test_create_conflicting_final_advice_different_advice_type_different_pv_gradings(
            self):
        """
        Different advice types, different pv gradings
        """
        inputs = [
            (self.gov_user, AdviceType.PROVISO, PvGrading.UK_OFFICIAL),
            (self.gov_user_2, AdviceType.REFUSE,
             PvGrading.UK_OFFICIAL_SENSITIVE),
            (self.gov_user_3, AdviceType.APPROVE, PvGrading.NATO_CONFIDENTIAL),
        ]
        for user, advice_type, pv_grading in inputs:
            self.create_advice(user, self.standard_case, "good", advice_type,
                               AdviceLevel.TEAM, pv_grading)

        response = self.client.get(self.standard_case_url, **self.gov_headers)
        response_data = response.json()["advice"]

        self.assertEqual(response_data[0].get("type").get("key"),
                         "conflicting")
        pv_gradings = Advice.objects.get(
            id=response_data[0]["id"]).collated_pv_grading
        self.assertIn("\n-------\n", pv_gradings)
        for _, _, pv_grading in inputs:
            self.assertIn(PvGrading.to_str(pv_grading), pv_gradings)

    # Normal restrictions on team advice items
    @parameterized.expand([
        [AdviceType.APPROVE],
        [AdviceType.PROVISO],
        [AdviceType.REFUSE],
        [AdviceType.NO_LICENCE_REQUIRED],
        [AdviceType.NOT_APPLICABLE],
    ])
    def test_create_end_user_case_final_advice(self, advice_type):
        """
        Tests that a gov user can create an approval/proviso/refuse/nlr/not_applicable
        piece of team level advice for an end user
        """
        data = {
            "text": "I Am Easy to Find",
            "note": "I Am Easy to Find",
            "type": advice_type,
            "end_user": str(self.standard_application.end_user.party.id),
        }

        if advice_type == AdviceType.PROVISO:
            data["proviso"] = "I am easy to proviso"

        if advice_type == AdviceType.REFUSE:
            data["denial_reasons"] = ["1a", "1b", "1c"]

        response = self.client.post(self.standard_case_url,
                                    **self.gov_headers,
                                    data=[data])

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertIsNotNone(Advice.objects.get())

    def test_user_cannot_create_final_advice_without_permissions(self):
        """
        Tests that the permissions are required to perform final level actions
        """
        self.gov_user.role.permissions.set([])
        self.gov_user.save()
        response = self.client.get(self.standard_case_url, **self.gov_headers)

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

        response = self.client.post(self.standard_case_url, **self.gov_headers)

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

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

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

    def test_cannot_submit_user_level_advice_if_final_advice_exists_on_that_case(
            self):
        """
        Logically blocks the submission of lower tier advice if higher tier advice exists
        """
        FinalAdviceFactory(user=self.gov_user_2,
                           case=self.standard_case,
                           good=self.good)

        data = {
            "text": "I Am Easy to Find",
            "note": "I Am Easy to Find",
            "type": AdviceType.APPROVE,
            "end_user": str(self.standard_application.end_user.party.id),
        }

        response = self.client.post(reverse(
            "cases:user_advice", kwargs={"pk": self.standard_case.id}),
                                    **self.gov_headers,
                                    data=[data])

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

    def test_can_submit_user_level_advice_if_final_advice_has_been_cleared_for_that_team_on_that_case(
        self, ):
        """
        No residual data is left to block lower tier advice being submitted after a clear
        """
        self.create_advice(self.gov_user_2, self.standard_case, "good",
                           AdviceType.PROVISO, AdviceLevel.USER)

        self.client.delete(self.standard_case_url, **self.gov_headers)

        data = {
            "text": "I Am Easy to Find",
            "note": "I Am Easy to Find",
            "type": AdviceType.APPROVE,
            "end_user": str(self.standard_application.end_user.party.id),
        }

        response = self.client.post(reverse(
            "cases:user_advice", kwargs={"pk": self.standard_case.id}),
                                    **self.gov_headers,
                                    data=[data])

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

    def test_cannot_submit_team_level_advice_if_final_advice_exists_for_that_team_on_that_case(
        self, ):
        """
        Logically blocks the submission of lower tier advice if higher tier advice exists
        """
        self.create_advice(self.gov_user_2, self.standard_case, "good",
                           AdviceType.PROVISO, AdviceLevel.FINAL)

        data = {
            "text": "I Am Easy to Find",
            "note": "I Am Easy to Find",
            "type": AdviceType.APPROVE,
            "end_user": str(self.standard_application.end_user.party.id),
        }

        response = self.client.post(reverse(
            "cases:team_advice", kwargs={"pk": self.standard_case.id}),
                                    **self.gov_headers,
                                    data=[data])

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

    def test_can_submit_team_level_advice_if_final_advice_has_been_cleared_for_that_team_on_that_case(
        self, ):
        """
        No residual data is left to block lower tier advice being submitted after a clear
        """
        self.create_advice(self.gov_user_2, self.standard_case, "good",
                           AdviceType.PROVISO, AdviceLevel.TEAM)

        self.client.delete(self.standard_case_url, **self.gov_headers)

        data = {
            "text": "I Am Easy to Find",
            "note": "I Am Easy to Find",
            "type": AdviceType.APPROVE,
            "end_user": str(self.standard_application.end_user.party.id),
        }

        response = self.client.post(reverse(
            "cases:team_advice", kwargs={"pk": self.standard_case.id}),
                                    **self.gov_headers,
                                    data=[data])

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

    def test_create_and_delete_audit_trail_is_created_when_the_appropriate_actions_take_place(
        self, ):
        """
        Audit trail is created when clearing or combining advice
        """
        self.create_advice(self.gov_user, self.standard_case, "end_user",
                           AdviceType.NO_LICENCE_REQUIRED, AdviceLevel.TEAM)
        self.create_advice(self.gov_user_2, self.standard_case, "good",
                           AdviceType.REFUSE, AdviceLevel.TEAM)
        self.create_advice(self.gov_user_3, self.standard_case, "good",
                           AdviceType.PROVISO, AdviceLevel.TEAM)

        self.client.get(self.standard_case_url, **self.gov_headers)
        self.client.delete(self.standard_case_url, **self.gov_headers)

        response = self.client.get(
            reverse("cases:activity", kwargs={"pk": self.standard_case.id}),
            **self.gov_headers)

        self.assertEqual(len(response.json()["activity"]), 3)

    def test_creating_final_advice_does_not_overwrite_user_level_advice_or_team_level_advice(
        self, ):
        """
        Because of the shared parent class, make sure the parent class "save" method is overridden by the child class
        """
        self.create_advice(self.gov_user, self.standard_case, "end_user",
                           AdviceType.NO_LICENCE_REQUIRED, AdviceLevel.USER)
        self.create_advice(self.gov_user, self.standard_case, "end_user",
                           AdviceType.NO_LICENCE_REQUIRED, AdviceLevel.TEAM)
        self.create_advice(self.gov_user, self.standard_case, "end_user",
                           AdviceType.NO_LICENCE_REQUIRED, AdviceLevel.FINAL)

        self.client.get(self.standard_case_url, **self.gov_headers)

        self.assertEqual(Advice.objects.count(), 3)

    @parameterized.expand(CaseStatusEnum.terminal_statuses())
    def test_cannot_create_final_advice_on_case_in_terminal_state(
            self, terminal_status):
        self.standard_application.status = get_case_status_by_status(
            terminal_status)
        self.standard_application.save()

        data = {
            "text": "I Am Easy to Find",
            "note": "I Am Easy to Find",
            "type": AdviceType.APPROVE,
            "end_user": str(self.standard_application.end_user.party.id),
        }

        response = self.client.post(self.standard_case_url,
                                    **self.gov_headers,
                                    data=[data])

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

    def test_get_entity_from_final_advice_model(self):
        data = {
            "text": "I Am Easy to Find",
            "note": "I Am Easy to Find",
            "type": AdviceType.APPROVE,
            "end_user": str(self.standard_application.end_user.party.id),
        }

        self.client.post(self.standard_case_url,
                         **self.gov_headers,
                         data=[data])

        advice_object = Advice.objects.get(
            entity_id=self.standard_application.end_user.party.id)
        self.assertEqual(str(advice_object.end_user.id), data["end_user"])
        self.assertEqual(advice_object.entity, advice_object.end_user)

        entity_field = Advice.ENTITY_FIELDS.copy()
        entity_field.remove("end_user")
        for field in entity_field:
            self.assertIsNone(getattr(advice_object, field, None))

    def test_updating_final_advice_removes_draft_decision_documents(self):
        good = self.standard_application.goods.first().good
        FinalAdviceFactory(
            user=self.gov_user,
            team=self.team,
            case=self.standard_case,
            good=good,
            type=AdviceType.APPROVE,
        )
        template = self.create_letter_template(
            case_types=[self.standard_case.case_type],
            decisions=[Decision.objects.get(name=AdviceType.APPROVE)],
        )
        self.create_generated_case_document(self.standard_case,
                                            template,
                                            advice_type=AdviceType.APPROVE,
                                            visible_to_exporter=False)

        data = {
            "text": "I Am Easy to Find",
            "note": "I Am Easy to Find",
            "type": AdviceType.APPROVE,
            "good": str(good.id),
        }
        response = self.client.post(self.standard_case_url,
                                    **self.gov_headers,
                                    data=[data])

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertFalse(
            GeneratedCaseDocument.objects.filter(
                case=self.standard_case).exists())
class GoodsVerifiedTestsStandardApplication(DataTestClient):
    def setUp(self):
        super().setUp()

        self.report_summary = self.create_picklist_item(
            "Report Summary", self.team, PicklistType.REPORT_SUMMARY,
            PickListStatus.ACTIVE)

        self.good_1 = GoodFactory(
            organisation=self.organisation,
            flags=[FlagFactory(level=FlagLevels.GOOD, team=self.team)])
        self.good_2 = GoodFactory(organisation=self.organisation)

        role = Role(name="review_goods")
        role.permissions.set([constants.GovPermissions.REVIEW_GOODS.name])
        role.save()
        self.gov_user.role = role
        self.gov_user.save()

        self.application = self.create_draft_standard_application(
            organisation=self.organisation)
        self.good_on_application_1 = GoodOnApplication.objects.create(
            good=self.good_1,
            application=self.application,
            quantity=10,
            unit=Units.NAR,
            value=500)
        self.good_on_application_2 = GoodOnApplication.objects.create(
            good=self.good_2,
            application=self.application,
            quantity=10,
            unit=Units.NAR,
            value=500)
        self.case = self.submit_application(self.application)
        self.url = reverse_lazy("goods:control_list_entries",
                                kwargs={"case_pk": self.case.id})

    def test_verify_multiple_goods(self):
        """
        Post multiple goods to the endpoint, and check that the control code is updated for both
        """

        data = {
            "objects": [self.good_1.pk, self.good_2.pk],
            "comment": "I Am Easy to Find",
            "report_summary": self.report_summary.pk,
            "control_list_entries": ["ML1a"],
            "is_good_controlled": True,
        }

        response = self.client.post(self.url, data, **self.gov_headers)
        self.assertEquals(response.status_code, status.HTTP_200_OK)

        verified_good_1 = Good.objects.get(pk=self.good_1.pk)
        verified_good_2 = Good.objects.get(pk=self.good_2.pk)

        self.assertEqual(verified_good_1.control_list_entries.get().rating,
                         "ML1a")
        self.assertEqual(verified_good_2.control_list_entries.get().rating,
                         "ML1a")

    def test_verify_multiple_goods_NLR(self):
        """
        Post multiple goods to the endpoint, and check that the control code is not set if good is not controlled
        """
        data = {
            "objects": [self.good_1.pk, self.good_2.pk],
            "comment": "I Am Easy to Find",
            "report_summary": self.report_summary.pk,
            "control_list_entries": ["ML1a"],
            "is_good_controlled": False,
        }

        response = self.client.post(self.url, data, **self.gov_headers)
        self.assertEquals(response.status_code, status.HTTP_200_OK)

        self.good_1.refresh_from_db()
        self.good_2.refresh_from_db()
        self.assertEqual(self.good_1.control_list_entries.count(), 1)
        self.assertEqual(self.good_2.control_list_entries.count(), 1)

    def test_invalid_good_pk(self):
        # given one of the good pk is invalid
        data = {
            "objects": [self.team.pk, self.good_1.pk],
            "comment": "I Am Easy to Find",
            "report_summary": self.report_summary.pk,
            "is_good_controlled": False,
            "control_list_entries": ["ML1b"],
        }

        # when I review the goods
        response = self.client.post(self.url, data, **self.gov_headers)
        self.assertEquals(response.status_code, 200)

        # then the valid good is updated
        verified_good = Good.objects.get(pk=self.good_1.pk)
        self.assertEqual(verified_good.control_list_entries.count(), 1)

    @parameterized.expand([
        (
            # legacy where frontend doesn't send is_precedent
            {
                "comment": "I Am Easy to Find",
                "is_good_controlled": False,
                "control_list_entries": [],
            },
            False,
        ),
        (
            # precedent = False
            {
                "comment": "I Am Easy to Find",
                "is_good_controlled": False,
                "control_list_entries": [],
                "is_precedent": False,
            },
            False,
        ),
        (
            # precedent = True
            {
                "comment": "I Am Easy to Find",
                "is_good_controlled": False,
                "control_list_entries": [],
                "is_precedent": True,
            },
            True,
        ),
    ])
    def test_is_precedent_is_set(self, input, expected_is_precedent):
        defaults = {
            "objects": [self.good_1.pk],
            "report_summary": self.report_summary.pk,
        }
        data = {**defaults, **input}

        # when I review the goods
        response = self.client.post(self.url, data, **self.gov_headers)
        self.assertEquals(response.status_code, 200)

        # then the good_on_application is updated
        verified_good_on_application = GoodOnApplication.objects.get(
            pk=self.good_on_application_1.pk)
        self.assertEqual(verified_good_on_application.is_precedent,
                         expected_is_precedent)

    def test_standard_invalid_control_list_entries(self):
        """
        Post multiple goods to the endpoint, and that a bad request is returned, and that flags is not updated
        """
        data = {
            "objects": [self.good_1.pk, self.good_2.pk],
            "comment": "I Am Easy to Find",
            "report_summary": self.report_summary.pk,
            "is_good_controlled": True,
            "control_list_entries": ["invalid"],
        }

        response = self.client.post(self.url, data, **self.gov_headers)
        self.assertEquals(response.status_code, status.HTTP_400_BAD_REQUEST)

        # since it has an invalid control code, flags should not be removed
        verified_good = Good.objects.get(pk=self.good_1.pk)
        self.assertTrue(is_not_verified_flag_set_on_good(verified_good))

    def test_standard_controlled_good_empty_control_list_entries(self):
        """
        Post multiple goods, with an blank control_list_entries and is controlled, for a 400 response, and no update of goods
        """
        data = {
            "objects": [self.good_1.pk, self.good_2.pk],
            "comment": "I Am Easy to Find",
            "report_summary": self.report_summary.pk,
            "is_good_controlled": True,
            "control_list_entries": [],
        }

        response = self.client.post(self.url, data, **self.gov_headers)
        self.assertEquals(response.status_code, 200)

    def test_user_cannot_review_good_without_permissions(self):
        """
        Tests that the right level of permissions are required by a gov user to review a good.
        """
        # create a second user to adopt the super user role as it will
        # overwritten otherwise if we try and remove the role from the first
        valid_user = GovUserFactory(
            baseuser_ptr__email="*****@*****.**",
            baseuser_ptr__first_name="John",
            baseuser_ptr__last_name="Smith",
            team=self.team,
            role=self.super_user_role,
        )
        valid_user.save()

        self.gov_user.role = self.default_role
        self.gov_user.save()

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

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

    @parameterized.expand(CaseStatusEnum.terminal_statuses())
    def test_cannot_set_control_list_entries_when_application_in_terminal_state(
            self, terminal_status):
        self.application.status = get_case_status_by_status(terminal_status)
        self.application.save()

        data = {
            "objects": self.good_1.pk,
            "comment": "I Am Easy to Find",
            "report_summary": self.report_summary.pk,
            "control_list_entries": "ML1a",
            "is_good_controlled": "yes",
        }

        response = self.client.post(self.url, data, **self.gov_headers)
        self.assertEquals(response.status_code, status.HTTP_400_BAD_REQUEST)
Exemple #24
0
                                    case=case).exists():
                                CaseAssignment(
                                    user=rule.user,
                                    queue=rule.queue,
                                    case=case).save(audit_user=system_user)
                        team_rule_tier = rule.tier
                        rules_have_been_applied = True
                        break

        # If no rules have been applied, we wish to either move to the next status, or break loop if keep_status is True
        #   or the next status is terminal
        if not rules_have_been_applied:
            next_status = get_next_status_in_workflow_sequence(case)
            if next_status and not next_status.is_terminal and not keep_status:
                old_status = case.status
                case.status = next_status
                case.save()
                audit_trail_service.create(
                    actor=system_user,
                    verb=AuditType.UPDATED_STATUS,
                    target=case,
                    payload={
                        "status": {
                            "new": CaseStatusEnum.get_text(next_status.status),
                            "old": CaseStatusEnum.get_text(old_status.status),
                        }
                    },
                )
            else:
                rules_have_been_applied = True
Exemple #25
0
def apply_flagging_rule_to_all_open_cases(flagging_rule: FlaggingRule):
    """
    Takes a flagging rule and creates a relationship between it's flag and objects that meet match conditions
    """
    if flagging_rule.status == FlagStatuses.ACTIVE and flagging_rule.flag.status == FlagStatuses.ACTIVE:
        # Flagging rules should only be applied to open cases
        draft_and_terminal_statuses = [
            CaseStatusEnum.DRAFT, *CaseStatusEnum.terminal_statuses()
        ]
        open_cases = Case.objects.exclude(
            status__status__in=draft_and_terminal_statuses)

        # Apply the flagging rule to different entities depending on the rule's level
        if flagging_rule.level == FlagLevels.CASE:
            # Add flag to all open Cases
            open_cases = open_cases.filter(
                case_type__reference__in=flagging_rule.matching_values
            ).values_list("id", flat=True)

            flagging_rule.flag.cases.add(*open_cases)

        elif flagging_rule.level == FlagLevels.GOOD:
            clc_entries_of_groups = []
            for group in flagging_rule.matching_groups:
                child_entries = get_clc_child_nodes(group)
                clc_entries_of_groups.extend(child_entries)

            matching_values = flagging_rule.matching_values + clc_entries_of_groups

            # excluded_values contain individual entries and groups
            excluded_values = []
            for rating in flagging_rule.excluded_values:
                entries = get_clc_child_nodes(rating)
                excluded_values.extend(entries)

            # Add flag to all Goods on open Goods Queries
            goods_in_query = GoodsQuery.objects.filter(
                good__control_list_entries__rating__in=matching_values
            ).exclude(status__status__in=draft_and_terminal_statuses)

            if excluded_values:
                # exclusion entries - goods that doesn't contain given control list entries
                goods_in_query = goods_in_query.exclude(
                    good__control_list_entries__rating__in=excluded_values)

            if flagging_rule.is_for_verified_goods_only:
                goods_in_query = goods_in_query.filter(
                    good__status=GoodStatus.VERIFIED)

            goods_in_query = goods_in_query.values_list("good_id", flat=True)
            flagging_rule.flag.goods.add(*goods_in_query)

            # Add flag to all Goods Types
            goods_types = GoodsType.objects.filter(
                application_id__in=open_cases,
                control_list_entries__rating__in=matching_values)

            if excluded_values:
                goods_types = goods_types.exclude(
                    application_id__in=open_cases,
                    control_list_entries__rating__in=excluded_values)

            goods_types = goods_types.values_list("id", flat=True)

            flagging_rule.flag.goods_type.add(*goods_types)

            # Add flag to all open Applications
            goods = GoodOnApplication.objects.filter(
                application_id__in=open_cases,
                good__control_list_entries__rating__in=matching_values)

            if excluded_values:
                goods = goods.exclude(
                    application_id__in=open_cases,
                    good__control_list_entries__rating__in=excluded_values)

            if flagging_rule.is_for_verified_goods_only:
                goods = goods.filter(good__status=GoodStatus.VERIFIED)

            goods = goods.values_list("good_id", flat=True)
            flagging_rule.flag.goods.add(*goods)

        elif flagging_rule.level == FlagLevels.DESTINATION:
            # Add flag to all End Users on open End User Advisory Queries
            end_users = (EndUserAdvisoryQuery.objects.filter(
                end_user__country_id__in=flagging_rule.matching_values
            ).exclude(
                status__status__in=draft_and_terminal_statuses).values_list(
                    "end_user_id", flat=True))
            flagging_rule.flag.parties.add(*end_users)

            # Add flag to all Parties on open Applications
            parties = PartyOnApplication.objects.filter(
                application_id__in=open_cases,
                party__country_id__in=flagging_rule.matching_values
            ).values_list("party_id", flat=True)
            flagging_rule.flag.parties.add(*parties)

            countries = Country.objects.filter(
                id__in=flagging_rule.matching_values).values_list("id",
                                                                  flat=True)
            flagging_rule.flag.countries.add(*countries)
Exemple #26
0
def get_status_value_from_case_status_enum(case_status):
    if CaseStatusEnum.is_system_status(case_status):
        return case_status
    return [x for x in CaseStatusEnum.choices if x[0] == case_status][0][1]
Exemple #27
0
    def post(self, request, case_pk):
        if CaseStatusEnum.is_terminal(self.application.status.status):
            return JsonResponse(
                data={
                    "errors": {
                        "error": [
                            strings.Applications.Generic.
                            TERMINAL_CASE_CANNOT_PERFORM_OPERATION_ERROR
                        ]
                    }
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        case = get_case(case_pk)

        for good in self.get_queryset():
            serializer = self.get_serializer(good)
            serializer.is_valid(raise_exception=True)
            old_control_list_entries = list(
                good.control_list_entries.values_list("rating", flat=True))
            old_is_controlled = good.is_good_controlled
            serializer.save()
            if "control_list_entries" in serializer.data or "is_good_controlled" in serializer.data:
                new_control_list_entries = [
                    item.rating for item in
                    serializer.validated_data["control_list_entries"]
                ]
                new_is_controlled = serializer.validated_data[
                    "is_good_controlled"]
                if new_control_list_entries != old_control_list_entries or new_is_controlled != old_is_controlled:
                    if isinstance(good, GoodsType):
                        good.flags.clear()
                    else:
                        good.good.flags.clear()
                    default_control = [strings.Goods.GOOD_NO_CONTROL_CODE]
                    audit_trail_service.create(
                        actor=request.user,
                        verb=AuditType.GOOD_REVIEWED,
                        action_object=good,
                        target=case,
                        payload={
                            "good_name":
                            good.description,
                            "new_control_list_entry":
                            new_control_list_entries or default_control,
                            "old_control_list_entry":
                            old_control_list_entries or default_control,
                            "old_is_good_controlled":
                            "Yes" if old_is_controlled else "No",
                            "new_is_good_controlled":
                            "Yes" if new_is_controlled else "No",
                            "additional_text":
                            serializer.validated_data["comment"],
                            "is_precedent":
                            serializer.validated_data.get(
                                "is_precedent", False),
                        },
                    )
        apply_good_flagging_rules_for_case(case)
        return JsonResponse(data={}, status=status.HTTP_200_OK)
Exemple #28
0
def get_case_status_list() -> List[Dict]:
    return CaseStatusEnum.as_list()
Exemple #29
0
    def test_apply_flagging_rule_to_open_cases(self, case_status):
        if case_status == CaseStatusEnum.DRAFT:
            case = self.create_draft_standard_application(self.organisation)
        else:
            case = self.create_standard_application_case(self.organisation)
            case.status = get_case_status_by_status(case_status)
            case.save()

        flag = self.create_flag(case.case_type.reference, FlagLevels.CASE, self.team)
        flagging_rule = self.create_flagging_rule(FlagLevels.CASE, self.team, flag, [case.case_type.reference])

        apply_flagging_rule_to_all_open_cases(flagging_rule)

        case.refresh_from_db()

        if CaseStatusEnum.is_terminal(case_status) or case_status == CaseStatusEnum.DRAFT:
            self.assertNotIn(flag, case.flags.all())
        else:
            self.assertIn(flag, case.flags.all())

    def test_apply_verified_goods_only_flagging_rule_to_open_cases_failure(self):
        """ Test flag not applied to good when flagging rule is for verified goods only. """
        case = self.create_standard_application_case(self.organisation)

        flag = self.create_flag("good flag", FlagLevels.GOOD, self.team)
        flagging_rule = self.create_flagging_rule(
            FlagLevels.GOOD, self.team, flag, [case.case_type.reference], is_for_verified_goods_only=True
        )
        good = GoodOnApplication.objects.filter(application_id=case.id).first().good

        apply_flagging_rule_to_all_open_cases(flagging_rule)
    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,
        )