diff --git a/src/backend/joanie/core/models/products.py b/src/backend/joanie/core/models/products.py index 4e79b25499..342023020e 100644 --- a/src/backend/joanie/core/models/products.py +++ b/src/backend/joanie/core/models/products.py @@ -37,7 +37,6 @@ from joanie.core.utils import contract_definition as contract_definition_utility from joanie.core.utils import issuers, webhooks from joanie.core.utils.payment_schedule import generate as generate_payment_schedule -from joanie.core.utils.signature import handle_signature_deletion_error from joanie.signature.backends import get_signature_backend from joanie.signature.exceptions import DeleteSignatureProcedureFailed @@ -967,25 +966,30 @@ def submit_for_signature(self, user: User): ) if should_be_resubmitted: - # The signature provider may take some time to respond with the confirmation of the - # deletion. If we reach the timeout limit, we should reset the contract submission - # values because the signature provider will delete them. - # We won't be able to use the `contract.signature_backend_reference` again. - # There can be edge case where the signature backend reference was already deleted, - # causing an error that the reference was not found at the signature provider side. + # The signature provider may delay confirming deletion. If timeout occurs, reset + # submission values, as the signature provider will delete them. In an edge case, the + # reference `contract.signature_backend_reference` cannot be used and may already + # be deleted causing a 'not found' error from the signature provider. try: backend_signature.delete_signing_procedure( contract.signature_backend_reference ) - except BackendTimeout as exception: # pylint: disable=unused-variable - handle_signature_deletion_error( - order=self, error_message="Timeout on signature reference deletion" + except (BackendTimeout, DeleteSignatureProcedureFailed) as exception: + logger.error( + exception, + extra={ + "context": { + "order": self.to_dict(), + "product": self.product.to_dict(), + "signature_backend_reference": ( + contract.signature_backend_reference + ), + } + }, ) - except DeleteSignatureProcedureFailed as exception: # pylint: disable=unused-variable - handle_signature_deletion_error( - order=self, error_message="Failed to delete signature procedure" - ) - was_already_submitted = False + finally: + contract.reset_submission_for_signature() + was_already_submitted = False # We want to submit or re-submit the contract for signature in three cases: # 1- the contract was never submitted for signature before diff --git a/src/backend/joanie/core/utils/signature.py b/src/backend/joanie/core/utils/signature.py index 7179ee3ddf..cdeaf5db79 100644 --- a/src/backend/joanie/core/utils/signature.py +++ b/src/backend/joanie/core/utils/signature.py @@ -36,24 +36,3 @@ def check_signature(request, settings_name): ) if not signature_is_valid: raise exceptions.AuthenticationFailed("Invalid authentication.") - - -def handle_signature_deletion_error(order, error_message): - """ - Handles the exception raised on the deletion of a signing procedure. - It's responsible for resetting the submission values from the outdated - contract of the order. - """ - logger.error( - error_message, - extra={ - "context": { - "order": order.to_dict(), - "product": order.product.to_dict(), - "signature_backend_reference": ( - order.contract.signature_backend_reference - ), - } - }, - ) - order.contract.reset_submission_for_signature() diff --git a/src/backend/joanie/signature/backends/lex_persona.py b/src/backend/joanie/signature/backends/lex_persona.py index e604ac8da4..75176b4d5b 100644 --- a/src/backend/joanie/signature/backends/lex_persona.py +++ b/src/backend/joanie/signature/backends/lex_persona.py @@ -528,7 +528,7 @@ def delete_signing_procedure(self, reference_id: str): response = requests.delete(url, headers=headers, timeout=timeout) except ReadTimeout as exception: raise BackendTimeout( - "Deletion request is taking longer than expected." + f"Deletion request is taking longer than expected for reference: {reference_id}" ) from exception if not response.ok: diff --git a/src/backend/joanie/tests/core/test_models_order.py b/src/backend/joanie/tests/core/test_models_order.py index bd9ccc41b7..85b3c739a9 100644 --- a/src/backend/joanie/tests/core/test_models_order.py +++ b/src/backend/joanie/tests/core/test_models_order.py @@ -1338,11 +1338,14 @@ def test_models_order_submit_for_signature_step_delete_signing_procedure_timeout # Change the contract definition title to trigger the `should_be_resubmitted` condition order.product.contract_definition.title = "You know nothing John Snow." order.product.contract_definition.save() - # Prepare the ReadTimeout on the `delete_signing_procedure` method + # Prepare the `BackendTimeout` on the `delete_signing_procedure` method + # when the second call of `submit_for_signature` occurs responses.add( responses.DELETE, f"https://lex_persona.test01.com/api/workflows/{workflow_id}", - body=BackendTimeout(), + body=BackendTimeout( + f"Deletion request is taking longer than expected for reference: {workflow_id}" + ), ) # Prepare the data for the new document to sign on the contract new_workflow_id = "wfl_id_fake_2" @@ -1533,13 +1536,13 @@ def test_models_order_submit_for_signature_step_delete_signing_procedure_timeout with self.assertLogs("joanie") as logger: order.submit_for_signature(user=user) - # We should find the in the logger message the reference wfl_id_fake_1 being deleted + # We should find in the logger message the reference wfl_id_fake_1 being deleted self.assertLogsEquals( logger.records, [ ( "ERROR", - "Timeout on signature reference deletion", + f"Deletion request is taking longer than expected for reference: {workflow_id}", { "order": dict, "product": dict, @@ -1824,7 +1827,8 @@ def test_models_order_submit_for_signature_step_delete_signing_procedure_referen with self.assertLogs("joanie") as logger: order.submit_for_signature(user=user) - # We should find the in the logger message the reference wfl_id_fake_1 being deleted + # We should find in the logger message the reference wfl_id_fake_1 trying to deleted + # but fails self.assertLogsEquals( logger.records, [ @@ -1835,17 +1839,13 @@ def test_models_order_submit_for_signature_step_delete_signing_procedure_referen ), ( "ERROR", - "Failed to delete signature procedure", - { - "order": dict, - "product": dict, - "signature_backend_reference": str, - }, + "Lex Persona: Unable to delete the signature procedure the reference " + f"does not exist {workflow_id}", ), ], ) - # Check we have the latest data from db for the contract + # Our contract must have the new values of the document to sign contract.refresh_from_db() self.assertIsNotNone(contract.submitted_for_signature_on) self.assertEqual(contract.signature_backend_reference, new_workflow_id)