Skip to content

Commit

Permalink
feat: add function that performs delete/cancel request to Ahjo
Browse files Browse the repository at this point in the history
  • Loading branch information
rikuke committed Dec 8, 2023
1 parent ef8d7bc commit 77a66fc
Show file tree
Hide file tree
Showing 2 changed files with 200 additions and 70 deletions.
96 changes: 70 additions & 26 deletions backend/benefit/applications/services/ahjo_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@
from django.db.models import QuerySet
from django.urls import reverse

from applications.enums import AhjoStatus as AhjoStatusEnum, ApplicationStatus
from applications.models import AhjoSetting, AhjoStatus, Application
from applications.enums import (
AhjoRequestType,
AhjoStatus as AhjoStatusEnum,
ApplicationStatus,
)
from applications.models import AhjoSetting, AhjoStatus, Application, Attachment
from applications.services.ahjo_authentication import AhjoConnector
from applications.services.ahjo_payload import prepare_open_case_payload
from applications.services.applications_csv_report import ApplicationsCsvService
Expand Down Expand Up @@ -383,9 +387,14 @@ def get_token() -> str:
return


def prepare_headers(access_token: str, application_uuid: uuid) -> dict:
def prepare_headers(
access_token: str, application: Application, request_type: AhjoRequestType
) -> dict:
"""Prepare the headers for the Ahjo request."""
url = reverse("ahjo_callback_url", kwargs={"uuid": str(application_uuid)})
url = reverse(
"ahjo_callback_url",
kwargs={"request_type": request_type, "uuid": str(application.id)},
)

return {
"Authorization": f"Bearer {access_token}",
Expand All @@ -394,7 +403,7 @@ def prepare_headers(access_token: str, application_uuid: uuid) -> dict:
}


def get_application_for_ahjo(id: uuid) -> Optional[Application]:
def get_application_for_ahjo(id: uuid.UUID) -> Optional[Application]:
"""Get the first accepted application."""
application = (
Application.objects.filter(pk=id, status=ApplicationStatus.ACCEPTED)
Expand All @@ -411,52 +420,87 @@ def get_application_for_ahjo(id: uuid) -> Optional[Application]:
return application


def create_status_for_application(application: Application):
def create_status_for_application(application: Application, status: AhjoStatusEnum):
"""Create a new AhjoStatus for the application."""
AhjoStatus.objects.create(
application=application, status=AhjoStatusEnum.REQUEST_TO_OPEN_CASE_SENT
)
AhjoStatus.objects.create(application=application, status=status)


def do_ahjo_request_with_json_payload(
url: str, headers: dict, data: dict, application: Application, timeout: int = 10
def send_request_to_ahjo(
request_type: AhjoRequestType,
headers: dict,
application: Application,
data: dict = {},
timeout: int = 10,
):
"""Send a request to Ahjo."""
headers["Content-Type"] = "application/json"

json_data = json.dumps(data)
url_base = f"{settings.AHJO_REST_API_URL}/cases"

if request_type == AhjoRequestType.OPEN_CASE:
method = "POST"
status = AhjoStatusEnum.REQUEST_TO_OPEN_CASE_SENT
api_url = url_base
data = json.dumps(data)
elif request_type == AhjoRequestType.DELETE_APPLICATION:
method = "DELETE"
status = AhjoStatusEnum.DELETE_REQUEST_SENT
api_url = f"{url_base}/{application.ahjo_case_id}"

try:
response = requests.post(
f"{url}/cases", headers=headers, timeout=timeout, data=json_data
response = requests.request(
method, api_url, headers=headers, timeout=timeout, data=data
)
response.raise_for_status()

if response.ok:
create_status_for_application(application)
create_status_for_application(application, status)
LOGGER.info(
f"Open case for application {application.id} Request to Ahjo was successful."
f"Request for application {application.id} to Ahjo was successful."
)

except requests.exceptions.HTTPError as e:
# Handle the HTTP error
LOGGER.error(f"HTTP error occurred while sending request to Ahjo: {e}")
LOGGER.error(
f"HTTP error occurred while sending a {request_type} request to Ahjo: {e}"
)
raise
except requests.exceptions.RequestException as e:
# Handle the network error
LOGGER.error(f"Network error occurred while sending request to Ahjo: {e}")
LOGGER.error(
f"Network error occurred while sending a {request_type} request to Ahjo: {e}"
)
raise
except Exception as e:
# Handle any other error
LOGGER.error(f"Error occurred while sending request to Ahjo: {e}")
LOGGER.error(
f"Error occurred while sending request a {request_type} to Ahjo: {e}"
)
raise


def open_case_in_ahjo(application_id: uuid):
def open_case_in_ahjo(application_id: uuid.UUID):
"""Open a case in Ahjo."""
try:
application = get_application_for_ahjo(application_id)
ahjo_api_url = settings.AHJO_REST_API_URL
ahjo_token = get_token()
headers = prepare_headers(ahjo_token.access_token, application.id)
headers = prepare_headers(
ahjo_token.access_token, application.id, AhjoRequestType.OPEN_CASE
)
data = prepare_open_case_payload(application)
do_ahjo_request_with_json_payload(ahjo_api_url, headers, data, application)
send_request_to_ahjo(AhjoRequestType.OPEN_CASE, headers, data, application)
except ObjectDoesNotExist as e:
LOGGER.error(f"Object not found: {e}")
except ImproperlyConfigured as e:
LOGGER.error(f"Improperly configured: {e}")


def delete_application_in_ahjo(application_id: uuid.UUID):
"""Delete/cancel an application in Ahjo."""
try:
application = get_application_for_ahjo(application_id)
ahjo_token = get_token()
headers = prepare_headers(
ahjo_token.access_token, application.id, AhjoRequestType.DELETE_APPLICATION
)
send_request_to_ahjo(AhjoRequestType.DELETE_APPLICATION, headers, application)
except ObjectDoesNotExist as e:
LOGGER.error(f"Object not found: {e}")
except ImproperlyConfigured as e:
Expand Down
174 changes: 130 additions & 44 deletions backend/benefit/applications/tests/test_ahjo_requests.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
import uuid
from unittest.mock import patch

import pytest
import requests
import requests_mock
from django.conf import settings
from django.urls import reverse

from applications.enums import AhjoStatus
from applications.services.ahjo_integration import (
do_ahjo_request_with_json_payload,
prepare_headers,
)
from applications.enums import AhjoRequestType, AhjoStatus
from applications.services.ahjo_integration import prepare_headers, send_request_to_ahjo


@pytest.fixture
def application_with_ahjo_case_id(decided_application):
decided_application.ahjo_case_id = "12345"
decided_application.save()
return decided_application


def test_prepare_headers(settings):
@pytest.mark.parametrize(
"request_type",
[
(AhjoRequestType.OPEN_CASE,),
(AhjoRequestType.DELETE_APPLICATION,),
],
)
def test_prepare_headers(settings, request_type, decided_application):
settings.API_BASE_URL = "http://test.com"
access_token = "test_token"
application_uuid = uuid.uuid4()

headers = prepare_headers(access_token, application_uuid)
url = reverse(
"ahjo_callback_url",
kwargs={"request_type": request_type, "uuid": decided_application.id},
)

headers = prepare_headers(access_token, decided_application, request_type)

url = reverse("ahjo_callback_url", kwargs={"uuid": str(application_uuid)})
expected_headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/hal+json",
Expand All @@ -29,61 +44,132 @@ def test_prepare_headers(settings):
assert headers == expected_headers


def test_do_ahjo_request_with_json_payload_success(
decided_application, ahjo_open_case_payload
@pytest.mark.parametrize(
"request_type, request_url, ahjo_status",
[
(
AhjoRequestType.OPEN_CASE,
f"{settings.AHJO_REST_API_URL}/cases",
AhjoStatus.REQUEST_TO_OPEN_CASE_SENT,
),
(
AhjoRequestType.DELETE_APPLICATION,
f"{settings.AHJO_REST_API_URL}/cases/12345",
AhjoStatus.DELETE_REQUEST_SENT,
),
],
)
def test_send_request_to_ahjo(
request_type,
request_url,
ahjo_status,
application_with_ahjo_case_id,
ahjo_open_case_payload,
):
url = "http://test.com"
headers = {"Authorization": "Bearer test"}

with requests_mock.Mocker() as m:
m.post(f"{url}/cases", text="data")
do_ahjo_request_with_json_payload(
url, headers, ahjo_open_case_payload, decided_application
if request_type == AhjoRequestType.OPEN_CASE:
m.post(request_url, text="data")
elif request_type == AhjoRequestType.DELETE_APPLICATION:
m.delete(request_url)
send_request_to_ahjo(
request_type, headers, application_with_ahjo_case_id, ahjo_open_case_payload
)
decided_application.refresh_from_db()
assert (
decided_application.ahjo_status.latest().status
== AhjoStatus.REQUEST_TO_OPEN_CASE_SENT
)


application_with_ahjo_case_id.refresh_from_db()
assert application_with_ahjo_case_id.ahjo_status.latest().status == ahjo_status


@pytest.mark.parametrize(
"request_type, request_url, exception",
[
(
AhjoRequestType.OPEN_CASE,
f"{settings.AHJO_REST_API_URL}/cases",
requests.exceptions.HTTPError,
),
(
AhjoRequestType.DELETE_APPLICATION,
f"{settings.AHJO_REST_API_URL}/cases/12345",
requests.exceptions.HTTPError,
),
],
)
@patch("applications.services.ahjo_integration.LOGGER")
def test_http_error(mock_logger, decided_application, ahjo_open_case_payload):
url = "http://mockedurl.com"
def test_http_error(
request_type, request_url, exception, mock_logger, application_with_ahjo_case_id
):
headers = {}
data = ahjo_open_case_payload
application = decided_application

with requests_mock.Mocker() as m:
m.post(f"{url}/cases", status_code=400)
do_ahjo_request_with_json_payload(url, headers, data, application)
with requests_mock.Mocker() as m, pytest.raises(exception):
if request_type == AhjoRequestType.OPEN_CASE:
m.post(request_url, text="data")
elif request_type == AhjoRequestType.DELETE_APPLICATION:
m.delete(request_url)
send_request_to_ahjo(request_type, headers, application_with_ahjo_case_id)

mock_logger.error.assert_called()


@pytest.mark.parametrize(
"request_type, request_url, exception",
[
(
AhjoRequestType.OPEN_CASE,
f"{settings.AHJO_REST_API_URL}/cases",
requests.exceptions.ConnectionError,
),
(
AhjoRequestType.DELETE_APPLICATION,
f"{settings.AHJO_REST_API_URL}/cases/12345",
requests.exceptions.ConnectionError,
),
],
)
@patch("applications.services.ahjo_integration.LOGGER")
def test_network_error(mock_logger, decided_application, ahjo_open_case_payload):
url = "http://mockedurl.com"
def test_network_error(
request_type, request_url, exception, mock_logger, application_with_ahjo_case_id
):
headers = {}
data = ahjo_open_case_payload
application = decided_application

with requests_mock.Mocker() as m:
m.post(f"{url}/cases", exc=requests.exceptions.ConnectionError)
do_ahjo_request_with_json_payload(url, headers, data, application)
with requests_mock.Mocker() as m, pytest.raises(exception):
if request_type == AhjoRequestType.OPEN_CASE:
m.post(request_url, exc=exception)
elif request_type == AhjoRequestType.DELETE_APPLICATION:
m.delete(request_url, exc=exception)

send_request_to_ahjo(request_type, headers, application_with_ahjo_case_id)

mock_logger.error.assert_called()


@pytest.mark.parametrize(
"request_type, request_url, exception",
[
(
AhjoRequestType.OPEN_CASE,
f"{settings.AHJO_REST_API_URL}/cases",
Exception("Some error"),
),
(
AhjoRequestType.DELETE_APPLICATION,
f"{settings.AHJO_REST_API_URL}/cases/12345",
Exception("Some error"),
),
],
)
@patch("applications.services.ahjo_integration.LOGGER")
def test_other_exception(mock_logger, decided_application, ahjo_open_case_payload):
url = "http://mockedurl.com"
def test_other_exception(
request_type, request_url, exception, mock_logger, application_with_ahjo_case_id
):
headers = {}
data = ahjo_open_case_payload
application = decided_application

with requests_mock.Mocker() as m:
m.post(f"{url}/cases", exc=Exception("Some error"))
do_ahjo_request_with_json_payload(url, headers, data, application)
with requests_mock.Mocker() as m, pytest.raises(exception):
if request_type == AhjoRequestType.OPEN_CASE:
m.post(request_url, exc=exception)
elif request_type == AhjoRequestType.DELETE_APPLICATION:
m.delete(request_url, exc=exception)

send_request_to_ahjo(request_type, headers, application_with_ahjo_case_id)

mock_logger.error.assert_called()

0 comments on commit 77a66fc

Please sign in to comment.