From ef8d7bc14d50c9f809f1d2a59750a4bde1ed13a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Riku=20Kestila=CC=88?= Date: Thu, 7 Dec 2023 15:28:42 +0200 Subject: [PATCH] feat: add callback for receiving delete success message from Ahjo --- .../api/v1/ahjo_integration_views.py | 53 ++++++++++++---- backend/benefit/applications/enums.py | 5 ++ .../tests/test_ahjo_integration.py | 61 ++++++++++++++++--- backend/benefit/helsinkibenefit/urls.py | 2 +- 4 files changed, 100 insertions(+), 21 deletions(-) diff --git a/backend/benefit/applications/api/v1/ahjo_integration_views.py b/backend/benefit/applications/api/v1/ahjo_integration_views.py index 388d4dd24f..4e14dfccb9 100644 --- a/backend/benefit/applications/api/v1/ahjo_integration_views.py +++ b/backend/benefit/applications/api/v1/ahjo_integration_views.py @@ -11,7 +11,11 @@ from rest_framework.views import APIView from applications.api.v1.serializers.ahjo_callback import AhjoCallbackSerializer -from applications.enums import AhjoCallBackStatus, AhjoStatus as AhjoStatusEnum +from applications.enums import ( + AhjoCallBackStatus, + AhjoRequestType, + AhjoStatus as AhjoStatusEnum, +) from applications.models import AhjoStatus, Application, Attachment from common.permissions import SafeListPermission from shared.audit_log import audit_logging @@ -76,7 +80,14 @@ class AhjoCallbackView(APIView): required=True, type=OpenApiTypes.UUID, location=OpenApiParameter.PATH, - ) + ), + OpenApiParameter( + name="request_id", + description="The type of request that Ahjo responded to", + required=True, + type=OpenApiTypes.STR, + location=OpenApiParameter.PATH, + ), ], description="Callback endpoint for Ahjo to send updates to the application.", request=AhjoCallbackSerializer, @@ -97,21 +108,28 @@ def post(self, request, *args, **kwargs): if callback_data["message"] == AhjoCallBackStatus.SUCCESS: ahjo_request_id = callback_data["requestId"] application = get_object_or_404(Application, pk=application_id) - application.ahjo_case_guid = callback_data["caseGuid"] - application.ahjo_case_id = callback_data["caseId"] - application.save() - - AhjoStatus.objects.create( - application=application, status=AhjoStatusEnum.CASE_OPENED - ) + request_type = self.kwargs["request_type"] + + if request_type == AhjoRequestType.OPEN_CASE: + application = self._handle_open_case_callback( + application, callback_data + ) + ahjo_status = AhjoStatusEnum.CASE_OPENED + info = f"""Application ahjo_case_guid and ahjo_case_id + were updated by Ahjo request id: {ahjo_request_id}""" + elif request_type == AhjoRequestType.DELETE_APPLICATION: + self._handle_delete_callback() + ahjo_status = AhjoStatusEnum.DELETE_REQUEST_RECEIVED + info = f"""Application was marked for cancellation in Ahjo with request id: {ahjo_request_id}""" + + AhjoStatus.objects.create(application=application, status=ahjo_status) audit_logging.log( request.user, "", Operation.UPDATE, application, - additional_information=f"""Application ahjo_case_guid and ahjo_case_id were updated - by Ahjo request id: {ahjo_request_id}""", + additional_information=info, ) return Response( @@ -128,3 +146,16 @@ def post(self, request, *args, **kwargs): {"message": "Callback received but unsuccessful"}, status=status.HTTP_200_OK, ) + + def _create_status(self, application: Application, status: AhjoStatusEnum): + return AhjoStatus.objects.create(application=application, status=status) + + def _handle_open_case_callback(self, application: Application, callback_data: dict): + application.ahjo_case_guid = callback_data["caseGuid"] + application.ahjo_case_id = callback_data["caseId"] + application.save() + return application + + def _handle_delete_callback(self): + # do anything that needs to be done when Ahjo sends a delete callback + pass diff --git a/backend/benefit/applications/enums.py b/backend/benefit/applications/enums.py index 7e073f28c0..c102863f05 100644 --- a/backend/benefit/applications/enums.py +++ b/backend/benefit/applications/enums.py @@ -172,3 +172,8 @@ class ApplicationActions(models.TextChoices): class AhjoCallBackStatus(models.TextChoices): SUCCESS = "Success", _("Success") FAILURE = "Failure", _("Failure") + + +class AhjoRequestType(models.TextChoices): + OPEN_CASE = "open_case", _("Open case in Ahjo") + DELETE_APPLICATION = "delete_application", _("Delete application in Ahjo") diff --git a/backend/benefit/applications/tests/test_ahjo_integration.py b/backend/benefit/applications/tests/test_ahjo_integration.py index 2ad185c4eb..b8e67caa35 100644 --- a/backend/benefit/applications/tests/test_ahjo_integration.py +++ b/backend/benefit/applications/tests/test_ahjo_integration.py @@ -13,6 +13,7 @@ from applications.api.v1.ahjo_integration_views import AhjoAttachmentView from applications.enums import ( AhjoCallBackStatus, + AhjoRequestType, AhjoStatus, ApplicationStatus, BenefitType, @@ -365,9 +366,27 @@ def test_get_attachment_unauthorized_ip_not_allowed( assert response.status_code == 403 +@pytest.mark.parametrize( + "request_type, ahjo_status", + [ + ( + AhjoRequestType.OPEN_CASE, + AhjoStatus.CASE_OPENED, + ), + ( + AhjoRequestType.DELETE_APPLICATION, + AhjoStatus.DELETE_REQUEST_RECEIVED, + ), + ], +) @pytest.mark.django_db def test_ahjo_callback_success( - ahjo_client, ahjo_user_token, decided_application, settings + ahjo_client, + ahjo_user_token, + decided_application, + settings, + request_type, + ahjo_status, ): settings.NEXT_PUBLIC_MOCK_FLAG = True auth_headers = {"HTTP_AUTHORIZATION": "Token " + ahjo_user_token.key} @@ -377,22 +396,36 @@ def test_ahjo_callback_success( "caseId": "HEL 2023-999999", "caseGuid": f"{uuid.uuid4()}", } - url = reverse("ahjo_callback_url", kwargs={"uuid": decided_application.id}) + url = reverse( + "ahjo_callback_url", + kwargs={"request_type": request_type, "uuid": decided_application.id}, + ) response = ahjo_client.post(url, **auth_headers, data=callback_payload) decided_application.refresh_from_db() assert response.status_code == 200 assert response.data == {"message": "Callback received"} - assert decided_application.ahjo_case_id == callback_payload["caseId"] - assert str(decided_application.ahjo_case_guid) == callback_payload["caseGuid"] - assert decided_application.ahjo_status.latest().status == AhjoStatus.CASE_OPENED + if request_type == AhjoRequestType.OPEN_CASE: + assert decided_application.ahjo_case_id == callback_payload["caseId"] + assert str(decided_application.ahjo_case_guid) == callback_payload["caseGuid"] + assert decided_application.ahjo_status.latest().status == ahjo_status +@pytest.mark.parametrize( + "request_type", + [ + (AhjoRequestType.OPEN_CASE,), + (AhjoRequestType.DELETE_APPLICATION,), + ], +) def test_ahjo_callback_unauthorized_wrong_or_missing_credentials( - anonymous_client, decided_application, settings + anonymous_client, decided_application, settings, request_type ): settings.NEXT_PUBLIC_MOCK_FLAG = True - url = reverse("ahjo_callback_url", kwargs={"uuid": decided_application.id}) + url = reverse( + "ahjo_callback_url", + kwargs={"request_type": request_type, "uuid": decided_application.id}, + ) response = anonymous_client.post(url) assert response.status_code == 401 @@ -403,11 +436,21 @@ def test_ahjo_callback_unauthorized_wrong_or_missing_credentials( assert response.status_code == 401 +@pytest.mark.parametrize( + "request_type", + [ + (AhjoRequestType.OPEN_CASE,), + (AhjoRequestType.DELETE_APPLICATION,), + ], +) def test_ahjo_callback_unauthorized_ip_not_allowed( - ahjo_client, ahjo_user_token, decided_application, settings + ahjo_client, ahjo_user_token, decided_application, settings, request_type ): settings.NEXT_PUBLIC_MOCK_FLAG = False - url = reverse("ahjo_callback_url", kwargs={"uuid": decided_application.id}) + url = reverse( + "ahjo_callback_url", + kwargs={"request_type": request_type, "uuid": decided_application.id}, + ) auth_headers = {"HTTP_AUTHORIZATION": "Token " + ahjo_user_token.key} response = ahjo_client.post(url, **auth_headers) diff --git a/backend/benefit/helsinkibenefit/urls.py b/backend/benefit/helsinkibenefit/urls.py index e498eb28c2..e290d9a149 100644 --- a/backend/benefit/helsinkibenefit/urls.py +++ b/backend/benefit/helsinkibenefit/urls.py @@ -66,7 +66,7 @@ urlpatterns = [ path("admin/", admin.site.urls), path( - "v1/ahjo-integration/callback/", + "v1/ahjo-integration/callback//", AhjoCallbackView.as_view(), name="ahjo_callback_url", ),