Skip to content

Commit

Permalink
feat: add callback for receiving delete success message from Ahjo
Browse files Browse the repository at this point in the history
  • Loading branch information
rikuke committed Dec 7, 2023
1 parent faa899c commit ef8d7bc
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 21 deletions.
53 changes: 42 additions & 11 deletions backend/benefit/applications/api/v1/ahjo_integration_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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(
Expand All @@ -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
5 changes: 5 additions & 0 deletions backend/benefit/applications/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
61 changes: 52 additions & 9 deletions backend/benefit/applications/tests/test_ahjo_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from applications.api.v1.ahjo_integration_views import AhjoAttachmentView
from applications.enums import (
AhjoCallBackStatus,
AhjoRequestType,
AhjoStatus,
ApplicationStatus,
BenefitType,
Expand Down Expand Up @@ -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}
Expand All @@ -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
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion backend/benefit/helsinkibenefit/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
urlpatterns = [
path("admin/", admin.site.urls),
path(
"v1/ahjo-integration/callback/<uuid:uuid>",
"v1/ahjo-integration/callback/<str:request_type>/<uuid:uuid>",
AhjoCallbackView.as_view(),
name="ahjo_callback_url",
),
Expand Down

0 comments on commit ef8d7bc

Please sign in to comment.