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

571
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...")
]
crystal = None chemins_installation = [
prog_id_utilisee = None 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",
]
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:
print(f" ❌ Absent : {chemin}")
if not crystal: if not crystal_trouve:
print("\n❌ ÉCHEC : Aucune version de Crystal disponible") print("\nPROBLÈME MAJEUR : Crystal Reports n'est pas installé")
print(" → Vérifier installation") problemes.append("Crystal Reports non installé")
print(" → Redémarrer le serveur si juste installé") solutions.append("Télécharger et installer SAP Crystal Reports Runtime")
return False return {"problemes": problemes, "solutions": solutions, "installe": False}
print(f"\n✅ Crystal opérationnel : {prog_id_utilisee}") # ==========================================
# 2. CHERCHER LES DLL CRITIQUES
# ==========================================
print("\n📦 2. Recherche DLL critiques...")
# 2. Vérifier méthodes disponibles dll_critiques = {
print("\n2. Vérification méthodes d'export...") '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',
}
methodes_requises = ['OpenReport', 'Export'] dll_trouvees = {}
for methode in methodes_requises: for dll_nom, description in dll_critiques.items():
if hasattr(crystal, methode): trouve = False
print(f"{methode}()")
else:
print(f"{methode}() manquante")
print("\n✅ Crystal Reports est prêt pour générer des PDF !") for root, dirs, files in os.walk(chemin_crystal):
return True 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
except Exception as e: if not trouve:
print(f"\n❌ ERREUR : {e}") print(f"{dll_nom} - {description}")
return False 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")
def tester_pdf_avec_sage(sage_connector, numero: str, type_doc: int): # ==========================================
""" # 3. VÉRIFIER LE REGISTRE
Test de génération PDF via Sage avec Crystal # ==========================================
print("\n📋 3. Vérification registre Windows...")
Args: prog_ids = [
sage_connector: Instance de ton SageConnector "CrystalRuntime.Application.140",
numero: Numéro document (ex: "FA00123") "CrystalRuntime.Application.13",
type_doc: Type document (0=devis, 60=facture, etc.) "CrystalRuntime.Application.12",
"CrystalRuntime.Application",
"CrystalDesignRunTime.Application",
]
Returns: prog_ids_trouves = []
tuple: (success: bool, pdf_bytes: bytes, message: str)
""" for prog_id in prog_ids:
print("\n" + "="*70) try:
print(f"🧪 TEST GÉNÉRATION PDF SAGE + CRYSTAL") # Vérifier existence
print(f" Document: {numero} (type={type_doc})") key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, prog_id)
print("="*70) 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"
}
)
else:
# Analyser erreur
analyser_erreur_generation(message)
from fastapi import HTTPException services_trouves = []
raise HTTPException( for service in services_crystal_attendus:
status_code=500, if service.lower() in result.stdout.lower():
detail={ services_trouves.append(service)
"error": message, print(f" ✅ Service trouvé: {service}")
"recommandation": "Consulter les logs pour analyse détaillée"
} 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")
# Lister méthodes disponibles
print(f" Méthodes disponibles:")
for attr in dir(obj):
if not attr.startswith('_') and callable(getattr(obj, attr, None)):
print(f" - {attr}()")
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")