diff --git a/gui_ollama.py b/gui_ollama.py
index 6ef6d348..aed62aa8 100644
--- a/gui_ollama.py
+++ b/gui_ollama.py
@@ -71,10 +71,10 @@ def chat_interface(user, user_input):
# Affichage des derniers messages sous forme de bulle de chat
history_display = ""
for c in user_history[-5:]:
- history_display += f"👤 **{user}** : {c['user']}\n"
- history_display += f"🤖 **Bot** : {c['bot']}\n\n"
+ history_display += f"Utilisateur : {c['user']}\n"
+ history_display += f"Bot : {c['bot']}\n\n"
- return f"📌 **Utilisateur :** {user}\n\n{history_display}👤 **{user}** : {user_input}\n🤖 **Bot** : {response}"
+ return f"Utilisateur : {user}\n\n{history_display}Utilisateur : {user_input}\nBot : {response}"
# Interface Gradio stylisée
with gr.Blocks(css="""
@@ -85,7 +85,7 @@ with gr.Blocks(css="""
.gr-button {background-color: #007bff; color: white; border-radius: 5px;}
""") as iface:
with gr.Column():
- gr.Markdown("
đź’¬ Chat avec Ollama OVH
")
+ gr.Markdown("Chat avec Ollama OVH
")
with gr.Row():
user_input = gr.Textbox(label="Nom d'utilisateur", placeholder="Entrez votre nom...", interactive=True)
diff --git a/odoo_data/odoo_toolkit_new/main.py b/odoo_data/odoo_toolkit_new/main.py
index 49599d07..3d894a29 100755
--- a/odoo_data/odoo_toolkit_new/main.py
+++ b/odoo_data/odoo_toolkit_new/main.py
@@ -1,16 +1,6 @@
from menu_principal import run_menu
def main():
- """Point d'entrée principal de l'application"""
- print("=================================================")
- print(" GESTIONNAIRE DE TICKETS ODOO SIMPLIFIÉ ")
- print("=================================================")
- print("Fonctionnalités:")
- print("1. Afficher la liste des modèles disponibles")
- print("2. Afficher les champs d'un modèle donné")
- print("3. Exporter les informations des champs en JSON")
- print("4. Exporter les tickets d'un projet par étape")
- print("=================================================")
run_menu()
diff --git a/odoo_data/odoo_toolkit_new/ticket_manager.py b/odoo_data/odoo_toolkit_new/ticket_manager.py
index 7c102d6c..7c468b84 100644
--- a/odoo_data/odoo_toolkit_new/ticket_manager.py
+++ b/odoo_data/odoo_toolkit_new/ticket_manager.py
@@ -15,32 +15,24 @@ class TicketManager:
self.model_name = "project.task"
def _check_connection(self):
- """Vérifie que la connexion Odoo est active"""
+ """Vérifie la connexion Odoo"""
if self.odoo is None:
- print("Erreur: La connexion à Odoo n'est pas établie.")
- print("Tentative de reconnexion...")
try:
self.conn = OdooConnection()
self.odoo = self.conn.get_odoo_instance()
except Exception as e:
- print(f"Erreur lors de la tentative de reconnexion: {e}")
+ print(f"Erreur de connexion: {e}")
self.odoo = None
-
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():
return None
-
try:
- if self.odoo is None:
- print("Erreur: Impossible d'exécuter la commande, la connexion à Odoo est inactive.")
- return None
-
return self.odoo.execute(model, method, *args)
except Exception as e:
- print(f"Erreur lors de l'exécution de {method} sur {model}: {e}")
+ print(f"Erreur lors de {method} sur {model}: {e}")
return None
def list_models(self):
@@ -54,7 +46,7 @@ class TicketManager:
for model in models:
print(f"Modèle: {model['name']} (ID: {model['model']})")
return models
-
+
def list_model_fields(self, model_name):
"""Affiche les champs d'un modèle donné"""
fields_info = self._safe_execute(model_name, 'fields_get')
@@ -66,285 +58,7 @@ class TicketManager:
for field_name, field_data in fields_info.items():
print(f"Champ: {field_name} - Type: {field_data['type']}")
return fields_info
-
- def export_model_fields_to_json(self, model_name, filename):
- """Exporte les informations des champs d'un modèle en JSON"""
- fields_info = self.list_model_fields(model_name)
- if not fields_info:
- return False
-
- file_path = os.path.join(EXPORT_DIR, f"{filename}.json")
- try:
- with open(file_path, 'w', encoding='utf-8') as f:
- json.dump(fields_info, f, indent=4, ensure_ascii=False)
- print(f"Informations des champs exportées dans {file_path}")
- return True
- except Exception as e:
- print(f"Erreur lors de l'exportation des champs: {str(e)}")
- return False
- def get_ticket_by_id(self, ticket_id):
- """Récupère un ticket par son ID"""
- all_fields = self._safe_execute(self.model_name, 'fields_get')
- if not all_fields:
- return None
-
- field_names = list(all_fields.keys())
-
- ticket_data = self._safe_execute(self.model_name, 'read', [ticket_id], field_names)
- if not ticket_data:
- return None
-
- ticket = ticket_data[0]
- formatted_ticket = {
- "ID du Ticket": ticket["id"],
- "Nom": ticket["name"],
- "Code": ticket.get("code", "N/A"),
- "Date Limite": ticket.get("date_deadline", "Non défini"),
- "Champs Simples": {},
- "Champs Relationnels": {},
- "Discussions": []
- }
-
- # Classer les champs par type
- for field_name, field_info in all_fields.items():
- field_type = field_info.get('type')
- if field_type in ["many2one", "one2many", "many2many"]:
- if field_name in ticket:
- formatted_ticket["Champs Relationnels"][field_name] = ticket[field_name]
- else:
- if field_name in ticket:
- formatted_ticket["Champs Simples"][field_name] = ticket[field_name]
-
- # Récupérer les discussions
- if "message_ids" in ticket and ticket["message_ids"]:
- formatted_ticket["Discussions"] = self.get_ticket_discussions(ticket["message_ids"])
-
- return formatted_ticket
-
- def get_ticket_discussions(self, message_ids):
- """Récupère et nettoie les discussions associées à un ticket"""
- model_name = "mail.message"
-
- if not message_ids:
- return []
-
- messages = self._safe_execute(model_name, 'read', message_ids, ["id", "subject", "body", "author_id", "date"])
- if messages is None:
- return []
-
- formatted_messages = []
- for msg in messages:
- # Utiliser la fonction clean_html de data_filter
- from data_filter import clean_html
- cleaned_content = clean_html(msg["body"])
-
- if cleaned_content:
- formatted_messages.append({
- "ID Message": msg["id"],
- "Sujet": msg["subject"] or "Sans sujet",
- "Contenu": cleaned_content,
- "Auteur": msg["author_id"][1] if msg["author_id"] else "Inconnu",
- "Date": msg["date"]
- })
-
- return formatted_messages
-
- def search_tickets_by_fields(self, field_criteria, limit=50):
- """Recherche des tickets selon des critères de champs"""
- # Construire le domaine de recherche
- domain = []
- for field, value in field_criteria.items():
- domain.append((field, '=', value))
-
- print(f"\nRecherche de tickets avec les critères: {field_criteria}")
-
- # Rechercher les tickets correspondants
- ticket_ids = self._safe_execute(self.model_name, 'search', domain, 0, limit)
- if not ticket_ids:
- print("Aucun ticket ne correspond aux critères de recherche.")
- return []
-
- print(f"Nombre de tickets trouvés: {len(ticket_ids)}")
-
- # Récupérer tous les tickets trouvés
- tickets = []
- for ticket_id in ticket_ids:
- ticket = self.get_ticket_by_id(ticket_id)
- if ticket:
- tickets.append(ticket)
-
- return tickets
-
- def export_tickets_by_project_and_stage(self, project_id, selected_stage_ids=None):
- """Exporte les tickets d'un projet classés par étape
-
- Args:
- project_id (int): L'ID du projet
- selected_stage_ids (list, optional): Liste des IDs d'étapes à inclure. Si None, toutes les étapes sont incluses.
- """
- try:
- # Convertir project_id en entier
- project_id = int(project_id)
-
- # Vérifier si le projet existe
- projects = self._safe_execute('project.project', 'search_read', [('id', '=', project_id)], ['id', 'name'])
- if not projects:
- print(f"Aucun projet trouvé avec l'ID: {project_id}")
- return
-
- project_name = projects[0]['name']
- print(f"\nRécupération des tickets du projet: {project_name} (ID: {project_id})")
-
- # Construire le domaine de recherche
- domain = [('project_id', '=', project_id)]
-
- # Si des étapes spécifiques sont sélectionnées, ajouter à la condition
- if selected_stage_ids and len(selected_stage_ids) > 0:
- domain.append(('stage_id', 'in', selected_stage_ids))
- print(f"Filtrage sur {len(selected_stage_ids)} étapes sélectionnées")
-
- ticket_ids = self._safe_execute(self.model_name, 'search', domain, 0, 1000)
-
- if not ticket_ids:
- print(f"Aucun ticket trouvé avec les critères spécifiés.")
- return
-
- # Récupérer les tickets avec les champs essentiels
- fields_to_read = ['id', 'name', 'code', 'stage_id', 'date_deadline',
- 'description', 'priority', 'sequence', 'message_ids']
-
- 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
-
- print(f"Nombre de tickets trouvés: {len(tickets_data)}")
-
- # Convertir les tickets au format approprié et les filtrer
- formatted_tickets = []
- for ticket in tickets_data:
- formatted_ticket = {
- "ID du Ticket": ticket["id"],
- "Nom": ticket["name"],
- "Code": ticket.get("code", "N/A"),
- "Date Limite": ticket.get("date_deadline", "Non défini"),
- "Champs Simples": {
- "description": ticket.get("description", ""),
- "priority": ticket.get("priority", ""),
- "sequence": ticket.get("sequence", "")
- },
- "Champs Relationnels": {
- "project_id": [project_id, project_name],
- "stage_id": ticket.get("stage_id", [0, "Inconnu"])
- },
- "Discussions": []
- }
-
- # Récupérer les discussions si nécessaire
- if ticket.get("message_ids"):
- formatted_ticket["Discussions"] = self.get_ticket_discussions(ticket["message_ids"])
-
- # Filtrer le ticket
- filtered_ticket = filter_ticket_data(formatted_ticket)
- formatted_tickets.append(filtered_ticket)
-
- if not formatted_tickets:
- print("Aucun ticket n'a pu être formaté correctement.")
- return
-
- # Créer un répertoire pour le projet avec son nom pour plus de clarté
- safe_project_name = project_name.replace('/', '_').replace(' ', '_').replace('\\', '_')
- project_dir = ensure_export_directory(f"project_{project_id}_{safe_project_name}")
-
- print(f"\nExportation des tickets pour le projet {project_name} (ID: {project_id}):")
-
- # Classer les tickets par stage_id
- tickets_by_stage = {}
- for ticket in formatted_tickets:
- # Vérifier que stage_id existe dans les champs relationnels
- if 'Champs Relationnels' in ticket and 'stage_id' in ticket['Champs Relationnels']:
- stage_data = ticket['Champs Relationnels']['stage_id']
-
- if isinstance(stage_data, list) and len(stage_data) > 0:
- stage_id = stage_data[0]
- stage_name = stage_data[1] if len(stage_data) > 1 else "Inconnu"
- else:
- # Si stage_id n'est pas une liste, utiliser une valeur par défaut
- stage_id = 0
- stage_name = "Inconnu"
-
- key = f"{stage_id}_{stage_name}"
- if key not in tickets_by_stage:
- tickets_by_stage[key] = []
- tickets_by_stage[key].append(ticket)
- else:
- # Si le ticket n'a pas de stage_id, le mettre dans "Non classé"
- key = "0_Non_classé"
- if key not in tickets_by_stage:
- tickets_by_stage[key] = []
- tickets_by_stage[key].append(ticket)
-
- # Vérifier si des tickets ont été classés
- if not tickets_by_stage:
- print("Aucun ticket n'a pu être classé par stage_id.")
- # Sauvegarde tous les tickets dans un seul fichier
- all_tickets_file = os.path.join(project_dir, "all_tickets.json")
- save_json(all_tickets_file, formatted_tickets)
- print(f"Tous les tickets ont été sauvegardés dans {all_tickets_file}")
- return
-
- # Créer des répertoires pour chaque stage_id et sauvegarder les tickets
- for stage_key, stage_tickets in tickets_by_stage.items():
- stage_parts = stage_key.split('_', 1)
- stage_id = stage_parts[0]
- stage_name = stage_parts[1] if len(stage_parts) > 1 else "Inconnu"
- safe_stage_name = stage_name.replace('/', '_').replace('\\', '_')
- stage_dir = os.path.join(project_dir, f"{stage_id}_{safe_stage_name}")
- os.makedirs(stage_dir, exist_ok=True)
-
- print(f"- Stage '{stage_name}' (ID: {stage_id}): {len(stage_tickets)} tickets")
-
- # Sauvegarder tous les tickets du stage dans un fichier unique
- all_tickets_file = os.path.join(stage_dir, f"all_tickets.json")
- save_json(all_tickets_file, stage_tickets)
-
- # Sauvegarder chaque ticket individuellement
- for ticket in stage_tickets:
- ticket_code = ticket.get('Code', 'N/A')
- ticket_id = ticket.get('ID du Ticket', 'N/A')
- ticket_file = os.path.join(stage_dir, f"ticket_{ticket_code}_{ticket_id}.json")
- save_json(ticket_file, ticket)
-
- print(f" Tickets sauvegardés dans {stage_dir}/")
-
- print(f"\nExportation terminée dans {project_dir}/")
-
- except ValueError:
- print(f"Erreur: Le project_id '{project_id}' n'est pas un nombre valide.")
- except Exception as e:
- print(f"Erreur lors de l'exportation des tickets: {e}")
- import traceback
- traceback.print_exc()
-
- def get_available_projects(self):
- """Récupère la liste des projets disponibles"""
- projects = self._safe_execute('project.project', 'search_read', [], ['id', 'name'])
- if not projects:
- print("Aucun projet disponible.")
- return {}
-
- projects_dict = {}
- print("\nProjets disponibles:")
- for project in projects:
- project_id = project['id']
- project_name = project['name']
- projects_dict[project_id] = project_name
- print(f"ID: {project_id} - {project_name}")
-
- return projects_dict
-
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)]
@@ -354,7 +68,6 @@ class TicketManager:
print(f"Aucun ticket trouvé pour le projet ID: {project_id}")
return []
- # Récupérer des informations résumées sur les tickets
fields_to_read = ['id', 'name', 'code', 'stage_id', 'date_deadline']
tickets_data = self._safe_execute(self.model_name, 'read', ticket_ids, fields_to_read)
@@ -362,7 +75,6 @@ class TicketManager:
print("Erreur lors de la récupération des données des tickets.")
return []
- # Formater les données pour l'affichage
summary_tickets = []
for ticket in tickets_data:
stage_name = "Non défini"
@@ -379,51 +91,41 @@ class TicketManager:
})
return summary_tickets
-
- def get_project_stages(self, project_id):
- """Récupère les étapes (stage_id) disponibles pour un projet donné
+
+ def export_tickets_by_project_and_stage(self, project_id, selected_stage_ids=None):
+ """Exporte les tickets d'un projet classés par étape"""
+ 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")
+ return
- Args:
- project_id (int): L'ID du projet
-
- Returns:
- dict: Un dictionnaire des étapes {stage_id: stage_name}
- """
- # Récupérer les tickets du projet
+ project_name = project_data[0]['name']
domain = [('project_id', '=', project_id)]
+ if selected_stage_ids:
+ domain.append(('stage_id', 'in', selected_stage_ids))
+
ticket_ids = self._safe_execute(self.model_name, 'search', domain, 0, 1000)
-
if not ticket_ids:
- print(f"Aucun ticket trouvé pour le projet ID: {project_id}")
- return {}
+ print("Aucun ticket trouvé")
+ return
- # Récupérer uniquement les stage_id des tickets
- tickets_data = self._safe_execute(self.model_name, 'read', ticket_ids, ['stage_id'])
+ tickets = [self.get_ticket_by_id(ticket_id) for ticket_id in ticket_ids]
- if not tickets_data:
- print("Erreur lors de la récupération des étapes.")
- return {}
+ 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}"
+
+ if key not in tickets_by_stage:
+ tickets_by_stage[key] = []
+ tickets_by_stage[key].append(ticket)
- # Extraire les stage_id uniques
- stage_ids = set()
- for ticket in tickets_data:
- if ticket.get('stage_id'):
- stage_ids.add(ticket['stage_id'][0])
+ project_dir = ensure_export_directory(f"project_{project_id}_{project_name.replace(' ', '_')}")
- if not stage_ids:
- print("Aucune étape trouvée pour ce projet.")
- return {}
+ 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)
- # Récupérer les noms des étapes
- stages_data = self._safe_execute('project.task.type', 'read', list(stage_ids), ['id', 'name'])
-
- if not stages_data:
- print("Erreur lors de la récupération des noms des étapes.")
- return {}
-
- # Créer un dictionnaire des étapes
- stages_dict = {}
- for stage in stages_data:
- stages_dict[stage['id']] = stage['name']
-
- return stages_dict
\ No newline at end of file
+ print(f"Exportation terminée dans {project_dir}/")