diff --git a/utils/universign_status_mapping.py b/utils/universign_status_mapping.py index 6bc0c9e..5bc4733 100644 --- a/utils/universign_status_mapping.py +++ b/utils/universign_status_mapping.py @@ -1,76 +1,46 @@ -""" -Mapping exhaustif : Universign ↔ Local ↔ Sage -""" - -from typing import Dict, Optional -from enum import Enum - - -# ======================================== -# MAPPING UNIVERSIGN → LOCAL -# ======================================== +from typing import Dict UNIVERSIGN_TO_LOCAL: Dict[str, str] = { - # États initiaux - "draft": "EN_ATTENTE", # Transaction créée - "ready": "EN_ATTENTE", # Prête mais pas envoyée - # En cours - "started": "EN_COURS", # Envoyée, en attente de signature - # États finaux (succès) - "completed": "SIGNE", # ✓ Signé avec succès - # États finaux (échec) - "refused": "REFUSE", # ✗ Refusé par un signataire - "expired": "EXPIRE", # ⏰ Délai expiré - "canceled": "REFUSE", # ✗ Annulé manuellement - "failed": "ERREUR", # ⚠️ Erreur technique + "draft": "EN_ATTENTE", + "ready": "EN_ATTENTE", + "started": "EN_COURS", + "completed": "SIGNE", + "refused": "REFUSE", + "expired": "EXPIRE", + "canceled": "REFUSE", + "failed": "ERREUR", } - -# ======================================== -# MAPPING LOCAL → SAGE (CHAMP LIBRE) -# ======================================== - LOCAL_TO_SAGE_STATUS: Dict[str, int] = { - """ - À stocker dans un champ libre Sage (ex: CB_STATUT_SIGNATURE) - """ - "EN_ATTENTE": 0, # Non envoyé - "EN_COURS": 1, # Envoyé, en attente - "SIGNE": 2, # ✓ Signé (peut déclencher workflow) - "REFUSE": 3, # ✗ Refusé - "EXPIRE": 4, # ⏰ Expiré - "ERREUR": 5, # ⚠️ Erreur + "EN_ATTENTE": 0, + "EN_COURS": 1, + "SIGNE": 2, + "REFUSE": 3, + "EXPIRE": 4, + "ERREUR": 5, } - -# ======================================== -# ACTIONS MÉTIER PAR STATUT -# ======================================== - STATUS_ACTIONS: Dict[str, Dict[str, any]] = { - """ - Actions automatiques à déclencher selon le statut - """ "SIGNE": { - "update_sage_status": True, # Mettre à jour Sage - "trigger_workflow": True, # Déclencher transformation (devis→commande) - "send_notification": True, # Email de confirmation - "archive_document": True, # Archiver le PDF signé - "update_sage_field": "CB_DateSignature", # Champ libre Sage + "update_sage_status": True, + "trigger_workflow": True, + "send_notification": True, + "archive_document": True, + "update_sage_field": "CB_DateSignature", }, "REFUSE": { "update_sage_status": True, "trigger_workflow": False, "send_notification": True, "archive_document": False, - "alert_sales": True, # Alerter commercial + "alert_sales": True, }, "EXPIRE": { "update_sage_status": True, "trigger_workflow": False, "send_notification": True, "archive_document": False, - "schedule_reminder": True, # Programmer relance + "schedule_reminder": True, }, "ERREUR": { "update_sage_status": False, @@ -81,141 +51,60 @@ STATUS_ACTIONS: Dict[str, Dict[str, any]] = { }, } - -# ======================================== -# RÈGLES DE TRANSITION -# ======================================== - ALLOWED_TRANSITIONS: Dict[str, list] = { - """ - Transitions de statuts autorisées (validation) - """ "EN_ATTENTE": ["EN_COURS", "ERREUR"], "EN_COURS": ["SIGNE", "REFUSE", "EXPIRE", "ERREUR"], - "SIGNE": [], # État final, pas de retour - "REFUSE": [], # État final - "EXPIRE": [], # État final - "ERREUR": ["EN_ATTENTE", "EN_COURS"], # Retry possible + "SIGNE": [], + "REFUSE": [], + "EXPIRE": [], + "ERREUR": ["EN_ATTENTE", "EN_COURS"], } -# ======================================== -# FONCTION DE MAPPING -# ======================================== - - def map_universign_to_local(universign_status: str) -> str: - """ - Convertit un statut Universign en statut local - - Args: - universign_status: Statut brut Universign - - Returns: - Statut local normalisé - """ return UNIVERSIGN_TO_LOCAL.get( universign_status.lower(), - "ERREUR", # Fallback si statut inconnu + "ERREUR", ) def get_sage_status_code(local_status: str) -> int: - """ - Obtient le code numérique pour Sage - - Args: - local_status: Statut local (EN_ATTENTE, SIGNE, etc.) - - Returns: - Code numérique pour champ libre Sage - """ return LOCAL_TO_SAGE_STATUS.get(local_status, 5) def is_transition_allowed(from_status: str, to_status: str) -> bool: - """ - Vérifie si une transition de statut est valide - - Args: - from_status: Statut actuel - to_status: Nouveau statut - - Returns: - True si la transition est autorisée - """ if from_status == to_status: - return True # Même statut = OK (idempotence) + return True allowed = ALLOWED_TRANSITIONS.get(from_status, []) return to_status in allowed def get_status_actions(local_status: str) -> Dict[str, any]: - """ - Obtient les actions à exécuter pour un statut - - Args: - local_status: Statut local - - Returns: - Dictionnaire des actions à exécuter - """ return STATUS_ACTIONS.get(local_status, {}) def is_final_status(local_status: str) -> bool: - """ - Détermine si le statut est final (pas de synchronisation nécessaire) - - Args: - local_status: Statut local - - Returns: - True si statut final - """ return local_status in ["SIGNE", "REFUSE", "EXPIRE"] -# ======================================== -# PRIORITÉS DE STATUTS (POUR CONFLITS) -# ======================================== - STATUS_PRIORITY: Dict[str, int] = { - """ - En cas de conflit de synchronisation, prendre le statut - avec la priorité la plus élevée - """ - "ERREUR": 0, # Priorité la plus basse + "ERREUR": 0, "EN_ATTENTE": 1, "EN_COURS": 2, "EXPIRE": 3, "REFUSE": 4, - "SIGNE": 5, # Priorité la plus élevée (état final souhaité) + "SIGNE": 5, } def resolve_status_conflict(status_a: str, status_b: str) -> str: - """ - Résout un conflit entre deux statuts (prend le plus prioritaire) - - Args: - status_a: Premier statut - status_b: Second statut - - Returns: - Statut prioritaire - """ priority_a = STATUS_PRIORITY.get(status_a, 0) priority_b = STATUS_PRIORITY.get(status_b, 0) return status_a if priority_a >= priority_b else status_b -# ======================================== -# MESSAGES UTILISATEUR -# ======================================== - STATUS_MESSAGES: Dict[str, Dict[str, str]] = { "EN_ATTENTE": { "fr": "Document en attente d'envoi", @@ -257,16 +146,6 @@ STATUS_MESSAGES: Dict[str, Dict[str, str]] = { def get_status_message(local_status: str, lang: str = "fr") -> str: - """ - Obtient le message utilisateur pour un statut - - Args: - local_status: Statut local - lang: Langue (fr, en) - - Returns: - Message formaté - """ status_info = STATUS_MESSAGES.get(local_status, {}) icon = status_info.get("icon", "") message = status_info.get(lang, local_status)