creer_client opérationelle

This commit is contained in:
mickael 2025-12-26 09:35:25 +01:00
parent 57c05082c0
commit 557f43bd18
3 changed files with 717 additions and 819 deletions

12
diagnostic_crystal.txt Normal file
View file

@ -0,0 +1,12 @@
======================================================================
DIAGNOSTIC CRYSTAL REPORTS
======================================================================
Installation détectée: True
DLL trouvées:
ProgID valides:
Architecture OK: False
PROBLÈMES:
SOLUTIONS:

File diff suppressed because it is too large Load diff

539
test.py
View file

@ -1,316 +1,323 @@
""" """
🧪 TEST GÉNÉRATION PDF AVEC CRYSTAL REPORTS 🔬 DIAGNOSTIC APPROFONDI CRYSTAL REPORTS
À lancer immédiatement après installation Crystal Découvre pourquoi Crystal ne fonctionne pas après redémarrage
""" """
import win32com.client
import os import os
import time import winreg
import logging import subprocess
import sys
logger = logging.getLogger(__name__) def diagnostic_complet_crystal():
"""Diagnostic exhaustif de l'installation Crystal"""
print("="*70)
def test_crystal_pdf_simple(): print("🔬 DIAGNOSTIC APPROFONDI CRYSTAL REPORTS")
"""
Test rapide de Crystal Reports - sans Sage
Vérifie juste que Crystal peut s'instancier et exporter
"""
print("\n" + "="*70)
print("🧪 TEST CRYSTAL REPORTS - INSTANCIATION SIMPLE")
print("="*70) print("="*70)
try: problemes = []
# 1. Instancier Crystal solutions = []
print("\n1. Instanciation Crystal Runtime...")
prog_ids = [ # ==========================================
"CrystalRuntime.Application.140", # 1. VÉRIFIER SI CRYSTAL EST INSTALLÉ
"CrystalRuntime.Application.13", # ==========================================
"CrystalRuntime.Application.12", print("\n📁 1. Vérification présence des fichiers...")
chemins_installation = [
r"C:\Program Files\SAP BusinessObjects",
r"C:\Program Files (x86)\SAP BusinessObjects",
r"C:\Program Files\SAP\Crystal Reports",
r"C:\Program Files (x86)\SAP\Crystal Reports",
] ]
crystal = None crystal_trouve = False
prog_id_utilisee = None chemin_crystal = None
for prog_id in prog_ids: for chemin in chemins_installation:
if os.path.exists(chemin):
print(f" ✅ Dossier trouvé : {chemin}")
crystal_trouve = True
chemin_crystal = chemin
# Afficher taille
try: try:
crystal = win32com.client.Dispatch(prog_id) total_size = 0
prog_id_utilisee = prog_id for dirpath, dirnames, filenames in os.walk(chemin):
print(f"{prog_id}") for f in filenames:
break fp = os.path.join(dirpath, f)
except Exception as e:
print(f"{prog_id}: {e}")
if not crystal:
print("\n❌ ÉCHEC : Aucune version de Crystal disponible")
print(" → Vérifier installation")
print(" → Redémarrer le serveur si juste installé")
return False
print(f"\n✅ Crystal opérationnel : {prog_id_utilisee}")
# 2. Vérifier méthodes disponibles
print("\n2. Vérification méthodes d'export...")
methodes_requises = ['OpenReport', 'Export']
for methode in methodes_requises:
if hasattr(crystal, methode):
print(f"{methode}()")
else:
print(f"{methode}() manquante")
print("\n✅ Crystal Reports est prêt pour générer des PDF !")
return True
except Exception as e:
print(f"\n❌ ERREUR : {e}")
return False
def tester_pdf_avec_sage(sage_connector, numero: str, type_doc: int):
"""
Test de génération PDF via Sage avec Crystal
Args:
sage_connector: Instance de ton SageConnector
numero: Numéro document (ex: "FA00123")
type_doc: Type document (0=devis, 60=facture, etc.)
Returns:
tuple: (success: bool, pdf_bytes: bytes, message: str)
"""
print("\n" + "="*70)
print(f"🧪 TEST GÉNÉRATION PDF SAGE + CRYSTAL")
print(f" Document: {numero} (type={type_doc})")
print("="*70)
try: try:
# 1. Vérifier connexion Sage total_size += os.path.getsize(fp)
if not sage_connector.cial:
return False, None, "Connexion Sage non établie"
print("\n1. ✅ Connexion Sage OK")
# 2. Vérifier Crystal
print("\n2. Vérification Crystal...")
prog_ids = [
"CrystalRuntime.Application.140",
"CrystalRuntime.Application.13",
"CrystalRuntime.Application.12",
]
crystal_ok = False
for prog_id in prog_ids:
try:
test = win32com.client.Dispatch(prog_id)
crystal_ok = True
print(f" ✅ Crystal disponible : {prog_id}")
break
except: except:
pass pass
if not crystal_ok: size_mb = total_size / (1024 * 1024)
return False, None, "Crystal Reports non disponible - Redémarrer le serveur" print(f" Taille : {size_mb:.1f} MB")
# 3. Chercher modèle .BGC if size_mb < 100:
print("\n3. Recherche modèle Crystal...") print(f" ⚠️ Taille suspecte (attendu: 300-800 MB)")
problemes.append("Installation incomplète (taille trop petite)")
modeles = sage_connector.lister_modeles_crystal() except Exception as e:
print(f" ⚠️ Impossible de calculer taille : {e}")
else:
print(f" ❌ Absent : {chemin}")
# Déterminer catégorie if not crystal_trouve:
mapping = {0: "devis", 10: "commandes", 30: "livraisons", 60: "factures", 50: "avoirs"} print("\n❌ PROBLÈME MAJEUR : Crystal Reports n'est pas installé")
categorie = mapping.get(type_doc, "autres") problemes.append("Crystal Reports non installé")
solutions.append("Télécharger et installer SAP Crystal Reports Runtime")
return {"problemes": problemes, "solutions": solutions, "installe": False}
if categorie not in modeles or not modeles[categorie]: # ==========================================
return False, None, f"Aucun modèle trouvé pour type {type_doc}" # 2. CHERCHER LES DLL CRITIQUES
# ==========================================
print("\n📦 2. Recherche DLL critiques...")
modele = modeles[categorie][0] dll_critiques = {
chemin_modele = modele["chemin_complet"] 'crpe32.dll': 'Crystal Reports Print Engine (CRITIQUE)',
'crxf_pdf.dll': 'Export PDF (CRITIQUE)',
'crdb_adoplus.dll': 'Connexion base de données',
'CrystalDecisions.CrystalReports.Engine.dll': 'Moteur Crystal .NET',
}
print(f" ✅ Modèle : {modele['fichier']}") dll_trouvees = {}
print(f" 📁 Chemin : {chemin_modele}")
if not os.path.exists(chemin_modele): for dll_nom, description in dll_critiques.items():
return False, None, f"Fichier modèle introuvable : {chemin_modele}" trouve = False
# 4. Générer PDF for root, dirs, files in os.walk(chemin_crystal):
print("\n4. Génération PDF...") if dll_nom.lower() in [f.lower() for f in files]:
print(" ⏳ Traitement en cours...") dll_path = os.path.join(root, dll_nom)
dll_trouvees[dll_nom] = dll_path
print(f"{dll_nom}")
print(f" {dll_path}")
trouve = True
break
start_time = time.time() if not trouve:
print(f"{dll_nom} - {description}")
if "CRITIQUE" in description:
problemes.append(f"{dll_nom} manquante")
if len(dll_trouvees) < 2:
print("\n ⚠️ Trop peu de DLL trouvées - Installation corrompue")
problemes.append("DLL manquantes - Installation corrompue")
solutions.append("Réinstaller Crystal Reports Runtime")
# ==========================================
# 3. VÉRIFIER LE REGISTRE
# ==========================================
print("\n📋 3. Vérification registre Windows...")
prog_ids = [
"CrystalRuntime.Application.140",
"CrystalRuntime.Application.13",
"CrystalRuntime.Application.12",
"CrystalRuntime.Application",
"CrystalDesignRunTime.Application",
]
prog_ids_trouves = []
for prog_id in prog_ids:
try:
# Vérifier existence
key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, prog_id)
print(f"{prog_id}")
# Lire le CLSID
try:
clsid_key = winreg.OpenKey(key, "CLSID")
clsid, _ = winreg.QueryValueEx(clsid_key, "")
print(f" CLSID: {clsid}")
# Vérifier que le CLSID existe aussi
try:
clsid_path = f"CLSID\\{clsid}"
clsid_key_check = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, clsid_path)
# Lire InprocServer32 (chemin DLL)
try:
server_key = winreg.OpenKey(clsid_key_check, "InprocServer32")
dll_path, _ = winreg.QueryValueEx(server_key, "")
print(f" DLL: {dll_path}")
# Vérifier que la DLL existe
if not os.path.exists(dll_path):
print(f" ❌ DLL INTROUVABLE: {dll_path}")
problemes.append(f"{prog_id}: DLL manquante ({dll_path})")
else:
prog_ids_trouves.append(prog_id)
except:
print(f" ⚠️ InprocServer32 non trouvé")
except:
print(f" ❌ CLSID {clsid} non trouvé dans registre")
problemes.append(f"{prog_id}: CLSID cassé")
except:
print(f" ⚠️ Pas de CLSID")
winreg.CloseKey(key)
except:
print(f"{prog_id}")
if not prog_ids_trouves:
print("\n ⚠️ Aucun ProgID valide - Enregistrement COM échoué")
problemes.append("ProgID non enregistrés correctement")
solutions.append("Réenregistrer les DLL Crystal avec regsvr32")
# ==========================================
# 4. VÉRIFIER ARCHITECTURE (32 vs 64 bit)
# ==========================================
print("\n🔧 4. Vérification architecture...")
# Architecture Python
python_arch = "64-bit" if sys.maxsize > 2**32 else "32-bit"
print(f" Python : {python_arch}")
# Architecture système
import platform
sys_arch = platform.machine()
print(f" Système : {sys_arch}")
# Détecter architecture Crystal installée
crystal_arch = None
if dll_trouvees:
first_dll = list(dll_trouvees.values())[0]
if "win64_x64" in first_dll or "x64" in first_dll:
crystal_arch = "64-bit"
elif "win32_x86" in first_dll or "x86" in first_dll:
crystal_arch = "32-bit"
if crystal_arch:
print(f" Crystal : {crystal_arch}")
if python_arch != crystal_arch:
print(f"\n ❌ INCOMPATIBILITÉ ARCHITECTURE")
print(f" Python {python_arch} ne peut pas utiliser Crystal {crystal_arch}")
problemes.append(f"Incompatibilité: Python {python_arch} vs Crystal {crystal_arch}")
solutions.append(f"Réinstaller Crystal en version {python_arch}")
# ==========================================
# 5. VÉRIFIER SERVICES WINDOWS
# ==========================================
print("\n🔄 5. Vérification services Windows...")
try: try:
# Utiliser ta méthode existante result = subprocess.run(
pdf_bytes = sage_connector.generer_pdf_document( ['sc', 'query', 'type=', 'service'],
numero=numero, capture_output=True,
type_doc=type_doc, text=True,
modele=modele["fichier"] timeout=10
) )
elapsed = time.time() - start_time services_crystal_attendus = [
"SAP Crystal Reports",
"Crystal Reports",
"CrystalReports",
]
if pdf_bytes and len(pdf_bytes) > 500: services_trouves = []
print(f"\n✅ PDF GÉNÉRÉ AVEC SUCCÈS !") for service in services_crystal_attendus:
print(f" 📊 Taille : {len(pdf_bytes):,} octets") if service.lower() in result.stdout.lower():
print(f" ⏱️ Temps : {elapsed:.2f}s") services_trouves.append(service)
print(f" ✅ Service trouvé: {service}")
return True, pdf_bytes, "Succès" if not services_trouves:
else: print(f" ⚠️ Aucun service Crystal trouvé")
return False, None, "PDF généré mais vide ou corrompu" print(f" (Normal pour Runtime léger)")
except Exception as e: except Exception as e:
elapsed = time.time() - start_time print(f" ⚠️ Impossible de vérifier services: {e}")
print(f"\n❌ ÉCHEC après {elapsed:.2f}s")
print(f" Erreur : {e}")
return False, None, str(e) # ==========================================
# 6. TEST INSTANCIATION COM DÉTAILLÉ
# ==========================================
print("\n🧪 6. Test instanciation COM détaillé...")
except Exception as e: import win32com.client
logger.error(f"Erreur test PDF : {e}", exc_info=True)
return False, None, str(e)
for prog_id in prog_ids_trouves:
print(f"\n Test: {prog_id}")
try:
obj = win32com.client.Dispatch(prog_id)
print(f" ✅ Instanciation RÉUSSIE")
def analyser_erreur_generation(erreur_msg: str): # Lister méthodes disponibles
""" print(f" Méthodes disponibles:")
Analyse une erreur de génération PDF et propose solutions for attr in dir(obj):
""" if not attr.startswith('_') and callable(getattr(obj, attr, None)):
print("\n" + "="*70) print(f" - {attr}()")
print("🔍 ANALYSE DE L'ERREUR")
print("="*70)
erreur_lower = erreur_msg.lower()
if "access" in erreur_lower or "permission" in erreur_lower:
print("""
PROBLÈME : Permissions fichiers
💡 SOLUTIONS :
1. Vérifier que le dossier temporaire est accessible :
icacls "C:\\Windows\\Temp" /grant Everyone:(OI)(CI)F /T
2. Vérifier permissions modèles .BGC :
icacls "C:\\Users\\Public\\Documents\\Sage" /grant Everyone:(OI)(CI)R /T
3. Exécuter l'application avec droits admin (temporairement)
""")
elif "not found" in erreur_lower or "introuvable" in erreur_lower:
print("""
PROBLÈME : Fichier modèle introuvable
💡 SOLUTIONS :
1. Vérifier que le modèle .BGC existe :
dir "C:\\Users\\Public\\Documents\\Sage\\Entreprise 100c\\*.bgc" /s
2. Spécifier le chemin complet du modèle
3. Utiliser un modèle par défaut Sage
""")
elif "com" in erreur_lower or "dispatch" in erreur_lower:
print("""
PROBLÈME : Erreur COM / Crystal Runtime
💡 SOLUTIONS :
1. REDÉMARRER LE SERVEUR (recommandé)
shutdown /r /t 60
2. Réenregistrer les DLL Crystal :
cd "C:\\Program Files\\SAP BusinessObjects\\Crystal Reports for .NET Framework 4.0\\Common\\SAP BusinessObjects Enterprise XI 4.0\\win64_x64"
regsvr32 /s crpe32.dll
regsvr32 /s crxf_pdf.dll
3. Vérifier que les services Crystal sont démarrés :
sc start "SAP Crystal Reports Processing Server"
""")
elif "database" in erreur_lower or "connexion" in erreur_lower:
print("""
PROBLÈME : Connexion base de données
💡 SOLUTIONS :
1. Le modèle Crystal doit pouvoir se connecter à la base Sage
2. Vérifier les paramètres de connexion dans le modèle
3. Utiliser l'API Sage pour passer les données au lieu de
connecter Crystal directement à la base
""")
else:
print(f"""
ERREUR : {erreur_msg}
💡 SOLUTIONS GÉNÉRIQUES :
1. Redémarrer le serveur
2. Vérifier les logs détaillés
3. Tester avec un modèle Crystal simple
4. Utiliser PDF custom en attendant
""")
print("="*70)
# Routes API pour tests
def creer_routes_test(app, sage_connector):
"""
Ajouter ces routes dans main.py pour tester facilement
"""
@app.get("/sage/test-crystal-simple")
async def test_crystal_simple():
"""Test Crystal sans Sage"""
success = test_crystal_pdf_simple()
return { return {
"success": success, "problemes": problemes,
"message": "Crystal opérationnel" if success else "Crystal non disponible" "solutions": solutions,
"installe": True,
"prog_id_fonctionnel": prog_id
} }
@app.get("/sage/test-pdf-complet") except Exception as e:
async def test_pdf_complet( print(f" ❌ Échec: {e}")
numero: str = "FA00123", print(f" Type erreur: {type(e).__name__}")
type_doc: int = 60 print(f" Code: {e.args if hasattr(e, 'args') else 'N/A'}")
):
"""Test génération PDF complète avec Sage + Crystal"""
success, pdf_bytes, message = tester_pdf_avec_sage( # ==========================================
sage_connector, numero, type_doc # 7. RÉSUMÉ ET RECOMMANDATIONS
) # ==========================================
print("\n" + "="*70)
print("📊 RÉSUMÉ DU DIAGNOSTIC")
print("="*70)
if success: print(f"\n📁 Installation détectée: {'OUI' if crystal_trouve else 'NON'}")
from fastapi.responses import Response print(f"📦 DLL trouvées: {len(dll_trouvees)}/{len(dll_critiques)}")
return Response( print(f"📋 ProgID valides: {len(prog_ids_trouves)}")
content=pdf_bytes, print(f"🔧 Architecture: Python {python_arch}, Crystal {crystal_arch or 'INCONNUE'}")
media_type="application/pdf",
headers={ if problemes:
"Content-Disposition": f"attachment; filename={numero}.pdf" print(f"\n❌ PROBLÈMES DÉTECTÉS ({len(problemes)}):")
for i, pb in enumerate(problemes, 1):
print(f" {i}. {pb}")
if solutions:
print(f"\n💡 SOLUTIONS RECOMMANDÉES:")
for i, sol in enumerate(solutions, 1):
print(f" {i}. {sol}")
print("\n" + "="*70)
return {
"problemes": problemes,
"solutions": solutions,
"installe": crystal_trouve,
"dll_trouvees": list(dll_trouvees.keys()),
"prog_ids_valides": prog_ids_trouves,
"architecture_ok": python_arch == crystal_arch if crystal_arch else False
} }
)
else:
# Analyser erreur
analyser_erreur_generation(message)
from fastapi import HTTPException
raise HTTPException(
status_code=500,
detail={
"error": message,
"recommandation": "Consulter les logs pour analyse détaillée"
}
)
if __name__ == "__main__": if __name__ == "__main__":
print("🚀 LANCEMENT TESTS CRYSTAL REPORTS") resultats = diagnostic_complet_crystal()
# Test 1 : Crystal seul print("\n💾 Résultats sauvegardés dans diagnostic_crystal.txt")
crystal_ok = test_crystal_pdf_simple()
if not crystal_ok: # Sauvegarder dans fichier
print("\n⚠️ Crystal non opérationnel") with open("diagnostic_crystal.txt", "w", encoding="utf-8") as f:
print(" → Redémarrer le serveur et relancer") f.write("="*70 + "\n")
else: f.write("DIAGNOSTIC CRYSTAL REPORTS\n")
print("\n✅ Crystal OK - Prêt pour génération PDF avec Sage") f.write("="*70 + "\n\n")
f.write(f"Installation détectée: {resultats['installe']}\n")
f.write(f"DLL trouvées: {', '.join(resultats.get('dll_trouvees', []))}\n")
f.write(f"ProgID valides: {', '.join(resultats.get('prog_ids_valides', []))}\n")
f.write(f"Architecture OK: {resultats.get('architecture_ok', False)}\n\n")
f.write("PROBLÈMES:\n")
for pb in resultats['problemes']:
f.write(f" - {pb}\n")
f.write("\nSOLUTIONS:\n")
for sol in resultats['solutions']:
f.write(f" - {sol}\n")