Diagnostic document transformation error
This commit is contained in:
parent
3505ecfd2b
commit
92c79f1362
2 changed files with 328 additions and 226 deletions
216
main.py
216
main.py
|
|
@ -1061,6 +1061,222 @@ def diagnostiquer_devis(numero: str):
|
||||||
raise HTTPException(500, str(e))
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/sage/diagnostic/configuration", dependencies=[Depends(verify_token)])
|
||||||
|
def diagnostic_configuration():
|
||||||
|
"""
|
||||||
|
DIAGNOSTIC COMPLET de la configuration Sage
|
||||||
|
|
||||||
|
Teste:
|
||||||
|
- Quelles méthodes COM sont disponibles
|
||||||
|
- Quels types de documents sont autorisés
|
||||||
|
- Quelles permissions l'utilisateur a
|
||||||
|
- Version de Sage
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if not sage or not sage.cial:
|
||||||
|
raise HTTPException(503, "Service Sage indisponible")
|
||||||
|
|
||||||
|
with sage._com_context(), sage._lock_com:
|
||||||
|
diagnostic = {
|
||||||
|
"connexion": "OK",
|
||||||
|
"chemin_base": sage.chemin_base,
|
||||||
|
"utilisateur": sage.utilisateur,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Version Sage
|
||||||
|
try:
|
||||||
|
version = getattr(sage.cial, "Version", "Inconnue")
|
||||||
|
diagnostic["version_sage"] = str(version)
|
||||||
|
except:
|
||||||
|
diagnostic["version_sage"] = "Non disponible"
|
||||||
|
|
||||||
|
# Test des méthodes disponibles sur IBSCIALApplication3
|
||||||
|
methodes_disponibles = []
|
||||||
|
methodes_a_tester = [
|
||||||
|
"CreateProcess_Document",
|
||||||
|
"FactoryDocumentVente",
|
||||||
|
"FactoryArticle",
|
||||||
|
"CptaApplication",
|
||||||
|
"BeginTrans",
|
||||||
|
"CommitTrans",
|
||||||
|
"RollbackTrans",
|
||||||
|
]
|
||||||
|
|
||||||
|
for methode in methodes_a_tester:
|
||||||
|
try:
|
||||||
|
if hasattr(sage.cial, methode):
|
||||||
|
methodes_disponibles.append(methode)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
diagnostic["methodes_cial_disponibles"] = methodes_disponibles
|
||||||
|
|
||||||
|
# Test des types de documents autorisés
|
||||||
|
types_autorises = []
|
||||||
|
types_bloques = []
|
||||||
|
|
||||||
|
for type_doc in range(6): # 0-5
|
||||||
|
try:
|
||||||
|
# Essayer de créer un process (sans le valider)
|
||||||
|
process = sage.cial.CreateProcess_Document(type_doc)
|
||||||
|
if process:
|
||||||
|
types_autorises.append(
|
||||||
|
{
|
||||||
|
"type": type_doc,
|
||||||
|
"libelle": {
|
||||||
|
0: "Devis",
|
||||||
|
1: "Bon de livraison",
|
||||||
|
2: "Bon de retour",
|
||||||
|
3: "Commande",
|
||||||
|
4: "Preparation",
|
||||||
|
5: "Facture",
|
||||||
|
}[type_doc],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# Ne pas valider, juste tester
|
||||||
|
del process
|
||||||
|
except Exception as e:
|
||||||
|
types_bloques.append(
|
||||||
|
{
|
||||||
|
"type": type_doc,
|
||||||
|
"libelle": {
|
||||||
|
0: "Devis",
|
||||||
|
1: "Bon de livraison",
|
||||||
|
2: "Bon de retour",
|
||||||
|
3: "Commande",
|
||||||
|
4: "Preparation",
|
||||||
|
5: "Facture",
|
||||||
|
}[type_doc],
|
||||||
|
"erreur": str(e)[:200],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
diagnostic["types_documents_autorises"] = types_autorises
|
||||||
|
diagnostic["types_documents_bloques"] = types_bloques
|
||||||
|
|
||||||
|
# Test TransformInto() sur un devis test
|
||||||
|
try:
|
||||||
|
factory = sage.cial.FactoryDocumentVente
|
||||||
|
|
||||||
|
# Chercher n'importe quel devis
|
||||||
|
index = 1
|
||||||
|
devis_test = None
|
||||||
|
|
||||||
|
while index < 100:
|
||||||
|
try:
|
||||||
|
persist = factory.List(index)
|
||||||
|
if persist is None:
|
||||||
|
break
|
||||||
|
|
||||||
|
doc = win32com.client.CastTo(persist, "IBODocumentVente3")
|
||||||
|
doc.Read()
|
||||||
|
|
||||||
|
if getattr(doc, "DO_Type", -1) == 0: # Devis
|
||||||
|
devis_test = doc
|
||||||
|
break
|
||||||
|
|
||||||
|
index += 1
|
||||||
|
except:
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
if devis_test:
|
||||||
|
# Tester si TransformInto existe
|
||||||
|
if hasattr(devis_test, "TransformInto"):
|
||||||
|
diagnostic["transforminto_disponible"] = True
|
||||||
|
diagnostic["transforminto_test"] = "Methode existe (non testee)"
|
||||||
|
else:
|
||||||
|
diagnostic["transforminto_disponible"] = False
|
||||||
|
diagnostic["transforminto_test"] = (
|
||||||
|
"Methode TransformInto() inexistante"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
diagnostic["transforminto_disponible"] = (
|
||||||
|
"Impossible de tester (aucun devis trouve)"
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
diagnostic["transforminto_disponible"] = False
|
||||||
|
diagnostic["transforminto_erreur"] = str(e)
|
||||||
|
|
||||||
|
# Modules Sage actifs
|
||||||
|
try:
|
||||||
|
# Tester l'accès aux différentes factories
|
||||||
|
modules = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
sage.cial.FactoryDocumentVente
|
||||||
|
modules["Ventes"] = "OK"
|
||||||
|
except:
|
||||||
|
modules["Ventes"] = "INACCESSIBLE"
|
||||||
|
|
||||||
|
try:
|
||||||
|
sage.cial.CptaApplication.FactoryClient
|
||||||
|
modules["Clients"] = "OK"
|
||||||
|
except:
|
||||||
|
modules["Clients"] = "INACCESSIBLE"
|
||||||
|
|
||||||
|
try:
|
||||||
|
sage.cial.FactoryArticle
|
||||||
|
modules["Articles"] = "OK"
|
||||||
|
except:
|
||||||
|
modules["Articles"] = "INACCESSIBLE"
|
||||||
|
|
||||||
|
diagnostic["modules_actifs"] = modules
|
||||||
|
except Exception as e:
|
||||||
|
diagnostic["modules_actifs_erreur"] = str(e)
|
||||||
|
|
||||||
|
# Compter documents existants
|
||||||
|
try:
|
||||||
|
counts = {}
|
||||||
|
factory = sage.cial.FactoryDocumentVente
|
||||||
|
|
||||||
|
for type_doc in range(6):
|
||||||
|
count = 0
|
||||||
|
index = 1
|
||||||
|
|
||||||
|
while index < 1000:
|
||||||
|
try:
|
||||||
|
persist = factory.List(index)
|
||||||
|
if persist is None:
|
||||||
|
break
|
||||||
|
|
||||||
|
doc = win32com.client.CastTo(persist, "IBODocumentVente3")
|
||||||
|
doc.Read()
|
||||||
|
|
||||||
|
if getattr(doc, "DO_Type", -1) == type_doc:
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
index += 1
|
||||||
|
except:
|
||||||
|
index += 1
|
||||||
|
break
|
||||||
|
|
||||||
|
counts[
|
||||||
|
{
|
||||||
|
0: "Devis",
|
||||||
|
1: "Bons_livraison",
|
||||||
|
2: "Bons_retour",
|
||||||
|
3: "Commandes",
|
||||||
|
4: "Preparations",
|
||||||
|
5: "Factures",
|
||||||
|
}[type_doc]
|
||||||
|
] = count
|
||||||
|
|
||||||
|
diagnostic["documents_existants"] = counts
|
||||||
|
except Exception as e:
|
||||||
|
diagnostic["documents_existants_erreur"] = str(e)
|
||||||
|
|
||||||
|
logger.info("[DIAG] Configuration Sage analysee")
|
||||||
|
|
||||||
|
return {"success": True, "diagnostic": diagnostic}
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[DIAG] Erreur diagnostic config: {e}", exc_info=True)
|
||||||
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
# =====================================================
|
# =====================================================
|
||||||
# LANCEMENT
|
# LANCEMENT
|
||||||
# =====================================================
|
# =====================================================
|
||||||
|
|
|
||||||
|
|
@ -1026,13 +1026,15 @@ class SageConnector:
|
||||||
|
|
||||||
def transformer_document(self, numero_source, type_source, type_cible):
|
def transformer_document(self, numero_source, type_source, type_cible):
|
||||||
"""
|
"""
|
||||||
Transformation de document avec gestion complète des statuts
|
Transformation de document avec la méthode NATIVE de Sage
|
||||||
|
|
||||||
CORRECTIONS:
|
CHANGEMENT MAJEUR:
|
||||||
- Pas d'émojis dans les logs
|
- Utilise TransformInto() au lieu de CreateProcess_Document()
|
||||||
- Validation stricte des statuts Sage
|
- Méthode officielle Sage pour les transformations
|
||||||
- Gestion des documents "Réalisé partiellement"
|
- Gère automatiquement les numéros, statuts, et lignes
|
||||||
- Meilleure détection d'erreurs
|
|
||||||
|
Documentation Sage:
|
||||||
|
IBODocumentVente3.TransformInto(DO_Type: int) -> IBODocumentVente3
|
||||||
"""
|
"""
|
||||||
if not self.cial:
|
if not self.cial:
|
||||||
raise RuntimeError("Connexion Sage non etablie")
|
raise RuntimeError("Connexion Sage non etablie")
|
||||||
|
|
@ -1058,8 +1060,10 @@ class SageConnector:
|
||||||
transformations_autorisees = {
|
transformations_autorisees = {
|
||||||
(0, 3): "Devis -> Commande",
|
(0, 3): "Devis -> Commande",
|
||||||
(0, 1): "Devis -> Bon de livraison",
|
(0, 1): "Devis -> Bon de livraison",
|
||||||
|
(0, 5): "Devis -> Facture", # Peut être supporté selon config
|
||||||
(3, 1): "Commande -> Bon de livraison",
|
(3, 1): "Commande -> Bon de livraison",
|
||||||
(3, 4): "Commande -> Preparation",
|
(3, 4): "Commande -> Preparation",
|
||||||
|
(3, 5): "Commande -> Facture", # Direct si autorisé
|
||||||
(1, 5): "Bon de livraison -> Facture",
|
(1, 5): "Bon de livraison -> Facture",
|
||||||
(4, 1): "Preparation -> Bon de livraison",
|
(4, 1): "Preparation -> Bon de livraison",
|
||||||
}
|
}
|
||||||
|
|
@ -1081,7 +1085,9 @@ class SageConnector:
|
||||||
persist_source = factory.ReadPiece(type_source, numero_source)
|
persist_source = factory.ReadPiece(type_source, numero_source)
|
||||||
|
|
||||||
if not persist_source:
|
if not persist_source:
|
||||||
logger.warning(f"ReadPiece failed, searching in List()...")
|
logger.warning(
|
||||||
|
f"[TRANSFORM] ReadPiece failed, searching in List()..."
|
||||||
|
)
|
||||||
persist_source = self._find_document_in_list(
|
persist_source = self._find_document_in_list(
|
||||||
numero_source, type_source
|
numero_source, type_source
|
||||||
)
|
)
|
||||||
|
|
@ -1110,14 +1116,7 @@ class SageConnector:
|
||||||
f"pas de type {type_source}"
|
f"pas de type {type_source}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# RÈGLES DE STATUT SAGE
|
# RÈGLES DE STATUT
|
||||||
# 0=Brouillon, 1=Soumis, 2=Accepte, 3=Realise partiellement,
|
|
||||||
# 4=Realise totalement, 5=Transforme, 6=Annule
|
|
||||||
|
|
||||||
# CORRECTION CRITIQUE: Statut 3 = "Réalisé partiellement"
|
|
||||||
# Cela signifie qu'une partie du document a déjà été transformée
|
|
||||||
# mais pas tout. Sage REFUSE de créer un nouveau document dans ce cas.
|
|
||||||
|
|
||||||
if statut_actuel == 5:
|
if statut_actuel == 5:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Document {numero_source} deja transforme (statut=5). "
|
f"Document {numero_source} deja transforme (statut=5). "
|
||||||
|
|
@ -1130,12 +1129,10 @@ class SageConnector:
|
||||||
f"Impossible de le transformer."
|
f"Impossible de le transformer."
|
||||||
)
|
)
|
||||||
|
|
||||||
# CORRECTION: Statut 3 ou 4 = document déjà réalisé/livré
|
|
||||||
if statut_actuel in [3, 4]:
|
if statut_actuel in [3, 4]:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Document {numero_source} deja realise (statut={statut_actuel}). "
|
f"Document {numero_source} deja realise (statut={statut_actuel}). "
|
||||||
f"Ce document a deja ete transforme partiellement ou totalement."
|
f"Ce document a deja ete transforme partiellement ou totalement."
|
||||||
f"Verifiez si une commande/BL/facture n'existe pas deja pour ce document."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Forcer statut "Accepté" si brouillon
|
# Forcer statut "Accepté" si brouillon
|
||||||
|
|
@ -1157,25 +1154,7 @@ class SageConnector:
|
||||||
f"Echec changement statut: toujours a {nouveau_statut}"
|
f"Echec changement statut: toujours a {nouveau_statut}"
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"Impossible de changer le statut: {e}")
|
||||||
f"Impossible de changer le statut du devis: {e}. "
|
|
||||||
f"Le devis doit etre accepte avant transformation."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Récupérer client
|
|
||||||
client_code = ""
|
|
||||||
try:
|
|
||||||
client_obj = getattr(doc_source, "Client", None)
|
|
||||||
if client_obj:
|
|
||||||
client_obj.Read()
|
|
||||||
client_code = getattr(client_obj, "CT_Num", "").strip()
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Erreur lecture client: {e}")
|
|
||||||
|
|
||||||
if not client_code:
|
|
||||||
raise ValueError(
|
|
||||||
f"Client introuvable pour document {numero_source}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# ===== TRANSACTION =====
|
# ===== TRANSACTION =====
|
||||||
transaction_active = False
|
transaction_active = False
|
||||||
|
|
@ -1183,27 +1162,31 @@ class SageConnector:
|
||||||
self.cial.CptaApplication.BeginTrans()
|
self.cial.CptaApplication.BeginTrans()
|
||||||
transaction_active = True
|
transaction_active = True
|
||||||
logger.debug("[TRANSFORM] Transaction demarree")
|
logger.debug("[TRANSFORM] Transaction demarree")
|
||||||
|
except AttributeError:
|
||||||
|
# BeginTrans n'existe pas sur cette version
|
||||||
|
logger.debug(
|
||||||
|
"[TRANSFORM] BeginTrans non disponible, continue sans transaction"
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"[TRANSFORM] BeginTrans echoue: {e}")
|
logger.warning(f"[TRANSFORM] BeginTrans echoue: {e}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# CRÉATION DOCUMENT CIBLE
|
# ✅✅✅ MÉTHODE NATIVE SAGE: TransformInto() ✅✅✅
|
||||||
logger.info(f"[TRANSFORM] CreateProcess_Document({type_cible})...")
|
logger.info(f"[TRANSFORM] Appel TransformInto({type_cible})...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
process = self.cial.CreateProcess_Document(type_cible)
|
# La méthode TransformInto() retourne le nouveau document
|
||||||
except Exception as e:
|
doc_cible = doc_source.TransformInto(type_cible)
|
||||||
logger.error(
|
|
||||||
f"[TRANSFORM] CreateProcess_Document echoue pour type {type_cible}: {e}"
|
if doc_cible is None:
|
||||||
)
|
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"Sage refuse de creer un document de type {type_cible}. "
|
"TransformInto() a retourne None. "
|
||||||
f"Verifiez la configuration Sage et les permissions. "
|
"Verifiez la configuration Sage et les autorisations."
|
||||||
f"Erreur: {e}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
doc_cible = process.Document
|
logger.info("[TRANSFORM] TransformInto() execute avec succes")
|
||||||
|
|
||||||
|
# Cast vers le bon type
|
||||||
try:
|
try:
|
||||||
doc_cible = win32com.client.CastTo(
|
doc_cible = win32com.client.CastTo(
|
||||||
doc_cible, "IBODocumentVente3"
|
doc_cible, "IBODocumentVente3"
|
||||||
|
|
@ -1211,186 +1194,87 @@ class SageConnector:
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
logger.info(f"[TRANSFORM] Document cible cree (type {type_cible})")
|
# Lire le document cible
|
||||||
|
doc_cible.Read()
|
||||||
|
|
||||||
# Associer client
|
# Récupérer le numéro
|
||||||
try:
|
|
||||||
factory_client = self.cial.CptaApplication.FactoryClient
|
|
||||||
persist_client = factory_client.ReadNumero(client_code)
|
|
||||||
|
|
||||||
if not persist_client:
|
|
||||||
raise ValueError(f"Client {client_code} introuvable")
|
|
||||||
|
|
||||||
client_obj_cible = win32com.client.CastTo(
|
|
||||||
persist_client, "IBOClient3"
|
|
||||||
)
|
|
||||||
client_obj_cible.Read()
|
|
||||||
doc_cible.SetDefaultClient(client_obj_cible)
|
|
||||||
doc_cible.Write()
|
|
||||||
logger.info(f"[TRANSFORM] Client {client_code} associe")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"[TRANSFORM] Erreur association client: {e}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
# Date
|
|
||||||
import pywintypes
|
|
||||||
|
|
||||||
doc_cible.DO_Date = pywintypes.Time(datetime.now())
|
|
||||||
|
|
||||||
# Référence
|
|
||||||
try:
|
|
||||||
doc_cible.DO_Ref = f"Trans. {numero_source}"
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# ===== COPIE LIGNES =====
|
|
||||||
try:
|
|
||||||
factory_lignes_source = doc_source.FactoryDocumentLigne
|
|
||||||
factory_lignes_cible = doc_cible.FactoryDocumentLigne
|
|
||||||
except:
|
|
||||||
factory_lignes_source = doc_source.FactoryDocumentVenteLigne
|
|
||||||
factory_lignes_cible = doc_cible.FactoryDocumentVenteLigne
|
|
||||||
|
|
||||||
factory_article = self.cial.FactoryArticle
|
|
||||||
index = 1
|
|
||||||
nb_lignes = 0
|
|
||||||
erreurs_lignes = []
|
|
||||||
|
|
||||||
while index <= 1000:
|
|
||||||
try:
|
|
||||||
ligne_source_p = factory_lignes_source.List(index)
|
|
||||||
if ligne_source_p is None:
|
|
||||||
break
|
|
||||||
|
|
||||||
ligne_source = win32com.client.CastTo(
|
|
||||||
ligne_source_p, "IBODocumentLigne3"
|
|
||||||
)
|
|
||||||
ligne_source.Read()
|
|
||||||
|
|
||||||
# Créer ligne cible
|
|
||||||
ligne_cible_p = factory_lignes_cible.Create()
|
|
||||||
ligne_cible = win32com.client.CastTo(
|
|
||||||
ligne_cible_p, "IBODocumentLigne3"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Récupérer article
|
|
||||||
article_ref = ""
|
|
||||||
try:
|
|
||||||
article_ref = getattr(
|
|
||||||
ligne_source, "AR_Ref", ""
|
|
||||||
).strip()
|
|
||||||
if not article_ref:
|
|
||||||
article_obj = getattr(ligne_source, "Article", None)
|
|
||||||
if article_obj:
|
|
||||||
article_obj.Read()
|
|
||||||
article_ref = getattr(
|
|
||||||
article_obj, "AR_Ref", ""
|
|
||||||
).strip()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Associer article
|
|
||||||
if article_ref:
|
|
||||||
try:
|
|
||||||
persist_article = factory_article.ReadReference(
|
|
||||||
article_ref
|
|
||||||
)
|
|
||||||
if persist_article:
|
|
||||||
article_obj = win32com.client.CastTo(
|
|
||||||
persist_article, "IBOArticle3"
|
|
||||||
)
|
|
||||||
article_obj.Read()
|
|
||||||
|
|
||||||
quantite = float(
|
|
||||||
getattr(ligne_source, "DL_Qte", 1.0)
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
ligne_cible.SetDefaultArticleReference(
|
|
||||||
article_ref, quantite
|
|
||||||
)
|
|
||||||
except:
|
|
||||||
ligne_cible.SetDefaultArticle(
|
|
||||||
article_obj, quantite
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
logger.debug(
|
|
||||||
f"Erreur association article {article_ref}: {e}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Copier propriétés
|
|
||||||
ligne_cible.DL_Design = getattr(
|
|
||||||
ligne_source, "DL_Design", ""
|
|
||||||
)
|
|
||||||
ligne_cible.DL_Qte = float(
|
|
||||||
getattr(ligne_source, "DL_Qte", 0.0)
|
|
||||||
)
|
|
||||||
ligne_cible.DL_PrixUnitaire = float(
|
|
||||||
getattr(ligne_source, "DL_PrixUnitaire", 0.0)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Remise
|
|
||||||
try:
|
|
||||||
remise = float(
|
|
||||||
getattr(ligne_source, "DL_Remise01REM_Valeur", 0.0)
|
|
||||||
)
|
|
||||||
if remise > 0:
|
|
||||||
ligne_cible.DL_Remise01REM_Valeur = remise
|
|
||||||
ligne_cible.DL_Remise01REM_Type = 0
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
ligne_cible.Write()
|
|
||||||
nb_lignes += 1
|
|
||||||
index += 1
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
erreurs_lignes.append(f"Ligne {index}: {str(e)}")
|
|
||||||
logger.debug(f"Erreur ligne {index}: {e}")
|
|
||||||
index += 1
|
|
||||||
if index > 1000:
|
|
||||||
break
|
|
||||||
|
|
||||||
if nb_lignes == 0:
|
|
||||||
raise RuntimeError(
|
|
||||||
f"Aucune ligne copiee. Erreurs: {'; '.join(erreurs_lignes)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info(f"[TRANSFORM] {nb_lignes} lignes copiees")
|
|
||||||
|
|
||||||
# ===== VALIDATION =====
|
|
||||||
doc_cible.Write()
|
|
||||||
logger.info("[TRANSFORM] Document cible ecrit")
|
|
||||||
|
|
||||||
process.Process()
|
|
||||||
logger.info("[TRANSFORM] Process() execute")
|
|
||||||
|
|
||||||
# Récupérer numéro
|
|
||||||
numero_cible = None
|
|
||||||
try:
|
|
||||||
doc_result = process.DocumentResult
|
|
||||||
if doc_result:
|
|
||||||
doc_result = win32com.client.CastTo(
|
|
||||||
doc_result, "IBODocumentVente3"
|
|
||||||
)
|
|
||||||
doc_result.Read()
|
|
||||||
numero_cible = getattr(doc_result, "DO_Piece", "")
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not numero_cible:
|
|
||||||
numero_cible = getattr(doc_cible, "DO_Piece", "")
|
numero_cible = getattr(doc_cible, "DO_Piece", "")
|
||||||
|
|
||||||
if not numero_cible:
|
if not numero_cible:
|
||||||
raise RuntimeError("Numero document cible vide apres creation")
|
raise RuntimeError(
|
||||||
|
"Numero document cible vide apres transformation"
|
||||||
|
)
|
||||||
|
|
||||||
# Commit
|
# Compter les lignes
|
||||||
|
try:
|
||||||
|
factory_lignes = doc_cible.FactoryDocumentLigne
|
||||||
|
except:
|
||||||
|
factory_lignes = doc_cible.FactoryDocumentVenteLigne
|
||||||
|
|
||||||
|
nb_lignes = 0
|
||||||
|
index = 1
|
||||||
|
while index <= 1000:
|
||||||
|
try:
|
||||||
|
ligne_p = factory_lignes.List(index)
|
||||||
|
if ligne_p is None:
|
||||||
|
break
|
||||||
|
nb_lignes += 1
|
||||||
|
index += 1
|
||||||
|
except:
|
||||||
|
break
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"[TRANSFORM] Document cible cree: {numero_cible} avec {nb_lignes} lignes"
|
||||||
|
)
|
||||||
|
|
||||||
|
except AttributeError as e:
|
||||||
|
# TransformInto() n'existe pas sur cette version de Sage
|
||||||
|
logger.error(f"[TRANSFORM] TransformInto() non disponible: {e}")
|
||||||
|
raise RuntimeError(
|
||||||
|
f"La methode TransformInto() n'est pas disponible sur votre version de Sage 100c. "
|
||||||
|
f"Vous devez soit: "
|
||||||
|
f"(1) Mettre a jour Sage, ou "
|
||||||
|
f"(2) Activer le module de gestion commerciale pour les commandes, ou "
|
||||||
|
f"(3) Utiliser l'interface Sage manuellement pour les transformations."
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[TRANSFORM] TransformInto() echoue: {e}")
|
||||||
|
|
||||||
|
# Essayer de déterminer la cause
|
||||||
|
if "Valeur invalide" in str(e):
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Sage refuse la transformation vers le type {type_cible}. "
|
||||||
|
f"Causes possibles:\n"
|
||||||
|
f"1. Le module 'Commandes' n'est pas active dans votre licence Sage\n"
|
||||||
|
f"2. L'utilisateur n'a pas les droits sur ce type de document\n"
|
||||||
|
f"3. La configuration Sage bloque ce type de transformation\n"
|
||||||
|
f"4. Il manque des parametres obligatoires (depot, tarif, etc.)\n\n"
|
||||||
|
f"Verifiez dans Sage: Fichier > Autorisations > Gestion Commerciale"
|
||||||
|
)
|
||||||
|
elif "Acces refuse" in str(e) or "Access denied" in str(e):
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Acces refuse pour creer une commande (type {type_cible}). "
|
||||||
|
f"Verifiez les droits utilisateur dans Sage: "
|
||||||
|
f"Fichier > Autorisations > Votre utilisateur"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Erreur Sage lors de la transformation: {e}\n"
|
||||||
|
f"Consultez les logs Sage pour plus de details."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Commit transaction
|
||||||
if transaction_active:
|
if transaction_active:
|
||||||
|
try:
|
||||||
self.cial.CptaApplication.CommitTrans()
|
self.cial.CptaApplication.CommitTrans()
|
||||||
logger.info("[TRANSFORM] Transaction committee")
|
logger.info("[TRANSFORM] Transaction committee")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# MAJ statut source -> Transformé
|
# MAJ statut source -> Transformé
|
||||||
try:
|
try:
|
||||||
|
doc_source.Read() # Re-lire au cas où
|
||||||
doc_source.DO_Statut = 5
|
doc_source.DO_Statut = 5
|
||||||
doc_source.Write()
|
doc_source.Write()
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|
@ -1446,6 +1330,7 @@ class SageConnector:
|
||||||
getattr(doc, "DO_Type", -1) == type_doc
|
getattr(doc, "DO_Type", -1) == type_doc
|
||||||
and getattr(doc, "DO_Piece", "") == numero
|
and getattr(doc, "DO_Piece", "") == numero
|
||||||
):
|
):
|
||||||
|
logger.info(f"[TRANSFORM] Document trouve a l'index {index}")
|
||||||
return persist
|
return persist
|
||||||
|
|
||||||
index += 1
|
index += 1
|
||||||
|
|
@ -1454,7 +1339,8 @@ class SageConnector:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return None
|
return None
|
||||||
except:
|
except Exception as e:
|
||||||
|
logger.error(f"[TRANSFORM] Erreur recherche document: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue