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
|
||||
|
||||
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:
|
||||
raise RuntimeError("Connexion Sage non établie")
|
||||
|
||||
logger.info(
|
||||
f"📝 Début création collaborateur: {data.get('nom')} {data.get('prenom', '')}"
|
||||
)
|
||||
# Validation préalable
|
||||
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:
|
||||
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}")
|
||||
|
||||
# ===== 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"
|
||||
# ===== VÉRIFICATION DOUBLON VIA SQL =====
|
||||
logger.info("🔍 Vérification doublon...")
|
||||
with self._get_sql_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"SELECT CO_No FROM F_COLLABORATEUR WHERE CO_Nom = ? AND CO_Prenom = ?",
|
||||
(nom_upper, prenom),
|
||||
)
|
||||
except Exception:
|
||||
# Fallback si IBOCollaborateur3 n'existe pas
|
||||
collab_obj = win32com.client.CastTo(
|
||||
persist_collab, "IBOCollaborateur"
|
||||
existing = cursor.fetchone()
|
||||
if existing:
|
||||
raise ValueError(
|
||||
f"Le collaborateur '{nom_upper} {prenom}' existe déjà (N°{existing[0]})"
|
||||
)
|
||||
logger.info("✓ Pas de doublon")
|
||||
|
||||
logger.info("✓ Objet collaborateur créé")
|
||||
|
||||
# ===== 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:
|
||||
# ===== FACTORY + CREATE =====
|
||||
try:
|
||||
setattr(collab_obj, sage_field, str(data[py_field]))
|
||||
logger.debug(f" ✓ {sage_field}: {data[py_field]}")
|
||||
except Exception as e:
|
||||
logger.warning(f" ⚠ {sage_field} non défini: {e}")
|
||||
factory = self.cial.FactoryCollaborateur
|
||||
except AttributeError:
|
||||
factory = self.cial.CptaApplication.FactoryCollaborateur
|
||||
|
||||
# ===== CHAMPS BOOLÉENS =====
|
||||
bool_mapping = {
|
||||
"est_vendeur": "CO_Vendeur",
|
||||
"est_caissier": "CO_Caissier",
|
||||
"est_acheteur": "CO_Acheteur",
|
||||
"est_chef_ventes": "CO_ChefVentes",
|
||||
}
|
||||
persist = factory.Create()
|
||||
|
||||
for py_field, sage_field in bool_mapping.items():
|
||||
if py_field in data:
|
||||
# Cast vers interface
|
||||
collab = None
|
||||
for iface in [
|
||||
"IBOCollaborateur3",
|
||||
"IBOCollaborateur2",
|
||||
"IBOCollaborateur",
|
||||
]:
|
||||
try:
|
||||
valeur = 1 if data[py_field] else 0
|
||||
setattr(collab_obj, sage_field, valeur)
|
||||
logger.debug(f" ✓ {sage_field}: {valeur}")
|
||||
except Exception as e:
|
||||
logger.warning(f" ⚠ {sage_field} non défini: {e}")
|
||||
collab = win32com.client.CastTo(persist, iface)
|
||||
logger.info(f"✓ Cast vers {iface}")
|
||||
break
|
||||
except:
|
||||
pass
|
||||
if not collab:
|
||||
collab = persist
|
||||
|
||||
# ===== CO_SOMMEIL (inversé: est_actif → 0=actif, 1=inactif) =====
|
||||
if "est_actif" in data:
|
||||
# ===== SETDEFAULT =====
|
||||
try:
|
||||
valeur_sommeil = 0 if data["est_actif"] else 1
|
||||
collab_obj.CO_Sommeil = valeur_sommeil
|
||||
logger.debug(
|
||||
f" ✓ CO_Sommeil: {valeur_sommeil} (actif={data['est_actif']})"
|
||||
)
|
||||
collab.SetDefault()
|
||||
logger.info("✓ SetDefault()")
|
||||
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 =====
|
||||
collab_obj.Write()
|
||||
logger.info("💾 Collaborateur écrit dans Sage")
|
||||
|
||||
# Commit transaction
|
||||
if transaction_active:
|
||||
logger.info("💾 Write()...")
|
||||
try:
|
||||
self.cial.CptaApplication.CommitTrans()
|
||||
logger.info("✓ Transaction committée")
|
||||
except Exception:
|
||||
pass
|
||||
collab.Write()
|
||||
logger.info("✅ Write() RÉUSSI!")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Write() échoué: {e}")
|
||||
raise RuntimeError(f"Échec Write(): {e}")
|
||||
|
||||
# ===== RÉCUPÉRATION DU NUMÉRO =====
|
||||
numero_cree = None
|
||||
|
||||
# Via Read()
|
||||
try:
|
||||
collab_obj.Read()
|
||||
numero = getattr(collab_obj, "CO_No", None)
|
||||
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:
|
||||
collab.Read()
|
||||
for attr in ["No", "CO_No", "Numero"]:
|
||||
try:
|
||||
self.cial.CptaApplication.RollbackTrans()
|
||||
logger.error("❌ Transaction annulée (rollback)")
|
||||
except Exception:
|
||||
val = getattr(collab, attr)
|
||||
if val and isinstance(val, int):
|
||||
numero_cree = val
|
||||
break
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
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:
|
||||
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)}")
|
||||
|
||||
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:
|
||||
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:
|
||||
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 =====
|
||||
factory_collab = self.cial.FactoryCollaborateur
|
||||
persist_collab = factory_collab.ReadNumero(numero)
|
||||
try:
|
||||
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")
|
||||
|
||||
# Cast vers l'interface IBOCollaborateur3
|
||||
# Cast vers interface
|
||||
collab = None
|
||||
for iface in [
|
||||
"IBOCollaborateur3",
|
||||
"IBOCollaborateur2",
|
||||
"IBOCollaborateur",
|
||||
]:
|
||||
try:
|
||||
collab_obj = win32com.client.CastTo(
|
||||
persist_collab, "IBOCollaborateur3"
|
||||
)
|
||||
except Exception:
|
||||
collab_obj = win32com.client.CastTo(
|
||||
persist_collab, "IBOCollaborateur"
|
||||
)
|
||||
collab = win32com.client.CastTo(persist, iface)
|
||||
logger.info(f"✓ Cast vers {iface}")
|
||||
break
|
||||
except:
|
||||
pass
|
||||
if not collab:
|
||||
collab = persist
|
||||
|
||||
collab_obj.Read()
|
||||
# Charger les données actuelles
|
||||
try:
|
||||
collab.Read()
|
||||
logger.info(f"✓ Collaborateur {numero} chargé")
|
||||
except Exception as e:
|
||||
logger.warning(f"Read() ignoré: {e}")
|
||||
|
||||
# ===== MAPPING ET MODIFICATION 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",
|
||||
}
|
||||
# ===== HELPER =====
|
||||
def safe_set(obj, attr, value, max_len=None):
|
||||
"""Affecte une valeur de manière sécurisée"""
|
||||
if value is None:
|
||||
return False
|
||||
try:
|
||||
val = str(value) if not isinstance(value, bool) else value
|
||||
if max_len and isinstance(val, str):
|
||||
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_modifies = []
|
||||
|
||||
# Champs texte
|
||||
for py_field, sage_field in mapping.items():
|
||||
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 DIRECTS SUR COLLABORATEUR =====
|
||||
logger.info("📝 Champs directs...")
|
||||
|
||||
# ===== CHAMPS BOOLÉENS =====
|
||||
bool_mapping = {
|
||||
"est_vendeur": "CO_Vendeur",
|
||||
"est_caissier": "CO_Caissier",
|
||||
"est_acheteur": "CO_Acheteur",
|
||||
"est_chef_ventes": "CO_ChefVentes",
|
||||
champs_directs = {
|
||||
"nom": ("Nom", 35),
|
||||
"prenom": ("Prenom", 35),
|
||||
"fonction": ("Fonction", 35),
|
||||
"service": ("Service", 35),
|
||||
"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:
|
||||
try:
|
||||
valeur = 1 if data[py_field] else 0
|
||||
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}")
|
||||
val = data[py_field]
|
||||
# Cas spécial: nom en majuscules
|
||||
if py_field == "nom" and val:
|
||||
val = str(val).upper().strip()
|
||||
if safe_set(collab, sage_attr, val, max_len):
|
||||
champs_modifies.append(sage_attr)
|
||||
|
||||
# ===== CO_SOMMEIL (inversé) =====
|
||||
if "est_actif" in data:
|
||||
# ===== SOUS-OBJET ADRESSE =====
|
||||
logger.info("📍 Adresse...")
|
||||
try:
|
||||
valeur_sommeil = 0 if data["est_actif"] else 1
|
||||
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}")
|
||||
adresse_obj = collab.Adresse
|
||||
|
||||
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:
|
||||
logger.info("ℹ Aucun champ à modifier")
|
||||
logger.info("ℹ️ Aucun champ à modifier")
|
||||
return self.lire_collaborateur(numero)
|
||||
|
||||
logger.info(
|
||||
f"📋 {len(champs_modifies)} champ(s) à modifier: {champs_modifies}"
|
||||
)
|
||||
|
||||
# ===== WRITE =====
|
||||
collab_obj.Write()
|
||||
logger.info(
|
||||
f"💾 Collaborateur modifié ({len(champs_modifies)} champs)"
|
||||
)
|
||||
|
||||
# Commit transaction
|
||||
if transaction_active:
|
||||
logger.info("💾 Write()...")
|
||||
try:
|
||||
self.cial.CptaApplication.CommitTrans()
|
||||
logger.info("✓ Transaction committée")
|
||||
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
|
||||
|
||||
collab.Write()
|
||||
logger.info("✅ Write() RÉUSSI!")
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"❌ ERREUR MODIFICATION COLLABORATEUR {numero}: {e}", exc_info=True
|
||||
)
|
||||
logger.error(f"❌ Write() échoué: {e}")
|
||||
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)}")
|
||||
|
|
|
|||
Loading…
Reference in a new issue