From 37e2e81121495a259770e8232b9da2d6cf5856a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Riku=20Kestila=CC=88?= Date: Wed, 22 Nov 2023 16:46:05 +0200 Subject: [PATCH] feat: open a case in Ahjo via Ahjo Rest API --- .../applications/services/ahjo_integration.py | 272 ++++++++++++++++-- .../benefit/applications/tests/conftest.py | 225 +++++++++++++++ .../tests/test_ahjo_integration.py | 147 ++++++++++ .../applications/tests/test_ahjo_requests.py | 53 ++++ backend/benefit/helsinkibenefit/settings.py | 3 + 5 files changed, 677 insertions(+), 23 deletions(-) create mode 100644 backend/benefit/applications/tests/test_ahjo_requests.py diff --git a/backend/benefit/applications/services/ahjo_integration.py b/backend/benefit/applications/services/ahjo_integration.py index 00be0e7ef2..25a82dd72e 100644 --- a/backend/benefit/applications/services/ahjo_integration.py +++ b/backend/benefit/applications/services/ahjo_integration.py @@ -1,10 +1,14 @@ +import json import logging import os +import urllib.request +import uuid import zipfile from collections import defaultdict from dataclasses import dataclass +from datetime import datetime from io import BytesIO -from typing import List, Optional +from typing import List, Optional, Tuple, Union import jinja2 import pdfkit @@ -12,12 +16,15 @@ from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.db.models import QuerySet +from django.urls import reverse -from applications.enums import ApplicationStatus -from applications.models import AhjoSetting, Application +from applications.enums import AhjoStatus as AhjoStatusEnum, ApplicationStatus +from applications.models import AhjoSetting, AhjoStatus, Application, Attachment from applications.services.ahjo_authentication import AhjoConnector from applications.services.applications_csv_report import ApplicationsCsvService +from common.utils import encode_multipart_formdata, hash_file from companies.models import Company +from users.models import User @dataclass @@ -356,44 +363,263 @@ def export_application_batch(batch) -> bytes: return generate_zip(pdf_files) -def dummy_ahjo_request(): - """Dummy function for preliminary testing of Ahjo integration""" - ahjo_api_url = settings.AHJO_REST_API_URL +def get_token() -> str: + """Get the access token from Ahjo Service.""" try: ahjo_auth_code = AhjoSetting.objects.get(name="ahjo_code").data LOGGER.info(f"Retrieved auth code: {ahjo_auth_code}") + connector = AhjoConnector(requests) + + if not connector.is_configured(): + LOGGER.warning("AHJO connector is not configured") + return + return connector.get_access_token(ahjo_auth_code["code"]) except ObjectDoesNotExist: LOGGER.error( "Error: Ahjo auth code not found in database. Please set the 'ahjo_code' setting." ) return - - connector = AhjoConnector(requests) - - if not connector.is_configured(): - LOGGER.warning("AHJO connector is not configured") - return - try: - ahjo_token = connector.get_access_token(ahjo_auth_code["code"]) except Exception as e: LOGGER.warning(f"Error retrieving access token: {e}") return - headers = { - "Authorization": f"Bearer {ahjo_token.access_token}", + + +def prepare_headers(access_token: str, application_uuid: uuid) -> dict: + """Prepare the headers for the Ahjo request.""" + url = reverse("ahjo_callback_url", kwargs={"uuid": str(application_uuid)}) + + return { + "Authorization": f"Bearer {access_token}", + "Accept": "application/hal+json", + "X-CallbackURL": f"{settings.API_BASE_URL}{url}", } - print(headers) + + +def get_application() -> Optional[Application]: + """Get the first accepted application.""" + application = ( + Application.objects.filter(status=ApplicationStatus.ACCEPTED) + .prefetch_related("attachments", "calculation", "company") + .first() + ) + if not application: + LOGGER.info("No applications found.") + # Check that the handler has an ad_username set, if not, log an error and return None + if not application.calculation.handler.ad_username: + LOGGER.error("No ad_username set for the handler.") + return None + return application + + +def create_status_for_application(application: Application): + """Create a new AhjoStatus for the application.""" + AhjoStatus.objects.create( + application=application, status=AhjoStatusEnum.REQUEST_TO_OPEN_CASE_SENT + ) + + +def do_ahjo_request_with_form_data( + url: str, + headers: dict, + data: dict, + application: Application, +): + json_data = json.dumps(data) + form_data, content_type = encode_multipart_formdata({"case": json_data}) + + headers["Content-Type"] = content_type + try: - response = requests.get( - f"{ahjo_api_url}/cases", headers=headers, timeout=connector.timout + request = urllib.request.Request( + f"{url}/cases", + method="POST", + headers=headers, + data=form_data.encode("utf-8"), + ) + + with urllib.request.urlopen(request) as response: + response_data = response.read() + print(response.status) + print(response_data.decode("utf-8")) + + create_status_for_application(application) + except Exception as e: + # Handle any other error + LOGGER.error(f"Error occurred: {e}") + + +def do_ahjo_request_with_json_payload( + url: str, headers: dict, data: dict, application: Application, timeout: int = 10 +): + headers["Content-Type"] = "application/json" + + json_data = json.dumps(data) + + try: + response = requests.post( + f"{url}/cases", + headers=headers, + timeout=timeout, + data=json_data ) response.raise_for_status() - print(response.json()) + + if response.ok: + create_status_for_application(application) + LOGGER.info(f"Open case for application {application.id} Request to Ahjo was successful.") + except requests.exceptions.HTTPError as e: # Handle the HTTP error - LOGGER.error(f"HTTP error occurred: {e}") + LOGGER.error(f"HTTP error occurred while sending request to Ahjo: {e}") except requests.exceptions.RequestException as e: # Handle the network error - LOGGER.errror(f"Network error occurred: {e}") + LOGGER.error(f"Network error occurred while sending request to Ahjo: {e}") except Exception as e: # Handle any other error - LOGGER.error(f"Error occurred: {e}") + LOGGER.error(f"Error occurred while sending request to Ahjo: {e}") + + +def open_case_in_ahjo(): + """Open a case in Ahjo.""" + application = get_application() + # if no suitable application is found, or the handler has no ad_id, bail out + if not application: + return + + ahjo_api_url = settings.AHJO_REST_API_URL + ahjo_token = get_token() + headers = prepare_headers(ahjo_token.access_token, application.id) + data = prepare_open_case_payload(application) + + # do_ahjo_request_with_form_data(ahjo_api_url, headers, data, application) + do_ahjo_request_with_json_payload(ahjo_api_url, headers, data, application) + + +def _prepare_open_case_dict(application: Application, case_records: List[dict]) -> dict: + """Prepare the dictionary that is sent to Ahjo""" + application_date = application.created_at.isoformat() + application_year = application.created_at.year + title = f"Avustuksen myöntäminen, työllisyyspalvelut, \ +työnantajan Helsinki-lisä vuonna {application_year}, \ +työnantaja {application.company_name}" + + contact_person = ( + application.company_contact_person_first_name + + " " + + application.company_contact_person_last_name + ) + + case_dict = { + "Title": title, + "Acquired": application_date, + "ClassificationCode": "02 05 01 00", + "ClassificationTitle": "Kunnan myöntämät avustukset", + "Language": "fi", + "PublicityClass": "Julkinen", + "InternalTitle": f"Avustuksen myöntäminen, työllisyyspalvelut, \ + työnantajan Helsinki-lisä vuonna {application_year}, \ + työnantaja {application.company_name}", + "Subjects": [ + {"Subject": "Helsinki-lisät", "Scheme": "hki-yhpa"}, + {"Subject": "kunnan myöntämät avustukset", "Scheme": "hki-yhpa"}, + {"Subject": "työnantajat", "Scheme": "hki-yhpa"}, + {"Subject": "työllisyydenhoito"}, + ], + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": application.application_number, + "Records": case_records, + "Agents": [ + { + "Role": "sender_initiator", + "CorporateName": application.company.name, + "ContactPerson": contact_person, + "Type": "ExterOnal", + "Email": application.company_contact_person_email, + "AddressStreet": application.company.street_address, + "AddressPostalCode": application.company.postcode, + "AddressCity": application.company.city, + } + ], + } + return case_dict + + +def _prepare_record_document_dict(attachment: Attachment) -> dict: + """Prepare a documents dict for a record""" + # If were running in mock mode, use the local file URI + file_url = reverse("ahjo_attachment_url", kwargs={"uuid": attachment.id}) + hash_value = hash_file(attachment.attachment_file) + return { + "FileName": f"{attachment.attachment_file.name}", + "FormatName": f"{attachment.content_type}", + "HashAlgorithm": "sha256", + "HashValue": hash_value, + "FileURI": f"{settings.API_BASE_URL}{file_url}", + } + + +def _prepare_record( + record_title: str, + record_type: str, + acquired: datetime, + reference: Union[int, uuid.UUID], + documents: List[dict], + handler: User, + publicity_class: str = "Salassa pidettävä", +): + """Prepare a single record dict for Ahjo.""" + + return { + "Title": record_title, + "Type": record_type, + "Acquired": acquired, + "PublicityClass": publicity_class, + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": str(reference), + "Documents": documents, + "Agents": [ + { + "Role": "mainCreator", + "Name": f"{handler.last_name}, {handler.first_name}", + "ID": handler.ad_username, + } + ], + } + + +def _prepare_case_records(application: Application) -> List[dict]: + """Prepare the list of case records""" + case_records = [] + handler = application.calculation.handler + main_document_record = _prepare_record( + "Hakemus", + "hakemus", + application.created_at.isoformat(), + application.application_number, + [], # TODO Pdf version of the application goes here with prepare_record() + handler, + ) + + case_records.append(main_document_record) + + for attachment in application.attachments.all(): + document_record = _prepare_record( + "Hakemuksen Liite", + "liite", + attachment.created_at.isoformat(), + attachment.id, + [_prepare_record_document_dict(attachment)], + handler, + ) + case_records.append(document_record) + + return case_records + + +def prepare_open_case_payload(application: Application) -> dict: + "Prepare the complete dictionary payload that is sent to Ahjo" + case_records = _prepare_case_records(application) + payload = _prepare_open_case_dict(application, case_records) + return payload diff --git a/backend/benefit/applications/tests/conftest.py b/backend/benefit/applications/tests/conftest.py index 8e8ba1c98f..179f0daa0a 100755 --- a/backend/benefit/applications/tests/conftest.py +++ b/backend/benefit/applications/tests/conftest.py @@ -257,6 +257,231 @@ def set_debug_to_false(settings): settings.DEBUG = False +@pytest.fixture() +def ahjo_open_case_payload(): + return { + "Title": "Avustuksen myöntäminen, työllisyyspalvelut, työnantajan Helsinki-lisä vuonna 2023, työnantaja Capital day.", + "Acquired": "2023-10-30T02:06:08+00:00", + "ClassificationCode": "02 05 01 00", + "ClassificationTitle": "Kunnan myöntämät avustukset", + "Language": "fi", + "PublicityClass": "Julkinen", + "InternalTitle": "Avustuksen myöntäminen, työllisyyspalvelut, työnantajan Helsinki-lisä vuonna 2023, työnantaja Capital day.", + "Subjects": [ + {"Subject": "Helsinki-lisät", "Scheme": "hki-yhpa"}, + {"Subject": "kunnan myöntämät avustukset", "Scheme": "hki-yhpa"}, + {"Subject": "työnantajat", "Scheme": "hki-yhpa"}, + {"Subject": "työllisyydenhoito"}, + ], + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": 125037, + "Records": [ + { + "Title": "Hakemus", + "Type": "hakemus", + "Acquired": "2023-10-30T02:06:08+00:00", + "PublicityClass": "Salassa pidettävä", + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": "125037", + "Documents": [], + "Agents": [ + {"Role": "mainCreator", "Name": "Rice, Aaron", "ID": "ahjo_id"} + ], + }, + { + "Title": "Hakemuksen Liite", + "Type": "liite", + "Acquired": "2023-11-23T12:35:33.177923+00:00", + "PublicityClass": "Salassa pidettävä", + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": "3591c520-87ac-4284-a58d-885efd6288be", + "Documents": [ + { + "FileName": "attachment_pdf_file_Td3FFBj.pdf", + "FormatName": "application/pdf", + "HashAlgorithm": "sha256", + "HashValue": "a18319a581811b0869c47788ac4e1d7cf1015c8ef51e69b62abc6cd720f6809e", + "FileURI": "/v1/ahjo-integration/attachment/3591c520-87ac-4284-a58d-885efd6288be", + } + ], + "Agents": [ + {"Role": "mainCreator", "Name": "Rice, Aaron", "ID": "ahjo_id"} + ], + }, + { + "Title": "Hakemuksen Liite", + "Type": "liite", + "Acquired": "2023-11-23T12:35:33.185044+00:00", + "PublicityClass": "Salassa pidettävä", + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": "b2a0eaec-164a-4630-8e4f-50e993a9a732", + "Documents": [ + { + "FileName": "attachment_pdf_file_uH8jNXH.pdf", + "FormatName": "application/pdf", + "HashAlgorithm": "sha256", + "HashValue": "a18319a581811b0869c47788ac4e1d7cf1015c8ef51e69b62abc6cd720f6809e", + "FileURI": "/v1/ahjo-integration/attachment/b2a0eaec-164a-4630-8e4f-50e993a9a732", + } + ], + "Agents": [ + {"Role": "mainCreator", "Name": "Rice, Aaron", "ID": "ahjo_id"} + ], + }, + { + "Title": "Hakemuksen Liite", + "Type": "liite", + "Acquired": "2023-11-23T12:35:33.196182+00:00", + "PublicityClass": "Salassa pidettävä", + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": "085b17e7-3740-40a9-b6db-6dee6fbda131", + "Documents": [ + { + "FileName": "attachment_pdf_file_CvJgAnN.pdf", + "FormatName": "application/pdf", + "HashAlgorithm": "sha256", + "HashValue": "a18319a581811b0869c47788ac4e1d7cf1015c8ef51e69b62abc6cd720f6809e", + "FileURI": "/v1/ahjo-integration/attachment/085b17e7-3740-40a9-b6db-6dee6fbda131", + } + ], + "Agents": [ + {"Role": "mainCreator", "Name": "Rice, Aaron", "ID": "ahjo_id"} + ], + }, + { + "Title": "Hakemuksen Liite", + "Type": "liite", + "Acquired": "2023-11-23T12:35:33.165901+00:00", + "PublicityClass": "Salassa pidettävä", + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": "121b22d6-11c6-4bd3-9db4-bd56268b0a81", + "Documents": [ + { + "FileName": "attachment_pdf_file_4VX4wex.pdf", + "FormatName": "application/pdf", + "HashAlgorithm": "sha256", + "HashValue": "a18319a581811b0869c47788ac4e1d7cf1015c8ef51e69b62abc6cd720f6809e", + "FileURI": "/v1/ahjo-integration/attachment/121b22d6-11c6-4bd3-9db4-bd56268b0a81", + } + ], + "Agents": [ + {"Role": "mainCreator", "Name": "Rice, Aaron", "ID": "ahjo_id"} + ], + }, + { + "Title": "Hakemuksen Liite", + "Type": "liite", + "Acquired": "2023-11-23T12:35:33.201458+00:00", + "PublicityClass": "Salassa pidettävä", + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": "fd47b2cf-8fd6-44b8-a0a4-f5c7d3583ffa", + "Documents": [ + { + "FileName": "attachment_pdf_file_HMJ47jQ.pdf", + "FormatName": "application/pdf", + "HashAlgorithm": "sha256", + "HashValue": "a18319a581811b0869c47788ac4e1d7cf1015c8ef51e69b62abc6cd720f6809e", + "FileURI": "/v1/ahjo-integration/attachment/fd47b2cf-8fd6-44b8-a0a4-f5c7d3583ffa", + } + ], + "Agents": [ + {"Role": "mainCreator", "Name": "Rice, Aaron", "ID": "ahjo_id"} + ], + }, + { + "Title": "Hakemuksen Liite", + "Type": "liite", + "Acquired": "2023-11-23T12:35:33.190702+00:00", + "PublicityClass": "Salassa pidettävä", + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": "245ac4fc-d686-4ba3-864d-6d720be462f5", + "Documents": [ + { + "FileName": "attachment_pdf_file_I5Hegqx.pdf", + "FormatName": "application/pdf", + "HashAlgorithm": "sha256", + "HashValue": "a18319a581811b0869c47788ac4e1d7cf1015c8ef51e69b62abc6cd720f6809e", + "FileURI": "/v1/ahjo-integration/attachment/245ac4fc-d686-4ba3-864d-6d720be462f5", + } + ], + "Agents": [ + {"Role": "mainCreator", "Name": "Rice, Aaron", "ID": "ahjo_id"} + ], + }, + { + "Title": "Hakemuksen Liite", + "Type": "liite", + "Acquired": "2023-11-23T12:35:33.207081+00:00", + "PublicityClass": "Salassa pidettävä", + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": "f7c360af-eb3c-432a-bf5e-35c829f7d99e", + "Documents": [ + { + "FileName": "attachment_pdf_file_8SjQgXo.pdf", + "FormatName": "application/pdf", + "HashAlgorithm": "sha256", + "HashValue": "a18319a581811b0869c47788ac4e1d7cf1015c8ef51e69b62abc6cd720f6809e", + "FileURI": "/v1/ahjo-integration/attachment/f7c360af-eb3c-432a-bf5e-35c829f7d99e", + } + ], + "Agents": [ + {"Role": "mainCreator", "Name": "Rice, Aaron", "ID": "ahjo_id"} + ], + }, + { + "Title": "Hakemuksen Liite", + "Type": "liite", + "Acquired": "2023-11-23T12:35:33.172114+00:00", + "PublicityClass": "Salassa pidettävä", + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": "9dbff899-fe1b-4974-ad09-f9fefaccc7b2", + "Documents": [ + { + "FileName": "attachment_pdf_file_ETgEHwC.pdf", + "FormatName": "application/pdf", + "HashAlgorithm": "sha256", + "HashValue": "a18319a581811b0869c47788ac4e1d7cf1015c8ef51e69b62abc6cd720f6809e", + "FileURI": "/v1/ahjo-integration/attachment/9dbff899-fe1b-4974-ad09-f9fefaccc7b2", + } + ], + "Agents": [ + {"Role": "mainCreator", "Name": "Rice, Aaron", "ID": "ahjo_id"} + ], + }, + ], + "Agents": [ + { + "Role": "sender_initiator", + "CorporateName": "Niskanen", + "ContactPerson": "Aapo Männistö", + "Type": "ExterOnal", + "Email": "marita34@example.com", + "AddressStreet": "Gunnel Nymanin katu 598", + "AddressPostalCode": "08144", + "AddressCity": "Hanko", + } + ], + } + + def split_lines_at_semicolon(csv_string): # split CSV into lines and columns without using the csv library csv_lines = csv_string.splitlines() diff --git a/backend/benefit/applications/tests/test_ahjo_integration.py b/backend/benefit/applications/tests/test_ahjo_integration.py index 5cdbdc2145..246d0bc123 100644 --- a/backend/benefit/applications/tests/test_ahjo_integration.py +++ b/backend/benefit/applications/tests/test_ahjo_integration.py @@ -25,10 +25,15 @@ generate_single_approved_file, generate_single_declined_file, REJECTED_TITLE, + _prepare_record, + _prepare_case_records, + _prepare_record_document_dict, + prepare_open_case_payload, ) from applications.tests.factories import ApplicationFactory, DecidedApplicationFactory from calculator.models import Calculation from calculator.tests.factories import PaySubsidyFactory +from common.utils import hash_file from companies.tests.factories import CompanyFactory from helsinkibenefit.tests.conftest import * # noqa from shared.common.tests.utils import normalize_whitespace @@ -410,3 +415,145 @@ def test_ahjo_callback_unauthorized_ip_not_allowed( response = ahjo_client.post(url, **auth_headers) assert response.status_code == 403 + +def test_prepare_open_case_payload(decided_application): + application = decided_application + application_date = application.created_at.isoformat() + application_year = application.created_at.year + title = f"Avustuksen myöntäminen, työllisyyspalvelut, työnantajan Helsinki-lisä vuonna {application_year}, \ +työnantaja {application.company_name}" + + wanted = { + "Title": f"{title}", + "Acquired": f"{application_date}", + "ClassificationCode": "02 05 01 00", + "ClassificationTitle": "Kunnan myöntämät avustukset", + "Language": "fi", + "PublicityClass": "Julkinen", + "InternalTitle": f"Avustuksen myöntäminen, työllisyyspalvelut, \ + työnantajan Helsinki-lisä vuonna {application_year}, \ + työnantaja {application.company_name}", + "Subjects": [ + {"Subject": "Helsinki-lisät", "Scheme": "hki-yhpa"}, + {"Subject": "kunnan myöntämät avustukset", "Scheme": "hki-yhpa"}, + {"Subject": "työnantajat", "Scheme": "hki-yhpa"}, + {"Subject": "työllisyydenhoito"}, + ], + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": f"{application.application_number}", + "Records": [], + "Agents": [ + { + "Role": "sender_initiator", + "CorporateName": f"{application.company.name}", + "ContactPerson": f"{application.company_contact_person_first_name} \ + {application.company_contact_person_last_name}", + "Type": "External", + "Email": f"{application.company_contact_person_email}", + "AddressStreet": f"{application.company.street_address}", + "AddressPostalCode": f"{application.company.postcode}", + "AddressCity": f"{application.company.city}", + } + ], + } + + got = prepare_open_case_payload(application) + + assert wanted == got + + +def test_prepare_record(decided_application): + application = decided_application + + record_title = "Hakemus" + record_type = ("hakemus",) + acquired = application.created_at.isoformat() + reference = application.application_number + documents = [] + agent = application.calculation.handler + publicity_class = "Salassa pidettävä" + + wanted = ( + { + "Title": record_title, + "Type": record_type, + "Acquired": acquired, + "PublicityClass": publicity_class, + "SecurityReasons": ["JulkL (621/1999) 24.1 § 25 k"], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": reference, + "Documents": documents, + "Agents": [ + { + "Role": "mainCreator", + "Name": f"{agent.last_name}, {agent.first_name}", + "ID": agent.ad_username, + } + ], + }, + ) + + got = _prepare_record( + record_title, + record_type, + application.created_at.isoformat(), + application.application_number, + [], + application.calculation.handler, + ) + + assert wanted == got + + +def test_prepare_record_document_dict(decided_application, settings): + settings.DEBUG = True + attachment = decided_application.attachments.first() + hash_value = hash_file(attachment.attachment_file) + file_url = reverse("ahjo_attachment_url", kwargs={"uuid": attachment.id}) + + want = { + "FileName": attachment.attachment_file.name, + "FormatName": attachment.content_type, + "HashAlgorithm": "sha256", + "HashValue": hash_value, + "FileURI": file_url, + } + + got = _prepare_record_document_dict(attachment) + + assert want == got + + +def test_prepare_case_records(decided_application, settings): + settings.DEBUG = True + application = decided_application + handler_name = f"{application.calculation.handler.last_name}, {application.calculation.handler.first_name}" + want = [ + { + "Title": "Hakemus", + "Type": "hakemus", + "Acquired": f"{application.created_at.isoformat()}", + "PublicityClass": "Salassa pidettävä", + "SecurityReasons": [ + "JulkL (621/1999) 24.1 § 25 k" + ], + "Language": "fi", + "PersonalData": "Sisältää erityisiä henkilötietoja", + "Reference": f"{application.application_number}", + "Documents": [], + "Agents": [ + { + "Role": "mainCreator", + "Name": f"{handler_name}", + "ID": f"{application.calculation.handler.ad_username}", + } + ], + + } + ] + + got = _prepare_case_records(application) + + assert want == got + diff --git a/backend/benefit/applications/tests/test_ahjo_requests.py b/backend/benefit/applications/tests/test_ahjo_requests.py new file mode 100644 index 0000000000..969281d27f --- /dev/null +++ b/backend/benefit/applications/tests/test_ahjo_requests.py @@ -0,0 +1,53 @@ +import pytest +import requests +import requests_mock +import uuid +from applications.enums import AhjoStatus +from applications.services.ahjo_integration import prepare_headers, do_ahjo_request_with_json_payload +from django.urls import reverse + +def test_prepare_headers(settings): + 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={"uuid": str(application_uuid)}) + expected_headers = { + "Authorization": f"Bearer {access_token}", + "Accept": "application/hal+json", + "X-CallbackURL": f"{settings.API_BASE_URL}{url}", + } + + assert headers == expected_headers + + +def test_do_ahjo_request_with_json_payload_success(decided_application, 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) + decided_application.refresh_from_db() + assert decided_application.ahjo_status.latest().status == AhjoStatus.REQUEST_TO_OPEN_CASE_SENT + + +def test_do_ahjo_request_with_json_payload_http_error(decided_application, ahjo_open_case_payload): + url = 'http://test.com' + headers = {'Authorization': 'Bearer test'} + + with requests_mock.Mocker() as m: + m.post(f"{url}/cases", status_code=500) + with pytest.raises(requests.exceptions.HTTPError): + do_ahjo_request_with_json_payload(url, headers, ahjo_open_case_payload, decided_application) + +def test_do_ahjo_request_with_json_payload_request_exception(decided_application, ahjo_open_case_payload): + url = 'http://test.com' + headers = {'Authorization': 'Bearer test'} + + with requests_mock.Mocker() as m: + m.post(f"{url}/cases", exc=requests.exceptions.RequestException) + with pytest.raises(requests.exceptions.RequestException): + do_ahjo_request_with_json_payload(url, headers, ahjo_open_case_payload, decided_application) \ No newline at end of file diff --git a/backend/benefit/helsinkibenefit/settings.py b/backend/benefit/helsinkibenefit/settings.py index 2acddb29cc..ac5ba0c56c 100644 --- a/backend/benefit/helsinkibenefit/settings.py +++ b/backend/benefit/helsinkibenefit/settings.py @@ -20,6 +20,7 @@ default_var_root = environ.Path(checkout_dir("var")) env = environ.Env( + API_BASE_URL=(str, "https://localhost:8000"), DEBUG=(bool, False), SECRET_KEY=(str, ""), MEDIA_ROOT=(environ.Path(), default_var_root("media")), @@ -170,6 +171,8 @@ os.environ["HTTPS"] = "on" +API_BASE_URL = env.str("API_BASE_URL") + BASE_DIR = str(checkout_dir) DEBUG = env.bool("DEBUG")