#!/usr/bin/env python3 """ Script pour extraire des lots de tickets Odoo par critères (projet, statut, etc.). Ce script permet d'automatiser la récupération de nombreux tickets en évitant de recharger des tickets déjà traités. """ import os import sys import json import logging import argparse from datetime import datetime from .auth_manager import AuthManager from .ticket_manager import TicketManager from .batch_ticket_manager import BatchTicketManager from .retrieve_ticket import load_config from core.utils import setup_logging, log_separator def retrieve_tickets_batch(domain=None, limit=50, offset=0, output=None, config_file="config.json", verbose=False, skip_existing=True): """ Extrait un lot de tickets répondant à des critères spécifiques. Args: domain: Liste de critères de recherche au format Odoo ex: [["project_id", "=", 1], ["stage_id", "=", 5]] limit: Nombre maximal de tickets à extraire offset: Index de départ pour la pagination output: Répertoire de sortie config_file: Chemin vers le fichier de configuration verbose: Mode verbeux pour les logs skip_existing: Ignorer les tickets déjà extraits Returns: Dictionnaire avec le résultat de l'opération ou None en cas d'erreur """ config = load_config(config_file) # Si config est vide, initialiser avec des valeurs par défaut if not config: logging.error("Impossible de charger la configuration, utilisation des valeurs par défaut") config = {"odoo": {}, "output_dir": "output"} # Configurer la journalisation log_level = logging.DEBUG if verbose else logging.INFO setup_logging(log_level, "retrieve_tickets_batch.log") # Extraire les informations de connexion odoo_config = config.get("odoo", {}) url = odoo_config.get("url") db = odoo_config.get("db") username = odoo_config.get("username") api_key = odoo_config.get("api_key") if not all([url, db, username, api_key]): logging.error("Informations de connexion Odoo manquantes dans le fichier de configuration") return None # Définir le répertoire de sortie base_output_dir = output or config.get("output_dir", "output") logging.info(f"Démarrage de l'extraction par lot avec les critères: {domain}") logging.info(f"Limite: {limit} tickets, offset: {offset}") log_separator() try: # Initialiser les gestionnaires auth_manager = AuthManager( url=url, db=db, username=username, api_key=api_key ) if not auth_manager.login(): logging.error("Échec de l'authentification à Odoo") return None # Initialiser les gestionnaires ticket_manager = TicketManager(auth_manager) batch_manager = BatchTicketManager(ticket_manager) # Vérifier combien de tickets correspondent aux critères total_count = batch_manager.get_ticket_count(domain) logging.info(f"Nombre total de tickets correspondant aux critères: {total_count}") if total_count == 0: logging.warning("Aucun ticket ne correspond aux critères spécifiés") return {"status": "warning", "message": "Aucun ticket ne correspond aux critères"} # Extraire les tickets par lot result = batch_manager.extract_tickets_batch( domain=domain, limit=limit, offset=offset, base_output_dir=base_output_dir, skip_existing=skip_existing ) # Afficher le résumé log_separator() logging.info(f"Extraction par lot terminée") logging.info(f"Tickets traités: {result.get('processed', 0)}") logging.info(f"Tickets ignorés: {result.get('skipped', 0)}") logging.info(f"Répertoire: {result.get('batch_dir', '')}") log_separator() return result except Exception as e: logging.exception(f"Une erreur est survenue: {e}") return None def list_projects(config_file="config.json"): """ Liste tous les projets disponibles dans Odoo. Args: config_file: Chemin vers le fichier de configuration Returns: Liste des projets ou None en cas d'erreur """ config = load_config(config_file) # Extraire les informations de connexion odoo_config = config.get("odoo", {}) url = odoo_config.get("url") db = odoo_config.get("db") username = odoo_config.get("username") api_key = odoo_config.get("api_key") if not all([url, db, username, api_key]): print("Informations de connexion Odoo manquantes dans le fichier de configuration") return None try: # Initialiser les gestionnaires auth_manager = AuthManager( url=url, db=db, username=username, api_key=api_key ) if not auth_manager.login(): print("Échec de l'authentification à Odoo") return None # Récupérer la liste des projets ticket_manager = TicketManager(auth_manager) batch_manager = BatchTicketManager(ticket_manager) projects = batch_manager.get_projects() if not projects: print("Aucun projet trouvé") return None print("\nListe des projets disponibles:") print("-" * 50) for project in projects: print(f"ID: {project['id']}, Nom: {project['name']}") print("-" * 50) return projects except Exception as e: print(f"Une erreur est survenue: {e}") return None def list_stages(config_file="config.json"): """ Liste tous les statuts (étapes) disponibles dans Odoo. Args: config_file: Chemin vers le fichier de configuration Returns: Liste des étapes ou None en cas d'erreur """ config = load_config(config_file) # Extraire les informations de connexion odoo_config = config.get("odoo", {}) url = odoo_config.get("url") db = odoo_config.get("db") username = odoo_config.get("username") api_key = odoo_config.get("api_key") if not all([url, db, username, api_key]): print("Informations de connexion Odoo manquantes dans le fichier de configuration") return None try: # Initialiser les gestionnaires auth_manager = AuthManager( url=url, db=db, username=username, api_key=api_key ) if not auth_manager.login(): print("Échec de l'authentification à Odoo") return None # Récupérer la liste des étapes ticket_manager = TicketManager(auth_manager) batch_manager = BatchTicketManager(ticket_manager) stages = batch_manager.get_stages() if not stages: print("Aucune étape trouvée") return None print("\nListe des étapes disponibles:") print("-" * 50) for stage in stages: print(f"ID: {stage['id']}, Nom: {stage['name']}") print("-" * 50) return stages except Exception as e: print(f"Une erreur est survenue: {e}") return None def parse_domain(domain_str): """ Convertit une chaîne de critères en domaine Odoo. Format attendu: "field1:op1:value1;field2:op2:value2" Exemple: "project_id:=:1;stage_id:=:5" Args: domain_str: Chaîne de critères Returns: Liste de critères au format Odoo """ if not domain_str: return [] domain = [] criteria = domain_str.split(";") for criterion in criteria: if not criterion: continue parts = criterion.split(":") if len(parts) != 3: print(f"Format invalide pour le critère: {criterion}") continue field, operator, value = parts # Convertir value en entier si possible try: if value.isdigit(): value = int(value) elif value.lower() == "true": value = True elif value.lower() == "false": value = False except: pass domain.append([field, operator, value]) return domain def parse_arguments(): parser = argparse.ArgumentParser(description="Récupère des tickets Odoo par lots selon des critères.") subparsers = parser.add_subparsers(dest="command", help="Commande à exécuter") # Commande pour extraire un lot de tickets batch_parser = subparsers.add_parser("batch", help="Extrait un lot de tickets") batch_parser.add_argument("--domain", "-d", help="Critères de recherche (format: field1:op1:value1;field2:op2:value2)") batch_parser.add_argument("--project", "-p", type=int, help="ID du projet") batch_parser.add_argument("--stage", "-s", type=int, help="ID de l'étape/statut") batch_parser.add_argument("--limit", "-l", type=int, default=50, help="Nombre maximum de tickets à extraire") batch_parser.add_argument("--offset", "-o", type=int, default=0, help="Index de départ pour la pagination") batch_parser.add_argument("--output", help="Répertoire de sortie") batch_parser.add_argument("--include-existing", action="store_true", help="Inclure les tickets déjà extraits") batch_parser.add_argument("--config", "-c", default="config.json", help="Fichier de configuration") batch_parser.add_argument("--verbose", "-v", action="store_true", help="Mode verbeux") # Commande pour lister les projets projects_parser = subparsers.add_parser("projects", help="Liste les projets disponibles") projects_parser.add_argument("--config", "-c", default="config.json", help="Fichier de configuration") # Commande pour lister les étapes stages_parser = subparsers.add_parser("stages", help="Liste les étapes/statuts disponibles") stages_parser.add_argument("--config", "-c", default="config.json", help="Fichier de configuration") # Commande pour extraire un ticket unique (compatibilité avec retrieve_ticket.py) ticket_parser = subparsers.add_parser("ticket", help="Extrait un ticket unique par son code") ticket_parser.add_argument("ticket_code", help="Code du ticket à extraire") ticket_parser.add_argument("--output", help="Répertoire de sortie") ticket_parser.add_argument("--config", "-c", default="config.json", help="Fichier de configuration") ticket_parser.add_argument("--verbose", "-v", action="store_true", help="Mode verbeux") return parser.parse_args() def main(): args = parse_arguments() if args.command == "projects": list_projects(args.config) elif args.command == "stages": list_stages(args.config) elif args.command == "ticket": # Compatibilité avec retrieve_ticket.py from .retrieve_ticket import retrieve_ticket result = retrieve_ticket( ticket_code=args.ticket_code, output=args.output, config_file=args.config, verbose=args.verbose ) if not result: sys.exit(1) elif args.command == "batch": # Construire le domaine à partir des options domain = [] if args.domain: domain = parse_domain(args.domain) # Ajouter project_id et stage_id si spécifiés if args.project: domain.append(["project_id", "=", args.project]) if args.stage: domain.append(["stage_id", "=", args.stage]) result = retrieve_tickets_batch( domain=domain, limit=args.limit, offset=args.offset, output=args.output, config_file=args.config, verbose=args.verbose, skip_existing=not args.include_existing ) if not result or result.get("status") == "error": sys.exit(1) else: # Aucune commande spécifiée, afficher l'aide parser = argparse.ArgumentParser(description="Récupère des tickets Odoo par lots selon des critères.") parser.print_help() sys.exit(1) if __name__ == "__main__": main()