From c48a3f033a16879673d0fdf19b5648b273e972ec Mon Sep 17 00:00:00 2001 From: Fanilo-Nantenaina Date: Fri, 5 Dec 2025 22:37:51 +0300 Subject: [PATCH] fix(sage_connector): enforce mandatory casting after Create() in client creation --- sage_connector.py | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/sage_connector.py b/sage_connector.py index db7777f..e922a0e 100644 --- a/sage_connector.py +++ b/sage_connector.py @@ -2377,45 +2377,36 @@ class SageConnector: def creer_client(self, client_data: Dict) -> Dict: """ - Crée un nouveau client dans Sage 100c via l'API COM, - en utilisant Create() pour obtenir l'objet Tiers. + Crée un nouveau client dans Sage 100c via l'API COM. + ✅ CORRECTION : Cast obligatoire après Create() """ if not self.cial: raise RuntimeError("Connexion Sage non établie") try: with self._com_context(), self._lock_com: - # 1. Accès à la Factory Client (CptaApplication si Tiers) + # 1. Accès à la Factory Client factory_client = self.cial.CptaApplication.FactoryClient - # ✅ Utiliser Create() qui retourne directement l'objet utilisable - client = factory_client.Create() + # ✅ Create() retourne IBIPersistObject (générique) + persist = factory_client.Create() - if not client: + if not persist: raise RuntimeError("Factory.Create() a retourné None") - logger.debug(f"📦 Objet créé, type: {type(client)}") + logger.debug(f"📦 Objet IBIPersistObject créé : {type(persist)}") - # ✅ PAS DE CAST - L'objet retourné par Create() est déjà typé correctement - # Tester l'accès aux propriétés pour vérifier que l'objet est valide + # ✅ CAST OBLIGATOIRE vers IBOClient3 pour accéder aux propriétés métier try: - test_intitule = getattr(client, "CT_Intitule", None) - logger.debug(f"✅ Objet valide, CT_Intitule accessible: {test_intitule}") - except AttributeError as e: - logger.error(f"❌ Objet invalide: {e}") - # Si ça échoue, essayer le cast en dernier recours - logger.warning("Tentative de cast en IBOClient3...") - try: - client = win32com.client.CastTo(client, "IBOClient3") - logger.debug("✅ Cast réussi") - except Exception as cast_err: - raise RuntimeError(f"Impossible d'accéder aux propriétés du client. Objet type: {type(client)}, erreur: {e}") - - # 2. Remplissage des Champs OBLIGATOIRES (Conformes F_COMPTET) + client = win32com.client.CastTo(persist, "IBOClient3") + logger.debug(f"✅ Cast réussi vers IBOClient3") + except Exception as e: + raise RuntimeError(f"Impossible de caster vers IBOClient3: {e}") + # 2. Remplissage des Champs OBLIGATOIRES logger.info(f"📝 Création client: {client_data['intitule']}") - # CT_Intitule - OBLIGATOIRE (définir en premier) + # CT_Intitule - OBLIGATOIRE try: client.CT_Intitule = client_data["intitule"] logger.debug(f"✅ CT_Intitule défini: {client_data['intitule']}") @@ -2433,7 +2424,6 @@ class SageConnector: num_prop = client_data.get("num", "") if num_prop: try: - # S'assurer que le numéro est en majuscule (conforme Alpha Majuscule) client.CT_Num = num_prop.upper() logger.debug(f"✅ CT_Num défini: {num_prop.upper()}") except Exception as e: @@ -2564,5 +2554,4 @@ class SageConnector: except: pass - # Le connecteur lève maintenant un RuntimeError clair raise RuntimeError(f"Erreur technique Sage: {error_message}") \ No newline at end of file