diff --git a/backend/benefit/applications/enums.py b/backend/benefit/applications/enums.py index c102863f05..d059e69ae4 100644 --- a/backend/benefit/applications/enums.py +++ b/backend/benefit/applications/enums.py @@ -100,6 +100,7 @@ class AttachmentType(models.TextChoices): EMPLOYEE_CONSENT = "employee_consent", _("employee consent") FULL_APPLICATION = "full_application", _("full application") OTHER_ATTACHMENT = "other_attachment", _("other attachment") + PDF_SUMMARY = "pdf_summary", _("pdf summary") class AttachmentRequirement(models.TextChoices): diff --git a/backend/benefit/applications/migrations/0048_alter_attachment_attachment_type.py b/backend/benefit/applications/migrations/0048_alter_attachment_attachment_type.py new file mode 100644 index 0000000000..49d8130c25 --- /dev/null +++ b/backend/benefit/applications/migrations/0048_alter_attachment_attachment_type.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.23 on 2023-12-20 11:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('applications', '0047_remove_phone_number_restriction'), + ] + + operations = [ + migrations.AlterField( + model_name='attachment', + name='attachment_type', + field=models.CharField(choices=[('employment_contract', 'employment contract'), ('pay_subsidy_decision', 'pay subsidy decision'), ('commission_contract', 'commission contract'), ('education_contract', 'education contract of the apprenticeship office'), ('helsinki_benefit_voucher', 'helsinki benefit voucher'), ('employee_consent', 'employee consent'), ('full_application', 'full application'), ('other_attachment', 'other attachment'), ('pdf_summary', 'pdf summary')], max_length=64, verbose_name='attachment type in business rules'), + ), + ] diff --git a/backend/benefit/applications/services/ahjo_integration.py b/backend/benefit/applications/services/ahjo_integration.py index c92c363e49..79b5f558ff 100644 --- a/backend/benefit/applications/services/ahjo_integration.py +++ b/backend/benefit/applications/services/ahjo_integration.py @@ -13,6 +13,7 @@ import requests from django.conf import settings from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist +from django.core.files.base import ContentFile from django.db.models import QuerySet from django.urls import reverse @@ -20,11 +21,15 @@ AhjoRequestType, AhjoStatus as AhjoStatusEnum, ApplicationStatus, + AttachmentType, ) -from applications.models import AhjoSetting, AhjoStatus, Application +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 +from applications.services.generate_application_summary import ( + generate_application_summary_file, +) from companies.models import Company @@ -366,6 +371,21 @@ def export_application_batch(batch) -> bytes: return generate_zip(pdf_files) +def generate_pdf_summary_as_attachment(application: Application) -> Attachment: + """Generate a pdf summary of the given application and return it as an Attachment.""" + pdf_data = generate_application_summary_file(application) + pdf_file = ContentFile( + pdf_data, f"application_summary_{application.application_number}.pdf" + ) + attachment = Attachment.objects.create( + application=application, + attachment_file=pdf_file, + content_type="application/pdf", + attachment_type=AttachmentType.PDF_SUMMARY, + ) + return attachment + + def get_token() -> str: """Get the access token from Ahjo Service.""" try: @@ -484,7 +504,8 @@ def open_case_in_ahjo(application_id: uuid.UUID): headers = prepare_headers( ahjo_token.access_token, application.id, AhjoRequestType.OPEN_CASE ) - data = prepare_open_case_payload(application) + pdf_summary = generate_pdf_summary_as_attachment(application) + data = prepare_open_case_payload(application, pdf_summary) send_request_to_ahjo(AhjoRequestType.OPEN_CASE, headers, data, application) except ObjectDoesNotExist as e: LOGGER.error(f"Object not found: {e}") diff --git a/backend/benefit/applications/services/ahjo_payload.py b/backend/benefit/applications/services/ahjo_payload.py index 2caf2c51a3..f913ff96dc 100644 --- a/backend/benefit/applications/services/ahjo_payload.py +++ b/backend/benefit/applications/services/ahjo_payload.py @@ -5,6 +5,7 @@ from django.conf import settings from django.urls import reverse +from applications.enums import AttachmentType from applications.models import Application, Attachment from common.utils import hash_file from users.models import User @@ -98,8 +99,11 @@ def _prepare_record( } -def _prepare_case_records(application: Application) -> List[dict]: - """Prepare the list of case records""" +def _prepare_case_records( + application: Application, pdf_summary: Attachment +) -> List[dict]: + """Prepare the list of case records from application's attachments, + including the pdf summary of the application.""" case_records = [] handler = application.calculation.handler main_document_record = _prepare_record( @@ -107,13 +111,15 @@ def _prepare_case_records(application: Application) -> List[dict]: "hakemus", application.created_at.isoformat(), application.application_number, - [], # TODO Pdf version of the application goes here with prepare_record() + [_prepare_record_document_dict(pdf_summary)], handler, ) case_records.append(main_document_record) - for attachment in application.attachments.all(): + for attachment in application.attachments.exclude( + attachment_type=AttachmentType.PDF_SUMMARY + ): document_record = _prepare_record( "Hakemuksen Liite", "liite", @@ -127,8 +133,10 @@ def _prepare_case_records(application: Application) -> List[dict]: return case_records -def prepare_open_case_payload(application: Application) -> dict: +def prepare_open_case_payload( + application: Application, pdf_summary: Attachment +) -> dict: "Prepare the complete dictionary payload that is sent to Ahjo" - case_records = _prepare_case_records(application) + case_records = _prepare_case_records(application, pdf_summary) payload = _prepare_top_level_dict(application, case_records) return payload diff --git a/backend/benefit/applications/tests/conftest.py b/backend/benefit/applications/tests/conftest.py index 8c6aa1a981..a8c9a233d6 100755 --- a/backend/benefit/applications/tests/conftest.py +++ b/backend/benefit/applications/tests/conftest.py @@ -9,7 +9,6 @@ from applications.enums import ApplicationStatus, BenefitType from applications.models import Application -from applications.services.ahjo_payload import prepare_open_case_payload from applications.services.applications_csv_report import ApplicationsCsvService from applications.tests.factories import ( ApplicationBatchFactory, @@ -353,8 +352,3 @@ def pytest_sessionfinish(session, exitstatus): except OSError as e: print(f"Error while deleting file in media folder: {e}") print(f"\nTests finished, deleted {number_of_files} files in the media folder") - - -@pytest.fixture() -def ahjo_open_case_payload(decided_application): - return prepare_open_case_payload(decided_application) diff --git a/backend/benefit/applications/tests/test_ahjo_integration.py b/backend/benefit/applications/tests/test_ahjo_integration.py index b8e67caa35..b268d2aa8d 100644 --- a/backend/benefit/applications/tests/test_ahjo_integration.py +++ b/backend/benefit/applications/tests/test_ahjo_integration.py @@ -1,4 +1,5 @@ import io +import os import uuid import zipfile from datetime import date @@ -16,14 +17,16 @@ AhjoRequestType, AhjoStatus, ApplicationStatus, + AttachmentType, BenefitType, ) -from applications.models import Application +from applications.models import Application, Attachment from applications.services.ahjo_integration import ( ACCEPTED_TITLE, export_application_batch, ExportFileInfo, generate_composed_files, + generate_pdf_summary_as_attachment, generate_single_approved_file, generate_single_declined_file, get_application_for_ahjo, @@ -476,3 +479,21 @@ def test_get_application_for_ahjo_no_ad_username(decided_application): # Try to get an application with a handler that has no ad_username with pytest.raises(ImproperlyConfigured): get_application_for_ahjo(decided_application.id) + + +@pytest.mark.django_db +def test_generate_pdf_summary_as_attachment(decided_application): + attachment = generate_pdf_summary_as_attachment(decided_application) + assert isinstance(attachment, Attachment) + + assert attachment.application == decided_application + assert attachment.content_type == "application/pdf" + assert attachment.attachment_type == AttachmentType.PDF_SUMMARY + assert ( + attachment.attachment_file.name + == f"application_summary_{decided_application.application_number}.pdf" + ) + assert attachment.attachment_file.size > 0 + assert os.path.exists(attachment.attachment_file.path) + if os.path.exists(attachment.attachment_file.path): + os.remove(attachment.attachment_file.path) diff --git a/backend/benefit/applications/tests/test_ahjo_payload.py b/backend/benefit/applications/tests/test_ahjo_payload.py index b3fe4e9efa..a946bbd332 100644 --- a/backend/benefit/applications/tests/test_ahjo_payload.py +++ b/backend/benefit/applications/tests/test_ahjo_payload.py @@ -1,5 +1,8 @@ +from django.core.files.base import ContentFile from django.urls import reverse +from applications.enums import AttachmentType +from applications.models import Attachment from applications.services.ahjo_payload import ( _prepare_case_records, _prepare_record, @@ -47,6 +50,18 @@ def test_prepare_record_document_dict(decided_application, settings): def test_prepare_case_records(decided_application, settings): settings.DEBUG = True application = decided_application + + fake_file = ContentFile( + b"fake file content", + f"application_summary_{application.application_number}.pdf", + ) + + fake_summary = Attachment.objects.create( + application=application, + attachment_file=fake_file, + content_type="application/pdf", + attachment_type=AttachmentType.PDF_SUMMARY, + ) handler = application.calculation.handler handler_name = f"{handler.last_name}, {handler.first_name}" want = [ @@ -59,7 +74,7 @@ def test_prepare_case_records(decided_application, settings): "Language": "fi", "PersonalData": "Sisältää erityisiä henkilötietoja", "Reference": str(application.application_number), - "Documents": [], + "Documents": [_prepare_record_document_dict(fake_summary)], "Agents": [ { "Role": "mainCreator", @@ -70,7 +85,9 @@ def test_prepare_case_records(decided_application, settings): } ] - for attachment in application.attachments.all(): + for attachment in application.attachments.exclude( + attachment_type=AttachmentType.PDF_SUMMARY + ): document_record = _prepare_record( "Hakemuksen Liite", "liite", @@ -82,7 +99,7 @@ def test_prepare_case_records(decided_application, settings): want.append(document_record) - got = _prepare_case_records(application) + got = _prepare_case_records(application, fake_summary) assert want == got diff --git a/backend/benefit/applications/tests/test_ahjo_requests.py b/backend/benefit/applications/tests/test_ahjo_requests.py index a9c9801cf0..af60b1bc95 100644 --- a/backend/benefit/applications/tests/test_ahjo_requests.py +++ b/backend/benefit/applications/tests/test_ahjo_requests.py @@ -64,7 +64,6 @@ def test_send_request_to_ahjo( request_url, ahjo_status, application_with_ahjo_case_id, - ahjo_open_case_payload, ): headers = {"Authorization": "Bearer test"} @@ -74,7 +73,7 @@ def test_send_request_to_ahjo( 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 + request_type, headers, application_with_ahjo_case_id, {"foo": "bar"} ) assert m.called