From 757573f52ce71173579deeed6a4bd762e963d0ab Mon Sep 17 00:00:00 2001
From: Jonathan Reveille <jon.rev93001@gmail.com>
Date: Wed, 18 Sep 2024 16:27:55 +0200
Subject: [PATCH] =?UTF-8?q?fixup!=20=F0=9F=90=9B(backend)=20submit=20for?=
 =?UTF-8?q?=20signature=20handle=20timeout=20delete=20signing=20procedure?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/backend/joanie/core/models/products.py    | 34 +++++++++++--------
 src/backend/joanie/core/utils/signature.py    | 21 ------------
 .../joanie/signature/backends/lex_persona.py  |  2 +-
 .../joanie/tests/core/test_models_order.py    | 24 ++++++-------
 4 files changed, 32 insertions(+), 49 deletions(-)

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)