modifier_contact successful
This commit is contained in:
parent
3e617d070a
commit
7f64a2a548
1 changed files with 164 additions and 130 deletions
|
|
@ -6962,7 +6962,7 @@ class SageConnector:
|
||||||
def modifier_contact(self, numero: str, contact_numero: int, updates: Dict) -> Dict:
|
def modifier_contact(self, numero: str, contact_numero: int, updates: Dict) -> Dict:
|
||||||
"""
|
"""
|
||||||
Modifie un contact existant via COM
|
Modifie un contact existant via COM
|
||||||
VERSION CORRIGÉE pour Sage 100
|
VERSION REFACTORISÉE - Utilise FactoryTiersContact
|
||||||
"""
|
"""
|
||||||
if not self.cial:
|
if not self.cial:
|
||||||
raise RuntimeError("Connexion Sage non établie")
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
@ -6973,135 +6973,192 @@ class SageConnector:
|
||||||
logger.info(f"[MODIFICATION CONTACT] CT_No={contact_numero}")
|
logger.info(f"[MODIFICATION CONTACT] CT_No={contact_numero}")
|
||||||
logger.info("=" * 80)
|
logger.info("=" * 80)
|
||||||
|
|
||||||
# Lire le contact existant - CORRECTION ICI
|
# Charger le client
|
||||||
logger.info("[1] Lecture contact existant")
|
logger.info("[1] Chargement du client")
|
||||||
|
factory_client = self.cial.CptaApplication.FactoryClient
|
||||||
|
try:
|
||||||
|
persist_client = factory_client.ReadNumero(numero)
|
||||||
|
if not persist_client:
|
||||||
|
raise ValueError(f"Client {numero} non trouve")
|
||||||
|
|
||||||
|
client_obj = win32com.client.CastTo(persist_client, "IBOClient3")
|
||||||
|
client_obj.Read()
|
||||||
|
logger.info(f" OK Client charge")
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError(f"Client {numero} introuvable: {e}")
|
||||||
|
|
||||||
# Trouver la factory
|
# Charger le contact via FactoryTiersContact
|
||||||
factory_contact = None
|
logger.info("[2] Chargement du contact")
|
||||||
factory_names = [
|
|
||||||
"FactoryContact",
|
|
||||||
"FactoryContactTiers",
|
|
||||||
"FactoryTypeContacts",
|
|
||||||
]
|
|
||||||
|
|
||||||
for factory_name in factory_names:
|
if not hasattr(client_obj, 'FactoryTiersContact'):
|
||||||
try:
|
raise RuntimeError("FactoryTiersContact non trouvee sur le client")
|
||||||
if hasattr(self.cial.CptaApplication, factory_name):
|
|
||||||
factory_contact = getattr(self.cial.CptaApplication, factory_name)
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not factory_contact:
|
factory_contact = client_obj.FactoryTiersContact
|
||||||
raise RuntimeError("Aucune factory de contacts trouvée")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# ReadNumero peut accepter 1 ou 2 paramètres selon la version
|
# Chercher le contact par son CT_No
|
||||||
|
# Il faut lister et trouver celui avec le bon CT_No
|
||||||
|
# ou utiliser une autre méthode de lecture
|
||||||
|
|
||||||
|
# STRATÉGIE : Lister tous les contacts et trouver le bon
|
||||||
|
contacts_collection = None
|
||||||
|
all_contacts = []
|
||||||
|
|
||||||
|
# Essayer de lister via SQL d'abord (plus fiable)
|
||||||
try:
|
try:
|
||||||
persist = factory_contact.ReadNumero(numero, contact_numero)
|
with self._get_sql_connection() as conn:
|
||||||
except TypeError:
|
cursor = conn.cursor()
|
||||||
# Si 2 paramètres ne fonctionnent pas, essayer avec CT_No seulement
|
cursor.execute(
|
||||||
persist = factory_contact.ReadNumero(contact_numero)
|
"SELECT CT_Nom, CT_Prenom FROM F_CONTACTT WHERE CT_Num = ? AND CT_No = ?",
|
||||||
|
[numero, contact_numero]
|
||||||
|
)
|
||||||
|
row = cursor.fetchone()
|
||||||
|
|
||||||
|
if not row:
|
||||||
|
raise ValueError(f"Contact CT_No={contact_numero} non trouve")
|
||||||
|
|
||||||
|
nom_recherche = row.CT_Nom.strip() if row.CT_Nom else ""
|
||||||
|
prenom_recherche = row.CT_Prenom.strip() if row.CT_Prenom else ""
|
||||||
|
|
||||||
|
logger.info(f" Contact trouve en SQL: {prenom_recherche} {nom_recherche}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError(f"Contact introuvable: {e}")
|
||||||
|
|
||||||
|
# Charger via ReadNomPrenom
|
||||||
|
factory_dossier = self.cial.CptaApplication.FactoryDossierContact
|
||||||
|
persist = factory_dossier.ReadNomPrenom(nom_recherche, prenom_recherche)
|
||||||
|
|
||||||
if not persist:
|
if not persist:
|
||||||
raise ValueError(f"Contact CT_No={contact_numero} non trouvé pour client {numero}")
|
raise ValueError(f"Contact non trouvable via ReadNomPrenom")
|
||||||
|
|
||||||
# Essayer de caster
|
|
||||||
contact = None
|
|
||||||
for interface_name in ["IBOContactT3", "IBOContact3", "IBOContactT"]:
|
|
||||||
try:
|
|
||||||
contact = win32com.client.CastTo(persist, interface_name)
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not contact:
|
|
||||||
contact = persist
|
|
||||||
|
|
||||||
|
contact = win32com.client.CastTo(persist, "IBOTiersContact3")
|
||||||
contact.Read()
|
contact.Read()
|
||||||
logger.info(f" ✓ Contact chargé: {getattr(contact, 'CT_Nom', '?')}")
|
logger.info(f" OK Contact charge: {contact.Nom}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError(f"Contact introuvable: {e}")
|
raise ValueError(f"Contact introuvable: {e}")
|
||||||
|
|
||||||
# Appliquer les modifications
|
# Appliquer les modifications
|
||||||
logger.info("[2] Application des modifications")
|
logger.info("[3] Application des modifications")
|
||||||
modifications_appliquees = []
|
modifications_appliquees = []
|
||||||
|
|
||||||
# Identité
|
# Identité
|
||||||
if "civilite" in updates:
|
if "civilite" in updates:
|
||||||
civilite_map = {"M.": 0, "Mme": 1, "Mlle": 2, "Société": 3}
|
civilite_map = {"M.": 0, "Mme": 1, "Mlle": 2, "Societe": 3}
|
||||||
civilite_code = civilite_map.get(updates["civilite"])
|
civilite_code = civilite_map.get(updates["civilite"])
|
||||||
if civilite_code is not None:
|
if civilite_code is not None:
|
||||||
self._try_set_attribute(contact, "CT_Civilite", civilite_code)
|
try:
|
||||||
logger.info(f" CT_Civilite = {civilite_code}")
|
contact.Civilite = civilite_code
|
||||||
modifications_appliquees.append("civilite")
|
logger.info(f" Civilite = {civilite_code}")
|
||||||
|
modifications_appliquees.append("civilite")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
if "nom" in updates:
|
if "nom" in updates:
|
||||||
nom = self._clean_str(updates["nom"], 35)
|
nom = self._clean_str(updates["nom"], 35)
|
||||||
if nom:
|
if nom:
|
||||||
self._try_set_attribute(contact, "CT_Nom", nom)
|
try:
|
||||||
logger.info(f" CT_Nom = {nom}")
|
contact.Nom = nom
|
||||||
modifications_appliquees.append("nom")
|
logger.info(f" Nom = {nom}")
|
||||||
|
modifications_appliquees.append("nom")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
if "prenom" in updates:
|
if "prenom" in updates:
|
||||||
prenom = self._clean_str(updates["prenom"], 35)
|
prenom = self._clean_str(updates["prenom"], 35)
|
||||||
self._try_set_attribute(contact, "CT_Prenom", prenom)
|
try:
|
||||||
logger.info(f" CT_Prenom = {prenom}")
|
contact.Prenom = prenom
|
||||||
modifications_appliquees.append("prenom")
|
logger.info(f" Prenom = {prenom}")
|
||||||
|
modifications_appliquees.append("prenom")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
if "fonction" in updates:
|
if "fonction" in updates:
|
||||||
fonction = self._clean_str(updates["fonction"], 35)
|
fonction = self._clean_str(updates["fonction"], 35)
|
||||||
self._try_set_attribute(contact, "CT_Fonction", fonction)
|
try:
|
||||||
logger.info(f" CT_Fonction = {fonction}")
|
contact.Fonction = fonction
|
||||||
modifications_appliquees.append("fonction")
|
logger.info(f" Fonction = {fonction}")
|
||||||
|
modifications_appliquees.append("fonction")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# Service
|
# Service
|
||||||
if "service_code" in updates:
|
if "service_code" in updates:
|
||||||
service = self._safe_int(updates["service_code"])
|
service = self._safe_int(updates["service_code"])
|
||||||
if service is not None:
|
if service is not None and hasattr(contact, 'ServiceContact'):
|
||||||
self._try_set_attribute(contact, "N_Service", service)
|
try:
|
||||||
logger.info(f" N_Service = {service}")
|
contact.ServiceContact = service
|
||||||
modifications_appliquees.append("service_code")
|
logger.info(f" ServiceContact = {service}")
|
||||||
|
modifications_appliquees.append("service_code")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# Coordonnées
|
# Coordonnées via Telecom
|
||||||
coord_fields = {
|
if hasattr(contact, 'Telecom'):
|
||||||
"telephone": ("CT_Telephone", 21),
|
|
||||||
"portable": ("CT_TelPortable", 21),
|
|
||||||
"telecopie": ("CT_Telecopie", 21),
|
|
||||||
"email": ("CT_EMail", 69),
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, (attr, max_len) in coord_fields.items():
|
|
||||||
if key in updates:
|
|
||||||
value = self._clean_str(updates[key], max_len)
|
|
||||||
self._try_set_attribute(contact, attr, value)
|
|
||||||
logger.info(f" {attr} = {value}")
|
|
||||||
modifications_appliquees.append(key)
|
|
||||||
|
|
||||||
# Réseaux sociaux
|
|
||||||
social_fields = {
|
|
||||||
"facebook": ("CT_Facebook", 69),
|
|
||||||
"linkedin": ("CT_LinkedIn", 69),
|
|
||||||
"skype": ("CT_Skype", 69),
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, (attr, max_len) in social_fields.items():
|
|
||||||
if key in updates:
|
|
||||||
value = self._clean_str(updates[key], max_len)
|
|
||||||
self._try_set_attribute(contact, attr, value)
|
|
||||||
logger.info(f" {attr} = {value}")
|
|
||||||
modifications_appliquees.append(key)
|
|
||||||
|
|
||||||
# Enregistrement du contact
|
|
||||||
logger.info("[3] WRITE CONTACT")
|
|
||||||
try:
|
|
||||||
contact.Write()
|
|
||||||
try:
|
try:
|
||||||
contact.Read()
|
telecom = contact.Telecom
|
||||||
|
|
||||||
|
if "telephone" in updates:
|
||||||
|
telephone = self._clean_str(updates["telephone"], 21)
|
||||||
|
if self._try_set_attribute(telecom, "Telephone", telephone):
|
||||||
|
logger.info(f" Telephone = {telephone}")
|
||||||
|
modifications_appliquees.append("telephone")
|
||||||
|
|
||||||
|
if "portable" in updates:
|
||||||
|
portable = self._clean_str(updates["portable"], 21)
|
||||||
|
if self._try_set_attribute(telecom, "Portable", portable):
|
||||||
|
logger.info(f" Portable = {portable}")
|
||||||
|
modifications_appliquees.append("portable")
|
||||||
|
|
||||||
|
if "email" in updates:
|
||||||
|
email = self._clean_str(updates["email"], 69)
|
||||||
|
if self._try_set_attribute(telecom, "EMail", email):
|
||||||
|
logger.info(f" EMail = {email}")
|
||||||
|
modifications_appliquees.append("email")
|
||||||
|
|
||||||
|
if "telecopie" in updates:
|
||||||
|
fax = self._clean_str(updates["telecopie"], 21)
|
||||||
|
if self._try_set_attribute(telecom, "Telecopie", fax):
|
||||||
|
logger.info(f" Telecopie = {fax}")
|
||||||
|
modifications_appliquees.append("telecopie")
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
logger.info(" ✓ Write() réussi")
|
|
||||||
|
# Réseaux sociaux
|
||||||
|
if "facebook" in updates:
|
||||||
|
facebook = self._clean_str(updates["facebook"], 69)
|
||||||
|
try:
|
||||||
|
contact.Facebook = facebook
|
||||||
|
logger.info(f" Facebook = {facebook}")
|
||||||
|
modifications_appliquees.append("facebook")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if "linkedin" in updates:
|
||||||
|
linkedin = self._clean_str(updates["linkedin"], 69)
|
||||||
|
try:
|
||||||
|
contact.LinkedIn = linkedin
|
||||||
|
logger.info(f" LinkedIn = {linkedin}")
|
||||||
|
modifications_appliquees.append("linkedin")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if "skype" in updates:
|
||||||
|
skype = self._clean_str(updates["skype"], 69)
|
||||||
|
try:
|
||||||
|
contact.Skype = skype
|
||||||
|
logger.info(f" Skype = {skype}")
|
||||||
|
modifications_appliquees.append("skype")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Enregistrement du contact
|
||||||
|
logger.info("[4] Enregistrement")
|
||||||
|
try:
|
||||||
|
contact.Write()
|
||||||
|
contact.Read()
|
||||||
|
logger.info(" OK Write() reussi")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_detail = str(e)
|
error_detail = str(e)
|
||||||
try:
|
try:
|
||||||
|
|
@ -7110,67 +7167,44 @@ class SageConnector:
|
||||||
error_detail = f"{sage_error.Description} (Code: {sage_error.Number})"
|
error_detail = f"{sage_error.Description} (Code: {sage_error.Number})"
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
logger.error(f" ✗ Erreur Write: {error_detail}")
|
logger.error(f" ERROR Write: {error_detail}")
|
||||||
raise RuntimeError(f"Échec modification contact: {error_detail}")
|
raise RuntimeError(f"Echec modification contact: {error_detail}")
|
||||||
|
|
||||||
logger.info(f" Modifications appliquées: {', '.join(modifications_appliquees)}")
|
logger.info(f" Modifications appliquees: {', '.join(modifications_appliquees)}")
|
||||||
|
|
||||||
# Gestion du contact par défaut
|
# Gestion du contact par défaut
|
||||||
est_defaut_demande = updates.get("est_defaut")
|
est_defaut_demande = updates.get("est_defaut")
|
||||||
est_actuellement_defaut = False
|
est_actuellement_defaut = False
|
||||||
|
|
||||||
if est_defaut_demande is not None and est_defaut_demande:
|
if est_defaut_demande is not None and est_defaut_demande:
|
||||||
logger.info("[4] Gestion contact par défaut")
|
logger.info("[5] Gestion contact par defaut")
|
||||||
try:
|
try:
|
||||||
# Construire le nom complet
|
nom_complet = f"{contact.Prenom} {contact.Nom}".strip() if contact.Prenom else contact.Nom
|
||||||
nom_final = getattr(contact, "CT_Nom", "")
|
|
||||||
prenom_final = getattr(contact, "CT_Prenom", "")
|
|
||||||
nom_complet = f"{prenom_final} {nom_final}".strip() if prenom_final else nom_final
|
|
||||||
|
|
||||||
# Charger le client
|
|
||||||
factory_client = self.cial.CptaApplication.FactoryClient
|
|
||||||
persist_client = factory_client.ReadNumero(numero)
|
persist_client = factory_client.ReadNumero(numero)
|
||||||
client_obj = win32com.client.CastTo(persist_client, "IBOClient3")
|
client_obj = win32com.client.CastTo(persist_client, "IBOClient3")
|
||||||
client_obj.Read()
|
client_obj.Read()
|
||||||
|
|
||||||
# Mettre à jour CT_Contact
|
|
||||||
ancien_contact = getattr(client_obj, "CT_Contact", "")
|
|
||||||
client_obj.CT_Contact = nom_complet
|
client_obj.CT_Contact = nom_complet
|
||||||
logger.info(f" CT_Contact: '{ancien_contact}' → '{nom_complet}'")
|
logger.info(f" CT_Contact = '{nom_complet}'")
|
||||||
|
|
||||||
# Essayer CT_NoContact si disponible
|
if hasattr(client_obj, 'CT_NoContact'):
|
||||||
if self._try_set_attribute(client_obj, "CT_NoContact", contact_numero):
|
try:
|
||||||
logger.info(f" CT_NoContact = {contact_numero}")
|
client_obj.CT_NoContact = contact_numero
|
||||||
|
logger.info(f" CT_NoContact = {contact_numero}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# Enregistrer le client
|
|
||||||
client_obj.Write()
|
client_obj.Write()
|
||||||
client_obj.Read()
|
client_obj.Read()
|
||||||
logger.info(" ✓ Contact défini comme par défaut")
|
logger.info(" OK Contact par defaut defini")
|
||||||
est_actuellement_defaut = True
|
est_actuellement_defaut = True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f" ⚠ Échec définition par défaut: {e}")
|
logger.warning(f" WARN Echec: {e}")
|
||||||
else:
|
|
||||||
# Vérifier si c'est déjà le contact par défaut
|
|
||||||
try:
|
|
||||||
factory_client = self.cial.CptaApplication.FactoryClient
|
|
||||||
persist_client = factory_client.ReadNumero(numero)
|
|
||||||
client_obj = win32com.client.CastTo(persist_client, "IBOClient3")
|
|
||||||
client_obj.Read()
|
|
||||||
|
|
||||||
ct_contact = getattr(client_obj, "CT_Contact", "")
|
|
||||||
nom_final = getattr(contact, "CT_Nom", "")
|
|
||||||
prenom_final = getattr(contact, "CT_Prenom", "")
|
|
||||||
nom_complet = f"{prenom_final} {nom_final}".strip() if prenom_final else nom_final
|
|
||||||
|
|
||||||
est_actuellement_defaut = (ct_contact == nom_complet)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
logger.info("=" * 80)
|
logger.info("=" * 80)
|
||||||
logger.info(f"[SUCCÈS] Contact modifié: CT_No={contact_numero}")
|
logger.info(f"[SUCCES] Contact modifie: CT_No={contact_numero}")
|
||||||
if est_actuellement_defaut:
|
|
||||||
logger.info(f" Contact par défaut")
|
|
||||||
logger.info("=" * 80)
|
logger.info("=" * 80)
|
||||||
|
|
||||||
contact_dict = self._contact_to_dict(contact)
|
contact_dict = self._contact_to_dict(contact)
|
||||||
|
|
@ -7184,7 +7218,7 @@ class SageConnector:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[ERREUR] {e}", exc_info=True)
|
logger.error(f"[ERREUR] {e}", exc_info=True)
|
||||||
raise RuntimeError(f"Erreur technique: {e}")
|
raise RuntimeError(f"Erreur technique: {e}")
|
||||||
|
|
||||||
|
|
||||||
def definir_contact_defaut(self, numero: str, contact_numero: int) -> Dict:
|
def definir_contact_defaut(self, numero: str, contact_numero: int) -> Dict:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue