diff --git a/sage_connector.py b/sage_connector.py index d8759d0..db7777f 100644 --- a/sage_connector.py +++ b/sage_connector.py @@ -2388,85 +2388,154 @@ class SageConnector: # 1. Accès à la Factory Client (CptaApplication si Tiers) factory_client = self.cial.CptaApplication.FactoryClient - # ✅ CORRECTION CRITIQUE: Utiliser Create() au lieu de CreateNew() - persist_client = factory_client.Create() + # ✅ Utiliser Create() qui retourne directement l'objet utilisable + client = factory_client.Create() - if not persist_client: + if not client: raise RuntimeError("Factory.Create() a retourné None") - # Cast en IBOClient3 pour accéder aux propriétés - client = win32com.client.CastTo(persist_client, "IBOClient3") + logger.debug(f"📦 Objet créé, type: {type(client)}") + + # ✅ 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 + 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) + logger.info(f"📝 Création client: {client_data['intitule']}") + + # CT_Intitule - OBLIGATOIRE (définir en premier) + try: + client.CT_Intitule = client_data["intitule"] + logger.debug(f"✅ CT_Intitule défini: {client_data['intitule']}") + except Exception as e: + raise RuntimeError(f"Impossible de définir CT_Intitule: {e}") + + # CT_Type - OBLIGATOIRE + try: + client.CT_Type = 0 # 0 = Client + logger.debug("✅ CT_Type = 0 (Client)") + except Exception as e: + raise RuntimeError(f"Impossible de définir CT_Type: {e}") + # CT_Num (Numéro de compte) - Optionnel si auto-numérotation num_prop = client_data.get("num", "") if num_prop: - # S'assurer que le numéro est en majuscule (conforme Alpha Majuscule) - client.CT_Num = num_prop.upper() + 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: + logger.warning(f"⚠️ Impossible de définir CT_Num: {e}") - # CT_Intitule - OBLIGATOIRE - client.CT_Intitule = client_data["intitule"] - client.CT_Type = 0 # 0 = Client + # ✅ Compte comptable général + try: + if client_data.get("compte_collectif"): + client.CT_CompteG = client_data["compte_collectif"] + logger.debug(f"✅ CT_CompteG: {client_data['compte_collectif']}") + except Exception as e: + logger.warning(f"⚠️ Impossible de définir CT_CompteG: {e}") - # ✅ CORRECTION : Utiliser CT_CompteG (mappé à CG_NumPrinc) - if client_data.get("compte_collectif"): - client.CT_CompteG = client_data["compte_collectif"] - - # Initialisation des champs obligatoires (N_...) - client.N_CatTarif = 1 - client.N_CatCompta = 1 - client.N_Period = 1 - client.N_Expedition = 1 - client.N_Condition = 1 - client.N_Risque = 1 + # Initialisation des champs catégoriels (si disponibles) + try: + client.N_CatTarif = 1 + client.N_CatCompta = 1 + client.N_Period = 1 + client.N_Expedition = 1 + client.N_Condition = 1 + client.N_Risque = 1 + logger.debug("✅ Catégories initialisées") + except Exception as e: + logger.warning(f"⚠️ Catégories non disponibles: {e}") - # CT_NumPayeur doit être défini - Si pas de num, sera auto-généré + # CT_NumPayeur - Géré après Write() si auto-numérotation if num_prop: - client.CT_NumPayeur = num_prop.upper() + try: + client.CT_NumPayeur = num_prop.upper() + logger.debug(f"✅ CT_NumPayeur: {num_prop.upper()}") + except Exception as e: + logger.warning(f"⚠️ Impossible de définir CT_NumPayeur: {e}") # 3. CHAMPS OPTIONNELS # --- Adresse principale (Accès via sous-objet Adresse) --- try: - if client_data.get("adresse"): - client.Adresse.Adresse = client_data["adresse"] - if client_data.get("code_postal"): - client.Adresse.CodePostal = client_data["code_postal"] - if client_data.get("ville"): - client.Adresse.Ville = client_data["ville"] - if client_data.get("pays"): - client.Adresse.Pays = client_data["pays"] + adresse_obj = getattr(client, "Adresse", None) + if adresse_obj: + if client_data.get("adresse"): + adresse_obj.Adresse = client_data["adresse"] + if client_data.get("code_postal"): + adresse_obj.CodePostal = client_data["code_postal"] + if client_data.get("ville"): + adresse_obj.Ville = client_data["ville"] + if client_data.get("pays"): + adresse_obj.Pays = client_data["pays"] + logger.debug("✅ Adresse définie") except Exception as e: - logger.warning(f"Impossible de définir l'adresse: {e}") + logger.warning(f"⚠️ Impossible de définir l'adresse: {e}") # --- Contact / Télécom (Accès via sous-objet Telecom) --- try: - if client_data.get("telephone"): - client.Telecom.Telephone = client_data["telephone"] - if client_data.get("email"): - client.Telecom.EMail = client_data["email"] + telecom_obj = getattr(client, "Telecom", None) + if telecom_obj: + if client_data.get("telephone"): + telecom_obj.Telephone = client_data["telephone"] + if client_data.get("email"): + telecom_obj.EMail = client_data["email"] + logger.debug("✅ Télécom défini") except Exception as e: - logger.warning(f"Impossible de définir les télécoms: {e}") + logger.warning(f"⚠️ Impossible de définir les télécoms: {e}") # --- Identifiants --- - if client_data.get("siret"): - client.CT_Siret = client_data["siret"] - if client_data.get("tva_intra"): - client.CT_Identifiant = client_data["tva_intra"] + try: + if client_data.get("siret"): + client.CT_Siret = client_data["siret"] + logger.debug(f"✅ SIRET: {client_data['siret']}") + if client_data.get("tva_intra"): + client.CT_Identifiant = client_data["tva_intra"] + logger.debug(f"✅ TVA: {client_data['tva_intra']}") + except Exception as e: + logger.warning(f"⚠️ Impossible de définir les identifiants: {e}") # 4. Écriture en base - client.Write() + logger.info("💾 Écriture du client dans Sage...") + try: + client.Write() + except Exception as e: + raise RuntimeError(f"Échec Write(): {e}") # ✅ IMPORTANT: Relire pour récupérer le numéro auto-généré - client.Read() + try: + client.Read() + except Exception as e: + logger.warning(f"⚠️ Impossible de relire après Write(): {e}") - num_final = client.CT_Num + num_final = getattr(client, "CT_Num", "") if not num_final: raise RuntimeError("CT_Num vide après Write() - création échouée") - logger.info(f"✅ Client créé: {num_final} - {client.CT_Intitule}") + # Si CT_NumPayeur était vide, le définir maintenant avec le numéro auto-généré + if not num_prop: + try: + client.CT_NumPayeur = num_final + client.Write() + logger.debug(f"✅ CT_NumPayeur auto-défini: {num_final}") + except Exception as e: + logger.warning(f"⚠️ Impossible de définir CT_NumPayeur après création: {e}") + + logger.info(f"✅ Client créé avec succès: {num_final} - {client.CT_Intitule}") # ✅ Forcer le refresh du cache pour que le nouveau client soit visible self._refresh_cache_clients()