Modified "modifier_commande" method to delete lines correctly

This commit is contained in:
Fanilo-Nantenaina 2025-12-08 08:42:03 +03:00
parent cc2b86d533
commit fc7216fe2f

View file

@ -4122,27 +4122,24 @@ class SageConnector:
def modifier_commande(self, numero: str, commande_data: Dict) -> Dict: def modifier_commande(self, numero: str, commande_data: Dict) -> Dict:
""" """
Modification commande - VERSION ULTRA-DIAGNOSTIQUE Modification commande - VERSION SIMPLIFIÉE
🔬 OBJECTIF: Identifier EXACTEMENT ça plante et pourquoi 🔧 STRATÉGIE REMPLACEMENT LIGNES:
- Si nouvelles lignes fournies Supprime TOUTES les anciennes puis ajoute les nouvelles
Stratégies testées dans l'ordre : - Utilise .Remove() pour la suppression
1. Diagnostic complet de l'état du document - Simple, robuste, prévisible
2. Comparaison avec un document qui fonctionne (BC00068)
3. Approche minimaliste (modifier 1 seul champ à la fois)
4. Approche progressive (ajouter champs un par un)
""" """
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:
logger.info(f"🔬 === DIAGNOSTIC MODIFICATION COMMANDE {numero} ===") logger.info(f"🔬 === MODIFICATION COMMANDE {numero} ===")
# ======================================== # ========================================
# PHASE 0 : DIAGNOSTIC COMPLET INITIAL # ÉTAPE 1 : CHARGER LE DOCUMENT
# ======================================== # ========================================
logger.info("📊 PHASE 0: Diagnostic état initial...") logger.info("📂 Chargement document...")
factory = self.cial.FactoryDocumentVente factory = self.cial.FactoryDocumentVente
persist = None persist = None
@ -4164,20 +4161,14 @@ class SageConnector:
doc = win32com.client.CastTo(persist, "IBODocumentVente3") doc = win32com.client.CastTo(persist, "IBODocumentVente3")
doc.Read() doc.Read()
# Diagnostic complet de l'état initial statut_actuel = getattr(doc, "DO_Statut", 0)
diag_initial = { type_reel = getattr(doc, "DO_Type", -1)
"DO_Piece": getattr(doc, "DO_Piece", ""),
"DO_Type": getattr(doc, "DO_Type", -1),
"DO_Statut": getattr(doc, "DO_Statut", -1),
"DO_Date": str(getattr(doc, "DO_Date", "")),
"DO_Ref": getattr(doc, "DO_Ref", ""),
"DO_TotalHT": float(getattr(doc, "DO_TotalHT", 0.0)),
"DO_TotalTTC": float(getattr(doc, "DO_TotalTTC", 0.0)),
}
logger.info(f" 📋 État initial: {diag_initial}") logger.info(f" 📊 Type={type_reel}, Statut={statut_actuel}")
# Charger le client INITIAL # ========================================
# ÉTAPE 2 : VÉRIFIER CLIENT INITIAL
# ========================================
client_code_initial = "" client_code_initial = ""
try: try:
client_obj = getattr(doc, "Client", None) client_obj = getattr(doc, "Client", None)
@ -4213,56 +4204,25 @@ class SageConnector:
logger.warning(f" ⚠️ Erreur comptage lignes: {e}") logger.warning(f" ⚠️ Erreur comptage lignes: {e}")
# ======================================== # ========================================
# PHASE 1 : COMPARAISON AVEC BC00068 (qui fonctionne) # ÉTAPE 3 : DÉTERMINER LES MODIFICATIONS
# ======================================== # ========================================
if numero != "BC00068": champs_modifies = []
logger.info("🔍 PHASE 1: Comparaison avec BC00068...")
modif_date = "date_commande" in commande_data
try: modif_statut = "statut" in commande_data
persist_ref = None modif_ref = "reference" in commande_data
for type_test in [10, 3, settings.SAGE_TYPE_BON_COMMANDE]: modif_lignes = "lignes" in commande_data and commande_data["lignes"] is not None
try:
persist_ref = factory.ReadPiece(type_test, "BC00068") logger.info(f"📋 Modifications demandées:")
if persist_ref: logger.info(f" Date: {modif_date}")
break logger.info(f" Statut: {modif_statut}")
except: logger.info(f" Référence: {modif_ref}")
continue logger.info(f" Lignes: {modif_lignes}")
if persist_ref:
doc_ref = win32com.client.CastTo(persist_ref, "IBODocumentVente3")
doc_ref.Read()
# Comparer tous les champs critiques
champs_a_comparer = [
"DO_Type", "DO_Statut", "DO_Domaine", "DO_Souche",
"DO_Transfere", "DO_Valide", "DO_Cloture"
]
differences = {}
for champ in champs_a_comparer:
val_doc = getattr(doc, champ, None)
val_ref = getattr(doc_ref, champ, None)
if val_doc != val_ref:
differences[champ] = {
"doc_actuel": str(val_doc),
"bc00068": str(val_ref)
}
if differences:
logger.warning(f" ⚠️ DIFFÉRENCES avec BC00068:")
for champ, vals in differences.items():
logger.warning(f" {champ}: {vals['doc_actuel']} != {vals['bc00068']}")
else:
logger.info(f" ✅ Aucune différence critique avec BC00068")
except Exception as e:
logger.warning(f" ⚠️ Impossible de comparer avec BC00068: {e}")
# ======================================== # ========================================
# PHASE 2 : TEST WRITE() BASIQUE (SANS AUCUNE MODIFICATION) # ÉTAPE 4 : TEST WRITE() BASIQUE
# ======================================== # ========================================
logger.info("🧪 PHASE 2: Test Write() basique (sans modification)...") logger.info("🧪 Test Write() basique (sans modification)...")
try: try:
doc.Write() doc.Write()
@ -4287,27 +4247,10 @@ class SageConnector:
raise ValueError(f"Document verrouillé, impossible de modifier: {e}") raise ValueError(f"Document verrouillé, impossible de modifier: {e}")
# ======================================== # ========================================
# PHASE 3 : STRATÉGIE SELON LES MODIFICATIONS DEMANDÉES # ÉTAPE 5 : MODIFICATIONS SIMPLES (pas de lignes)
# ========================================
champs_modifies = []
# Détecter ce qui doit être modifié
modif_date = "date_commande" in commande_data
modif_statut = "statut" in commande_data
modif_ref = "reference" in commande_data
modif_lignes = "lignes" in commande_data and commande_data["lignes"] is not None
logger.info(f"📋 Modifications demandées:")
logger.info(f" Date: {modif_date}")
logger.info(f" Statut: {modif_statut}")
logger.info(f" Référence: {modif_ref}")
logger.info(f" Lignes: {modif_lignes}")
# ========================================
# STRATÉGIE A : MODIFICATIONS SIMPLES (pas de lignes)
# ======================================== # ========================================
if not modif_lignes and (modif_date or modif_statut or modif_ref): if not modif_lignes and (modif_date or modif_statut or modif_ref):
logger.info("🎯 STRATÉGIE A: Modifications simples (sans lignes)...") logger.info("🎯 Modifications simples (sans lignes)...")
if modif_date: if modif_date:
logger.info(" 📅 Modification date...") logger.info(" 📅 Modification date...")
@ -4372,15 +4315,15 @@ class SageConnector:
raise ValueError(f"Sage refuse: {error_msg}") raise ValueError(f"Sage refuse: {error_msg}")
# ======================================== # ========================================
# STRATÉGIE B : MODIFICATION LIGNES (approche minimaliste) # ÉTAPE 6 : REMPLACEMENT COMPLET DES LIGNES
# ======================================== # ========================================
elif modif_lignes: elif modif_lignes:
logger.info("🎯 STRATÉGIE B: Modification lignes (approche minimaliste)...") logger.info("🎯 REMPLACEMENT COMPLET DES LIGNES...")
nouvelles_lignes = commande_data["lignes"] nouvelles_lignes = commande_data["lignes"]
nb_nouvelles = len(nouvelles_lignes) nb_nouvelles = len(nouvelles_lignes)
logger.info(f" 📊 {nb_lignes_initial} lignes existantes → {nb_nouvelles} nouvelles") logger.info(f" 📊 {nb_lignes_initial} lignes existantes → {nb_nouvelles} nouvelles lignes")
try: try:
factory_lignes = doc.FactoryDocumentLigne factory_lignes = doc.FactoryDocumentLigne
@ -4389,21 +4332,36 @@ class SageConnector:
factory_article = self.cial.FactoryArticle factory_article = self.cial.FactoryArticle
# APPROCHE MINIMALISTE: Tester avec UNE SEULE ligne d'abord # ============================================
logger.info(" 🧪 TEST: Modification de la ligne 1 uniquement...") # SOUS-ÉTAPE 1 : SUPPRIMER TOUTES LES LIGNES EXISTANTES
# ============================================
ligne_data = nouvelles_lignes[0] if nb_lignes_initial > 0:
logger.info(f" 🗑️ Suppression de {nb_lignes_initial} lignes existantes...")
try:
ligne_p = factory_lignes.List(1)
if ligne_p is None:
raise ValueError("Aucune ligne existante")
ligne = win32com.client.CastTo(ligne_p, "IBODocumentLigne3") # Supprimer depuis la fin pour éviter les problèmes d'index
ligne.Read() for idx in range(nb_lignes_initial, 0, -1):
try:
ligne_p = factory_lignes.List(idx)
if ligne_p:
ligne = win32com.client.CastTo(ligne_p, "IBODocumentLigne3")
ligne.Read()
# ✅ Utiliser .Remove() comme indiqué
ligne.Remove()
logger.debug(f" ✅ Ligne {idx} supprimée")
except Exception as e:
logger.warning(f" ⚠️ Impossible de supprimer ligne {idx}: {e}")
# Continuer même si une suppression échoue
logger.info(f" Article: {ligne_data['article_code']}") logger.info(" ✅ Toutes les lignes existantes supprimées")
logger.info(f" Quantité: {ligne_data['quantite']}")
# ============================================
# SOUS-ÉTAPE 2 : AJOUTER LES NOUVELLES LIGNES
# ============================================
logger.info(f" Ajout de {nb_nouvelles} nouvelles lignes...")
for idx, ligne_data in enumerate(nouvelles_lignes, 1):
logger.info(f" --- Ligne {idx}/{nb_nouvelles}: {ligne_data['article_code']} ---")
# Charger l'article # Charger l'article
persist_article = factory_article.ReadReference(ligne_data["article_code"]) persist_article = factory_article.ReadReference(ligne_data["article_code"])
@ -4413,50 +4371,66 @@ class SageConnector:
article_obj = win32com.client.CastTo(persist_article, "IBOArticle3") article_obj = win32com.client.CastTo(persist_article, "IBOArticle3")
article_obj.Read() article_obj.Read()
# MÉTHODE ULTRA-MINIMALISTE : Juste changer la quantité # Créer nouvelle ligne
logger.info(" 🔧 Modification quantité uniquement...") ligne_persist = factory_lignes.Create()
try:
ligne_obj = win32com.client.CastTo(ligne_persist, "IBODocumentLigne3")
except:
ligne_obj = win32com.client.CastTo(ligne_persist, "IBODocumentVenteLigne3")
quantite = float(ligne_data["quantite"]) quantite = float(ligne_data["quantite"])
ligne.DL_Qte = quantite
# Associer article
try:
ligne_obj.SetDefaultArticleReference(ligne_data["article_code"], quantite)
except:
try:
ligne_obj.SetDefaultArticle(article_obj, quantite)
except:
ligne_obj.DL_Design = ligne_data.get("designation", "")
ligne_obj.DL_Qte = quantite
# Prix
if ligne_data.get("prix_unitaire_ht"):
ligne_obj.DL_PrixUnitaire = float(ligne_data["prix_unitaire_ht"])
# Remise
if ligne_data.get("remise_pourcentage", 0) > 0:
try:
ligne_obj.DL_Remise01REM_Valeur = float(ligne_data["remise_pourcentage"])
ligne_obj.DL_Remise01REM_Type = 0
except:
pass
# Écrire la ligne # Écrire la ligne
logger.info(" 💾 Write() ligne...") ligne_obj.Write()
ligne.Write() logger.info(f" ✅ Ligne {idx} ajoutée")
logger.info(" ✅ Ligne 1 modifiée")
# Écrire le document
logger.info(" 💾 Write() document après ligne...")
doc.Write()
logger.info(" ✅ Document écrit")
doc.Read()
# Vérifier client
client_obj = getattr(doc, "Client", None)
if client_obj:
client_obj.Read()
client_apres = getattr(client_obj, "CT_Num", "")
logger.info(f" 👤 Client après modif: {client_apres}")
else:
logger.error(" ❌ Client NULL après modif")
champs_modifies.append("lignes")
except Exception as e: logger.info(f"{nb_nouvelles} nouvelles lignes ajoutées")
error_msg = str(e)
try: # Écrire le document
sage_error = self.cial.CptaApplication.LastError logger.info(" 💾 Write() document après remplacement lignes...")
if sage_error: doc.Write()
error_msg = f"{sage_error.Description} (Code: {sage_error.Number})" logger.info(" ✅ Document écrit")
except:
pass doc.Read()
logger.error(f" ❌ Modification ligne échoue: {error_msg}") # Vérifier client
raise ValueError(f"Sage refuse modification ligne: {error_msg}") client_obj = getattr(doc, "Client", None)
if client_obj:
client_obj.Read()
client_apres = getattr(client_obj, "CT_Num", "")
logger.info(f" 👤 Client après remplacement: {client_apres}")
else:
logger.error(" ❌ Client NULL après remplacement")
champs_modifies.append("lignes")
# ======================================== # ========================================
# PHASE FINALE : RELECTURE ET RETOUR # ÉTAPE 7 : RELECTURE ET RETOUR
# ======================================== # ========================================
logger.info("📊 PHASE FINALE: Relecture...") logger.info("📊 Relecture finale...")
import time import time
time.sleep(1) time.sleep(1)
@ -4522,7 +4496,5 @@ class SageConnector: