fix(sage_connector): improve client creation with better error handling
This commit is contained in:
parent
c48a3f033a
commit
53517136f2
1 changed files with 39 additions and 23 deletions
|
|
@ -2378,31 +2378,38 @@ class SageConnector:
|
|||
def creer_client(self, client_data: Dict) -> Dict:
|
||||
"""
|
||||
Crée un nouveau client dans Sage 100c via l'API COM.
|
||||
✅ CORRECTION : Cast obligatoire après Create()
|
||||
✅ CORRECTION : CT_Type est en lecture seule, défini automatiquement par la factory
|
||||
"""
|
||||
if not self.cial:
|
||||
raise RuntimeError("Connexion Sage non établie")
|
||||
|
||||
try:
|
||||
with self._com_context(), self._lock_com:
|
||||
# 1. Accès à la Factory Client
|
||||
# 1. Accès à la Factory Client (définit automatiquement CT_Type = 0)
|
||||
factory_client = self.cial.CptaApplication.FactoryClient
|
||||
|
||||
# ✅ Create() retourne IBIPersistObject (générique)
|
||||
# Create() retourne IBIPersistObject
|
||||
persist = factory_client.Create()
|
||||
|
||||
if not persist:
|
||||
raise RuntimeError("Factory.Create() a retourné None")
|
||||
|
||||
logger.debug(f"📦 Objet IBIPersistObject créé : {type(persist)}")
|
||||
logger.debug(f"📦 Objet IBIPersistObject créé")
|
||||
|
||||
# ✅ CAST OBLIGATOIRE vers IBOClient3 pour accéder aux propriétés métier
|
||||
# Cast vers IBOClient3
|
||||
try:
|
||||
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}")
|
||||
|
||||
# Vérifier que CT_Type est bien défini automatiquement
|
||||
try:
|
||||
ct_type_auto = getattr(client, "CT_Type", None)
|
||||
logger.debug(f"✅ CT_Type défini automatiquement par factory: {ct_type_auto}")
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ Impossible de lire CT_Type: {e}")
|
||||
|
||||
# 2. Remplissage des Champs OBLIGATOIRES
|
||||
logger.info(f"📝 Création client: {client_data['intitule']}")
|
||||
|
||||
|
|
@ -2413,12 +2420,8 @@ class SageConnector:
|
|||
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_Type - NE PAS DÉFINIR (lecture seule, auto-défini par factory)
|
||||
# La FactoryClient définit automatiquement CT_Type = 0
|
||||
|
||||
# CT_Num (Numéro de compte) - Optionnel si auto-numérotation
|
||||
num_prop = client_data.get("num", "")
|
||||
|
|
@ -2429,7 +2432,7 @@ class SageConnector:
|
|||
except Exception as e:
|
||||
logger.warning(f"⚠️ Impossible de définir CT_Num: {e}")
|
||||
|
||||
# ✅ Compte comptable général
|
||||
# Compte comptable général
|
||||
try:
|
||||
if client_data.get("compte_collectif"):
|
||||
client.CT_CompteG = client_data["compte_collectif"]
|
||||
|
|
@ -2459,7 +2462,7 @@ class SageConnector:
|
|||
|
||||
# 3. CHAMPS OPTIONNELS
|
||||
|
||||
# --- Adresse principale (Accès via sous-objet Adresse) ---
|
||||
# --- Adresse principale ---
|
||||
try:
|
||||
adresse_obj = getattr(client, "Adresse", None)
|
||||
if adresse_obj:
|
||||
|
|
@ -2475,7 +2478,7 @@ class SageConnector:
|
|||
except Exception as e:
|
||||
logger.warning(f"⚠️ Impossible de définir l'adresse: {e}")
|
||||
|
||||
# --- Contact / Télécom (Accès via sous-objet Telecom) ---
|
||||
# --- Contact / Télécom ---
|
||||
try:
|
||||
telecom_obj = getattr(client, "Telecom", None)
|
||||
if telecom_obj:
|
||||
|
|
@ -2502,12 +2505,22 @@ class SageConnector:
|
|||
logger.info("💾 Écriture du client dans Sage...")
|
||||
try:
|
||||
client.Write()
|
||||
logger.debug("✅ Write() réussi")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Échec Write(): {e}")
|
||||
# Récupérer l'erreur Sage détaillée si disponible
|
||||
error_detail = str(e)
|
||||
try:
|
||||
sage_error = self.cial.CptaApplication.LastError
|
||||
if sage_error:
|
||||
error_detail = f"{sage_error.Description} (Code: {sage_error.Number})"
|
||||
except:
|
||||
pass
|
||||
raise RuntimeError(f"Échec Write(): {error_detail}")
|
||||
|
||||
# ✅ IMPORTANT: Relire pour récupérer le numéro auto-généré
|
||||
# 5. Relire pour récupérer le numéro auto-généré
|
||||
try:
|
||||
client.Read()
|
||||
logger.debug("✅ Read() après Write() réussi")
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ Impossible de relire après Write(): {e}")
|
||||
|
||||
|
|
@ -2516,7 +2529,7 @@ class SageConnector:
|
|||
if not num_final:
|
||||
raise RuntimeError("CT_Num vide après Write() - création échouée")
|
||||
|
||||
# Si CT_NumPayeur était vide, le définir maintenant avec le numéro auto-généré
|
||||
# Si CT_NumPayeur était vide, le définir maintenant
|
||||
if not num_prop:
|
||||
try:
|
||||
client.CT_NumPayeur = num_final
|
||||
|
|
@ -2525,15 +2538,16 @@ class SageConnector:
|
|||
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}")
|
||||
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
|
||||
# 6. Forcer le refresh du cache
|
||||
self._refresh_cache_clients()
|
||||
|
||||
return {
|
||||
"numero": num_final,
|
||||
"intitule": client.CT_Intitule,
|
||||
"compte_collectif": getattr(client, "CT_CompteG", ""),
|
||||
"type": getattr(client, "CT_Type", 0), # Retourner le type auto-défini
|
||||
"adresse": client_data.get("adresse"),
|
||||
"ville": client_data.get("ville"),
|
||||
"email": client_data.get("email")
|
||||
|
|
@ -2542,15 +2556,17 @@ class SageConnector:
|
|||
except Exception as e:
|
||||
logger.error(f"❌ Erreur création client: {e}", exc_info=True)
|
||||
|
||||
# Gestion d'erreur remontant l'erreur COM détaillée (si disponible)
|
||||
# Gestion d'erreur avec détails Sage
|
||||
error_message = str(e)
|
||||
if self.cial:
|
||||
try:
|
||||
err = self.cial.LastError
|
||||
err = self.cial.CptaApplication.LastError
|
||||
if err:
|
||||
error_message = f"Erreur Sage: {err.Description}"
|
||||
if "doublon" in err.Description.lower():
|
||||
raise ValueError(f"Ce client ou ce numéro existe déjà. {error_message}")
|
||||
if "doublon" in err.Description.lower() or "existe" in err.Description.lower():
|
||||
raise ValueError(f"Ce client existe déjà dans Sage. {error_message}")
|
||||
except ValueError:
|
||||
raise # Re-lever les ValueError pour différencier erreurs métier vs techniques
|
||||
except:
|
||||
pass
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue