From e6c2ab66702747a3764eaf70a9fb2aa8ef30de00 Mon Sep 17 00:00:00 2001 From: Fanilo-Nantenaina Date: Fri, 28 Nov 2025 12:05:06 +0300 Subject: [PATCH] refactor: improve client association and validation by safeguarding the client object and adding re-association logic. --- sage_connector.py | 113 +++++++++++++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 37 deletions(-) diff --git a/sage_connector.py b/sage_connector.py index 0179f36..efff8fc 100644 --- a/sage_connector.py +++ b/sage_connector.py @@ -1266,16 +1266,15 @@ class SageConnector: if not client_obj_cible: raise ValueError(f"Impossible de charger client {client_code}") - # ✅ SOLUTION : Utiliser SetClient au lieu de SetDefaultClient - # SetClient définit UNIQUEMENT le client sans réinitialiser les autres champs + # ✅ Associer le client try: doc_cible.SetClient(client_obj_cible) logger.info( - f"[TRANSFORM] SetClient() appelé pour {client_code}" + f"[TRANSFORM] SetClient() appele pour {client_code}" ) except Exception as e: logger.warning( - f"[TRANSFORM] SetClient() échoué: {e}, tentative SetDefaultClient()" + f"[TRANSFORM] SetClient() echoue: {e}, tentative SetDefaultClient()" ) doc_cible.SetDefaultClient(client_obj_cible) @@ -1297,13 +1296,16 @@ class SageConnector: if not client_verifie: raise ValueError( - f"Échec association client {client_code} - CT_Num reste vide après Write()" + f"Echec association client {client_code} - CT_Num reste vide apres Write()" ) logger.info( - f"[TRANSFORM] Client {client_code} associé et vérifié (CT_Num={client_verifie})" + f"[TRANSFORM] Client {client_code} associe et verifie (CT_Num={client_verifie})" ) + # 🔒 GARDER UNE RÉFÉRENCE À L'OBJET CLIENT POUR RÉASSOCIATION + client_obj_sauvegarde = client_obj_cible + # ======================================== # ÉTAPE 7 : COPIER LES LIGNES # ======================================== @@ -1392,11 +1394,9 @@ class SageConnector: "[TRANSFORM] Completion champs obligatoires facture..." ) - # 1. Code journal (SEUL CHAMP VRAIMENT CRITIQUE) + # 1. Code journal try: journal = None - - # Essayer de récupérer du document source try: journal = getattr(doc_source, "DO_CodeJournal", None) if journal: @@ -1406,12 +1406,10 @@ class SageConnector: except: pass - # Si pas trouvé, utiliser "VTE" (Ventes - confirmé existant dans votre config) if not journal: journal = "VTE" logger.info("[TRANSFORM] Journal par defaut: VTE") - # Vérifier si le champ existe avant de l'assigner if hasattr(doc_cible, "DO_CodeJournal"): doc_cible.DO_CodeJournal = journal logger.info( @@ -1421,14 +1419,12 @@ class SageConnector: logger.warning( "[TRANSFORM] DO_CodeJournal inexistant sur ce document" ) - except Exception as e: - # Le journal n'est peut-être pas obligatoire sur votre installation logger.warning( f"[TRANSFORM] Impossible de definir code journal: {e}" ) - # 2. Souche de numérotation (copie depuis source) + # 2. Souche try: souche = getattr(doc_source, "DO_Souche", 0) if hasattr(doc_cible, "DO_Souche"): @@ -1437,7 +1433,7 @@ class SageConnector: except Exception as e: logger.debug(f"[TRANSFORM] Souche non definie: {e}") - # 3. Régime de TVA (si présent) + # 3. Régime de TVA try: regime = getattr(doc_source, "DO_Regime", None) if regime is not None and hasattr(doc_cible, "DO_Regime"): @@ -1446,7 +1442,7 @@ class SageConnector: except Exception as e: logger.debug(f"[TRANSFORM] Regime TVA non defini: {e}") - # 4. Type de transaction (si présent) + # 4. Type de transaction try: transaction = getattr(doc_source, "DO_Transaction", None) if transaction is not None and hasattr( @@ -1460,20 +1456,24 @@ class SageConnector: # 5. Domaine (Vente = 0) try: if hasattr(doc_cible, "DO_Domaine"): - doc_cible.DO_Domaine = 0 # 0 = Vente + doc_cible.DO_Domaine = 0 logger.info("[TRANSFORM] Domaine: 0 (Vente)") except Exception as e: logger.debug(f"[TRANSFORM] Domaine non defini: {e}") - # Écrire le document avec les champs complétés - logger.info( - "[TRANSFORM] Ecriture document avec champs completes..." - ) - doc_cible.Write() + # ======================================== + # 🔒 RÉASSOCIER LE CLIENT AVANT VALIDATION + # ======================================== + logger.info("[TRANSFORM] Reassociation client avant validation...") - # ============================================================================== - # ÉTAPE 9 : VALIDATION SIMPLIFIÉE (à remplacer aussi) - # ============================================================================== + try: + doc_cible.SetClient(client_obj_sauvegarde) + except: + doc_cible.SetDefaultClient(client_obj_sauvegarde) + + # Écriture finale avec tous les champs complétés + logger.info("[TRANSFORM] Ecriture document finale...") + doc_cible.Write() # ======================================== # ÉTAPE 9 : VALIDER LE DOCUMENT @@ -1483,15 +1483,13 @@ class SageConnector: # Relire pour vérifier doc_cible.Read() - # Diagnostic pré-validation (uniquement champs existants) + # Diagnostic pré-validation logger.info("[TRANSFORM] === PRE-VALIDATION CHECK ===") - # Liste des champs à vérifier (avec hasattr pour éviter les erreurs) champs_a_verifier = [ "DO_Type", "CT_Num", "DO_Date", - "DO_CodeJournal", "DO_Souche", "DO_Statut", "DO_Regime", @@ -1506,16 +1504,58 @@ class SageConnector: except: pass - # Vérifier UNIQUEMENT les champs absolument critiques - champs_manquants = [] + # ✅ VÉRIFICATION CLIENT AMÉLIORÉE + client_final = getattr(doc_cible, "CT_Num", None) - if not getattr(doc_cible, "CT_Num", None): - champs_manquants.append("Client (CT_Num)") + if not client_final: + try: + client_obj_test = getattr(doc_cible, "Client", None) + if client_obj_test: + client_obj_test.Read() + client_final = getattr(client_obj_test, "CT_Num", None) + logger.info( + f"[TRANSFORM] Client recupere via .Client: {client_final}" + ) + except: + pass - if champs_manquants: - erreur = f"Champs obligatoires manquants: {', '.join(champs_manquants)}" - logger.error(f"[TRANSFORM] {erreur}") - raise ValueError(erreur) + # Si toujours pas de client, dernière réassociation forcée + if not client_final: + logger.warning( + "[TRANSFORM] Client perdu ! Tentative reassociation d'urgence..." + ) + try: + doc_cible.SetClient(client_obj_sauvegarde) + except: + doc_cible.SetDefaultClient(client_obj_sauvegarde) + + doc_cible.Write() + doc_cible.Read() + + client_final = getattr(doc_cible, "CT_Num", None) + + if not client_final: + try: + client_obj_test = getattr(doc_cible, "Client", None) + if client_obj_test: + client_obj_test.Read() + client_final = getattr( + client_obj_test, "CT_Num", None + ) + except: + pass + + if not client_final: + logger.error( + "[TRANSFORM] IMPOSSIBLE d'associer le client malgre toutes les tentatives" + ) + raise ValueError( + f"Client {client_code} impossible a associer au document" + ) + + logger.info( + f"[TRANSFORM] ✅ Client confirme avant validation: {client_final}" + ) # Lancer le processus try: @@ -1527,7 +1567,6 @@ class SageConnector: logger.error(f"[TRANSFORM] ERREUR Process(): {e}") logger.error("[TRANSFORM] === DIAGNOSTIC COMPLET ===") - # Afficher uniquement les attributs DO_ et CT_ qui existent try: attributs_doc = [ attr