feat(signer-status): add new signer statuses and improve status handling
This commit is contained in:
parent
fbaa43e3fd
commit
bcaa621432
3 changed files with 48 additions and 35 deletions
|
|
@ -29,10 +29,14 @@ class UniversignTransactionStatus(str, Enum):
|
||||||
|
|
||||||
class UniversignSignerStatus(str, Enum):
|
class UniversignSignerStatus(str, Enum):
|
||||||
WAITING = "waiting"
|
WAITING = "waiting"
|
||||||
|
OPEN = "open"
|
||||||
VIEWED = "viewed"
|
VIEWED = "viewed"
|
||||||
SIGNED = "signed"
|
SIGNED = "signed"
|
||||||
|
COMPLETED = "completed"
|
||||||
REFUSED = "refused"
|
REFUSED = "refused"
|
||||||
EXPIRED = "expired"
|
EXPIRED = "expired"
|
||||||
|
STALLED = "stalled"
|
||||||
|
UNKNOWN = "unknown"
|
||||||
|
|
||||||
|
|
||||||
class LocalDocumentStatus(str, Enum):
|
class LocalDocumentStatus(str, Enum):
|
||||||
|
|
|
||||||
|
|
@ -251,46 +251,38 @@ class UniversignSyncService:
|
||||||
transaction: UniversignTransaction,
|
transaction: UniversignTransaction,
|
||||||
universign_data: Dict,
|
universign_data: Dict,
|
||||||
):
|
):
|
||||||
"""
|
|
||||||
CORRECTION : Synchronise les signataires sans perdre les données locales
|
|
||||||
"""
|
|
||||||
# Récupérer les participants depuis différents endroits possibles
|
|
||||||
signers_data = universign_data.get("participants", [])
|
signers_data = universign_data.get("participants", [])
|
||||||
if not signers_data:
|
if not signers_data:
|
||||||
signers_data = universign_data.get("signers", [])
|
signers_data = universign_data.get("signers", [])
|
||||||
|
|
||||||
# ⚠️ IMPORTANT : Ne pas toucher aux signers si Universign n'en retourne pas
|
|
||||||
if not signers_data:
|
if not signers_data:
|
||||||
logger.debug(
|
logger.debug("Aucun signataire dans les données Universign")
|
||||||
"Aucun signataire dans les données Universign, conservation des données locales"
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Créer un mapping email -> signer existant
|
|
||||||
existing_signers = {s.email: s for s in transaction.signers}
|
existing_signers = {s.email: s for s in transaction.signers}
|
||||||
|
|
||||||
for idx, signer_data in enumerate(signers_data):
|
for idx, signer_data in enumerate(signers_data):
|
||||||
email = signer_data.get("email", "")
|
email = signer_data.get("email", "")
|
||||||
|
|
||||||
if not email:
|
if not email:
|
||||||
logger.warning(f"Signataire sans email à l'index {idx}, ignoré")
|
logger.warning(f"Signataire sans email à l'index {idx}, ignoré")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if email in existing_signers:
|
# ✅ PROTECTION : gérer les statuts inconnus
|
||||||
# ✅ Mise à jour du signer existant (ne pas écraser si None)
|
raw_status = signer_data.get("status") or signer_data.get(
|
||||||
signer = existing_signers[email]
|
"state", "waiting"
|
||||||
|
)
|
||||||
# Mise à jour du statut
|
|
||||||
new_status = signer_data.get("status") or signer_data.get("state")
|
|
||||||
if new_status:
|
|
||||||
try:
|
try:
|
||||||
signer.status = UniversignSignerStatus(new_status)
|
status = UniversignSignerStatus(raw_status)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Statut inconnu pour signer {email}: {new_status}"
|
f"Statut inconnu pour signer {email}: {raw_status}, utilisation de 'unknown'"
|
||||||
)
|
)
|
||||||
|
status = UniversignSignerStatus.UNKNOWN
|
||||||
|
|
||||||
|
if email in existing_signers:
|
||||||
|
signer = existing_signers[email]
|
||||||
|
signer.status = status
|
||||||
|
|
||||||
# Mise à jour des dates (ne pas écraser si déjà renseignées)
|
|
||||||
viewed_at = self._parse_date(signer_data.get("viewed_at"))
|
viewed_at = self._parse_date(signer_data.get("viewed_at"))
|
||||||
if viewed_at and not signer.viewed_at:
|
if viewed_at and not signer.viewed_at:
|
||||||
signer.viewed_at = viewed_at
|
signer.viewed_at = viewed_at
|
||||||
|
|
@ -303,29 +295,26 @@ class UniversignSyncService:
|
||||||
if refused_at and not signer.refused_at:
|
if refused_at and not signer.refused_at:
|
||||||
signer.refused_at = refused_at
|
signer.refused_at = refused_at
|
||||||
|
|
||||||
# Mise à jour du nom si manquant
|
|
||||||
if signer_data.get("name") and not signer.name:
|
if signer_data.get("name") and not signer.name:
|
||||||
signer.name = signer_data.get("name")
|
signer.name = signer_data.get("name")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# ✅ Nouveau signer
|
# ✅ Nouveau signer avec gestion d'erreur intégrée
|
||||||
try:
|
try:
|
||||||
status = signer_data.get("status") or signer_data.get(
|
|
||||||
"state", "waiting"
|
|
||||||
)
|
|
||||||
signer = UniversignSigner(
|
signer = UniversignSigner(
|
||||||
id=f"{transaction.id}_signer_{idx}_{int(datetime.now().timestamp())}",
|
id=f"{transaction.id}_signer_{idx}_{int(datetime.now().timestamp())}",
|
||||||
transaction_id=transaction.id,
|
transaction_id=transaction.id,
|
||||||
email=email,
|
email=email,
|
||||||
name=signer_data.get("name"),
|
name=signer_data.get("name"),
|
||||||
status=UniversignSignerStatus(status),
|
status=status,
|
||||||
order_index=idx,
|
order_index=idx,
|
||||||
viewed_at=self._parse_date(signer_data.get("viewed_at")),
|
viewed_at=self._parse_date(signer_data.get("viewed_at")),
|
||||||
signed_at=self._parse_date(signer_data.get("signed_at")),
|
signed_at=self._parse_date(signer_data.get("signed_at")),
|
||||||
refused_at=self._parse_date(signer_data.get("refused_at")),
|
refused_at=self._parse_date(signer_data.get("refused_at")),
|
||||||
)
|
)
|
||||||
session.add(signer)
|
session.add(signer)
|
||||||
logger.info(f"➕ Nouveau signataire ajouté: {email}")
|
logger.info(
|
||||||
|
f"➕ Nouveau signataire ajouté: {email} (statut: {status.value})"
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Erreur création signer {email}: {e}")
|
logger.error(f"Erreur création signer {email}: {e}")
|
||||||
|
|
||||||
|
|
@ -534,15 +523,22 @@ class UniversignSyncService:
|
||||||
self, session: AsyncSession, transaction: UniversignTransaction, new_status: str
|
self, session: AsyncSession, transaction: UniversignTransaction, new_status: str
|
||||||
):
|
):
|
||||||
actions = get_status_actions(new_status)
|
actions = get_status_actions(new_status)
|
||||||
|
|
||||||
if not actions:
|
if not actions:
|
||||||
return
|
return
|
||||||
|
|
||||||
if actions.get("update_sage_status"):
|
if actions.get("update_sage_status") and self.sage_client:
|
||||||
await self._update_sage_status(transaction, new_status)
|
await self._update_sage_status(transaction, new_status)
|
||||||
|
elif actions.get("update_sage_status"):
|
||||||
|
logger.debug(
|
||||||
|
f"sage_client non configuré, skip MAJ Sage pour {transaction.sage_document_id}"
|
||||||
|
)
|
||||||
|
|
||||||
if actions.get("send_notification"):
|
if actions.get("send_notification") and self.email_queue and self.settings:
|
||||||
await self._send_notification(session, transaction, new_status)
|
await self._send_notification(session, transaction, new_status)
|
||||||
|
elif actions.get("send_notification"):
|
||||||
|
logger.debug(
|
||||||
|
f"email_queue/settings non configuré, skip notification pour {transaction.transaction_id}"
|
||||||
|
)
|
||||||
|
|
||||||
async def _update_sage_status(
|
async def _update_sage_status(
|
||||||
self, transaction: UniversignTransaction, status: str
|
self, transaction: UniversignTransaction, status: str
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
UNIVERSIGN_TO_LOCAL: Dict[str, str] = {
|
UNIVERSIGN_TO_LOCAL: Dict[str, str] = {
|
||||||
"draft": "EN_ATTENTE",
|
"draft": "EN_ATTENTE",
|
||||||
|
|
@ -111,8 +115,17 @@ STATUS_MESSAGES: Dict[str, Dict[str, str]] = {
|
||||||
|
|
||||||
|
|
||||||
def map_universign_to_local(universign_status: str) -> str:
|
def map_universign_to_local(universign_status: str) -> str:
|
||||||
"""Convertit un statut Universign en statut local."""
|
"""Convertit un statut Universign en statut local avec fallback robuste."""
|
||||||
return UNIVERSIGN_TO_LOCAL.get(universign_status.lower(), "ERREUR")
|
normalized = universign_status.lower().strip()
|
||||||
|
mapped = UNIVERSIGN_TO_LOCAL.get(normalized)
|
||||||
|
|
||||||
|
if not mapped:
|
||||||
|
logger.warning(
|
||||||
|
f"Statut Universign inconnu: '{universign_status}', mapping vers ERREUR"
|
||||||
|
)
|
||||||
|
return "ERREUR"
|
||||||
|
|
||||||
|
return mapped
|
||||||
|
|
||||||
|
|
||||||
def get_sage_status_code(local_status: str) -> int:
|
def get_sage_status_code(local_status: str) -> int:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue