Modified "modifier_commande" method to delete lines correctly
This commit is contained in:
parent
cc2b86d533
commit
fc7216fe2f
1 changed files with 115 additions and 143 deletions
|
|
@ -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 où ç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:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue