Skip to content

Commit

Permalink
feat: don't block ahjo requests if xml build fails (#3463)
Browse files Browse the repository at this point in the history
  • Loading branch information
rikuke authored Oct 30, 2024
1 parent 2203360 commit 8a03c49
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 22 deletions.
17 changes: 11 additions & 6 deletions backend/benefit/applications/services/ahjo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ def send_request_to_ahjo(
)
return None, None

def handle_http_error(self, e: requests.exceptions.HTTPError) -> Tuple[None, dict]:
def handle_http_error(self, e: requests.exceptions.HTTPError) -> None:
"""Handle HTTP errors that occur when sending a request to Ahjo.
Also log any validation errors received from Ahjo.
"""
Expand All @@ -292,13 +292,10 @@ def handle_http_error(self, e: requests.exceptions.HTTPError) -> Tuple[None, dic
if hasattr(self._request, "application"):
application_number = self._request.application.application_number

error_message = f"A HTTP error occurred while sending {self._request} for application \
{application_number} to Ahjo: {e}"
error_message = self.format_error_message(e, application_number)

else:
error_message = (
f"A HTTP error occurred while sending {self._request} to Ahjo: {e}"
)
error_message = self.format_error_message(e)

if error_json:
error_message += f" Error message: {error_json}"
Expand All @@ -307,3 +304,11 @@ def handle_http_error(self, e: requests.exceptions.HTTPError) -> Tuple[None, dic
status.save()

LOGGER.error(error_message)

def format_error_message(
self,
e: Union[requests.exceptions.HTTPError, requests.exceptions.RequestException],
application_number: Union[int, None] = None,
) -> str:
return f"A HTTP or network error occurred while sending {self.request} for application \
{application_number} to Ahjo: {e}"
13 changes: 13 additions & 0 deletions backend/benefit/applications/services/ahjo_error_writer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from applications.models import Application


class AhjoErrorWriter:
@staticmethod
def write_error_to_ahjo_status(application: Application, error: str) -> None:
latest_ahjo_status = application.ahjo_status.latest()
latest_ahjo_status.error_from_ahjo = {
"id": "NO_ID",
"context": f"{error}",
"message": "Ahjo-pyynnössä tapahtui virhe, mutta Ahjo ei palauttanut tarkempia tietoja.",
}
latest_ahjo_status.save()
49 changes: 37 additions & 12 deletions backend/benefit/applications/services/ahjo_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from django.core.files.base import ContentFile
from django.db.models import QuerySet
from django.urls import reverse
from lxml import etree
from lxml.etree import XMLSchemaParseError, XMLSyntaxError

from applications.enums import (
AhjoRequestType,
Expand Down Expand Up @@ -42,6 +44,7 @@
AhjoSubscribeDecisionRequest,
AhjoUpdateRecordsRequest,
)
from applications.services.ahjo_error_writer import AhjoErrorWriter
from applications.services.ahjo_payload import (
prepare_attachment_records_payload,
prepare_decision_proposal_payload,
Expand Down Expand Up @@ -551,6 +554,12 @@ def send_new_attachment_records_to_ahjo(
return result, response_text


class DecisionProposalError(Exception):
"""Custom exception for errors in XML generation."""

pass


def send_decision_proposal_to_ahjo(
application: Application, ahjo_token: AhjoToken
) -> Union[Tuple[Application, str], None]:
Expand All @@ -568,19 +577,35 @@ def send_decision_proposal_to_ahjo(

delete_existing_xml_attachments(application)

decision_xml = generate_application_attachment(
application, AttachmentType.DECISION_TEXT_XML, decision
)
secret_xml = generate_application_attachment(
application, AttachmentType.DECISION_TEXT_SECRET_XML
)
try:
decision_xml = generate_application_attachment(
application, AttachmentType.DECISION_TEXT_XML, decision
)
secret_xml = generate_application_attachment(
application, AttachmentType.DECISION_TEXT_SECRET_XML
)

data = prepare_decision_proposal_payload(
application=application,
decision_xml=decision_xml,
decision_text=decision,
secret_xml=secret_xml,
)
data = prepare_decision_proposal_payload(
application=application,
decision_xml=decision_xml,
decision_text=decision,
secret_xml=secret_xml,
)
except XMLSchemaParseError as e:
AhjoErrorWriter.write_error_to_ahjo_status(application, str(e))
return (None, None)
except XMLSyntaxError as e:
AhjoErrorWriter.write_error_to_ahjo_status(application, str(e))
return (None, None)
except etree.DocumentInvalid as e:
AhjoErrorWriter.write_error_to_ahjo_status(application, str(e))
return (None, None)
except DecisionProposalError as e:
LOGGER.error(
f"Error in generating decision proposal payload\
for application {application.application_number}: {e}"
)
return (None, None)
response, response_text = ahjo_client.send_request_to_ahjo(data)
return response, response_text

Expand Down
17 changes: 13 additions & 4 deletions backend/benefit/applications/services/ahjo_xml_builder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import copy
import logging
import os
from dataclasses import dataclass
from datetime import date
Expand All @@ -24,6 +25,8 @@

AhjoXMLString = str

LOGGER = logging.getLogger(__name__)


class AhjoXMLBuilder:
def __init__(self, application: Application) -> None:
Expand Down Expand Up @@ -60,14 +63,20 @@ def validate_against_schema(self, xml_string: str, xsd_string: str) -> bool:
) # This will raise an exception if the document is not valid
return True # Return True if no exception was raised
except XMLSchemaParseError as e:
print(f"Schema Error: {e}")
LOGGER.error(
f"Decision proposal XML Schema Error for application {self.application.application_number}: {e}"
)
raise
except XMLSyntaxError as e:
print(f"XML Error: {e}")
LOGGER.error(
f"Decision proposal XML Syntax Error for application {self.application.application_number}: {e}"
)
raise
except etree.DocumentInvalid as e:
print(f"Validation Error: {e}")
return False # Return False if the document is invalid
LOGGER.error(
f"Decision proposal Validation Error for application {self.application.application_number}: {e}"
)
return False # Return False if the document is invalid


class AhjoPublicXMLBuilder(AhjoXMLBuilder):
Expand Down

0 comments on commit 8a03c49

Please sign in to comment.