Added better handling for collaborator
This commit is contained in:
parent
69114ba0c3
commit
97a2bc01f0
1 changed files with 350 additions and 262 deletions
|
|
@ -7390,310 +7390,398 @@ class SageConnector:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def creer_collaborateur(self, data: dict) -> dict:
|
def creer_collaborateur(self, data: dict) -> dict:
|
||||||
"""Crée un nouveau collaborateur via COM Sage"""
|
"""Crée un nouveau collaborateur via COM Sage (BOI)"""
|
||||||
if not self.cial:
|
if not self.cial:
|
||||||
raise RuntimeError("Connexion Sage non établie")
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
logger.info(
|
# Validation préalable
|
||||||
f"📝 Début création collaborateur: {data.get('nom')} {data.get('prenom', '')}"
|
if not data.get("nom"):
|
||||||
)
|
raise ValueError("Le champ 'nom' est obligatoire")
|
||||||
|
|
||||||
|
nom_upper = str(data["nom"]).upper().strip()[:35]
|
||||||
|
prenom = str(data.get("prenom", "")).strip()[:35] if data.get("prenom") else ""
|
||||||
|
|
||||||
|
logger.info(f"\n{'=' * 70}")
|
||||||
|
logger.info(f"📝 CRÉATION COLLABORATEUR: {nom_upper} {prenom}")
|
||||||
|
logger.info(f"{'=' * 70}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self._com_context(), self._lock_com:
|
with self._com_context(), self._lock_com:
|
||||||
transaction_active = False
|
# ===== VÉRIFICATION DOUBLON VIA SQL =====
|
||||||
|
logger.info("🔍 Vérification doublon...")
|
||||||
try:
|
with self._get_sql_connection() as conn:
|
||||||
# Démarrage transaction
|
cursor = conn.cursor()
|
||||||
try:
|
cursor.execute(
|
||||||
self.cial.CptaApplication.BeginTrans()
|
"SELECT CO_No FROM F_COLLABORATEUR WHERE CO_Nom = ? AND CO_Prenom = ?",
|
||||||
transaction_active = True
|
(nom_upper, prenom),
|
||||||
logger.debug("✓ Transaction Sage démarrée")
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"BeginTrans échoué (non critique): {e}")
|
|
||||||
|
|
||||||
# ===== FACTORY COLLABORATEUR =====
|
|
||||||
factory_collab = self.cial.FactoryCollaborateur
|
|
||||||
persist_collab = factory_collab.Create()
|
|
||||||
|
|
||||||
# Cast vers l'interface IBOCollaborateur3
|
|
||||||
try:
|
|
||||||
collab_obj = win32com.client.CastTo(
|
|
||||||
persist_collab, "IBOCollaborateur3"
|
|
||||||
)
|
)
|
||||||
except Exception:
|
existing = cursor.fetchone()
|
||||||
# Fallback si IBOCollaborateur3 n'existe pas
|
if existing:
|
||||||
collab_obj = win32com.client.CastTo(
|
raise ValueError(
|
||||||
persist_collab, "IBOCollaborateur"
|
f"Le collaborateur '{nom_upper} {prenom}' existe déjà (N°{existing[0]})"
|
||||||
)
|
)
|
||||||
|
logger.info("✓ Pas de doublon")
|
||||||
|
|
||||||
logger.info("✓ Objet collaborateur créé")
|
# ===== FACTORY + CREATE =====
|
||||||
|
|
||||||
# ===== MAPPING ET AFFECTATION CHAMPS =====
|
|
||||||
mapping = {
|
|
||||||
"nom": "CO_Nom",
|
|
||||||
"prenom": "CO_Prenom",
|
|
||||||
"fonction": "CO_Fonction",
|
|
||||||
"adresse": "CO_Adresse",
|
|
||||||
"complement": "CO_Complement",
|
|
||||||
"code_postal": "CO_CodePostal",
|
|
||||||
"ville": "CO_Ville",
|
|
||||||
"region": "CO_CodeRegion",
|
|
||||||
"pays": "CO_Pays",
|
|
||||||
"service": "CO_Service",
|
|
||||||
"telephone": "CO_Telephone",
|
|
||||||
"telecopie": "CO_Telecopie",
|
|
||||||
"email": "CO_EMail",
|
|
||||||
"tel_portable": "CO_TelPortable",
|
|
||||||
"matricule": "CO_Matricule",
|
|
||||||
"facebook": "CO_Facebook",
|
|
||||||
"linkedin": "CO_LinkedIn",
|
|
||||||
"skype": "CO_Skype",
|
|
||||||
"chef_ventes_numero": "CO_NoChefVentes",
|
|
||||||
}
|
|
||||||
|
|
||||||
# Champs texte
|
|
||||||
for py_field, sage_field in mapping.items():
|
|
||||||
if py_field in data and data[py_field] is not None:
|
|
||||||
try:
|
try:
|
||||||
setattr(collab_obj, sage_field, str(data[py_field]))
|
factory = self.cial.FactoryCollaborateur
|
||||||
logger.debug(f" ✓ {sage_field}: {data[py_field]}")
|
except AttributeError:
|
||||||
except Exception as e:
|
factory = self.cial.CptaApplication.FactoryCollaborateur
|
||||||
logger.warning(f" ⚠ {sage_field} non défini: {e}")
|
|
||||||
|
|
||||||
# ===== CHAMPS BOOLÉENS =====
|
persist = factory.Create()
|
||||||
bool_mapping = {
|
|
||||||
"est_vendeur": "CO_Vendeur",
|
|
||||||
"est_caissier": "CO_Caissier",
|
|
||||||
"est_acheteur": "CO_Acheteur",
|
|
||||||
"est_chef_ventes": "CO_ChefVentes",
|
|
||||||
}
|
|
||||||
|
|
||||||
for py_field, sage_field in bool_mapping.items():
|
# Cast vers interface
|
||||||
if py_field in data:
|
collab = None
|
||||||
|
for iface in [
|
||||||
|
"IBOCollaborateur3",
|
||||||
|
"IBOCollaborateur2",
|
||||||
|
"IBOCollaborateur",
|
||||||
|
]:
|
||||||
try:
|
try:
|
||||||
valeur = 1 if data[py_field] else 0
|
collab = win32com.client.CastTo(persist, iface)
|
||||||
setattr(collab_obj, sage_field, valeur)
|
logger.info(f"✓ Cast vers {iface}")
|
||||||
logger.debug(f" ✓ {sage_field}: {valeur}")
|
break
|
||||||
except Exception as e:
|
except:
|
||||||
logger.warning(f" ⚠ {sage_field} non défini: {e}")
|
pass
|
||||||
|
if not collab:
|
||||||
|
collab = persist
|
||||||
|
|
||||||
# ===== CO_SOMMEIL (inversé: est_actif → 0=actif, 1=inactif) =====
|
# ===== SETDEFAULT =====
|
||||||
if "est_actif" in data:
|
|
||||||
try:
|
try:
|
||||||
valeur_sommeil = 0 if data["est_actif"] else 1
|
collab.SetDefault()
|
||||||
collab_obj.CO_Sommeil = valeur_sommeil
|
logger.info("✓ SetDefault()")
|
||||||
logger.debug(
|
|
||||||
f" ✓ CO_Sommeil: {valeur_sommeil} (actif={data['est_actif']})"
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f" ⚠ CO_Sommeil non défini: {e}")
|
logger.warning(f"SetDefault() ignoré: {e}")
|
||||||
|
|
||||||
|
# ===== HELPER =====
|
||||||
|
def safe_set(obj, attr, value, max_len=None):
|
||||||
|
"""Affecte une valeur de manière sécurisée"""
|
||||||
|
if value is None or value == "":
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
val = str(value)
|
||||||
|
if max_len:
|
||||||
|
val = val[:max_len]
|
||||||
|
setattr(obj, attr, val)
|
||||||
|
logger.debug(f" ✓ {attr} = '{val}'")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f" ✗ {attr}: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# ===== CHAMPS DIRECTS SUR COLLABORATEUR =====
|
||||||
|
logger.info("📝 Champs directs...")
|
||||||
|
|
||||||
|
# Obligatoire
|
||||||
|
safe_set(collab, "Nom", nom_upper, 35)
|
||||||
|
|
||||||
|
# Optionnels
|
||||||
|
safe_set(collab, "Prenom", prenom, 35)
|
||||||
|
safe_set(collab, "Fonction", data.get("fonction"), 35)
|
||||||
|
safe_set(collab, "Service", data.get("service"), 35)
|
||||||
|
safe_set(collab, "Matricule", data.get("matricule"), 10)
|
||||||
|
safe_set(collab, "Facebook", data.get("facebook"), 35)
|
||||||
|
safe_set(collab, "LinkedIn", data.get("linkedin"), 35)
|
||||||
|
safe_set(collab, "Skype", data.get("skype"), 35)
|
||||||
|
|
||||||
|
# ===== SOUS-OBJET ADRESSE =====
|
||||||
|
logger.info("📍 Adresse...")
|
||||||
|
try:
|
||||||
|
adresse_obj = collab.Adresse
|
||||||
|
safe_set(adresse_obj, "Adresse", data.get("adresse"), 35)
|
||||||
|
safe_set(adresse_obj, "Complement", data.get("complement"), 35)
|
||||||
|
safe_set(adresse_obj, "CodePostal", data.get("code_postal"), 9)
|
||||||
|
safe_set(adresse_obj, "Ville", data.get("ville"), 35)
|
||||||
|
safe_set(adresse_obj, "CodeRegion", data.get("code_region"), 25)
|
||||||
|
safe_set(adresse_obj, "Pays", data.get("pays"), 35)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"⚠️ Erreur Adresse: {e}")
|
||||||
|
|
||||||
|
# ===== SOUS-OBJET TELECOM =====
|
||||||
|
logger.info("📞 Telecom...")
|
||||||
|
try:
|
||||||
|
telecom_obj = collab.Telecom
|
||||||
|
safe_set(telecom_obj, "Telephone", data.get("telephone"), 21)
|
||||||
|
safe_set(telecom_obj, "Telecopie", data.get("telecopie"), 21)
|
||||||
|
safe_set(telecom_obj, "EMail", data.get("email"), 69)
|
||||||
|
safe_set(telecom_obj, "Portable", data.get("tel_portable"), 21)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"⚠️ Erreur Telecom: {e}")
|
||||||
|
|
||||||
|
# ===== CHAMPS BOOLÉENS (seulement si True) =====
|
||||||
|
logger.info("🔘 Booléens...")
|
||||||
|
if data.get("vendeur") is True:
|
||||||
|
try:
|
||||||
|
collab.Vendeur = True
|
||||||
|
logger.debug(" ✓ Vendeur = True")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if data.get("caissier") is True:
|
||||||
|
try:
|
||||||
|
collab.Caissier = True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if data.get("acheteur") is True:
|
||||||
|
try:
|
||||||
|
collab.Acheteur = True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if data.get("sommeil") is True:
|
||||||
|
try:
|
||||||
|
collab.Sommeil = True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if data.get("chef_ventes") is True:
|
||||||
|
try:
|
||||||
|
collab.ChefVentes = True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# ===== WRITE =====
|
# ===== WRITE =====
|
||||||
collab_obj.Write()
|
logger.info("💾 Write()...")
|
||||||
logger.info("💾 Collaborateur écrit dans Sage")
|
|
||||||
|
|
||||||
# Commit transaction
|
|
||||||
if transaction_active:
|
|
||||||
try:
|
try:
|
||||||
self.cial.CptaApplication.CommitTrans()
|
collab.Write()
|
||||||
logger.info("✓ Transaction committée")
|
logger.info("✅ Write() RÉUSSI!")
|
||||||
except Exception:
|
except Exception as e:
|
||||||
pass
|
logger.error(f"❌ Write() échoué: {e}")
|
||||||
|
raise RuntimeError(f"Échec Write(): {e}")
|
||||||
|
|
||||||
# ===== RÉCUPÉRATION DU NUMÉRO =====
|
# ===== RÉCUPÉRATION DU NUMÉRO =====
|
||||||
|
numero_cree = None
|
||||||
|
|
||||||
|
# Via Read()
|
||||||
try:
|
try:
|
||||||
collab_obj.Read()
|
collab.Read()
|
||||||
numero = getattr(collab_obj, "CO_No", None)
|
for attr in ["No", "CO_No", "Numero"]:
|
||||||
except Exception:
|
|
||||||
numero = None
|
|
||||||
|
|
||||||
if not numero:
|
|
||||||
raise RuntimeError(
|
|
||||||
"Numéro de collaborateur vide après création"
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info(f"📄 Collaborateur créé: CO_No={numero}")
|
|
||||||
|
|
||||||
# ===== RELECTURE POUR RETOUR COMPLET =====
|
|
||||||
collaborateur_final = self.lire_collaborateur(numero)
|
|
||||||
|
|
||||||
if not collaborateur_final:
|
|
||||||
raise RuntimeError(
|
|
||||||
f"Impossible de relire le collaborateur {numero}"
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"✅ COLLABORATEUR CRÉÉ: {numero} - "
|
|
||||||
f"{collaborateur_final['nom']} {collaborateur_final.get('prenom', '')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
return collaborateur_final
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
if transaction_active:
|
|
||||||
try:
|
try:
|
||||||
self.cial.CptaApplication.RollbackTrans()
|
val = getattr(collab, attr)
|
||||||
logger.error("❌ Transaction annulée (rollback)")
|
if val and isinstance(val, int):
|
||||||
except Exception:
|
numero_cree = val
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
pass
|
pass
|
||||||
raise
|
|
||||||
|
|
||||||
|
# Via SQL si pas trouvé
|
||||||
|
if not numero_cree:
|
||||||
|
try:
|
||||||
|
with self._get_sql_connection() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
query = f"SELECT CO_No FROM F_COLLABORATEUR WHERE CO_Nom = '{nom_upper}'"
|
||||||
|
if prenom:
|
||||||
|
query += f" AND CO_Prenom = '{prenom}'"
|
||||||
|
cursor.execute(query)
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if row:
|
||||||
|
numero_cree = row[0]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"❌ ERREUR CRÉATION COLLABORATEUR: {e}", exc_info=True)
|
logger.warning(f"SQL récup numéro: {e}")
|
||||||
|
|
||||||
|
logger.info(f"\n{'=' * 70}")
|
||||||
|
logger.info(
|
||||||
|
f"✅ COLLABORATEUR CRÉÉ: N°{numero_cree} - {nom_upper} {prenom}"
|
||||||
|
)
|
||||||
|
logger.info(f"{'=' * 70}")
|
||||||
|
|
||||||
|
# Retourner le collaborateur
|
||||||
|
if numero_cree:
|
||||||
|
return self.lire_collaborateur(numero_cree)
|
||||||
|
else:
|
||||||
|
return {"nom": nom_upper, "prenom": prenom, "status": "créé"}
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
logger.warning(f"⚠️ Validation: {e}")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Erreur création collaborateur: {e}", exc_info=True)
|
||||||
raise RuntimeError(f"Échec création collaborateur: {str(e)}")
|
raise RuntimeError(f"Échec création collaborateur: {str(e)}")
|
||||||
|
|
||||||
def modifier_collaborateur(self, numero: int, data: dict) -> dict:
|
def modifier_collaborateur(self, numero: int, data: dict) -> dict:
|
||||||
"""Modifie un collaborateur existant via COM Sage"""
|
"""Modifie un collaborateur existant via COM Sage (BOI)"""
|
||||||
if not self.cial:
|
if not self.cial:
|
||||||
raise RuntimeError("Connexion Sage non établie")
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
logger.info(f"📝 Début modification collaborateur CO_No={numero}")
|
logger.info(f"\n{'=' * 70}")
|
||||||
|
logger.info(f"📝 MODIFICATION COLLABORATEUR N°{numero}")
|
||||||
|
logger.info(f"{'=' * 70}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self._com_context(), self._lock_com:
|
with self._com_context(), self._lock_com:
|
||||||
transaction_active = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Démarrage transaction
|
|
||||||
try:
|
|
||||||
self.cial.CptaApplication.BeginTrans()
|
|
||||||
transaction_active = True
|
|
||||||
logger.debug("✓ Transaction Sage démarrée")
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"BeginTrans échoué (non critique): {e}")
|
|
||||||
|
|
||||||
# ===== LECTURE DU COLLABORATEUR EXISTANT =====
|
# ===== LECTURE DU COLLABORATEUR EXISTANT =====
|
||||||
factory_collab = self.cial.FactoryCollaborateur
|
try:
|
||||||
persist_collab = factory_collab.ReadNumero(numero)
|
factory = self.cial.FactoryCollaborateur
|
||||||
|
except AttributeError:
|
||||||
|
factory = self.cial.CptaApplication.FactoryCollaborateur
|
||||||
|
|
||||||
if not persist_collab:
|
# Lire par numéro
|
||||||
|
try:
|
||||||
|
persist = factory.ReadNumero(numero)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError(f"Collaborateur {numero} introuvable: {e}")
|
||||||
|
|
||||||
|
if not persist:
|
||||||
raise ValueError(f"Collaborateur {numero} introuvable")
|
raise ValueError(f"Collaborateur {numero} introuvable")
|
||||||
|
|
||||||
# Cast vers l'interface IBOCollaborateur3
|
# Cast vers interface
|
||||||
|
collab = None
|
||||||
|
for iface in [
|
||||||
|
"IBOCollaborateur3",
|
||||||
|
"IBOCollaborateur2",
|
||||||
|
"IBOCollaborateur",
|
||||||
|
]:
|
||||||
try:
|
try:
|
||||||
collab_obj = win32com.client.CastTo(
|
collab = win32com.client.CastTo(persist, iface)
|
||||||
persist_collab, "IBOCollaborateur3"
|
logger.info(f"✓ Cast vers {iface}")
|
||||||
)
|
break
|
||||||
except Exception:
|
except:
|
||||||
collab_obj = win32com.client.CastTo(
|
pass
|
||||||
persist_collab, "IBOCollaborateur"
|
if not collab:
|
||||||
)
|
collab = persist
|
||||||
|
|
||||||
collab_obj.Read()
|
# Charger les données actuelles
|
||||||
|
try:
|
||||||
|
collab.Read()
|
||||||
logger.info(f"✓ Collaborateur {numero} chargé")
|
logger.info(f"✓ Collaborateur {numero} chargé")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Read() ignoré: {e}")
|
||||||
|
|
||||||
# ===== MAPPING ET MODIFICATION CHAMPS =====
|
# ===== HELPER =====
|
||||||
mapping = {
|
def safe_set(obj, attr, value, max_len=None):
|
||||||
"nom": "CO_Nom",
|
"""Affecte une valeur de manière sécurisée"""
|
||||||
"prenom": "CO_Prenom",
|
if value is None:
|
||||||
"fonction": "CO_Fonction",
|
return False
|
||||||
"adresse": "CO_Adresse",
|
try:
|
||||||
"complement": "CO_Complement",
|
val = str(value) if not isinstance(value, bool) else value
|
||||||
"code_postal": "CO_CodePostal",
|
if max_len and isinstance(val, str):
|
||||||
"ville": "CO_Ville",
|
val = val[:max_len]
|
||||||
"region": "CO_CodeRegion",
|
setattr(obj, attr, val)
|
||||||
"pays": "CO_Pays",
|
logger.debug(f" ✓ {attr} = '{val}'")
|
||||||
"service": "CO_Service",
|
return True
|
||||||
"telephone": "CO_Telephone",
|
except Exception as e:
|
||||||
"telecopie": "CO_Telecopie",
|
logger.warning(f" ✗ {attr}: {e}")
|
||||||
"email": "CO_EMail",
|
return False
|
||||||
"tel_portable": "CO_TelPortable",
|
|
||||||
"matricule": "CO_Matricule",
|
|
||||||
"facebook": "CO_Facebook",
|
|
||||||
"linkedin": "CO_LinkedIn",
|
|
||||||
"skype": "CO_Skype",
|
|
||||||
"chef_ventes_numero": "CO_NoChefVentes",
|
|
||||||
}
|
|
||||||
|
|
||||||
champs_modifies = []
|
champs_modifies = []
|
||||||
|
|
||||||
# Champs texte
|
# ===== CHAMPS DIRECTS SUR COLLABORATEUR =====
|
||||||
for py_field, sage_field in mapping.items():
|
logger.info("📝 Champs directs...")
|
||||||
if py_field in data:
|
|
||||||
try:
|
|
||||||
valeur = (
|
|
||||||
str(data[py_field])
|
|
||||||
if data[py_field] is not None
|
|
||||||
else ""
|
|
||||||
)
|
|
||||||
setattr(collab_obj, sage_field, valeur)
|
|
||||||
champs_modifies.append(sage_field)
|
|
||||||
logger.debug(f" ✓ {sage_field}: {valeur}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f" ⚠ {sage_field} non modifié: {e}")
|
|
||||||
|
|
||||||
# ===== CHAMPS BOOLÉENS =====
|
champs_directs = {
|
||||||
bool_mapping = {
|
"nom": ("Nom", 35),
|
||||||
"est_vendeur": "CO_Vendeur",
|
"prenom": ("Prenom", 35),
|
||||||
"est_caissier": "CO_Caissier",
|
"fonction": ("Fonction", 35),
|
||||||
"est_acheteur": "CO_Acheteur",
|
"service": ("Service", 35),
|
||||||
"est_chef_ventes": "CO_ChefVentes",
|
"matricule": ("Matricule", 10),
|
||||||
|
"facebook": ("Facebook", 35),
|
||||||
|
"linkedin": ("LinkedIn", 35),
|
||||||
|
"skype": ("Skype", 35),
|
||||||
}
|
}
|
||||||
|
|
||||||
for py_field, sage_field in bool_mapping.items():
|
for py_field, (sage_attr, max_len) in champs_directs.items():
|
||||||
if py_field in data:
|
if py_field in data:
|
||||||
try:
|
val = data[py_field]
|
||||||
valeur = 1 if data[py_field] else 0
|
# Cas spécial: nom en majuscules
|
||||||
setattr(collab_obj, sage_field, valeur)
|
if py_field == "nom" and val:
|
||||||
champs_modifies.append(sage_field)
|
val = str(val).upper().strip()
|
||||||
logger.debug(f" ✓ {sage_field}: {valeur}")
|
if safe_set(collab, sage_attr, val, max_len):
|
||||||
except Exception as e:
|
champs_modifies.append(sage_attr)
|
||||||
logger.warning(f" ⚠ {sage_field} non modifié: {e}")
|
|
||||||
|
|
||||||
# ===== CO_SOMMEIL (inversé) =====
|
# ===== SOUS-OBJET ADRESSE =====
|
||||||
if "est_actif" in data:
|
logger.info("📍 Adresse...")
|
||||||
try:
|
try:
|
||||||
valeur_sommeil = 0 if data["est_actif"] else 1
|
adresse_obj = collab.Adresse
|
||||||
collab_obj.CO_Sommeil = valeur_sommeil
|
|
||||||
champs_modifies.append("CO_Sommeil")
|
|
||||||
logger.debug(f" ✓ CO_Sommeil: {valeur_sommeil}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f" ⚠ CO_Sommeil non modifié: {e}")
|
|
||||||
|
|
||||||
|
champs_adresse = {
|
||||||
|
"adresse": ("Adresse", 35),
|
||||||
|
"complement": ("Complement", 35),
|
||||||
|
"code_postal": ("CodePostal", 9),
|
||||||
|
"ville": ("Ville", 35),
|
||||||
|
"code_region": ("CodeRegion", 25),
|
||||||
|
"pays": ("Pays", 35),
|
||||||
|
}
|
||||||
|
|
||||||
|
for py_field, (sage_attr, max_len) in champs_adresse.items():
|
||||||
|
if py_field in data:
|
||||||
|
if safe_set(
|
||||||
|
adresse_obj, sage_attr, data[py_field], max_len
|
||||||
|
):
|
||||||
|
champs_modifies.append(f"Adresse.{sage_attr}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"⚠️ Erreur accès Adresse: {e}")
|
||||||
|
|
||||||
|
# ===== SOUS-OBJET TELECOM =====
|
||||||
|
logger.info("📞 Telecom...")
|
||||||
|
try:
|
||||||
|
telecom_obj = collab.Telecom
|
||||||
|
|
||||||
|
champs_telecom = {
|
||||||
|
"telephone": ("Telephone", 21),
|
||||||
|
"telecopie": ("Telecopie", 21),
|
||||||
|
"email": ("EMail", 69),
|
||||||
|
"tel_portable": ("Portable", 21),
|
||||||
|
}
|
||||||
|
|
||||||
|
for py_field, (sage_attr, max_len) in champs_telecom.items():
|
||||||
|
if py_field in data:
|
||||||
|
if safe_set(
|
||||||
|
telecom_obj, sage_attr, data[py_field], max_len
|
||||||
|
):
|
||||||
|
champs_modifies.append(f"Telecom.{sage_attr}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"⚠️ Erreur accès Telecom: {e}")
|
||||||
|
|
||||||
|
# ===== CHAMPS BOOLÉENS =====
|
||||||
|
logger.info("🔘 Booléens...")
|
||||||
|
|
||||||
|
champs_bool = {
|
||||||
|
"vendeur": "Vendeur",
|
||||||
|
"caissier": "Caissier",
|
||||||
|
"acheteur": "Acheteur",
|
||||||
|
"sommeil": "Sommeil",
|
||||||
|
"chef_ventes": "ChefVentes",
|
||||||
|
}
|
||||||
|
|
||||||
|
for py_field, sage_attr in champs_bool.items():
|
||||||
|
if py_field in data and data[py_field] is not None:
|
||||||
|
try:
|
||||||
|
val = bool(data[py_field])
|
||||||
|
setattr(collab, sage_attr, val)
|
||||||
|
champs_modifies.append(sage_attr)
|
||||||
|
logger.debug(f" ✓ {sage_attr} = {val}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f" ✗ {sage_attr}: {e}")
|
||||||
|
|
||||||
|
# ===== VÉRIFICATION =====
|
||||||
if not champs_modifies:
|
if not champs_modifies:
|
||||||
logger.info("ℹ Aucun champ à modifier")
|
logger.info("ℹ️ Aucun champ à modifier")
|
||||||
return self.lire_collaborateur(numero)
|
return self.lire_collaborateur(numero)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"📋 {len(champs_modifies)} champ(s) à modifier: {champs_modifies}"
|
||||||
|
)
|
||||||
|
|
||||||
# ===== WRITE =====
|
# ===== WRITE =====
|
||||||
collab_obj.Write()
|
logger.info("💾 Write()...")
|
||||||
logger.info(
|
|
||||||
f"💾 Collaborateur modifié ({len(champs_modifies)} champs)"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Commit transaction
|
|
||||||
if transaction_active:
|
|
||||||
try:
|
try:
|
||||||
self.cial.CptaApplication.CommitTrans()
|
collab.Write()
|
||||||
logger.info("✓ Transaction committée")
|
logger.info("✅ Write() RÉUSSI!")
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# ===== RELECTURE POUR RETOUR COMPLET =====
|
|
||||||
collaborateur_final = self.lire_collaborateur(numero)
|
|
||||||
|
|
||||||
if not collaborateur_final:
|
|
||||||
raise RuntimeError(
|
|
||||||
f"Impossible de relire le collaborateur {numero}"
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"✅ COLLABORATEUR MODIFIÉ: {numero} - "
|
|
||||||
f"{collaborateur_final['nom']} {collaborateur_final.get('prenom', '')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
return collaborateur_final
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
if transaction_active:
|
|
||||||
try:
|
|
||||||
self.cial.CptaApplication.RollbackTrans()
|
|
||||||
logger.error("❌ Transaction annulée (rollback)")
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
raise
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(
|
logger.error(f"❌ Write() échoué: {e}")
|
||||||
f"❌ ERREUR MODIFICATION COLLABORATEUR {numero}: {e}", exc_info=True
|
raise RuntimeError(f"Échec Write(): {e}")
|
||||||
)
|
|
||||||
|
# ===== RETOUR =====
|
||||||
|
logger.info(f"\n{'=' * 70}")
|
||||||
|
logger.info(f"✅ COLLABORATEUR MODIFIÉ: N°{numero}")
|
||||||
|
logger.info(f"{'=' * 70}")
|
||||||
|
|
||||||
|
return self.lire_collaborateur(numero)
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
logger.warning(f"⚠️ Validation: {e}")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Erreur modification collaborateur: {e}", exc_info=True)
|
||||||
raise RuntimeError(f"Échec modification collaborateur: {str(e)}")
|
raise RuntimeError(f"Échec modification collaborateur: {str(e)}")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue