refactor(sage_connector): improve client creation with better error handling and logging

This commit is contained in:
Fanilo-Nantenaina 2025-12-05 20:39:56 +03:00
parent 914ea61243
commit 49fdc8425b

View file

@ -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 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}")
# 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
# 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()