This commit is contained in:
Ladebeze66 2025-03-18 11:24:17 +01:00
parent ebf80209df
commit 6d21fd5b61
12 changed files with 105 additions and 68 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/odtkit

View File

@ -0,0 +1,2 @@
odoorpc
bs4

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,5 @@
from ticket_manager import TicketManager
from utils import get_user_choice
# Initialisation de l'objet
ticket_manager = TicketManager()

View File

@ -1,7 +1,7 @@
from odoo_connection import OdooConnection
import os
import json
from utils import save_json, ensure_export_directory
from utils import save_json, ensure_export_directory, print_error
from config import EXPORT_DIR
from data_filter import filter_ticket_data
@ -14,32 +14,57 @@ class TicketManager:
self.odoo = self.conn.get_odoo_instance()
self.model_name = "project.task"
def _check_connection(self):
"""Vérifie la connexion Odoo"""
if self.odoo is None:
try:
self.conn = OdooConnection()
self.odoo = self.conn.get_odoo_instance()
except Exception as e:
print(f"Erreur de connexion: {e}")
self.odoo = None
def _ensure_connection(self):
"""Vérifie et établit la onnexion si nécessaire"""
if not self.odoo:
self.odoo = self.conn.get_odoo_instance()
return self.odoo is not None
def _safe_execute(self, model, method, *args):
"""Exécute une méthode Odoo de manière sécurisée"""
if not self._check_connection():
"""
Exécute une méthode Odoo en toute sécurité via odoorpc.
Vérifie la connexion avant d'exécuter.
"""
# Vérifier que la connexion est bien établie
if not self._ensure_connection():
print_error("Connexion Odoo indisponible.")
return None
try:
return self.odoo.execute(model, method, *args)
except Exception as e:
print(f"Erreur lors de {method} sur {model}: {e}")
# Exécuter la méthode sur le modèle via OdooRPC
return self.odoo.execute(model, method, *args) # type: ignore
except odoorpc.error.RPCError as e: # type: ignore
print_error(f" Erreur RPC lors de '{method}' sur '{model}': {e}")
return None
except Exception as e:
print_error(f" Erreur inattendue lors de '{method}' sur '{model}': {e}")
return None
def get_ticket_by_id(self, ticket_id):
""" Récupère les détails d'un ticket par son ID et applique le filtre """
fields_to_read = ['id', 'name', 'code', 'stage_id', 'date_deadline', 'description', 'message_ids']
# Vérifier la connexion avant d'exécuter la requête
if not self._ensure_connection():
print_error("Connexion Odoo indisponible.")
return None
# Récupérer les données du ticket
ticket_data = self._safe_execute(self.model_name, 'read', [ticket_id], fields_to_read)
if not ticket_data:
print_error(f"Aucun ticket trouvé avec l'ID {ticket_id}")
return None
# Nettoyer et filtrer les données du ticket
return filter_ticket_data(ticket_data[0]) # Utilisation de data_filter.py
def list_models(self):
"""Affiche la liste des modèles disponibles dans Odoo"""
models = self._safe_execute('ir.model', 'search_read', [], ['model', 'name'])
if not models:
print("Aucun modèle disponible.")
print_error("Aucun modèle disponible.")
return []
print("\nListe des modèles disponibles:")
@ -51,7 +76,7 @@ class TicketManager:
"""Affiche les champs d'un modèle donné"""
fields_info = self._safe_execute(model_name, 'fields_get')
if not fields_info:
print(f"Aucun champ trouvé pour le modèle {model_name}.")
print_error(f"Aucun champ trouvé pour le modèle {model_name}.")
return []
print(f"\nChamps du modèle {model_name}:")
@ -59,73 +84,78 @@ class TicketManager:
print(f"Champ: {field_name} - Type: {field_data['type']}")
return fields_info
def get_project_tickets_summary(self, project_id):
"""Récupère un résumé des tickets d'un projet pour permettre la sélection"""
domain = [('project_id', '=', project_id)]
ticket_ids = self._safe_execute(self.model_name, 'search', domain, 0, 200)
def export_model_fields_to_json(self, model_name, filename):
"""Exporte les champs d'un modèle dans un fichier JSON"""
fields_info = self._safe_execute(model_name, 'fields_get')
if not fields_info:
print_error(f"Aucun champ trouvé pour le modèle {model_name}.")
return
if not ticket_ids:
print(f"Aucun ticket trouvé pour le projet ID: {project_id}")
return []
data = {field_name: field_data['type'] for field_name, field_data in fields_info.items()}
filepath = os.path.join(EXPORT_DIR, filename)
fields_to_read = ['id', 'name', 'code', 'stage_id', 'date_deadline']
tickets_data = self._safe_execute(self.model_name, 'read', ticket_ids, fields_to_read)
if not tickets_data:
print("Erreur lors de la récupération des données des tickets.")
return []
summary_tickets = []
for ticket in tickets_data:
stage_name = "Non défini"
if ticket.get('stage_id'):
stage_name = ticket['stage_id'][1] if isinstance(ticket['stage_id'], list) and len(ticket['stage_id']) > 1 else str(ticket['stage_id'])
summary_tickets.append({
'id': ticket['id'],
'name': ticket['name'],
'code': ticket.get('code', 'N/A'),
'stage_id': ticket.get('stage_id', [0, "Non défini"]),
'stage_name': stage_name,
'date_deadline': ticket.get('date_deadline', 'Non défini')
})
return summary_tickets
if save_json(filepath, data):
print(f"Champs du modèle {model_name} exportés dans {filepath}")
else:
print_error(f"Erreur lors de l'exportation des champs du modèle {model_name} dans {filepath}")
def export_tickets_by_project_and_stage(self, project_id, selected_stage_ids=None):
"""Exporte les tickets d'un projet classés par étape"""
""" Exporte les tickets d'un projet classés par étape """
# Vérifier la connexion Odoo
if not self._ensure_connection():
print_error("Connexion Odoo indisponible.")
return
# Récupérer le projet depuis Odoo
project_data = self._safe_execute('project.project', 'search_read', [('id', '=', project_id)], ['id', 'name'])
if not project_data:
print(f"Projet ID {project_id} introuvable")
print_error(f"Projet ID {project_id} introuvable.")
return
project_name = project_data[0]['name']
# Construire le domaine de recherche des tickets
domain = [('project_id', '=', project_id)]
if selected_stage_ids:
domain.append(('stage_id', 'in', selected_stage_ids))
# Récupérer les tickets du projet
ticket_ids = self._safe_execute(self.model_name, 'search', domain, 0, 1000)
if not ticket_ids:
print("Aucun ticket trouvé")
print_error("Aucun ticket trouvé pour ce projet.")
return
tickets = [self.get_ticket_by_id(ticket_id) for ticket_id in ticket_ids]
# Lire les détails des tickets
tickets = [self.get_ticket_by_id(ticket_id) for ticket_id in ticket_ids if self.get_ticket_by_id(ticket_id)]
# Trier les tickets par étape
tickets_by_stage = {}
for ticket in tickets:
stage_id = ticket["Champs Relationnels"].get("stage_id", [0, "Non classé"])[0]
stage_name = ticket["Champs Relationnels"].get("stage_id", [0, "Non classé"])[1]
key = f"{stage_id}_{stage_name}"
#Vérifier que ticket est bien un dictionnaire
if not isinstance(ticket, dict):
print_error("Erreur: le format du ticket est invalide.")
return None
# Vérifier que "Champs Relationnels" existe
champs_relationnels = ticket.get("Champs Relationnels", {})
# Vérifier que "stage_id" existe et est une liste avec au moins 2 éléments
stage_data = champs_relationnels.get("stage_id", [0, "Non classé"])
stage_id = stage_data[0] if isinstance(stage_data, list) and len(stage_data) > 0 else 0
stage_name = stage_data[1] if isinstance(stage_data, list) and len(stage_data) > 1 else "Non classé"
key = f"{stage_id}_{stage_name}"
if key not in tickets_by_stage:
tickets_by_stage[key] = []
tickets_by_stage[key].append(ticket)
# Créer le répertoire du projet
project_dir = ensure_export_directory(f"project_{project_id}_{project_name.replace(' ', '_')}")
# Sauvegarder les tickets par étape
for stage_key, stage_tickets in tickets_by_stage.items():
stage_dir = os.path.join(project_dir, stage_key)
os.makedirs(stage_dir, exist_ok=True)
save_json(os.path.join(stage_dir, "all_tickets.json"), stage_tickets)
print(f"Exportation terminée dans {project_dir}/")
print(f"Exportation terminée. Les fichiers sont enregistrés dans : {project_dir}/")

View File

@ -36,3 +36,6 @@ def get_user_choice(prompt, options):
print("Choix invalide. Veuillez réessayer.")
except ValueError:
print("Veuillez entrer un nombre valide.")
def print_error(message):
print(f" Erreur: {message}")