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

597
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"""
def test_crystal_pdf_simple(): print("="*70)
""" 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 = [ # 1. VÉRIFIER SI CRYSTAL EST INSTALLÉ
"CrystalRuntime.Application.140", # ==========================================
"CrystalRuntime.Application.13", print("\n📁 1. Vérification présence des fichiers...")
"CrystalRuntime.Application.12",
] chemins_installation = [
r"C:\Program Files\SAP BusinessObjects",
crystal = None r"C:\Program Files (x86)\SAP BusinessObjects",
prog_id_utilisee = None r"C:\Program Files\SAP\Crystal Reports",
r"C:\Program Files (x86)\SAP\Crystal Reports",
for prog_id in prog_ids: ]
crystal_trouve = False
chemin_crystal = None
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)
try:
total_size += os.path.getsize(fp)
except:
pass
size_mb = total_size / (1024 * 1024)
print(f" Taille : {size_mb:.1f} MB")
if size_mb < 100:
print(f" ⚠️ Taille suspecte (attendu: 300-800 MB)")
problemes.append("Installation incomplète (taille trop petite)")
except Exception as e: except Exception as e:
print(f"{prog_id}: {e}") print(f" ⚠️ Impossible de calculer taille : {e}")
else:
if not crystal: print(f" ❌ Absent : {chemin}")
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: if not crystal_trouve:
sage_connector: Instance de ton SageConnector print("\n❌ PROBLÈME MAJEUR : Crystal Reports n'est pas installé")
numero: Numéro document (ex: "FA00123") problemes.append("Crystal Reports non installé")
type_doc: Type document (0=devis, 60=facture, etc.) solutions.append("Télécharger et installer SAP Crystal Reports Runtime")
return {"problemes": problemes, "solutions": solutions, "installe": False}
Returns: # ==========================================
tuple: (success: bool, pdf_bytes: bytes, message: str) # 2. CHERCHER LES DLL CRITIQUES
""" # ==========================================
print("\n" + "="*70) print("\n📦 2. Recherche DLL critiques...")
print(f"🧪 TEST GÉNÉRATION PDF SAGE + CRYSTAL")
print(f" Document: {numero} (type={type_doc})") dll_critiques = {
print("="*70) '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',
}
dll_trouvees = {}
for dll_nom, description in dll_critiques.items():
trouve = False
for root, dirs, files in os.walk(chemin_crystal):
if dll_nom.lower() in [f.lower() for f in files]:
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
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:
# 1. Vérifier connexion Sage result = subprocess.run(
if not sage_connector.cial: ['sc', 'query', 'type=', 'service'],
return False, None, "Connexion Sage non établie" capture_output=True,
text=True,
print("\n1. ✅ Connexion Sage OK") timeout=10
# 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:
pass
if not crystal_ok:
return False, None, "Crystal Reports non disponible - Redémarrer le serveur"
# 3. Chercher modèle .BGC
print("\n3. Recherche modèle Crystal...")
modeles = sage_connector.lister_modeles_crystal()
# Déterminer catégorie
mapping = {0: "devis", 10: "commandes", 30: "livraisons", 60: "factures", 50: "avoirs"}
categorie = mapping.get(type_doc, "autres")
if categorie not in modeles or not modeles[categorie]:
return False, None, f"Aucun modèle trouvé pour type {type_doc}"
modele = modeles[categorie][0]
chemin_modele = modele["chemin_complet"]
print(f" ✅ Modèle : {modele['fichier']}")
print(f" 📁 Chemin : {chemin_modele}")
if not os.path.exists(chemin_modele):
return False, None, f"Fichier modèle introuvable : {chemin_modele}"
# 4. Générer PDF
print("\n4. Génération PDF...")
print(" ⏳ Traitement en cours...")
start_time = time.time()
try:
# Utiliser ta méthode existante
pdf_bytes = sage_connector.generer_pdf_document(
numero=numero,
type_doc=type_doc,
modele=modele["fichier"]
)
elapsed = time.time() - start_time
if pdf_bytes and len(pdf_bytes) > 500:
print(f"\n✅ PDF GÉNÉRÉ AVEC SUCCÈS !")
print(f" 📊 Taille : {len(pdf_bytes):,} octets")
print(f" ⏱️ Temps : {elapsed:.2f}s")
return True, pdf_bytes, "Succès"
else:
return False, None, "PDF généré mais vide ou corrompu"
except Exception as e:
elapsed = time.time() - start_time
print(f"\n❌ ÉCHEC après {elapsed:.2f}s")
print(f" Erreur : {e}")
return False, None, str(e)
except Exception as e:
logger.error(f"Erreur test PDF : {e}", exc_info=True)
return False, None, str(e)
def analyser_erreur_generation(erreur_msg: str):
"""
Analyse une erreur de génération PDF et propose solutions
"""
print("\n" + "="*70)
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 {
"success": success,
"message": "Crystal opérationnel" if success else "Crystal non disponible"
}
@app.get("/sage/test-pdf-complet")
async def test_pdf_complet(
numero: str = "FA00123",
type_doc: int = 60
):
"""Test génération PDF complète avec Sage + Crystal"""
success, pdf_bytes, message = tester_pdf_avec_sage(
sage_connector, numero, type_doc
) )
if success: services_crystal_attendus = [
from fastapi.responses import Response "SAP Crystal Reports",
return Response( "Crystal Reports",
content=pdf_bytes, "CrystalReports",
media_type="application/pdf", ]
headers={
"Content-Disposition": f"attachment; filename={numero}.pdf" services_trouves = []
} for service in services_crystal_attendus:
) if service.lower() in result.stdout.lower():
else: services_trouves.append(service)
# Analyser erreur print(f" ✅ Service trouvé: {service}")
analyser_erreur_generation(message)
if not services_trouves:
print(f" ⚠️ Aucun service Crystal trouvé")
print(f" (Normal pour Runtime léger)")
except Exception as e:
print(f" ⚠️ Impossible de vérifier services: {e}")
# ==========================================
# 6. TEST INSTANCIATION COM DÉTAILLÉ
# ==========================================
print("\n🧪 6. Test instanciation COM détaillé...")
import win32com.client
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")
from fastapi import HTTPException # Lister méthodes disponibles
raise HTTPException( print(f" Méthodes disponibles:")
status_code=500, for attr in dir(obj):
detail={ if not attr.startswith('_') and callable(getattr(obj, attr, None)):
"error": message, print(f" - {attr}()")
"recommandation": "Consulter les logs pour analyse détaillée"
} return {
) "problemes": problemes,
"solutions": solutions,
"installe": True,
"prog_id_fonctionnel": prog_id
}
except Exception as e:
print(f" ❌ Échec: {e}")
print(f" Type erreur: {type(e).__name__}")
print(f" Code: {e.args if hasattr(e, 'args') else 'N/A'}")
# ==========================================
# 7. RÉSUMÉ ET RECOMMANDATIONS
# ==========================================
print("\n" + "="*70)
print("📊 RÉSUMÉ DU DIAGNOSTIC")
print("="*70)
print(f"\n📁 Installation détectée: {'OUI' if crystal_trouve else 'NON'}")
print(f"📦 DLL trouvées: {len(dll_trouvees)}/{len(dll_critiques)}")
print(f"📋 ProgID valides: {len(prog_ids_trouves)}")
print(f"🔧 Architecture: Python {python_arch}, Crystal {crystal_arch or 'INCONNUE'}")
if problemes:
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
}
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")