diff --git a/backend/benefit/applications/api/v1/application_views.py b/backend/benefit/applications/api/v1/application_views.py index 7901321775..869906b151 100755 --- a/backend/benefit/applications/api/v1/application_views.py +++ b/backend/benefit/applications/api/v1/application_views.py @@ -1,6 +1,6 @@ import logging import re -from datetime import date +from datetime import date, timedelta from decimal import Decimal, ROUND_DOWN from typing import List @@ -50,6 +50,7 @@ Application, ApplicationAlteration, ApplicationBatch, + ApplicationLogEntry, ) from applications.services.ahjo_integration import ( ExportFileInfo, @@ -71,6 +72,7 @@ get_context_for_summary_context, ) from common.permissions import BFIsApplicant, BFIsHandler, TermsOfServiceAccepted +from messages.automatic_messages import send_application_reopened_message from messages.models import MessageType from shared.audit_log import audit_logging from shared.audit_log.enums import Operation @@ -858,14 +860,48 @@ def clone_as_draft(self, request, pk) -> HttpResponse: @transaction.atomic def require_additional_information(self, request, pk) -> HttpResponse: application = self.get_object() - application_status = request.data["status"] - if application_status in [ + to_status = request.data["status"] + from_status = application.status + if to_status in [ ApplicationStatus.ADDITIONAL_INFORMATION_NEEDED, ApplicationStatus.HANDLING, ]: - application.status = application_status + ApplicationLogEntry.objects.create( + application=application, + from_status=from_status, + to_status=to_status, + comment="", + ) + + application.status = to_status application.save() + if to_status == ApplicationStatus.ADDITIONAL_INFORMATION_NEEDED: + # Create an automatic message for the applicant + # self.instance.additional_information_requested_at is not updated at this point as + # it's a queryset annotation, so need to refresh + application.additional_information_requested_at = ( + Application.objects.get( + pk=application.pk + ).additional_information_requested_at + ) + + info_asked_timestamp = getattr( + application, "additional_information_requested_at", None + ) + if info_asked_timestamp: + info_asked_timestamp = info_asked_timestamp.date() + timedelta( + days=7 + ) + else: + info_asked_timestamp = None + + send_application_reopened_message( + request.user, + application, + info_asked_timestamp, + ) + return Response( status=status.HTTP_200_OK, ) diff --git a/backend/benefit/applications/api/v1/serializers/application.py b/backend/benefit/applications/api/v1/serializers/application.py index 7a4727f258..89e98f350f 100755 --- a/backend/benefit/applications/api/v1/serializers/application.py +++ b/backend/benefit/applications/api/v1/serializers/application.py @@ -77,7 +77,6 @@ ) from companies.api.v1.serializers import CompanySearchSerializer, CompanySerializer from companies.models import Company -from messages.automatic_messages import send_application_reopened_message from shared.audit_log import audit_logging from shared.audit_log.enums import Operation from terms.api.v1.serializers import ( @@ -1197,18 +1196,6 @@ def handle_status_transition( to_status=instance.status, comment=log_entry_comment or "", ) - if instance.status == ApplicationStatus.ADDITIONAL_INFORMATION_NEEDED: - # Create an automatic message for the applicant - # self.instance.additional_information_requested_at is not updated at this point as - # it's a queryset annotation, so need to refresh - self.instance.additional_information_requested_at = Application.objects.get( - pk=instance.pk - ).additional_information_requested_at - send_application_reopened_message( - get_request_user_from_context(self), - instance, - self.get_additional_information_needed_by(instance), - ) # Assign current user as handler if ( diff --git a/backend/benefit/applications/tests/test_applications_api.py b/backend/benefit/applications/tests/test_applications_api.py index c330d91e6a..684003d676 100755 --- a/backend/benefit/applications/tests/test_applications_api.py +++ b/backend/benefit/applications/tests/test_applications_api.py @@ -1387,18 +1387,6 @@ def test_application_status_change_as_handler( if handled_by_ahjo_automation: assert response.data["handled_by_ahjo_automation"] is True - if to_status == ApplicationStatus.ADDITIONAL_INFORMATION_NEEDED: - assert application.messages.count() == 1 - assert ( - "Please make the corrections and send application again by 11.06.2021" - in application.messages.first().content - ) - assert len(mailoutbox) == 1 - assert ( - get_additional_information_email_notification_subject() - in mailoutbox[0].subject - ) - if to_status in [ ApplicationStatus.CANCELLED, ApplicationStatus.REJECTED, @@ -2436,6 +2424,30 @@ def test_applications_with_unread_messages(api_client, handler_api_client, appli assert len(response.data) == 0 +def test_require_additional_information(handler_api_client, application, mailoutbox): + application.status = ApplicationStatus.HANDLING + application.save() + response = handler_api_client.patch( + reverse( + "v1:handler-application-require-additional-information", + kwargs={"pk": application.id}, + ), + {"status": ApplicationStatus.ADDITIONAL_INFORMATION_NEEDED}, + ) + assert response.status_code == 200 + print(response.__dict__) + + assert application.messages.count() == 1 + assert ( + "Please make the corrections and send application again by 11.06.2021" + in application.messages.first().content + ) + assert len(mailoutbox) == 1 + assert ( + get_additional_information_email_notification_subject() in mailoutbox[0].subject + ) + + def _create_random_applications(): f = faker.Faker() combos = [ diff --git a/frontend/benefit/handler/src/components/applicationList/ApplicationList.tsx b/frontend/benefit/handler/src/components/applicationList/ApplicationList.tsx index 01b6da59d9..7c07013f99 100644 --- a/frontend/benefit/handler/src/components/applicationList/ApplicationList.tsx +++ b/frontend/benefit/handler/src/components/applicationList/ApplicationList.tsx @@ -109,7 +109,7 @@ export const renderPaymentTagPerStatus = ( $TagWrapper> ); -const parseAhjoError = (ahjoError: AhjoError): JSX.Element[] => { +const renderAhjoError = (ahjoError: AhjoError): JSX.Element[] => { if (Array.isArray(ahjoError.errorFromAhjo)) return ahjoError.errorFromAhjo.map(({ message }) =>