From 5024cf8b13dae1923a0712edb01924fb477d5aaf Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Thu, 7 Oct 2021 14:12:28 +0100 Subject: [PATCH] Limit ARS updates to specific product on application Annual report summary (ARS) is specific to a product on application. If the same product is used on other application then updating ARS in one application was updating the value in the other application also. This has been fixed but the fix was failing if the same product is added twice in the same application. This is because API receives list of underlying product ids (Good) and we use them to retrieve all matching products on application (GoodOnApplication). This is the current behaviour because if the underlying product is same for all products on applications then reviewing one good CLC entries automatically marks all of them as verified. This is correct but it causes issues with Report summary. This is fixed by taking the current product on application as input and limiting the updates for this field only to this object. An Audit log is also created whenever ARS value is updated. --- api/audit_trail/enums.py | 1 + .../migrations/0002_auto_20211007_1352.py | 244 ++++++++++++++++++ api/audit_trail/payload.py | 1 + api/goods/tests/test_control_codes.py | 53 ++++ api/goods/views.py | 33 ++- api/workflow/tests/test_flagging_rules.py | 1 + 6 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 api/audit_trail/migrations/0002_auto_20211007_1352.py diff --git a/api/audit_trail/enums.py b/api/audit_trail/enums.py index e062e07e7..c8472cf82 100644 --- a/api/audit_trail/enums.py +++ b/api/audit_trail/enums.py @@ -117,6 +117,7 @@ class AuditType(LiteEnum): OGEL_REISSUED = autostr() LICENCE_UPDATED_STATUS = autostr() DOCUMENT_ON_ORGANISATION_CREATE = autostr() + REPORT_SUMMARY_UPDATED = autostr() def human_readable(self): """ diff --git a/api/audit_trail/migrations/0002_auto_20211007_1352.py b/api/audit_trail/migrations/0002_auto_20211007_1352.py new file mode 100644 index 000000000..960df6358 --- /dev/null +++ b/api/audit_trail/migrations/0002_auto_20211007_1352.py @@ -0,0 +1,244 @@ +# Generated by Django 3.1.8 on 2021-10-07 12:52 + +import api.audit_trail.enums +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("audit_trail", "0001_squashed_0028_merge_20210224_1641"), + ] + + operations = [ + migrations.AlterField( + model_name="audit", + name="verb", + field=models.CharField( + choices=[ + (api.audit_trail.enums.AuditType["CREATED"], "created"), + (api.audit_trail.enums.AuditType["OGL_CREATED"], "ogl_created"), + (api.audit_trail.enums.AuditType["OGL_FIELD_EDITED"], "ogl_field_edited"), + (api.audit_trail.enums.AuditType["OGL_MULTI_FIELD_EDITED"], "ogl_multi_field_edited"), + (api.audit_trail.enums.AuditType["ADD_FLAGS"], "add_flags"), + (api.audit_trail.enums.AuditType["REMOVE_FLAGS"], "remove_flags"), + (api.audit_trail.enums.AuditType["GOOD_REVIEWED"], "good_reviewed"), + (api.audit_trail.enums.AuditType["GOOD_ADD_FLAGS"], "good_add_flags"), + (api.audit_trail.enums.AuditType["GOOD_REMOVE_FLAGS"], "good_remove_flags"), + (api.audit_trail.enums.AuditType["GOOD_ADD_REMOVE_FLAGS"], "good_add_remove_flags"), + (api.audit_trail.enums.AuditType["DESTINATION_ADD_FLAGS"], "destination_add_flags"), + (api.audit_trail.enums.AuditType["DESTINATION_REMOVE_FLAGS"], "destination_remove_flags"), + (api.audit_trail.enums.AuditType["ADD_GOOD_TO_APPLICATION"], "add_good_to_application"), + (api.audit_trail.enums.AuditType["REMOVE_GOOD_FROM_APPLICATION"], "remove_good_from_application"), + (api.audit_trail.enums.AuditType["ADD_GOOD_TYPE_TO_APPLICATION"], "add_good_type_to_application"), + ( + api.audit_trail.enums.AuditType["REMOVE_GOOD_TYPE_FROM_APPLICATION"], + "remove_good_type_from_application", + ), + ( + api.audit_trail.enums.AuditType["UPDATE_APPLICATION_END_USE_DETAIL"], + "update_application_end_use_detail", + ), + ( + api.audit_trail.enums.AuditType["UPDATE_APPLICATION_TEMPORARY_EXPORT"], + "update_application_temporary_export", + ), + ( + api.audit_trail.enums.AuditType["REMOVED_SITES_FROM_APPLICATION"], + "removed_sites_from_application", + ), + (api.audit_trail.enums.AuditType["ADD_SITES_TO_APPLICATION"], "add_sites_to_application"), + ( + api.audit_trail.enums.AuditType["REMOVED_EXTERNAL_LOCATIONS_FROM_APPLICATION"], + "removed_external_locations_from_application", + ), + ( + api.audit_trail.enums.AuditType["ADD_EXTERNAL_LOCATIONS_TO_APPLICATION"], + "add_external_locations_to_application", + ), + ( + api.audit_trail.enums.AuditType["REMOVED_COUNTRIES_FROM_APPLICATION"], + "removed_countries_from_application", + ), + (api.audit_trail.enums.AuditType["ADD_COUNTRIES_TO_APPLICATION"], "add_countries_to_application"), + ( + api.audit_trail.enums.AuditType["ADD_ADDITIONAL_CONTACT_TO_CASE"], + "add_additional_contact_to_case", + ), + (api.audit_trail.enums.AuditType["MOVE_CASE"], "move_case"), + (api.audit_trail.enums.AuditType["ASSIGN_CASE"], "assign_case"), + (api.audit_trail.enums.AuditType["ASSIGN_USER_TO_CASE"], "assign_user_to_case"), + (api.audit_trail.enums.AuditType["REMOVE_CASE"], "remove_case"), + (api.audit_trail.enums.AuditType["REMOVE_CASE_FROM_ALL_QUEUES"], "remove_case_from_all_queues"), + ( + api.audit_trail.enums.AuditType["REMOVE_CASE_FROM_ALL_USER_ASSIGNMENTS"], + "remove_case_from_all_user_assignments", + ), + (api.audit_trail.enums.AuditType["CLC_RESPONSE"], "clc_response"), + (api.audit_trail.enums.AuditType["PV_GRADING_RESPONSE"], "pv_grading_response"), + (api.audit_trail.enums.AuditType["CREATED_CASE_NOTE"], "created_case_note"), + (api.audit_trail.enums.AuditType["ECJU_QUERY"], "ecju_query"), + (api.audit_trail.enums.AuditType["UPDATED_STATUS"], "updated_status"), + (api.audit_trail.enums.AuditType["UPDATED_APPLICATION_NAME"], "updated_application_name"), + ( + api.audit_trail.enums.AuditType["UPDATE_APPLICATION_LETTER_REFERENCE"], + "update_application_letter_reference", + ), + ( + api.audit_trail.enums.AuditType["UPDATE_APPLICATION_F680_CLEARANCE_TYPES"], + "update_application_f680_clearance_types", + ), + ( + api.audit_trail.enums.AuditType["ADDED_APPLICATION_LETTER_REFERENCE"], + "added_application_letter_reference", + ), + ( + api.audit_trail.enums.AuditType["REMOVED_APPLICATION_LETTER_REFERENCE"], + "removed_application_letter_reference", + ), + (api.audit_trail.enums.AuditType["ASSIGNED_COUNTRIES_TO_GOOD"], "assigned_countries_to_good"), + (api.audit_trail.enums.AuditType["REMOVED_COUNTRIES_FROM_GOOD"], "removed_countries_from_good"), + (api.audit_trail.enums.AuditType["CREATED_FINAL_ADVICE"], "created_final_advice"), + (api.audit_trail.enums.AuditType["CLEARED_FINAL_ADVICE"], "cleared_final_advice"), + (api.audit_trail.enums.AuditType["CREATED_TEAM_ADVICE"], "created_team_advice"), + (api.audit_trail.enums.AuditType["CLEARED_TEAM_ADVICE"], "cleared_team_advice"), + (api.audit_trail.enums.AuditType["CREATED_USER_ADVICE"], "created_user_advice"), + (api.audit_trail.enums.AuditType["ADD_PARTY"], "add_party"), + (api.audit_trail.enums.AuditType["REMOVE_PARTY"], "remove_party"), + (api.audit_trail.enums.AuditType["UPLOAD_PARTY_DOCUMENT"], "upload_party_document"), + (api.audit_trail.enums.AuditType["DELETE_PARTY_DOCUMENT"], "delete_party_document"), + (api.audit_trail.enums.AuditType["UPLOAD_APPLICATION_DOCUMENT"], "upload_application_document"), + (api.audit_trail.enums.AuditType["DELETE_APPLICATION_DOCUMENT"], "delete_application_document"), + (api.audit_trail.enums.AuditType["UPLOAD_CASE_DOCUMENT"], "upload_case_document"), + (api.audit_trail.enums.AuditType["GENERATE_CASE_DOCUMENT"], "generate_case_document"), + (api.audit_trail.enums.AuditType["ADD_CASE_OFFICER_TO_CASE"], "add_case_officer_to_case"), + (api.audit_trail.enums.AuditType["REMOVE_CASE_OFFICER_FROM_CASE"], "remove_case_officer_from_case"), + (api.audit_trail.enums.AuditType["GRANTED_APPLICATION"], "granted_application"), + (api.audit_trail.enums.AuditType["REINSTATED_APPLICATION"], "reinstated_application"), + (api.audit_trail.enums.AuditType["FINALISED_APPLICATION"], "finalised_application"), + (api.audit_trail.enums.AuditType["UNASSIGNED_QUEUES"], "unassigned_queues"), + (api.audit_trail.enums.AuditType["UNASSIGNED"], "unassigned"), + (api.audit_trail.enums.AuditType["CREATED_DOCUMENT_TEMPLATE"], "created_document_template"), + (api.audit_trail.enums.AuditType["UPDATED_LETTER_TEMPLATE_NAME"], "updated_letter_template_name"), + ( + api.audit_trail.enums.AuditType["ADDED_LETTER_TEMPLATE_CASE_TYPES"], + "added_letter_template_case_types", + ), + ( + api.audit_trail.enums.AuditType["UPDATED_LETTER_TEMPLATE_CASE_TYPES"], + "updated_letter_template_case_types", + ), + ( + api.audit_trail.enums.AuditType["REMOVED_LETTER_TEMPLATE_CASE_TYPES"], + "removed_letter_template_case_types", + ), + ( + api.audit_trail.enums.AuditType["ADDED_LETTER_TEMPLATE_DECISIONS"], + "added_letter_template_decisions", + ), + ( + api.audit_trail.enums.AuditType["UPDATED_LETTER_TEMPLATE_DECISIONS"], + "updated_letter_template_decisions", + ), + ( + api.audit_trail.enums.AuditType["REMOVED_LETTER_TEMPLATE_DECISIONS"], + "removed_letter_template_decisions", + ), + ( + api.audit_trail.enums.AuditType["UPDATED_LETTER_TEMPLATE_PARAGRAPHS"], + "updated_letter_template_paragraphs", + ), + ( + api.audit_trail.enums.AuditType["REMOVED_LETTER_TEMPLATE_PARAGRAPHS"], + "removed_letter_template_paragraphs", + ), + ( + api.audit_trail.enums.AuditType["ADDED_LETTER_TEMPLATE_PARAGRAPHS"], + "added_letter_template_paragraphs", + ), + ( + api.audit_trail.enums.AuditType["UPDATED_LETTER_TEMPLATE_LAYOUT"], + "updated_letter_template_layout", + ), + ( + api.audit_trail.enums.AuditType["UPDATED_LETTER_TEMPLATE_PARAGRAPHS_ORDERING"], + "updated_letter_template_paragraphs_ordering", + ), + ( + api.audit_trail.enums.AuditType["UPDATED_LETTER_TEMPLATE_INCLUDE_DIGITAL_SIGNATURE"], + "updated_letter_template_include_digital_signature", + ), + (api.audit_trail.enums.AuditType["CREATED_PICKLIST"], "created_picklist"), + (api.audit_trail.enums.AuditType["UPDATED_PICKLIST_TEXT"], "updated_picklist_text"), + (api.audit_trail.enums.AuditType["UPDATED_PICKLIST_NAME"], "updated_picklist_name"), + (api.audit_trail.enums.AuditType["DEACTIVATE_PICKLIST"], "deactivate_picklist"), + (api.audit_trail.enums.AuditType["REACTIVATE_PICKLIST"], "reactivate_picklist"), + ( + api.audit_trail.enums.AuditType["UPDATED_EXHIBITION_DETAILS_TITLE"], + "updated_exhibition_details_title", + ), + ( + api.audit_trail.enums.AuditType["UPDATED_EXHIBITION_DETAILS_START_DATE"], + "updated_exhibition_details_start_date", + ), + ( + api.audit_trail.enums.AuditType["UPDATED_EXHIBITION_DETAILS_REQUIRED_BY_DATE"], + "updated_exhibition_details_required_by_date", + ), + ( + api.audit_trail.enums.AuditType["UPDATED_EXHIBITION_DETAILS_REASON_FOR_CLEARANCE"], + "updated_exhibition_details_reason_for_clearance", + ), + (api.audit_trail.enums.AuditType["UPDATED_ROUTE_OF_GOODS"], "updated_route_of_goods"), + (api.audit_trail.enums.AuditType["UPDATED_ORGANISATION"], "updated_organisation"), + (api.audit_trail.enums.AuditType["CREATED_ORGANISATION"], "created_organisation"), + (api.audit_trail.enums.AuditType["REGISTER_ORGANISATION"], "register_organisation"), + (api.audit_trail.enums.AuditType["REJECTED_ORGANISATION"], "rejected_organisation"), + (api.audit_trail.enums.AuditType["APPROVED_ORGANISATION"], "approved_organisation"), + (api.audit_trail.enums.AuditType["REMOVED_FLAG_ON_ORGANISATION"], "removed_flag_on_organisation"), + (api.audit_trail.enums.AuditType["ADDED_FLAG_ON_ORGANISATION"], "added_flag_on_organisation"), + (api.audit_trail.enums.AuditType["RERUN_ROUTING_RULES"], "rerun_routing_rules"), + (api.audit_trail.enums.AuditType["ENFORCEMENT_CHECK"], "enforcement_check"), + (api.audit_trail.enums.AuditType["UPDATED_SITE"], "updated_site"), + (api.audit_trail.enums.AuditType["CREATED_SITE"], "created_site"), + (api.audit_trail.enums.AuditType["UPDATED_SITE_NAME"], "updated_site_name"), + (api.audit_trail.enums.AuditType["COMPLIANCE_SITE_CASE_CREATE"], "compliance_site_case_create"), + ( + api.audit_trail.enums.AuditType["COMPLIANCE_SITE_CASE_NEW_LICENCE"], + "compliance_site_case_new_licence", + ), + (api.audit_trail.enums.AuditType["ADDED_NEXT_REVIEW_DATE"], "added_next_review_date"), + (api.audit_trail.enums.AuditType["EDITED_NEXT_REVIEW_DATE"], "edited_next_review_date"), + (api.audit_trail.enums.AuditType["REMOVED_NEXT_REVIEW_DATE"], "removed_next_review_date"), + (api.audit_trail.enums.AuditType["COMPLIANCE_VISIT_CASE_CREATED"], "compliance_visit_case_created"), + (api.audit_trail.enums.AuditType["COMPLIANCE_VISIT_CASE_UPDATED"], "compliance_visit_case_updated"), + ( + api.audit_trail.enums.AuditType["COMPLIANCE_PEOPLE_PRESENT_CREATED"], + "compliance_people_present_created", + ), + ( + api.audit_trail.enums.AuditType["COMPLIANCE_PEOPLE_PRESENT_UPDATED"], + "compliance_people_present_updated", + ), + ( + api.audit_trail.enums.AuditType["COMPLIANCE_PEOPLE_PRESENT_DELETED"], + "compliance_people_present_deleted", + ), + ( + api.audit_trail.enums.AuditType["UPDATED_GOOD_ON_DESTINATION_MATRIX"], + "updated_good_on_destination_matrix", + ), + (api.audit_trail.enums.AuditType["LICENCE_UPDATED_GOOD_USAGE"], "licence_updated_good_usage"), + (api.audit_trail.enums.AuditType["OGEL_REISSUED"], "ogel_reissued"), + (api.audit_trail.enums.AuditType["LICENCE_UPDATED_STATUS"], "licence_updated_status"), + ( + api.audit_trail.enums.AuditType["DOCUMENT_ON_ORGANISATION_CREATE"], + "document_on_organisation_create", + ), + (api.audit_trail.enums.AuditType["REPORT_SUMMARY_UPDATED"], "report_summary_updated"), + ], + db_index=True, + max_length=255, + ), + ), + ] diff --git a/api/audit_trail/payload.py b/api/audit_trail/payload.py index fcd3caf36..8555430e2 100644 --- a/api/audit_trail/payload.py +++ b/api/audit_trail/payload.py @@ -125,4 +125,5 @@ def format_payload(audit_type, payload): AuditType.OGEL_REISSUED: strings.Audit.OGEL_REISSUED, AuditType.LICENCE_UPDATED_STATUS: strings.Audit.LICENCE_UPDATED_STATUS, AuditType.DOCUMENT_ON_ORGANISATION_CREATE: "added {document_type} '{file_name}' to organization", + AuditType.REPORT_SUMMARY_UPDATED: "updated ARS for {good_name} from {old_report_summary} to {report_summary}", } diff --git a/api/goods/tests/test_control_codes.py b/api/goods/tests/test_control_codes.py index 167c3ac20..31f484baf 100644 --- a/api/goods/tests/test_control_codes.py +++ b/api/goods/tests/test_control_codes.py @@ -2,6 +2,8 @@ from parameterized import parameterized from rest_framework import status +from api.audit_trail.enums import AuditType +from api.audit_trail.models import Audit from api.applications.models import GoodOnApplication from api.core import constants from api.flags.enums import FlagLevels @@ -56,6 +58,7 @@ def test_verify_multiple_goods(self): data = { "objects": [self.good_1.pk, self.good_2.pk], + "current_object": self.good_on_application_1.pk, "comment": "I Am Easy to Find", "report_summary": self.report_summary.text, "control_list_entries": ["ML1a"], @@ -78,6 +81,7 @@ def test_report_summary_saved_goodonapplication(self): data = { "objects": [self.good_1.pk], + "current_object": self.good_on_application_1.pk, "control_list_entries": ["ML1a"], "is_precedent": False, "is_good_controlled": True, @@ -98,6 +102,7 @@ def test_verify_multiple_goods_NLR(self): """ data = { "objects": [self.good_1.pk, self.good_2.pk], + "current_object": self.good_on_application_1.pk, "comment": "I Am Easy to Find", "report_summary": self.report_summary.text, "control_list_entries": ["ML1a"], @@ -116,6 +121,7 @@ def test_invalid_good_pk(self): # given one of the good pk is invalid data = { "objects": [self.team.pk, self.good_1.pk], + "current_object": self.good_on_application_1.pk, "comment": "I Am Easy to Find", "report_summary": self.report_summary.text, "is_good_controlled": False, @@ -162,6 +168,7 @@ def test_invalid_good_pk(self): def test_is_precedent_is_set(self, input, expected_is_precedent): defaults = { "objects": [self.good_1.pk], + "current_object": self.good_on_application_1.pk, "report_summary": self.report_summary.text, } data = {**defaults, **input} @@ -180,6 +187,7 @@ def test_standard_invalid_control_list_entries(self): """ data = { "objects": [self.good_1.pk, self.good_2.pk], + "current_object": self.good_on_application_1.pk, "comment": "I Am Easy to Find", "report_summary": self.report_summary.text, "is_good_controlled": True, @@ -199,6 +207,7 @@ def test_standard_controlled_good_empty_control_list_entries(self): """ data = { "objects": [self.good_1.pk, self.good_2.pk], + "current_object": self.good_on_application_1.pk, "comment": "I Am Easy to Find", "report_summary": self.report_summary.text, "is_good_controlled": True, @@ -237,6 +246,7 @@ def test_cannot_set_control_list_entries_when_application_in_terminal_state(self data = { "objects": self.good_1.pk, + "current_object": self.good_on_application_1.pk, "comment": "I Am Easy to Find", "report_summary": self.report_summary.text, "control_list_entries": "ML1a", @@ -246,6 +256,46 @@ def test_cannot_set_control_list_entries_when_application_in_terminal_state(self response = self.client.post(self.url, data, **self.gov_headers) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + def test_report_summary_updates_same_product_added_twice(self): + self.product_on_application1 = GoodOnApplication.objects.create( + good=self.good_1, + application=self.application, + quantity=10, + unit=Units.NAR, + value=500, + report_summary="Rifles (10)", + ) + self.product_on_application2 = GoodOnApplication.objects.create( + good=self.good_1, + application=self.application, + quantity=5, + unit=Units.NAR, + value=500, + report_summary="Rifles (5)", + ) + data = { + "objects": [self.good_1.pk], + "current_object": self.product_on_application1.pk, + "control_list_entries": ["ML1a"], + "is_precedent": False, + "is_good_controlled": True, + "end_use_control": [], + "report_summary": "Sniper rifles (10)", + "comment": "report summary update test", + } + + response = self.client.post(self.url, data, **self.gov_headers) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.product_on_application1.refresh_from_db() + + self.assertEqual(self.product_on_application1.report_summary, "Sniper rifles (10)") + self.assertEqual(self.product_on_application2.report_summary, "Rifles (5)") + audit_qs = Audit.objects.filter(verb=AuditType.REPORT_SUMMARY_UPDATED) + self.assertEqual(audit_qs.count(), 1) + audit_payload = audit_qs.first().payload + self.assertEqual(audit_payload["old_report_summary"], "Rifles (10)") + self.assertEqual(audit_payload["report_summary"], "Sniper rifles (10)") + class GoodsVerifiedTestsOpenApplication(DataTestClient): def setUp(self): @@ -276,6 +326,7 @@ def test_verify_single_good(self): """ data = { "objects": self.good_1.pk, + "current_object": self.good_1.pk, "comment": "I Am Easy to Find", "report_summary": self.report_summary.text, "is_good_controlled": True, @@ -300,6 +351,7 @@ def test_verify_only_change_comment_doesnt_remove_flags(self): self.good_1.save() data = { "objects": self.good_1.pk, + "current_object": self.good_1.pk, "comment": "I Am Easy to Find", "report_summary": self.report_summary.text, "control_list_entries": ["ML1a"], @@ -322,6 +374,7 @@ def test_invalid_control_list_entries(self): data = { "objects": [self.good_1.pk, self.good_2.pk], + "current_object": self.good_1.pk, "comment": "I Am Easy to Find", "report_summary": self.report_summary.text, "control_list_entries": ["invalid"], diff --git a/api/goods/views.py b/api/goods/views.py index 48459251a..78cc22ed3 100644 --- a/api/goods/views.py +++ b/api/goods/views.py @@ -92,11 +92,40 @@ def post(self, request, case_pk): case = get_case(case_pk) for good in self.get_queryset(): - serializer = self.get_serializer(good) + data = request.data.copy() + serializer_class = self.get_serializer_class() + if data["report_summary"] != good.report_summary and str(good.id) != data.get( + "current_object", str(good.id) + ): + data["report_summary"] = good.report_summary + + serializer = serializer_class(good, data=data) 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() + old_report_summary = good.report_summary + + obj = serializer.save() + + if request.data["report_summary"] != old_report_summary: + if str(good.id) == request.data.get("current_object", str(good.id)): + if isinstance(good, GoodsType): + name = good.description + else: + name = good.name + + audit_trail_service.create( + actor=request.user, + verb=AuditType.REPORT_SUMMARY_UPDATED, + action_object=obj, + target=case, + payload={ + "good_name": name, + "old_report_summary": old_report_summary, + "report_summary": obj.report_summary, + }, + ) + 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"] diff --git a/api/workflow/tests/test_flagging_rules.py b/api/workflow/tests/test_flagging_rules.py index c0688074b..418a41562 100644 --- a/api/workflow/tests/test_flagging_rules.py +++ b/api/workflow/tests/test_flagging_rules.py @@ -107,6 +107,7 @@ def test_goods_flag_before_and_after_reviewing_good(self): self.url = reverse_lazy("goods:control_list_entries", kwargs={"case_pk": case.id}) data = { "objects": [good.id], + "current_object": good.id, "comment": "Update rating to match with flag excluded value", "report_summary": "test report summary", "control_list_entries": ["ML8b"],