mirror of
https://github.com/Ladebeze66/odoo_toolkit.git
synced 2025-12-13 14:06:52 +01:00
first
This commit is contained in:
parent
ebf80209df
commit
6d21fd5b61
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/odtkit
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
odoorpc
|
||||||
|
bs4
|
||||||
BIN
__pycache__/config.cpython-312.pyc
Normal file
BIN
__pycache__/config.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/data_filter.cpython-312.pyc
Normal file
BIN
__pycache__/data_filter.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/menu_handlers.cpython-312.pyc
Normal file
BIN
__pycache__/menu_handlers.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/menu_principal.cpython-312.pyc
Normal file
BIN
__pycache__/menu_principal.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/odoo_connection.cpython-312.pyc
Normal file
BIN
__pycache__/odoo_connection.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/ticket_manager.cpython-312.pyc
Normal file
BIN
__pycache__/ticket_manager.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/utils.cpython-312.pyc
Normal file
BIN
__pycache__/utils.cpython-312.pyc
Normal file
Binary file not shown.
@ -1,4 +1,5 @@
|
|||||||
from ticket_manager import TicketManager
|
from ticket_manager import TicketManager
|
||||||
|
from utils import get_user_choice
|
||||||
|
|
||||||
# Initialisation de l'objet
|
# Initialisation de l'objet
|
||||||
ticket_manager = TicketManager()
|
ticket_manager = TicketManager()
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from odoo_connection import OdooConnection
|
from odoo_connection import OdooConnection
|
||||||
import os
|
import os
|
||||||
import json
|
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 config import EXPORT_DIR
|
||||||
from data_filter import filter_ticket_data
|
from data_filter import filter_ticket_data
|
||||||
|
|
||||||
@ -14,32 +14,57 @@ class TicketManager:
|
|||||||
self.odoo = self.conn.get_odoo_instance()
|
self.odoo = self.conn.get_odoo_instance()
|
||||||
self.model_name = "project.task"
|
self.model_name = "project.task"
|
||||||
|
|
||||||
def _check_connection(self):
|
def _ensure_connection(self):
|
||||||
"""Vérifie la connexion Odoo"""
|
"""Vérifie et établit la onnexion si nécessaire"""
|
||||||
if self.odoo is None:
|
if not self.odoo:
|
||||||
try:
|
self.odoo = self.conn.get_odoo_instance()
|
||||||
self.conn = OdooConnection()
|
|
||||||
self.odoo = self.conn.get_odoo_instance()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Erreur de connexion: {e}")
|
|
||||||
self.odoo = None
|
|
||||||
return self.odoo is not None
|
return self.odoo is not None
|
||||||
|
|
||||||
def _safe_execute(self, model, method, *args):
|
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
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self.odoo.execute(model, method, *args)
|
# Exécuter la méthode sur le modèle via OdooRPC
|
||||||
except Exception as e:
|
return self.odoo.execute(model, method, *args) # type: ignore
|
||||||
print(f"Erreur lors de {method} sur {model}: {e}")
|
|
||||||
|
except odoorpc.error.RPCError as e: # type: ignore
|
||||||
|
print_error(f" Erreur RPC lors de '{method}' sur '{model}': {e}")
|
||||||
return None
|
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):
|
def list_models(self):
|
||||||
"""Affiche la liste des modèles disponibles dans Odoo"""
|
"""Affiche la liste des modèles disponibles dans Odoo"""
|
||||||
models = self._safe_execute('ir.model', 'search_read', [], ['model', 'name'])
|
models = self._safe_execute('ir.model', 'search_read', [], ['model', 'name'])
|
||||||
if not models:
|
if not models:
|
||||||
print("Aucun modèle disponible.")
|
print_error("Aucun modèle disponible.")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
print("\nListe des modèles disponibles:")
|
print("\nListe des modèles disponibles:")
|
||||||
@ -51,7 +76,7 @@ class TicketManager:
|
|||||||
"""Affiche les champs d'un modèle donné"""
|
"""Affiche les champs d'un modèle donné"""
|
||||||
fields_info = self._safe_execute(model_name, 'fields_get')
|
fields_info = self._safe_execute(model_name, 'fields_get')
|
||||||
if not fields_info:
|
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 []
|
return []
|
||||||
|
|
||||||
print(f"\nChamps du modèle {model_name}:")
|
print(f"\nChamps du modèle {model_name}:")
|
||||||
@ -59,73 +84,78 @@ class TicketManager:
|
|||||||
print(f"Champ: {field_name} - Type: {field_data['type']}")
|
print(f"Champ: {field_name} - Type: {field_data['type']}")
|
||||||
return fields_info
|
return fields_info
|
||||||
|
|
||||||
def get_project_tickets_summary(self, project_id):
|
def export_model_fields_to_json(self, model_name, filename):
|
||||||
"""Récupère un résumé des tickets d'un projet pour permettre la sélection"""
|
"""Exporte les champs d'un modèle dans un fichier JSON"""
|
||||||
domain = [('project_id', '=', project_id)]
|
fields_info = self._safe_execute(model_name, 'fields_get')
|
||||||
ticket_ids = self._safe_execute(self.model_name, 'search', domain, 0, 200)
|
if not fields_info:
|
||||||
|
print_error(f"Aucun champ trouvé pour le modèle {model_name}.")
|
||||||
|
return
|
||||||
|
|
||||||
if not ticket_ids:
|
data = {field_name: field_data['type'] for field_name, field_data in fields_info.items()}
|
||||||
print(f"Aucun ticket trouvé pour le projet ID: {project_id}")
|
filepath = os.path.join(EXPORT_DIR, filename)
|
||||||
return []
|
|
||||||
|
|
||||||
fields_to_read = ['id', 'name', 'code', 'stage_id', 'date_deadline']
|
if save_json(filepath, data):
|
||||||
tickets_data = self._safe_execute(self.model_name, 'read', ticket_ids, fields_to_read)
|
print(f"Champs du modèle {model_name} exportés dans {filepath}")
|
||||||
|
else:
|
||||||
if not tickets_data:
|
print_error(f"Erreur lors de l'exportation des champs du modèle {model_name} dans {filepath}")
|
||||||
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
|
|
||||||
|
|
||||||
def export_tickets_by_project_and_stage(self, project_id, selected_stage_ids=None):
|
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'])
|
project_data = self._safe_execute('project.project', 'search_read', [('id', '=', project_id)], ['id', 'name'])
|
||||||
if not project_data:
|
if not project_data:
|
||||||
print(f"Projet ID {project_id} introuvable")
|
print_error(f"Projet ID {project_id} introuvable.")
|
||||||
return
|
return
|
||||||
|
|
||||||
project_name = project_data[0]['name']
|
project_name = project_data[0]['name']
|
||||||
|
|
||||||
|
# Construire le domaine de recherche des tickets
|
||||||
domain = [('project_id', '=', project_id)]
|
domain = [('project_id', '=', project_id)]
|
||||||
if selected_stage_ids:
|
if selected_stage_ids:
|
||||||
domain.append(('stage_id', 'in', 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)
|
ticket_ids = self._safe_execute(self.model_name, 'search', domain, 0, 1000)
|
||||||
if not ticket_ids:
|
if not ticket_ids:
|
||||||
print("Aucun ticket trouvé")
|
print_error("Aucun ticket trouvé pour ce projet.")
|
||||||
return
|
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 = {}
|
tickets_by_stage = {}
|
||||||
for ticket in tickets:
|
for ticket in tickets:
|
||||||
stage_id = ticket["Champs Relationnels"].get("stage_id", [0, "Non classé"])[0]
|
#Vérifier que ticket est bien un dictionnaire
|
||||||
stage_name = ticket["Champs Relationnels"].get("stage_id", [0, "Non classé"])[1]
|
if not isinstance(ticket, dict):
|
||||||
key = f"{stage_id}_{stage_name}"
|
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:
|
if key not in tickets_by_stage:
|
||||||
tickets_by_stage[key] = []
|
tickets_by_stage[key] = []
|
||||||
tickets_by_stage[key].append(ticket)
|
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(' ', '_')}")
|
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():
|
for stage_key, stage_tickets in tickets_by_stage.items():
|
||||||
stage_dir = os.path.join(project_dir, stage_key)
|
stage_dir = os.path.join(project_dir, stage_key)
|
||||||
os.makedirs(stage_dir, exist_ok=True)
|
os.makedirs(stage_dir, exist_ok=True)
|
||||||
save_json(os.path.join(stage_dir, "all_tickets.json"), stage_tickets)
|
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}/")
|
||||||
|
|||||||
3
utils.py
3
utils.py
@ -36,3 +36,6 @@ def get_user_choice(prompt, options):
|
|||||||
print("Choix invalide. Veuillez réessayer.")
|
print("Choix invalide. Veuillez réessayer.")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print("Veuillez entrer un nombre valide.")
|
print("Veuillez entrer un nombre valide.")
|
||||||
|
|
||||||
|
def print_error(message):
|
||||||
|
print(f" Erreur: {message}")
|
||||||
Loading…
x
Reference in New Issue
Block a user