feat: track electronic payment reporting status

This commit is contained in:
Julien Denizot
2026-06-21 10:55:44 +00:00
parent c5fb71d314
commit ce85d7765b
3 changed files with 180 additions and 16 deletions
+115 -15
View File
@@ -7,7 +7,7 @@ from typing import Any
import frappe
from frappe import _
from frappe.utils import flt
from frappe.utils import flt, now_datetime
from enuxia_einvoice.inbound_sync import (
_acquire_nonblocking_lock,
@@ -114,10 +114,7 @@ def _find_payment_received_event(
event.get("status_code") or ""
).strip()
if (
status_code
== PAYMENT_RECEIVED_STATUS
):
if status_code == PAYMENT_RECEIVED_STATUS:
return event
return None
@@ -143,6 +140,65 @@ def _payment_lock_name(
)
def _set_payment_tracking(
invoice,
*,
status: str,
event_id: Any = None,
error: str = "",
) -> None:
"""Mettre à jour le suivi d'encaissement de la facture."""
values: dict[str, Any] = {
"einvoice_payment_status": status,
"einvoice_payment_last_error": str(
error or ""
)[:1000],
}
if status == "Reported":
values.update(
{
"einvoice_payment_reported_at": (
now_datetime()
),
"einvoice_payment_event_id": (
str(event_id)
if event_id is not None
else ""
),
"einvoice_payment_last_error": "",
}
)
invoice.db_set(
values,
update_modified=True,
)
def _synchronize_after_payment(
invoice_name: str,
) -> tuple[dict[str, Any], list[str]]:
"""Synchroniser sans annuler un événement déjà créé."""
try:
result = sync_sales_invoice_status(
invoice_name
)
return result, []
except Exception as exc:
warning = _(
"L'encaissement a bien été déclaré, "
"mais la synchronisation complète du statut "
"a échoué : {0}"
).format(str(exc))
return {}, [warning]
@frappe.whitelist()
def report_payment_received(
invoice_name: str,
@@ -185,6 +241,17 @@ def report_payment_received(
)
try:
if (
invoice.get(
"einvoice_payment_status"
)
!= "Reported"
):
_set_payment_tracking(
invoice,
status="To Report",
)
client, access_token = (
get_authenticated_client(
invoice.company
@@ -211,8 +278,16 @@ def report_payment_received(
events_payload,
)
sync_result = (
sync_sales_invoice_status(
event_id = existing_event.get("id")
_set_payment_tracking(
invoice,
status="Reported",
event_id=event_id,
)
sync_result, warnings = (
_synchronize_after_payment(
invoice.name
)
)
@@ -227,14 +302,15 @@ def report_payment_received(
"provider_status": (
PAYMENT_RECEIVED_STATUS
),
"event_id": existing_event.get(
"id"
),
"payment_status": "Reported",
"event_id": event_id,
"latest_event": (
sync_result.get(
"latest_event"
)
or existing_event
),
"warnings": warnings,
"message": _(
"L'encaissement avait déjà été "
"déclaré auprès de SuperPDP."
@@ -251,8 +327,16 @@ def report_payment_received(
)
)
sync_result = (
sync_sales_invoice_status(
event_id = created_event.get("id")
_set_payment_tracking(
invoice,
status="Reported",
event_id=event_id,
)
sync_result, warnings = (
_synchronize_after_payment(
invoice.name
)
)
@@ -267,19 +351,35 @@ def report_payment_received(
"provider_status": (
PAYMENT_RECEIVED_STATUS
),
"event_id": created_event.get(
"id"
),
"payment_status": "Reported",
"event_id": event_id,
"latest_event": (
sync_result.get(
"latest_event"
)
or created_event
),
"warnings": warnings,
"message": _(
"L'encaissement a été déclaré "
"auprès de SuperPDP."
),
}
except Exception as exc:
if (
invoice.get(
"einvoice_payment_status"
)
!= "Reported"
):
_set_payment_tracking(
invoice,
status="Error",
error=str(exc),
)
raise
finally:
_release_lock(lock)
+49 -1
View File
@@ -238,11 +238,59 @@ CUSTOM_FIELDS = {
"insert_after": "einvoice_last_validation",
"read_only": 1,
},
{
"fieldname": "einvoice_payment_section",
"label": "Suivi de lencaissement",
"fieldtype": "Section Break",
"insert_after": "einvoice_last_sync",
"collapsible": 1,
},
{
"fieldname": "einvoice_payment_status",
"label": "Statut de lencaissement électronique",
"fieldtype": "Select",
"insert_after": "einvoice_payment_section",
"options": (
"Not Applicable\n"
"Waiting for Payment\n"
"To Report\n"
"Reported\n"
"Error"
),
"default": "Not Applicable",
"read_only": 1,
"allow_on_submit": 1,
"in_standard_filter": 1,
},
{
"fieldname": "einvoice_payment_reported_at",
"label": "Encaissement déclaré le",
"fieldtype": "Datetime",
"insert_after": "einvoice_payment_status",
"read_only": 1,
"allow_on_submit": 1,
},
{
"fieldname": "einvoice_payment_event_id",
"label": "Identifiant de l’événement de paiement",
"fieldtype": "Data",
"insert_after": "einvoice_payment_reported_at",
"read_only": 1,
"allow_on_submit": 1,
},
{
"fieldname": "einvoice_payment_last_error",
"label": "Erreur de déclaration de lencaissement",
"fieldtype": "Small Text",
"insert_after": "einvoice_payment_event_id",
"read_only": 1,
"allow_on_submit": 1,
},
{
"fieldname": "einvoice_diagnostics_section",
"label": "Diagnostic",
"fieldtype": "Section Break",
"insert_after": "einvoice_last_sync",
"insert_after": "einvoice_payment_last_error",
"collapsible": 1,
},
{
@@ -1,6 +1,7 @@
from __future__ import annotations
import unittest
from datetime import datetime
from unittest.mock import Mock, patch
from enuxia_einvoice.payment_reporting import (
@@ -20,6 +21,21 @@ class TestPaymentReporting(unittest.TestCase):
translation_patcher.start()
self.addCleanup(translation_patcher.stop)
datetime_patcher = patch(
"enuxia_einvoice.payment_reporting."
"now_datetime",
return_value=datetime(
2026,
6,
21,
12,
0,
0,
),
)
datetime_patcher.start()
self.addCleanup(datetime_patcher.stop)
def invoice(
self,
*,