Truncating too long fields

This commit is contained in:
Fanilo-Nantenaina 2025-12-06 08:01:50 +03:00
parent 53517136f2
commit 9d4f620bdc

View file

@ -2378,69 +2378,54 @@ class SageConnector:
def creer_client(self, client_data: Dict) -> Dict: def creer_client(self, client_data: Dict) -> Dict:
""" """
Crée un nouveau client dans Sage 100c via l'API COM. Crée un nouveau client dans Sage 100c via l'API COM.
CORRECTION : CT_Type est en lecture seule, défini automatiquement par la factory Gestion stricte des longueurs de champs
""" """
if not self.cial: if not self.cial:
raise RuntimeError("Connexion Sage non établie") raise RuntimeError("Connexion Sage non établie")
try: try:
with self._com_context(), self._lock_com: with self._com_context(), self._lock_com:
# 1. Accès à la Factory Client (définit automatiquement CT_Type = 0) # 1. Factory Client
factory_client = self.cial.CptaApplication.FactoryClient factory_client = self.cial.CptaApplication.FactoryClient
# Create() retourne IBIPersistObject
persist = factory_client.Create() persist = factory_client.Create()
if not persist: if not persist:
raise RuntimeError("Factory.Create() a retourné None") raise RuntimeError("Factory.Create() a retourné None")
logger.debug(f"📦 Objet IBIPersistObject créé")
# Cast vers IBOClient3 # Cast vers IBOClient3
try:
client = win32com.client.CastTo(persist, "IBOClient3") client = win32com.client.CastTo(persist, "IBOClient3")
logger.debug(f"✅ Cast réussi vers 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 # 2. Remplissage avec VALIDATION DES LONGUEURS
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']}") logger.info(f"📝 Création client: {client_data['intitule']}")
# CT_Intitule - OBLIGATOIRE # ===== CT_Intitule - OBLIGATOIRE (max 69 car) =====
intitule = client_data["intitule"][:69] # Tronquer si nécessaire
try: try:
client.CT_Intitule = client_data["intitule"] client.CT_Intitule = intitule
logger.debug(f"✅ CT_Intitule défini: {client_data['intitule']}") logger.debug(f"✅ CT_Intitule: {intitule}")
except Exception as e: except Exception as e:
raise RuntimeError(f"Impossible de définir CT_Intitule: {e}") raise RuntimeError(f"Impossible de définir CT_Intitule: {e}")
# ❌ CT_Type - NE PAS DÉFINIR (lecture seule, auto-défini par factory) # ===== CT_Num - Optionnel (max 17 car, ALPHA MAJ) =====
# 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", "") num_prop = client_data.get("num", "")
if num_prop: if num_prop:
num_prop = num_prop.upper()[:17] # Majuscules + tronquer
try: try:
client.CT_Num = num_prop.upper() client.CT_Num = num_prop
logger.debug(f"✅ CT_Num défini: {num_prop.upper()}") logger.debug(f"✅ CT_Num: {num_prop}")
except Exception as e: except Exception as e:
logger.warning(f"⚠️ Impossible de définir CT_Num: {e}") logger.warning(f"⚠️ CT_Num non défini: {e}")
# Compte comptable général # ===== CT_CompteG - Compte collectif (max 13 car) =====
compte = client_data.get("compte_collectif", "411000")[:13]
try: try:
if client_data.get("compte_collectif"): client.CT_CompteG = compte
client.CT_CompteG = client_data["compte_collectif"] logger.debug(f"✅ CT_CompteG: {compte}")
logger.debug(f"✅ CT_CompteG: {client_data['compte_collectif']}")
except Exception as e: except Exception as e:
logger.warning(f"⚠️ Impossible de définir CT_CompteG: {e}") logger.warning(f"⚠️ CT_CompteG non défini: {e}")
# Initialisation des champs catégoriels (si disponibles) # ===== Catégories (valeurs numériques, pas de pb de longueur) =====
try: try:
client.N_CatTarif = 1 client.N_CatTarif = 1
client.N_CatCompta = 1 client.N_CatCompta = 1
@ -2450,84 +2435,104 @@ class SageConnector:
client.N_Risque = 1 client.N_Risque = 1
logger.debug("✅ Catégories initialisées") logger.debug("✅ Catégories initialisées")
except Exception as e: except Exception as e:
logger.warning(f"⚠️ Catégories non disponibles: {e}") logger.warning(f"⚠️ Catégories: {e}")
# CT_NumPayeur - Géré après Write() si auto-numérotation # ===== CT_NumPayeur (max 17 car) =====
if num_prop: if num_prop:
try: try:
client.CT_NumPayeur = num_prop.upper() client.CT_NumPayeur = num_prop # Déjà tronqué plus haut
logger.debug(f"✅ CT_NumPayeur: {num_prop.upper()}") logger.debug(f"✅ CT_NumPayeur: {num_prop}")
except Exception as e: except Exception as e:
logger.warning(f"⚠️ Impossible de définir CT_NumPayeur: {e}") logger.warning(f"⚠️ CT_NumPayeur: {e}")
# 3. CHAMPS OPTIONNELS # ===== ADRESSE (tous max 35 car sauf code postal = 9) =====
# --- Adresse principale ---
try: try:
adresse_obj = getattr(client, "Adresse", None) adresse_obj = getattr(client, "Adresse", None)
if adresse_obj: if adresse_obj:
if client_data.get("adresse"): if client_data.get("adresse"):
adresse_obj.Adresse = client_data["adresse"] adresse_obj.Adresse = client_data["adresse"][:35]
if client_data.get("code_postal"): if client_data.get("code_postal"):
adresse_obj.CodePostal = client_data["code_postal"] adresse_obj.CodePostal = client_data["code_postal"][:9]
if client_data.get("ville"): if client_data.get("ville"):
adresse_obj.Ville = client_data["ville"] adresse_obj.Ville = client_data["ville"][:35]
if client_data.get("pays"): if client_data.get("pays"):
adresse_obj.Pays = client_data["pays"] adresse_obj.Pays = client_data["pays"][:35]
logger.debug("✅ Adresse définie") logger.debug("✅ Adresse définie")
except Exception as e: except Exception as e:
logger.warning(f"⚠️ Impossible de définir l'adresse: {e}") logger.warning(f"⚠️ Adresse: {e}")
# --- Contact / Télécom --- # ===== TELECOM (Téléphone max 21, Email max 69) =====
try: try:
telecom_obj = getattr(client, "Telecom", None) telecom_obj = getattr(client, "Telecom", None)
if telecom_obj: if telecom_obj:
if client_data.get("telephone"): if client_data.get("telephone"):
telecom_obj.Telephone = client_data["telephone"] telecom_obj.Telephone = client_data["telephone"][:21]
if client_data.get("email"): if client_data.get("email"):
telecom_obj.EMail = client_data["email"] telecom_obj.EMail = client_data["email"][:69]
logger.debug("✅ Télécom défini") logger.debug("✅ Télécom défini")
except Exception as e: except Exception as e:
logger.warning(f"⚠️ Impossible de définir les télécoms: {e}") logger.warning(f"⚠️ Télécom: {e}")
# --- Identifiants --- # ===== IDENTIFIANTS (SIRET max 14, TVA max 25) =====
try: try:
if client_data.get("siret"): if client_data.get("siret"):
client.CT_Siret = client_data["siret"] client.CT_Siret = client_data["siret"][:14]
logger.debug(f"✅ SIRET: {client_data['siret']}") logger.debug(f"✅ SIRET: {client_data['siret'][:14]}")
if client_data.get("tva_intra"): if client_data.get("tva_intra"):
client.CT_Identifiant = client_data["tva_intra"] client.CT_Identifiant = client_data["tva_intra"][:25]
logger.debug(f"✅ TVA: {client_data['tva_intra']}") logger.debug(f"✅ TVA: {client_data['tva_intra'][:25]}")
except Exception as e: except Exception as e:
logger.warning(f"⚠️ Impossible de définir les identifiants: {e}") logger.warning(f"⚠️ Identifiants: {e}")
# 3. DIAGNOSTIC PRÉ-WRITE (pour debug)
logger.info("🔍 === DIAGNOSTIC PRÉ-WRITE ===")
try:
logger.info(f" CT_Intitule: '{client.CT_Intitule}' (len={len(client.CT_Intitule)})")
logger.info(f" CT_Num: '{getattr(client, 'CT_Num', 'AUTO')}'")
logger.info(f" CT_CompteG: '{getattr(client, 'CT_CompteG', 'N/A')}'")
logger.info(f" CT_Type: {getattr(client, 'CT_Type', '?')}")
except Exception as e:
logger.warning(f"⚠️ Erreur diagnostic: {e}")
# 4. Écriture en base # 4. Écriture en base
logger.info("💾 Écriture du client dans Sage...") logger.info("💾 Écriture du client dans Sage...")
try: try:
client.Write() client.Write()
logger.debug("✅ Write() réussi") logger.info("✅ Write() réussi !")
except Exception as e: except Exception as e:
# Récupérer l'erreur Sage détaillée si disponible # Récupérer erreur Sage détaillée
error_detail = str(e) error_detail = str(e)
try: try:
sage_error = self.cial.CptaApplication.LastError sage_error = self.cial.CptaApplication.LastError
if sage_error: if sage_error:
error_detail = f"{sage_error.Description} (Code: {sage_error.Number})" error_detail = f"{sage_error.Description} (Code: {sage_error.Number})"
logger.error(f"❌ Erreur Sage détaillée: {error_detail}")
except: except:
pass pass
# Log des valeurs pour debug
logger.error("❌ ÉCHEC Write() - Dump des champs définis:")
for attr in dir(client):
if attr.startswith("CT_") or attr.startswith("N_"):
try:
val = getattr(client, attr, None)
if val and not callable(val):
logger.error(f" {attr}: {val} (len={len(str(val))})")
except:
pass
raise RuntimeError(f"Échec Write(): {error_detail}") raise RuntimeError(f"Échec Write(): {error_detail}")
# 5. 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: try:
client.Read() client.Read()
logger.debug("✅ Read() après Write() réussi")
except Exception as e: except Exception as e:
logger.warning(f"⚠️ Impossible de relire après Write(): {e}") logger.warning(f"⚠️ Impossible de relire: {e}")
num_final = getattr(client, "CT_Num", "") num_final = getattr(client, "CT_Num", "")
if not num_final: if not num_final:
raise RuntimeError("CT_Num vide après Write() - création échouée") raise RuntimeError("CT_Num vide après Write()")
# Si CT_NumPayeur était vide, le définir maintenant # Si CT_NumPayeur était vide, le définir maintenant
if not num_prop: if not num_prop:
@ -2536,18 +2541,18 @@ class SageConnector:
client.Write() client.Write()
logger.debug(f"✅ CT_NumPayeur auto-défini: {num_final}") logger.debug(f"✅ CT_NumPayeur auto-défini: {num_final}")
except Exception as e: except Exception as e:
logger.warning(f"⚠️ Impossible de définir CT_NumPayeur après création: {e}") logger.warning(f"⚠️ CT_NumPayeur: {e}")
logger.info(f"✅✅✅ Client créé avec succès: {num_final} - {client.CT_Intitule} ✅✅✅") logger.info(f"✅✅✅ CLIENT CRÉÉ: {num_final} - {client.CT_Intitule} ✅✅✅")
# 6. Forcer le refresh du cache # 6. Refresh cache
self._refresh_cache_clients() self._refresh_cache_clients()
return { return {
"numero": num_final, "numero": num_final,
"intitule": client.CT_Intitule, "intitule": client.CT_Intitule,
"compte_collectif": getattr(client, "CT_CompteG", ""), "compte_collectif": getattr(client, "CT_CompteG", ""),
"type": getattr(client, "CT_Type", 0), # Retourner le type auto-défini "type": getattr(client, "CT_Type", 0),
"adresse": client_data.get("adresse"), "adresse": client_data.get("adresse"),
"ville": client_data.get("ville"), "ville": client_data.get("ville"),
"email": client_data.get("email") "email": client_data.get("email")
@ -2556,7 +2561,6 @@ class SageConnector:
except Exception as e: except Exception as e:
logger.error(f"❌ Erreur création client: {e}", exc_info=True) logger.error(f"❌ Erreur création client: {e}", exc_info=True)
# Gestion d'erreur avec détails Sage
error_message = str(e) error_message = str(e)
if self.cial: if self.cial:
try: try:
@ -2564,9 +2568,9 @@ class SageConnector:
if err: if err:
error_message = f"Erreur Sage: {err.Description}" error_message = f"Erreur Sage: {err.Description}"
if "doublon" in err.Description.lower() or "existe" in err.Description.lower(): if "doublon" in err.Description.lower() or "existe" in err.Description.lower():
raise ValueError(f"Ce client existe déjà dans Sage. {error_message}") raise ValueError(f"Ce client existe déjà. {error_message}")
except ValueError: except ValueError:
raise # Re-lever les ValueError pour différencier erreurs métier vs techniques raise
except: except:
pass pass