135 KiB
Récupération de tickets projet 3 étape 8 (2025-04-15 08:48:01)
User
comment récupérer 10 tickets du project 3 stage 8
Assistant
Pour récupérer 10 tickets du projet avec l'ID 3 et à l'étape 8, vous pouvez utiliser la commande suivante :
python -m odoo.retrieve_tickets_batch batch --project 3 --stage 8 --limit 10
Cette commande spécifie le projet et l'étape, tout en limitant le nombre de tickets extraits à 10. Assurez-vous que votre fichier de configuration config.json est correctement configuré pour que la commande fonctionne.
User
J'utilise deux fichiers avec le même nom pour l'extraction de mes fichiers la commande de base retrieve_ticket.py à la racine suivi du code d'un ticket déclenche l'extraction du ticket et la génération d'un rapport final hors la commande retrieve_ticket_batch.py dans odoo extrait un groupe de ticket mais il me manque la génération des rapports pour chacun de ces ticket as tu compris ma demande? Si oui comment procèderais tu pour le régler
Assistant
Oui, j'ai compris votre demande. Vous souhaitez que le script retrieve_tickets_batch.py génère un rapport pour chaque ticket extrait, similaire à ce que fait le script retrieve_ticket.py pour un ticket unique.
Pour résoudre ce problème, voici les étapes que je suivrais :
-
Modifier la fonction d'extraction des tickets dans
retrieve_tickets_batch.py: Après avoir extrait les données de chaque ticket, vous devez appeler une fonction pour générer un rapport pour ce ticket. -
Réutiliser la logique de génération de rapport : Vous pouvez extraire la logique de génération de rapport de
retrieve_ticket.pydans une fonction séparée, que vous pourrez appeler à partir deretrieve_tickets_batch.py. -
Créer un répertoire de sortie pour chaque ticket : Assurez-vous que chaque ticket a son propre répertoire de sortie, comme cela est fait dans
retrieve_ticket.py.
Voici un exemple de ce à quoi pourrait ressembler la modification dans retrieve_tickets_batch.py :
Étape 1 : Créer une fonction pour générer le rapport
Ajoutez une fonction dans retrieve_tickets_batch.py pour générer le rapport :
def generate_ticket_report(ticket_code, ticket_dir, result):
"""
Génère un rapport pour un ticket extrait.
Args:
ticket_code: Code du ticket
ticket_dir: Répertoire où les données du ticket sont stockées
result: Résultat de l'extraction du ticket
"""
# Logique pour générer le rapport
summary = {
"ticket_code": ticket_code,
"output_directory": ticket_dir,
"message_count": result.get("messages_count", 0),
"attachment_count": result.get("attachments_count", 0),
# Ajoutez d'autres informations pertinentes ici
}
summary_path = os.path.join(ticket_dir, "extraction_summary.json")
with open(summary_path, 'w', encoding='utf-8') as f:
json.dump(summary, f, indent=2, ensure_ascii=False)
Étape 2 : Appeler cette fonction après l'extraction de chaque ticket
Modifiez la section où vous extrayez les tickets dans retrieve_tickets_batch.py pour appeler generate_ticket_report après chaque extraction :
# 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
)
# Pour chaque ticket extrait, générer un rapport
for ticket in result.get('tickets', []):
ticket_code = ticket['code']
ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp}")
os.makedirs(ticket_dir, exist_ok=True)
# Appeler la fonction d'extraction pour chaque ticket
ticket_result = ticket_manager.extract_ticket_data(ticket_code, ticket_dir)
# Générer le rapport pour ce ticket
generate_ticket_report(ticket_code, ticket_dir, ticket_result)
Étape 3 : Tester les modifications
Après avoir effectué ces modifications, testez le script retrieve_tickets_batch.py pour vous assurer que les rapports sont générés correctement pour chaque ticket extrait.
Ces étapes devraient vous permettre d'ajouter la fonctionnalité de génération de rapports pour chaque ticket extrait par le script de traitement par lots. Si vous avez besoin d'aide supplémentaire pour l'implémentation, n'hésitez pas à demander !
User
il me manque également l'extraction des attachments (pièces-jointes) et la génération de rapports au niveau de mon retrieve_ticket_batch.py je pense qu'une partie de ces fonctionalités sont dans le fichier racine qui porte le même non que celui de odoo il serait judicieux de changer le nom du fichier retrieve_ticket.py à la racine et lui incoporer comme pour retrieve_ticket dans odoo pour harmoniser avec retrieve_ticket_batch et pouvoir récupérer pour chaques tickets les pièces jointes et générer les rapport as tu compris ma demande? Si oui guide moi étape par étape pour que je règle le problème
Assistant
Oui, j'ai bien compris votre demande. Vous souhaitez harmoniser les fonctionnalités de génération de rapports et d'extraction des pièces jointes entre les scripts retrieve_ticket.py et retrieve_tickets_batch.py. Voici comment procéder étape par étape :
Étape 1 : Renommer le fichier retrieve_ticket.py
- Renommer le fichier : Changez le nom du fichier
retrieve_ticket.pyà la racine en quelque chose commeretrieve_single_ticket.pypour éviter toute confusion avec le fichierretrieve_ticket.pydans le dossierodoo.
Étape 2 : Modifier le fichier renommé pour inclure l'extraction des pièces jointes
- Ouvrir le fichier
retrieve_single_ticket.py(anciennementretrieve_ticket.py). - Ajouter la logique pour extraire les pièces jointes. Vous pouvez utiliser la logique existante dans
retrieve_ticket.pypour gérer les pièces jointes. Assurez-vous que la fonctionextract_ticket_datadansTicketManagergère également l'extraction des pièces jointes.
Voici un exemple de ce que vous pourriez ajouter :
# Dans retrieve_single_ticket.py
def extract_ticket_data(ticket_code, ticket_dir):
# Logique existante pour extraire les données du ticket
# ...
# Logique pour extraire les pièces jointes
attachments = self.get_attachments(ticket_code)
for attachment in attachments:
# Code pour sauvegarder chaque pièce jointe dans ticket_dir
with open(os.path.join(ticket_dir, attachment['name']), 'wb') as f:
f.write(attachment['data'])
Étape 3 : Modifier retrieve_tickets_batch.py pour utiliser le nouveau fichier
- Ouvrir
retrieve_tickets_batch.py. - Modifier l'importation pour utiliser le nouveau fichier :
from .retrieve_single_ticket import extract_ticket_data
- Appeler la fonction d'extraction des pièces jointes dans la boucle où vous traitez chaque ticket extrait :
# Pour chaque ticket extrait, générer un rapport et extraire les pièces jointes
for ticket in result.get('tickets', []):
ticket_code = ticket['code']
ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp}")
os.makedirs(ticket_dir, exist_ok=True)
# Appeler la fonction d'extraction pour chaque ticket
ticket_result = extract_ticket_data(ticket_code, ticket_dir)
# Générer le rapport pour ce ticket
generate_ticket_report(ticket_code, ticket_dir, ticket_result)
Étape 4 : Tester les modifications
- Exécuter le script
retrieve_tickets_batch.pypour vous assurer que les pièces jointes sont correctement extraites et que les rapports sont générés pour chaque ticket. - Vérifier les répertoires de sortie pour vous assurer que les pièces jointes sont présentes et que les rapports contiennent les informations correctes.
Étape 5 : Harmoniser les fonctions
- Vérifiez que toutes les fonctions nécessaires pour l'extraction des données et la génération des rapports sont présentes dans le nouveau fichier
retrieve_single_ticket.py. - Assurez-vous que la logique est cohérente entre les deux fichiers pour éviter toute duplication de code.
En suivant ces étapes, vous devriez être en mesure d'harmoniser les fonctionnalités d'extraction des pièces jointes et de génération de rapports entre vos scripts. Si vous avez besoin d'aide supplémentaire à n'importe quelle étape, n'hésitez pas à demander !
User
ce n'est pas tout à fait je que je voudrai le fichier retrieve_ticket.py à la racine je voudri qu'il soit une entrée à mes fonctionalités odoo. changeons son nom et qu'il soit capable d'exécuté l'extraction d'un ticket ou l'extraction d'un groupe de ticket. Regagerde bien ce fichier à la racine, les fichiers dans le répertoire odoo retrieve_ticket.py (la fonctionalité d'esxtraction d'un ticket est fonctionelle j'extrait les infos, les pièces_jointes et je génére des rapports) regarde bience fonctionnement et reproduit le pour l'extraction en groupe de ticket avec retrieve_ticket_batch.py.
Assistant
Je comprends maintenant. Vous souhaitez que le fichier retrieve_ticket.py à la racine serve de point d'entrée unifié pour toutes vos fonctionnalités d'extraction Odoo, qu'il s'agisse d'extraire un seul ticket ou un groupe de tickets.
Voici comment procéder étape par étape :
Étape 1 : Renommer et adapter le fichier retrieve_ticket.py à la racine
Renommez le fichier en quelque chose comme odoo_extractor.py pour indiquer clairement qu'il s'agit du point d'entrée principal.
Étape 2 : Modifier le fichier pour qu'il puisse gérer les deux types d'extraction
Modifiez le fichier pour qu'il puisse traiter à la fois l'extraction d'un ticket unique et l'extraction par lots :
#!/usr/bin/env python3
"""
Point d'entrée unifié pour l'extraction de données depuis Odoo.
Ce script permet d'extraire un ticket unique ou un groupe de tickets selon les paramètres fournis.
"""
import os
import sys
import json
import argparse
from datetime import datetime
from odoo.auth_manager import AuthManager
from odoo.ticket_manager import TicketManager
from odoo.retrieve_ticket import retrieve_ticket
from odoo.retrieve_tickets_batch import retrieve_tickets_batch, parse_domain
from core.utils import setup_logging, log_separator
from formatters.json_to_markdown import create_markdown_from_json
# Importation de l'extracteur d'images HTML (optionnel)
try:
from utils.image_extractor import extract_images_from_ticket
from utils.image_extractor.extract_all_images import enhance_ticket_data_with_images
HTML_IMAGE_EXTRACTOR_AVAILABLE = True
except ImportError:
HTML_IMAGE_EXTRACTOR_AVAILABLE = False
def parse_arguments():
"""Parse les arguments de ligne de commande."""
parser = argparse.ArgumentParser(description="Extrait des données depuis Odoo (ticket unique ou par lots).")
# Paramètres communs
parser.add_argument("--config", "-c", help="Fichier de configuration", default="config.json")
parser.add_argument("--verbose", "-v", action="store_true", help="Mode verbeux")
parser.add_argument("--output", "-o", help="Répertoire de sortie", default=None)
parser.add_argument("--no-md", action="store_true", help="Désactiver la génération automatique du fichier Markdown")
parser.add_argument("--extract-html-images", action="store_true", help="Activer l'extraction des images intégrées dans le HTML")
# Sous-parseurs pour les différentes commandes
subparsers = parser.add_subparsers(dest="command", help="Commande à exécuter")
# Commande pour extraire un ticket unique
single_parser = subparsers.add_parser("ticket", help="Extrait un ticket unique par son code")
single_parser.add_argument("ticket_code", help="Code du ticket à extraire")
# 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", type=int, default=0, help="Index de départ pour la pagination")
batch_parser.add_argument("--include-existing", action="store_true", help="Inclure les tickets déjà extraits")
# Commande pour lister les projets
projects_parser = subparsers.add_parser("projects", help="Liste les projets disponibles")
# Commande pour lister les étapes
stages_parser = subparsers.add_parser("stages", help="Liste les étapes/statuts disponibles")
return parser.parse_args()
def load_config(config_file):
"""Charge le fichier de configuration."""
try:
with open(config_file, 'r') as f:
return json.load(f)
except Exception as e:
print(f"Erreur lors du chargement du fichier de configuration: {e}")
sys.exit(1)
def main():
"""Fonction principale du script."""
args = parse_arguments()
config = load_config(args.config)
# Configurer la journalisation
log_level = "DEBUG" if args.verbose else "INFO"
setup_logging(log_level)
# 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")
sys.exit(1)
# Traiter la commande appropriée
if args.command == "ticket":
# Extraction d'un ticket unique
result = retrieve_ticket(
ticket_code=args.ticket_code,
output=args.output,
config_file=args.config,
verbose=args.verbose
)
if not result:
print(f"Échec de l'extraction du ticket {args.ticket_code}")
sys.exit(1)
if not args.no_md:
# Génération du rapport Markdown
json_file = os.path.join(result, "all_messages.json")
if os.path.exists(json_file):
md_file_path = os.path.join(result, "rapport.md")
print(f"Génération du rapport Markdown...")
if create_markdown_from_json(json_file, md_file_path):
print(f"Rapport Markdown créé: {md_file_path}")
else:
print("Échec de la génération du rapport Markdown")
elif args.command == "batch":
# Extraction par lots
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":
print("Échec de l'extraction par lots")
sys.exit(1)
# Générer des rapports Markdown pour chaque ticket extrait
if not args.no_md:
processed_tickets = result.get("processed_tickets", [])
for ticket_info in processed_tickets:
ticket_dir = ticket_info.get("output_dir")
if ticket_dir and os.path.exists(ticket_dir):
json_file = os.path.join(ticket_dir, "all_messages.json")
if os.path.exists(json_file):
md_file_path = os.path.join(ticket_dir, "rapport.md")
print(f"Génération du rapport Markdown pour {ticket_info.get('code')}...")
if create_markdown_from_json(json_file, md_file_path):
print(f"Rapport Markdown créé: {md_file_path}")
else:
print(f"Échec de la génération du rapport Markdown pour {ticket_info.get('code')}")
elif args.command == "projects":
# Lister les projets
from odoo.retrieve_tickets_batch import list_projects
list_projects(args.config)
elif args.command == "stages":
# Lister les étapes
from odoo.retrieve_tickets_batch import list_stages
list_stages(args.config)
else:
parser = argparse.ArgumentParser(description="Extrait des données depuis Odoo (ticket unique ou par lots).")
parser.print_help()
sys.exit(1)
if __name__ == "__main__":
main()
Étape 3 : Modifier retrieve_tickets_batch.py pour inclure l'extraction des pièces jointes et la génération de rapports
-
Ouvrir le fichier
odoo/retrieve_tickets_batch.py -
Modifiez la fonction
retrieve_tickets_batchpour inclure l'extraction des pièces jointes. Assurez-vous qu'elle utilise les mêmes mécanismes queretrieve_ticket.pydans le dossierodoo. -
Ajoutez la génération de rapports pour chaque ticket traité.
Voici un exemple de modification :
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.
"""
# ... code existant ...
# Après avoir trouvé et extrait les tickets
processed_tickets = []
for ticket in found_tickets:
ticket_code = ticket.get('code')
if not ticket_code:
continue
# Créer un dossier spécifique pour ce ticket
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp}")
os.makedirs(ticket_dir, exist_ok=True)
# Extraire les données du ticket, y compris les pièces jointes
ticket_result = ticket_manager.extract_ticket_data(ticket_code, ticket_dir)
if ticket_result:
# Ajouter le ticket à la liste des tickets traités
processed_tickets.append({
"code": ticket_code,
"name": ticket.get('name'),
"output_dir": ticket_dir,
"messages_count": ticket_result.get("messages_count", 0),
"attachments_count": ticket_result.get("attachments_count", 0)
})
# Créer un résumé d'extraction pour ce ticket
summary = {
"timestamp": timestamp,
"ticket_code": ticket_code,
"output_directory": ticket_dir,
"message_count": ticket_result.get("messages_count", 0),
"attachment_count": ticket_result.get("attachments_count", 0),
"files_created": [
os.path.basename(ticket_result.get("ticket_info", "")),
os.path.basename(ticket_result.get("ticket_summary", "")),
os.path.basename(ticket_result.get("messages_file", "")),
os.path.basename(ticket_result.get("ticket_data_file", ""))
]
}
summary_path = os.path.join(ticket_dir, "extraction_summary.json")
with open(summary_path, 'w', encoding='utf-8') as f:
json.dump(summary, f, indent=2, ensure_ascii=False)
# Ajouter les tickets traités au résultat
result["processed_tickets"] = processed_tickets
# ... reste du code existant ...
return result
Étape 4 : Tester les modifications
- Testez l'extraction d'un ticket unique avec la nouvelle commande :
python odoo_extractor.py ticket TS-1234
- Testez l'extraction par lots avec la nouvelle commande :
python odoo_extractor.py batch --project 3 --stage 8 --limit 10
- Vérifiez les dossiers de sortie pour vous assurer que toutes les données sont correctement extraites, y compris les pièces jointes, et que les rapports sont générés.
Étape 5 : Documentation
Mettez à jour votre documentation pour refléter les changements apportés et les nouvelles commandes disponibles.
Avec ces modifications, vous aurez un point d'entrée unifié pour toutes vos fonctionnalités d'extraction Odoo, avec une cohérence dans le traitement des tickets, qu'ils soient extraits individuellement ou par lots.
User
peux tu me dire précisément où je dois ajouter ce code dans mon fichier
Assistant
Bien sûr ! Voici les instructions précises sur où ajouter le code dans votre fichier odoo/retrieve_tickets_batch.py.
Étape 1 : Ajouter la logique d'extraction des pièces jointes et de génération de rapports
-
Ouvrez le fichier
odoo/retrieve_tickets_batch.py. -
Localisez la fonction
retrieve_tickets_batch. Cette fonction commence par la définition suivante :
def retrieve_tickets_batch(domain=None, limit=50, offset=0, output=None, config_file="config.json",
verbose=False, skip_existing=True):
- Ajoutez le code pour traiter chaque ticket extrait. Vous devez insérer le code après la section où vous avez extrait les tickets, généralement après l'appel à
batch_manager.extract_tickets_batch. Voici un exemple de la structure de la fonction avec les ajouts :
Exemple de code à insérer
Voici un exemple de ce que vous devez ajouter, avec des commentaires pour indiquer où insérer le code :
def retrieve_tickets_batch(domain=None, limit=50, offset=0, output=None, config_file="config.json",
verbose=False, skip_existing=True):
# ... code existant pour charger la configuration et l'authentification ...
# 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
)
# Ajoutez ce code après l'extraction des tickets
processed_tickets = []
for ticket in result.get('tickets', []):
ticket_code = ticket['code']
if not ticket_code:
continue
# Créer un dossier spécifique pour ce ticket
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp}")
os.makedirs(ticket_dir, exist_ok=True)
# Extraire les données du ticket, y compris les pièces jointes
ticket_result = ticket_manager.extract_ticket_data(ticket_code, ticket_dir)
if ticket_result:
# Ajouter le ticket à la liste des tickets traités
processed_tickets.append({
"code": ticket_code,
"name": ticket.get('name'),
"output_dir": ticket_dir,
"messages_count": ticket_result.get("messages_count", 0),
"attachments_count": ticket_result.get("attachments_count", 0)
})
# Créer un résumé d'extraction pour ce ticket
summary = {
"timestamp": timestamp,
"ticket_code": ticket_code,
"output_directory": ticket_dir,
"message_count": ticket_result.get("messages_count", 0),
"attachment_count": ticket_result.get("attachments_count", 0),
"files_created": [
os.path.basename(ticket_result.get("ticket_info", "")),
os.path.basename(ticket_result.get("ticket_summary", "")),
os.path.basename(ticket_result.get("messages_file", "")),
os.path.basename(ticket_result.get("ticket_data_file", ""))
]
}
summary_path = os.path.join(ticket_dir, "extraction_summary.json")
with open(summary_path, 'w', encoding='utf-8') as f:
json.dump(summary, f, indent=2, ensure_ascii=False)
# Ajouter les tickets traités au résultat
result["processed_tickets"] = processed_tickets
# ... reste du code existant ...
return result
Étape 2 : Vérifiez les dépendances
Assurez-vous que toutes les dépendances nécessaires (comme datetime, os, json, etc.) sont importées en haut de votre fichier si elles ne le sont pas déjà.
Étape 3 : Tester les modifications
Après avoir ajouté ce code, testez le script pour vous assurer que les pièces jointes sont extraites et que les rapports sont générés correctement pour chaque ticket.
Si vous avez besoin de plus d'aide ou de précisions, n'hésitez pas à demander !
User
For the code present, we get this error:
"{" was not closed
How can I resolve this? If you propose a fix, please make it concise.
Assistant
The error message indicates that there is an issue with the JSON-like structure in your code, specifically that a curly brace { was not closed properly.
In the snippet you provided, it looks like the summary dictionary is being created, but it may be missing some closing braces or commas for the key-value pairs.
Here’s a concise fix for the summary dictionary. Ensure that you include all necessary key-value pairs and close the dictionary properly:
# Créer un résumé d'extraction pour ce ticket
summary = {
"timestamp": timestamp,
"ticket_code": ticket_code,
"output_directory": ticket_dir,
"message_count": ticket_result.get("messages_count", 0),
"attachment_count": ticket_result.get("attachments_count", 0),
"files_created": [
os.path.basename(ticket_result.get("ticket_info", "")),
os.path.basename(ticket_result.get("ticket_summary", "")),
os.path.basename(ticket_result.get("messages_file", "")),
os.path.basename(ticket_result.get("ticket_data_file", ""))
]
} # Ensure this closing brace is present
Make sure that the entire structure is correctly formatted and that there are no missing commas or braces in the surrounding code as well. After making this change, the error should be resolved.
User
l'extration unique fonctionne mais par lot les commandes ne fonctionnent pas correctement
Assistant
Pour résoudre le problème d'extraction par lots dans votre script odoo_extractor.py, il semble que la commande pour extraire des tickets par lots ne soit pas correctement configurée. Voici quelques étapes pour diagnostiquer et corriger le problème :
Étape 1 : Vérifiez la commande de traitement des lots
Assurez-vous que la section de votre code qui traite la commande batch est correctement configurée. Voici un extrait de code que vous devriez avoir dans la fonction main() :
elif args.command == "batch":
# Extraction par lots
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":
print("Échec de l'extraction par lots")
sys.exit(1)
Étape 2 : Vérifiez les arguments de la ligne de commande
Assurez-vous que vous passez tous les arguments nécessaires lorsque vous exécutez la commande. Par exemple, la commande que vous avez utilisée :
python odoo_extractor.py batch --project 3 --stage 8 --limit 10
Vérifiez que vous avez également défini les arguments --domain si nécessaire, ou que vous avez bien configuré les autres options.
Étape 3 : Vérifiez la fonction retrieve_tickets_batch
Assurez-vous que la fonction retrieve_tickets_batch dans odoo/retrieve_tickets_batch.py est correctement définie et qu'elle gère les paramètres que vous lui passez. Voici un exemple de ce que vous devriez avoir :
def retrieve_tickets_batch(domain=None, limit=50, offset=0, output=None, config_file="config.json",
verbose=False, skip_existing=True):
# ... code pour charger la configuration et l'authentification ...
# 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
)
# ... code pour traiter les résultats ...
Étape 4 : Ajoutez des messages de débogage
Pour mieux comprendre où le problème se situe, vous pouvez ajouter des messages de débogage dans votre code. Par exemple, avant d'appeler retrieve_tickets_batch, vous pouvez imprimer les valeurs des paramètres :
print(f"Domain: {domain}, Limit: {args.limit}, Offset: {args.offset}, Output: {args.output}")
Étape 5 : Testez à nouveau
Après avoir vérifié et corrigé les points ci-dessus, testez à nouveau la commande d'extraction par lots :
python odoo_extractor.py batch --project 3 --stage 8 --limit 10
Si vous continuez à rencontrer des problèmes, veuillez fournir le message d'erreur exact ou le comportement observé, afin que je puisse vous aider davantage.
User
peux tu me guider précisément pour corriger le problème
Assistant
Voici les étapes précises pour corriger le problème dans votre fichier odoo_extractor.py :
Étape 1 : Ajouter la gestion des commandes "batch"
Vous devez ajouter le code qui manque dans votre fonction main() pour traiter la commande "batch". Ouvrez odoo_extractor.py et localisez la section suivante :
elif args.command == "projects":
# Lister les projets
from odoo.retrieve_tickets_batch import list_projects
list_projects(args.config)
elif args.command == "stages":
# Lister les étapes/statuts
from odoo.retrieve_tickets_batch import list_stages
list_stages(args.config)
Étape 2 : Ajouter la section de code pour la commande "batch"
Juste avant cette section (ou après la section traitant la commande "ticket"), ajoutez le code suivant :
elif args.command == "batch":
# Extraction par lots
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":
print("Échec de l'extraction par lots")
sys.exit(1)
# Générer des rapports Markdown pour chaque ticket extrait
if not args.no_md:
processed_tickets = result.get("processed_tickets", [])
for ticket_info in processed_tickets:
ticket_dir = ticket_info.get("output_dir")
if ticket_dir and os.path.exists(ticket_dir):
json_file = os.path.join(ticket_dir, "all_messages.json")
if os.path.exists(json_file):
md_file_path = os.path.join(ticket_dir, "rapport.md")
print(f"Génération du rapport Markdown pour {ticket_info.get('code')}...")
if create_markdown_from_json(json_file, md_file_path):
print(f"Rapport Markdown créé: {md_file_path}")
else:
print(f"Échec de la génération du rapport Markdown pour {ticket_info.get('code')}")
Étape 3 : Corriger la description de l'argument include-existing
Dans votre définition des arguments, l'option --include-existing a une description incorrecte. Trouvez cette ligne :
batch_parser.add_argument("--include-existing", action="store_true", help="Index de départ pour la pagination")
Et remplacez-la par :
batch_parser.add_argument("--include-existing", action="store_true", help="Inclure les tickets déjà extraits")
Étape 4 : Importer toutes les dépendances nécessaires
Assurez-vous que toutes les dépendances nécessaires sont importées en haut du fichier. Vérifiez particulièrement que vous avez ces importations :
from odoo.retrieve_tickets_batch import retrieve_tickets_batch, parse_domain, list_projects, list_stages
Étape 5 : Sauvegarder et tester
Sauvegardez le fichier et testez la commande d'extraction par lots :
python odoo_extractor.py batch --project 3 --stage 8 --limit 10
Avec ces modifications, la commande d'extraction par lots devrait fonctionner correctement. Si vous rencontrez encore des problèmes, n'hésitez pas à me le faire savoir.
User
peux tu corriger mon fichier odoo_extractor.py
Assistant
Read file: odoo_extractor.py
Read file: odoo/retrieve_tickets_batch.py
Je dois mettre à jour le fichier odoo_extractor.py pour corriger le problème avec les commandes d'extraction par lots. Voici les corrections que je vais apporter :
from formatters.json_to_markdown import create_markdown_from_json
from odoo.retrieve_ticket import retrieve_ticket
- from odoo.retrieve_tickets_batch import retrieve_tickets_batch, parse_domain
+ from odoo.retrieve_tickets_batch import retrieve_tickets_batch, parse_domain, list_projects, list_stages
#importation de l'extracteur d'images HTML (optionnel)
batch_parser.add_argument("--limit", "-l", type=int, default=50, help="Nombre maximum de tickets à extraire")
batch_parser.add_argument("--offset", type=int, default=0, help="Index de départ pour la pagination")
- batch_parser.add_argument("--include-existing", action="store_true", help="Index de départ pour la pagination")
+ batch_parser.add_argument("--include-existing", action="store_true", help="Inclure les tickets déjà extraits")
# Commande pour lister les projets
domain.append(["stage_id", "=", args.stage])
+ print(f"Démarrage de l'extraction par lot avec les critères: {domain}")
+ print(f"Limite: {args.limit} tickets, offset: {args.offset}")
+
result = retrieve_tickets_batch(
domain=domain,
sys.exit(1)
+ # Afficher un résumé des résultats
+ print(f"Extraction par lot terminée")
+ print(f"Tickets traités: {result.get('processed', 0)}")
+ print(f"Tickets ignorés: {result.get('skipped', 0)}")
+
# Générer des rapports Markdown pour chaque ticket extrait
if not args.no_md:
+ print("Génération des rapports Markdown pour les tickets extraits...")
processed_tickets = result.get("processed_tickets", [])
for ticket_info in processed_tickets:
print(f"Rapport Markdown créé: {md_file_path}")
else:
- print("Echec de la génération du rapport Markdown.")
+ print(f"Echec de la génération du rapport Markdown pour {ticket_info.get('code')}")
+ else:
+ print(f"Fichier de messages introuvable pour {ticket_info.get('code')}")
+ else:
+ print(f"Répertoire introuvable pour {ticket_info.get('code')}")
elif args.command == "projects":
# Lister les projets
- from odoo.retrieve_tickets_batch import list_projects
list_projects(args.config)
elif args.command == "stages":
# Lister les étapes/statuts
- from odoo.retrieve_tickets_batch import list_stages
list_stages(args.config)
Voilà ! J'ai corrigé votre fichier odoo_extractor.py pour résoudre les problèmes avec les commandes d'extraction par lots.
Les modifications principales sont :
- Correction de la description de l'option
--include-existing(remplacé "Index de départ pour la pagination" par "Inclure les tickets déjà extraits") - Importation des fonctions
list_projectsetlist_stagesdirectement au début du fichier pour éviter les importations multiples - Ajout d'affichages supplémentaires pour mieux suivre le processus d'extraction par lots
- Amélioration de la gestion des erreurs et des messages pour la génération des rapports Markdown
- Ajout de messages plus détaillés pour chaque ticket traité
Vous pouvez maintenant utiliser la commande suivante pour extraire 10 tickets du projet 3 à l'étape 8 :
python odoo_extractor.py batch --project 3 --stage 8 --limit 10
Cette commande devrait fonctionner correctement et extraire les tickets avec leurs pièces jointes et générer les rapports appropriés.
User
l'extraction des attachments semble se faire correctement mais le rapport json et md du ticket ne se fait pas correctement comme avec l'appel de retrieve_ticket.py. L'extraction se fait dans output dans un répertoire batch hors je voudrai que les tickets se charge directement dans output comme avec retrieve_ticket.py normalement j'ai implémenté une méthode pour ne pas recharger un ticket déjà présent avec retrieve_ticket_batch.py. Je voudrai que tu analyses la sources de ces problèmes et que tu me guides précisement pas à pas pour les régler. Avant de commencer résume ma demande nous ajusterons si c'est nécessaire
Assistant
Votre demande concerne deux problèmes dans l'extraction par lots avec retrieve_tickets_batch.py :
- Les rapports JSON et Markdown ne sont pas générés correctement, contrairement à l'extraction avec
retrieve_ticket.py - Les tickets extraits sont placés dans un sous-répertoire
batchdansoutput, alors que vous préférez qu'ils soient directement dansoutputcomme avecretrieve_ticket.py
Vous souhaitez conserver la fonctionnalité qui évite de recharger les tickets déjà extraits, mais vous voulez harmoniser le comportement des deux méthodes d'extraction.
Est-ce que cette compréhension de votre demande est correcte ?
User
oui
Assistant
Je vais vous guider pas à pas pour résoudre ces deux problèmes.
Étape 1 : Analyser le problème du répertoire de sortie
Le premier problème est que les tickets extraits par lots sont placés dans un sous-répertoire batch au lieu d'être directement dans le répertoire output. Cela est probablement géré dans la fonction extract_tickets_batch du fichier odoo/batch_ticket_manager.py.
Searched codebase "batch_ticket_manager.py" • **2** results
| File |
|---|
undefined |
undefined |
Read file: odoo/batch_ticket_manager.py
Searched codebase "def extract_tickets_batch in batch_ticket_manager.py" • **25** results
| File | Lines |
|---|---|
odoo/batch_ticket_manager.py |
L183-226 |
odoo/batch_ticket_manager.py |
L249-287 |
odoo/batch_ticket_manager.py |
L226-249 |
odoo/batch_ticket_manager.py |
L331-345 |
odoo/retrieve_tickets_batch.py |
L53-101 |
odoo/batch_ticket_manager.py |
L110-161 |
odoo/batch_ticket_manager.py |
L287-331 |
odoo/retrieve_tickets_batch.py |
L101-140 |
odoo/batch_ticket_manager.py |
L28-66 |
odoo/retrieve_tickets_batch.py |
L140-168 |
odoo/batch_ticket_manager.py |
L161-183 |
odoo/retrieve_tickets_batch.py |
L1-53 |
odoo/batch_ticket_manager.py |
L1-28 |
odoo/retrieve_tickets_batch.py |
L168-225 |
odoo/retrieve_tickets_batch.py |
L359-415 |
odoo/batch_ticket_manager.py |
L66-110 |
odoo/__init__.py |
L1-12 |
odoo/retrieve_tickets_batch.py |
L415-418 |
odoo/retrieve_tickets_batch.py |
L326-353 |
odoo/retrieve_tickets_batch.py |
L225-282 |
odoo/retrieve_tickets_batch.py |
L353-359 |
odoo/ticket_manager.py |
L206-220 |
odoo/retrieve_tickets_batch.py |
L282-326 |
docs/odoo/exemples.py |
L50-80 |
odoo/ticket_manager.py |
L1-45 |
Voici les étapes pour résoudre les deux problèmes identifiés :
Étape 1 : Comprendre la source des problèmes
Après analyse du code, j'ai identifié les sources des problèmes :
-
Problème de répertoire : Dans
batch_ticket_manager.py, à la ligne 221, un sous-répertoirebatch_{timestamp}est créé pour stocker tous les tickets extraits par lots :batch_dir = os.path.join(base_output_dir, f"batch_{timestamp}") -
Problème de rapports : Dans
retrieve_tickets_batch.py, il y a déjà une logique pour extraire les données des tickets et générer les rapports, mais elle n'est peut-être pas utilisée correctement.
Étape 2 : Modifier batch_ticket_manager.py
Nous devons modifier la fonction extract_tickets_batch pour ne pas créer un sous-répertoire batch_{timestamp} et traiter chaque ticket directement dans le répertoire principal.
Read file: odoo/batch_ticket_manager.py
Maintenant que j'ai bien identifié les problèmes, voici les étapes précises pour les résoudre :
Étape 1 : Modifier le fichier batch_ticket_manager.py
Vous devez modifier la fonction extract_tickets_batch dans le fichier odoo/batch_ticket_manager.py pour ne pas créer un sous-répertoire batch. Voici comment faire :
-
Ouvrez le fichier
odoo/batch_ticket_manager.py -
Localisez ces lignes (autour de la ligne 220-221) :
# Créer le répertoire principal de sortie timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") batch_dir = os.path.join(base_output_dir, f"batch_{timestamp}") ensure_dir(batch_dir) -
Remplacez-les par :
# Utiliser directement le répertoire principal de sortie ensure_dir(base_output_dir) batch_dir = base_output_dir # Pour compatibilité avec le reste du code -
Modifiez la création des répertoires de tickets (autour de la ligne 252) :
# Créer un sous-répertoire pour ce ticket ticket_dir = os.path.join(batch_dir, f"ticket_{ticket_code}")par :
# Créer un répertoire spécifique pour ce ticket avec timestamp timestamp_ticket = datetime.now().strftime("%Y%m%d_%H%M%S") ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp_ticket}") -
Modifiez également le nom du fichier de résumé global (autour de la ligne 310) :
batch_summary_path = os.path.join(batch_dir, "batch_summary.json")par :
batch_summary_path = os.path.join(base_output_dir, f"batch_summary_{timestamp}.json")
Étape 2 : Vérifier le problème des rapports JSON et MD
Le problème des rapports est probablement lié au fait que les rapports sont générés dans le fichier retrieve_tickets_batch.py, mais ils ne sont pas correctement intégrés dans le processus de traitement par lots. Vérifions cela.
Read file: odoo/retrieve_tickets_batch.py
Je comprends maintenant le problème. Le fichier retrieve_tickets_batch.py extrait déjà les données des tickets, mais il y a un conflit entre ce code et celui dans batch_ticket_manager.py. Nous avons un double traitement qui crée de la confusion. Voici comment procéder pour résoudre tous les problèmes :
Étape 3 : Modifier retrieve_tickets_batch.py
Le fichier retrieve_tickets_batch.py contient son propre code pour extraire les tickets et créer des répertoires, ce qui crée un conflit avec la logique dans batch_ticket_manager.py. Nous devons modifier ce fichier pour utiliser uniquement la fonctionnalité de batch_ticket_manager.py.
-
Ouvrez le fichier
odoo/retrieve_tickets_batch.py -
Localisez la section qui commence par (autour de la ligne 100) :
processed_tickets =[] for ticket in result.get('tickets', []): # ... code qui traite chaque ticket ... -
Remplacez toute cette section (jusqu'à la fin de la boucle) par :
# Les tickets traités sont déjà dans result["processed_tickets"] # Vous n'avez pas besoin de les traiter à nouveau ici
Étape 4 : Configurer la génération des rapports Markdown
Assurez-vous que la fonction de génération des rapports Markdown est correctement appelée depuis odoo_extractor.py.
- Vérifiez que le code suivant est présent dans
odoo_extractor.pydans la section de la commande "batch" :# Générer des rapports Markdown pour chaque ticket extrait if not args.no_md: print("Génération des rapports Markdown pour les tickets extraits...") processed_tickets = result.get("processed_tickets", []) for ticket_info in processed_tickets: ticket_dir = ticket_info.get("output_dir") if ticket_dir and os.path.exists(ticket_dir): json_file = os.path.join(ticket_dir, "all_messages.json") if os.path.exists(json_file): md_file_path = os.path.join(ticket_dir, "rapport.md") print(f"Génération du rapport Markdown pour {ticket_info.get('code')}...") if create_markdown_from_json(json_file, md_file_path): print(f"Rapport Markdown créé: {md_file_path}") else: print(f"Échec de la génération du rapport Markdown pour {ticket_info.get('code')}")
Récapitulatif des modifications à apporter
1. Dans odoo/batch_ticket_manager.py :
# Avant
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
batch_dir = os.path.join(base_output_dir, f"batch_{timestamp}")
ensure_dir(batch_dir)
# Après
ensure_dir(base_output_dir)
batch_dir = base_output_dir # Pour compatibilité avec le reste du code
# Avant
ticket_dir = os.path.join(batch_dir, f"ticket_{ticket_code}")
# Après
timestamp_ticket = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp_ticket}")
ensure_dir(ticket_dir)
# Avant
batch_summary_path = os.path.join(batch_dir, "batch_summary.json")
# Après
batch_summary_path = os.path.join(base_output_dir, f"batch_summary_{timestamp}.json")
2. Dans odoo/retrieve_tickets_batch.py :
Supprimez ou commentez la section de code qui duplique le traitement des tickets (lignes 100-150 environ).
Après ces modifications, les deux fonctions d'extraction devraient avoir un comportement cohérent :
- Les tickets seront extraits directement dans le répertoire output
- Les rapports JSON et Markdown seront générés correctement
- La fonction qui évite de recharger les tickets déjà extraits sera préservée
Est-ce que ces instructions sont suffisamment claires ? Voulez-vous que je détaille davantage une partie spécifique ?
User
il faut peut-être revoir la gestion batch dans ces 3 fichiers il y a peut être des éléments inutiles que l'on pourrait simplifier
Assistant
Vous avez raison, il y a plusieurs éléments redondants et des optimisations possibles dans les trois fichiers. Voici une analyse de la situation et mes recommandations pour simplifier le système :
Analyse des problèmes
-
Duplication de code : Il y a du code qui s'exécute en double entre
batch_ticket_manager.pyetretrieve_tickets_batch.py, notamment pour l'extraction des tickets. -
Structure de répertoires incohérente : Les tickets extraits sont actuellement placés dans un sous-répertoire
batch_timestampplutôt que directement dansoutput. -
Flux de traitement complexe : Le flux d'extraction des tickets est fragmenté entre plusieurs fichiers, ce qui rend difficile le suivi du processus.
Plan de simplification
Voici comment nous pouvons simplifier :
1. Modifications dans batch_ticket_manager.py
# Remplacer
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
batch_dir = os.path.join(base_output_dir, f"batch_{timestamp}")
ensure_dir(batch_dir)
# Par
ensure_dir(base_output_dir)
batch_dir = base_output_dir # Pour compatibilité
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# Remplacer
ticket_dir = os.path.join(batch_dir, f"ticket_{ticket_code}")
# Par
timestamp_ticket = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp_ticket}")
# Remplacer
processed_tickets.append({
"code": ticket_code,
"id": ticket.get("id"),
"name": ticket.get("name"),
"dir": ticket_dir,
"messages_count": result.get("messages_count", 0),
"attachments_count": result.get("attachments_count", 0)
})
# Par
processed_tickets.append({
"code": ticket_code,
"id": ticket.get("id"),
"name": ticket.get("name"),
"output_dir": ticket_dir, # Modifier la clé pour harmoniser avec retrieve_tickets_batch.py
"messages_count": result.get("messages_count", 0),
"attachments_count": result.get("attachments_count", 0)
})
# Remplacer
batch_summary_path = os.path.join(batch_dir, "batch_summary.json")
# Par
batch_summary_path = os.path.join(base_output_dir, f"batch_summary_{timestamp}.json")
2. Simplifier retrieve_tickets_batch.py
Cette fonction contient une duplication : elle appelle batch_manager.extract_tickets_batch() puis refait une extraction de tickets. Nous devrions supprimer ce code dupliqué.
# Supprimer ou commenter ce bloc
processed_tickets =[]
for ticket in result.get('tickets', []):
ticket_code = ticket['code']
if not ticket_code:
continue
# Créer un dossier spécifique pour ce ticket
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp}")
os.makedirs(ticket_dir, exist_ok=True)
# Extraire les données du ticket, y compris les pièces jointes
ticket_result = ticket_manager.extract_ticket_data(ticket_code, ticket_dir)
# ... reste du code ...
Au lieu de cela, nous pouvons simplement récupérer les tickets déjà traités :
# Ajouter ce bloc à la place
# Les tickets et leurs données sont déjà traités par batch_manager.extract_tickets_batch()
processed_tickets = result.get("processed_tickets", [])
3. Assurer la cohérence dans odoo_extractor.py
Le fichier odoo_extractor.py semble déjà bien configuré pour générer des rapports Markdown. Nous devrions juste nous assurer que les noms de champs correspondent à ce qui est retourné par batch_ticket_manager.py (notamment vérifier si c'est "dir" ou "output_dir").
Plan d'action
- Modifier d'abord
batch_ticket_manager.pypour changer la structure des répertoires et normaliser les noms de champs - Ensuite, simplifier
retrieve_tickets_batch.pyen supprimant le code redondant - Enfin, vérifier la cohérence dans
odoo_extractor.py
Voulez-vous que je vous guide étape par étape pour effectuer ces modifications ?
User
je te laisse la main pour corriger ces problèmes de répertoires et de génération de rapport markdown et json comme pour retrieve_ticket.py
Assistant
Je vais maintenant corriger les problèmes identifiés dans les fichiers. Commençons par les modifications du gestionnaire de lots de tickets.
Étape 1 : Modifier le fichier batch_ticket_manager.py
# Créer le répertoire principal de sortie
+ ensure_dir(base_output_dir)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
- batch_dir = os.path.join(base_output_dir, f"batch_{timestamp}")
- ensure_dir(batch_dir)
# Charger les tickets déjà extraits
logging.info(f"Traitement du ticket {ticket_code}...")
- # Créer un sous-répertoire pour ce ticket
- ticket_dir = os.path.join(batch_dir, f"ticket_{ticket_code}")
+ # Créer un répertoire spécifique pour ce ticket avec timestamp
+ timestamp_ticket = datetime.now().strftime("%Y%m%d_%H%M%S")
+ ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp_ticket}")
+ ensure_dir(ticket_dir)
try:
"id": ticket.get("id"),
"name": ticket.get("name"),
- "dir": ticket_dir,
+ "output_dir": ticket_dir, # Changé de "dir" à "output_dir" pour cohérence
"messages_count": result.get("messages_count", 0),
"attachments_count": result.get("attachments_count", 0)
batch_summary = {
"timestamp": timestamp,
- "batch_dir": batch_dir,
+ "batch_dir": base_output_dir,
"search_criteria": {
"domain": domain,
}
- batch_summary_path = os.path.join(batch_dir, "batch_summary.json")
+ batch_summary_path = os.path.join(base_output_dir, f"batch_summary_{timestamp}.json")
save_json(batch_summary, batch_summary_path)
logging.info(f"Tickets en échec: {len(failed_tickets)}")
logging.info(f"Tickets exclus par tag 'BRG-LAB WIN': {len(brg_lab_win_tickets)}") # Message pour les tickets exclus
- logging.info(f"Répertoire de sortie: {batch_dir}")
+ logging.info(f"Répertoire de sortie: {base_output_dir}")
return {
"status": "success",
- "batch_dir": batch_dir,
+ "batch_dir": base_output_dir,
"processed": len(processed_tickets),
"skipped": len(skipped_tickets),
"skipped_tickets": skipped_tickets,
"failed_tickets": failed_tickets,
- "excluded_tickets": brg_lab_win_tickets # Liste des tickets exclus
+ "excluded_tickets": brg_lab_win_tickets, # Liste des tickets exclus
+ "tickets": tickets # Ajouter la liste complète des tickets pour compatibilité avec le code existant
}
Étape 2 : Simplifier le fichier retrieve_tickets_batch.py en supprimant le code redondant
Maintenant, simplifions le fichier retrieve_tickets_batch.py en supprimant la partie qui duplique l'extraction des tickets.
)
- processed_tickets =[]
- for ticket in result.get('tickets', []):
- ticket_code = ticket['code']
- if not ticket_code:
- continue
-
- # Créer un dossier spécifique pour ce ticket
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
- ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp}")
- os.makedirs(ticket_dir, exist_ok=True)
-
- # Extraire les données du ticket, y compris les pièces jointes
- ticket_result = ticket_manager.extract_ticket_data(ticket_code, ticket_dir)
-
- if ticket_result:
- # Ajouter le ticket à la liste des tickets traités
- processed_tickets.append({
- "code": ticket_code,
- "name": ticket.get('name'),
- "output_dir": ticket_dir,
- "messages_count": ticket_result.get("messages_count", 0),
- "attachments_count": ticket_result.get("attachments_count",0)
- })
-
- # Créer un résumé d'extraction pour ce ticket
- summary = {
- "timestamp": timestamp,
- "ticket_code": ticket_code,
- "output_directory": ticket_dir,
- "message_count": ticket_result.get("messages_count", 0),
- "attachment_count": ticket_result.get("attachments_count", 0),
- "files_created": [
- os.path.basename(ticket_result.get("ticket_info", "")),
- os.path.basename(ticket_result.get("ticket_summary", "")),
- os.path.basename(ticket_result.get("messages_file", "")),
- os.path.basename(ticket_result.get("ticket_data_file", ""))
- ]
- }
-
- summary_path = os.path.join(ticket_dir, "extraction_summary.json")
- with open(summary_path, 'w', encoding='utf-8') as f:
- json.dump(summary, f, indent=2, ensure_ascii=False)
-
- # Ajouter les tickets traités au résultat
- result["processed_tickets"] = processed_tickets
# Afficher le résumé
log_separator()
Étape 3 : Mettre à jour le fichier odoo_extractor.py pour assurer la cohérence
Maintenant, vérifions et ajustons le fichier odoo_extractor.py pour s'assurer que les noms de champs et la génération des rapports Markdown sont cohérents.
Read file: odoo_extractor.py
Le fichier odoo_extractor.py semble déjà bien configuré pour gérer la génération des rapports Markdown. Il utilise le bon nom de champ output_dir pour localiser les répertoires de tickets et possède déjà la logique pour générer les rapports.
Maintenant, testons les modifications apportées pour vérifier que tout fonctionne correctement.
cd /home/fgras-ca/llm-ticket3 && python odoo_extractor.py batch --project 3 --stage 8 --limit 5 --verbose
<ython odoo_extractor.py batch --project 3 --stage 8 --limit 5 --verbose
usage: odoo_extractor.py [-h] [--config CONFIG] [--verbose] [--output OUTPUT] [--no-md]
[--extract-html-images]
{ticket,batch,projects,stages} ...
odoo_extractor.py: error: unrecognized arguments: --verbose
fgras-ca@PC-DEV:~/llm-ticket3$
Il semble y avoir un problème avec la façon dont les arguments sont traités. Le problème est que l'option --verbose est définie au niveau global et au niveau de la commande batch. Corrigeons cela dans le fichier odoo_extractor.py :
cd /home/fgras-ca/llm-ticket3 && python odoo_extractor.py batch --project 3 --stage 8 --limit 5
<cket3 && python odoo_extractor.py batch --project 3 --stage 8 --limit 5
Démarrage de l'extraction par lot avec les critères: [['project_id', '=', 3], ['stage_id', '=', 8]]
Limite: 5 tickets, offset: 0
2025-04-15 11:13:30 - root - INFO - Démarrage de l'extraction par lot avec les critères: [['project_id', '='
, 3], ['stage_id', '=', 8]]
2025-04-15 11:13:30 - root - INFO - Limite: 5 tickets, offset: 0
2025-04-15 11:13:30 - root - INFO - ------------------------------------------------------------
2025-04-15 11:13:30 - root - INFO - Tentative de connexion à https://odoo.cbao.fr avec l'utilisateur fernand
@cbao.fr
2025-04-15 11:13:30 - root - INFO - Authentification réussie. UID: 33
2025-04-15 11:13:30 - root - INFO - Nombre total de tickets correspondant aux critères: 6050
2025-04-15 11:13:31 - root - INFO - Traitement du ticket T11163...
2025-04-15 11:13:31 - root - INFO - Traitement de 1 pièces jointes pour le ticket 11142
2025-04-15 11:13:31 - root - INFO - Pièce jointe téléchargée: plaque statique V2.xlsx (1/1)
2025-04-15 11:13:31 - root - INFO - Ticket T11163 extrait avec succès
2025-04-15 11:13:31 - root - INFO - Traitement du ticket T11146...
2025-04-15 11:13:32 - root - INFO - Traitement de 2 pièces jointes pour le ticket 11125
2025-04-15 11:13:32 - root - INFO - Pièce jointe téléchargée: image002.jpg (1/2)
2025-04-15 11:13:32 - root - INFO - Pièce jointe téléchargée: image001.jpg (2/2)
2025-04-15 11:13:32 - root - INFO - Ticket T11146 extrait avec succès
2025-04-15 11:13:32 - root - INFO - Traitement du ticket T11143...
2025-04-15 11:13:32 - root - INFO - Traitement de 1 pièces jointes pour le ticket 11122
2025-04-15 11:13:32 - root - INFO - Pièce jointe téléchargée: image.png (1/1)
2025-04-15 11:13:32 - root - INFO - Ticket T11143 extrait avec succès
2025-04-15 11:13:32 - root - INFO - Traitement du ticket T11140...
2025-04-15 11:13:33 - root - INFO - Aucune pièce jointe trouvée pour le ticket 11119
2025-04-15 11:13:33 - root - INFO - Ticket T11140 extrait avec succès
2025-04-15 11:13:33 - root - INFO - Traitement du ticket T11132...
2025-04-15 11:13:33 - root - INFO - Aucune pièce jointe trouvée pour le ticket 11111
2025-04-15 11:13:33 - root - INFO - Ticket T11132 extrait avec succès
2025-04-15 11:13:33 - root - INFO - Extraction par lot terminée avec succès.
2025-04-15 11:13:33 - root - INFO - Tickets traités: 5
2025-04-15 11:13:33 - root - INFO - Tickets ignorés: 0
2025-04-15 11:13:33 - root - INFO - Tickets en échec: 0
2025-04-15 11:13:33 - root - INFO - Tickets exclus par tag 'BRG-LAB WIN': 0
2025-04-15 11:13:33 - root - INFO - Répertoire de sortie: output
2025-04-15 11:13:33 - root - INFO - ------------------------------------------------------------
2025-04-15 11:13:33 - root - INFO - Extraction par lot terminée
2025-04-15 11:13:33 - root - INFO - Tickets traités: 5
2025-04-15 11:13:33 - root - INFO - Tickets ignorés: 0
2025-04-15 11:13:33 - root - INFO - Tickets exclus par tag 'BRG-LAB WIN': 0
2025-04-15 11:13:33 - root - INFO - Répertoire: output
2025-04-15 11:13:33 - root - INFO - ------------------------------------------------------------
Extraction par lot terminée
Tickets traités: 5
Tickets ignorés: 0
Génération des rapports Markdown pour les tickets extraits...
Génération du rapport Markdown pour T11163...
Rapport Markdown créé : output/T11163_20250415_111331/T11163_rapports/T11163_rapport.md
Conversion terminée. Fichier JSON créé : output/T11163_20250415_111331/T11163_rapports/T11163_rapport.json
Fichier JSON créé : output/T11163_20250415_111331/T11163_rapports/T11163_rapport.json
Rapport Markdown créé: output/T11163_20250415_111331/rapport.md
Génération du rapport Markdown pour T11146...
Rapport Markdown créé : output/T11146_20250415_111331/T11146_rapports/T11146_rapport.md
Conversion terminée. Fichier JSON créé : output/T11146_20250415_111331/T11146_rapports/T11146_rapport.json
Fichier JSON créé : output/T11146_20250415_111331/T11146_rapports/T11146_rapport.json
Rapport Markdown créé: output/T11146_20250415_111331/rapport.md
Génération du rapport Markdown pour T11143...
Rapport Markdown créé : output/T11143_20250415_111332/T11143_rapports/T11143_rapport.md
Conversion terminée. Fichier JSON créé : output/T11143_20250415_111332/T11143_rapports/T11143_rapport.json
Fichier JSON créé : output/T11143_20250415_111332/T11143_rapports/T11143_rapport.json
Rapport Markdown créé: output/T11143_20250415_111332/rapport.md
Génération du rapport Markdown pour T11140...
Rapport Markdown créé : output/T11140_20250415_111332/T11140_rapports/T11140_rapport.md
Conversion terminée. Fichier JSON créé : output/T11140_20250415_111332/T11140_rapports/T11140_rapport.json
Fichier JSON créé : output/T11140_20250415_111332/T11140_rapports/T11140_rapport.json
Rapport Markdown créé: output/T11140_20250415_111332/rapport.md
Génération du rapport Markdown pour T11132...
Rapport Markdown créé : output/T11132_20250415_111333/T11132_rapports/T11132_rapport.md
Conversion terminée. Fichier JSON créé : output/T11132_20250415_111333/T11132_rapports/T11132_rapport.json
Fichier JSON créé : output/T11132_20250415_111333/T11132_rapports/T11132_rapport.json
Rapport Markdown créé: output/T11132_20250415_111333/rapport.md
fgras-ca@PC-DEV:~/llm-ticket3$
Il semble que l'exécution ait commencé, ce qui est un bon signe. Maintenant, vérifions la structure du répertoire pour voir si les tickets sont bien extraits directement dans le répertoire de sortie et non dans un sous-répertoire batch.
cd /home/fgras-ca/llm-ticket3 && ls -la output/
fgras-ca@PC-DEV:~/llm-ticket3$ cd /home/fgras-ca/llm-ticket3 && ls -la output/
total 36
drwxr-xr-x 7 fgras-ca fgras-ca 4096 Apr 15 11:13 .
drwxr-xr-x 17 fgras-ca fgras-ca 4096 Apr 15 09:11 ..
drwxr-xr-x 3 fgras-ca fgras-ca 4096 Apr 15 11:13 T11132_20250415_111333
drwxr-xr-x 3 fgras-ca fgras-ca 4096 Apr 15 11:13 T11140_20250415_111332
drwxr-xr-x 4 fgras-ca fgras-ca 4096 Apr 15 11:13 T11143_20250415_111332
drwxr-xr-x 4 fgras-ca fgras-ca 4096 Apr 15 11:13 T11146_20250415_111331
drwxr-xr-x 4 fgras-ca fgras-ca 4096 Apr 15 11:13 T11163_20250415_111331
-rw-r--r-- 1 fgras-ca fgras-ca 1551 Apr 15 11:13 batch_summary_20250415_111331.json
-rw-r--r-- 1 fgras-ca fgras-ca 96 Apr 15 11:13 extracted_tickets.json
fgras-ca@PC-DEV:~/llm-ticket3$
Excellent ! Les modifications ont réussi. Maintenant, les tickets sont extraits directement dans le répertoire output au lieu d'être dans un sous-répertoire batch.
Vérifions maintenant si les fichiers JSON et les rapports Markdown sont correctement générés dans les répertoires des tickets :
cd /home/fgras-ca/llm-ticket3 && ls -la output/T11163_20250415_111331/
fgras-ca@PC-DEV:~/llm-ticket3$ cd /home/fgras-ca/llm-ticket3 && ls -la output/T11163_20250415_111331/
total 48
drwxr-xr-x 4 fgras-ca fgras-ca 4096 Apr 15 11:13 .
drwxr-xr-x 7 fgras-ca fgras-ca 4096 Apr 15 11:13 ..
drwxr-xr-x 2 fgras-ca fgras-ca 4096 Apr 15 11:13 T11163_rapports
-rw-r--r-- 1 fgras-ca fgras-ca 2420 Apr 15 11:13 all_messages.json
-rw-r--r-- 1 fgras-ca fgras-ca 834 Apr 15 11:13 all_messages.txt
drwxr-xr-x 2 fgras-ca fgras-ca 4096 Apr 15 11:13 attachments
-rw-r--r-- 1 fgras-ca fgras-ca 523 Apr 15 11:13 attachments_info.json
-rw-r--r-- 1 fgras-ca fgras-ca 263 Apr 15 11:13 followers.json
-rw-r--r-- 1 fgras-ca fgras-ca 2735 Apr 15 11:13 messages_raw.json
-rw-r--r-- 1 fgras-ca fgras-ca 575 Apr 15 11:13 structure.json
-rw-r--r-- 1 fgras-ca fgras-ca 1588 Apr 15 11:13 ticket_info.json
-rw-r--r-- 1 fgras-ca fgras-ca 1009 Apr 15 11:13 ticket_summary.json
fgras-ca@PC-DEV:~/llm-ticket3$
Je ne vois pas de fichier rapport.md dans ce répertoire. Vérifions si la fonction de génération des rapports Markdown est bien appelée dans le fichier odoo_extractor.py :
cd /home/fgras-ca/llm-ticket3 && python odoo_extractor.py batch --project 3 --stage 8 --limit 1
<cket3 && python odoo_extractor.py batch --project 3 --stage 8 --limit 1
Démarrage de l'extraction par lot avec les critères: [['project_id', '=', 3], ['stage_id', '=', 8]]
Limite: 1 tickets, offset: 0
2025-04-15 11:17:18 - root - INFO - Démarrage de l'extraction par lot avec les critères: [['project_id', '='
, 3], ['stage_id', '=', 8]]
2025-04-15 11:17:18 - root - INFO - Limite: 1 tickets, offset: 0
2025-04-15 11:17:18 - root - INFO - ------------------------------------------------------------
2025-04-15 11:17:18 - root - INFO - Tentative de connexion à https://odoo.cbao.fr avec l'utilisateur fernand
@cbao.fr
2025-04-15 11:17:18 - root - INFO - Authentification réussie. UID: 33
2025-04-15 11:17:18 - root - INFO - Nombre total de tickets correspondant aux critères: 6050
2025-04-15 11:17:18 - root - INFO - Chargé 5 tickets déjà extraits
2025-04-15 11:17:18 - root - INFO - Ticket T11163 déjà extrait, ignoré
2025-04-15 11:17:18 - root - INFO - Extraction par lot terminée avec succès.
2025-04-15 11:17:18 - root - INFO - Tickets traités: 0
2025-04-15 11:17:18 - root - INFO - Tickets ignorés: 1
2025-04-15 11:17:18 - root - INFO - Tickets en échec: 0
2025-04-15 11:17:18 - root - INFO - Tickets exclus par tag 'BRG-LAB WIN': 0
2025-04-15 11:17:18 - root - INFO - Répertoire de sortie: output
2025-04-15 11:17:18 - root - INFO - ------------------------------------------------------------
2025-04-15 11:17:18 - root - INFO - Extraction par lot terminée
2025-04-15 11:17:18 - root - INFO - Tickets traités: 0
2025-04-15 11:17:18 - root - INFO - Tickets ignorés: 1
2025-04-15 11:17:18 - root - INFO - Tickets exclus par tag 'BRG-LAB WIN': 0
2025-04-15 11:17:18 - root - INFO - Répertoire: output
2025-04-15 11:17:18 - root - INFO - ------------------------------------------------------------
Extraction par lot terminée
Tickets traités: 0
Tickets ignorés: 1
Génération des rapports Markdown pour les tickets extraits...
fgras-ca@PC-DEV:~/llm-ticket3$
Je remarque que la génération des rapports Markdown est tentée, mais il n'y a pas de tickets traités dans cette exécution car le ticket T11163 a déjà été extrait.
Essayons une dernière fois avec l'option --include-existing pour forcer l'extraction même des tickets déjà présents, et ainsi générer les rapports Markdown :
cd /home/fgras-ca/llm-ticket3 && python odoo_extractor.py batch --project 3 --stage 8 --limit 1 --include-existing
<o_extractor.py batch --project 3 --stage 8 --limit 1 --include-existing
Démarrage de l'extraction par lot avec les critères: [['project_id', '=', 3], ['stage_id', '=', 8]]
Limite: 1 tickets, offset: 0
2025-04-15 11:17:38 - root - INFO - Démarrage de l'extraction par lot avec les critères: [['project_id', '='
, 3], ['stage_id', '=', 8]]
2025-04-15 11:17:38 - root - INFO - Limite: 1 tickets, offset: 0
2025-04-15 11:17:38 - root - INFO - ------------------------------------------------------------
2025-04-15 11:17:38 - root - INFO - Tentative de connexion à https://odoo.cbao.fr avec l'utilisateur fernand
@cbao.fr
2025-04-15 11:17:39 - root - INFO - Authentification réussie. UID: 33
2025-04-15 11:17:39 - root - INFO - Nombre total de tickets correspondant aux critères: 6050
2025-04-15 11:17:39 - root - INFO - Traitement du ticket T11163...
2025-04-15 11:17:39 - root - INFO - Traitement de 1 pièces jointes pour le ticket 11142
2025-04-15 11:17:39 - root - INFO - Pièce jointe téléchargée: plaque statique V2.xlsx (1/1)
2025-04-15 11:17:39 - root - INFO - Ticket T11163 extrait avec succès
2025-04-15 11:17:39 - root - INFO - Extraction par lot terminée avec succès.
2025-04-15 11:17:39 - root - INFO - Tickets traités: 1
2025-04-15 11:17:39 - root - INFO - Tickets ignorés: 0
2025-04-15 11:17:39 - root - INFO - Tickets en échec: 0
2025-04-15 11:17:39 - root - INFO - Tickets exclus par tag 'BRG-LAB WIN': 0
2025-04-15 11:17:39 - root - INFO - Répertoire de sortie: output
2025-04-15 11:17:39 - root - INFO - ------------------------------------------------------------
2025-04-15 11:17:39 - root - INFO - Extraction par lot terminée
2025-04-15 11:17:39 - root - INFO - Tickets traités: 1
2025-04-15 11:17:39 - root - INFO - Tickets ignorés: 0
2025-04-15 11:17:39 - root - INFO - Tickets exclus par tag 'BRG-LAB WIN': 0
2025-04-15 11:17:39 - root - INFO - Répertoire: output
2025-04-15 11:17:39 - root - INFO - ------------------------------------------------------------
Extraction par lot terminée
Tickets traités: 1
Tickets ignorés: 0
Génération des rapports Markdown pour les tickets extraits...
Génération du rapport Markdown pour T11163...
Rapport Markdown créé : output/T11163_20250415_111739/T11163_rapports/T11163_rapport.md
Conversion terminée. Fichier JSON créé : output/T11163_20250415_111739/T11163_rapports/T11163_rapport.json
Fichier JSON créé : output/T11163_20250415_111739/T11163_rapports/T11163_rapport.json
Rapport Markdown créé: output/T11163_20250415_111739/rapport.md
fgras-ca@PC-DEV:~/llm-ticket3$
Parfait ! Cette fois, nous voyons que la génération des rapports Markdown a fonctionné. Un rapport a été créé à l'emplacement output/T11163_20250415_111739/rapport.md.
Vérifions le contenu du répertoire du ticket pour confirmer que tous les fichiers attendus sont bien présents :
cd /home/fgras-ca/llm-ticket3 && ls -la output/T11163_20250415_111739/
fgras-ca@PC-DEV:~/llm-ticket3$ cd /home/fgras-ca/llm-ticket3 && ls -la output/T11163_20250415_111739/
total 48
drwxr-xr-x 4 fgras-ca fgras-ca 4096 Apr 15 11:17 .
drwxr-xr-x 8 fgras-ca fgras-ca 4096 Apr 15 11:17 ..
drwxr-xr-x 2 fgras-ca fgras-ca 4096 Apr 15 11:17 T11163_rapports
-rw-r--r-- 1 fgras-ca fgras-ca 2420 Apr 15 11:17 all_messages.json
-rw-r--r-- 1 fgras-ca fgras-ca 834 Apr 15 11:17 all_messages.txt
drwxr-xr-x 2 fgras-ca fgras-ca 4096 Apr 15 11:17 attachments
-rw-r--r-- 1 fgras-ca fgras-ca 523 Apr 15 11:17 attachments_info.json
-rw-r--r-- 1 fgras-ca fgras-ca 263 Apr 15 11:17 followers.json
-rw-r--r-- 1 fgras-ca fgras-ca 2735 Apr 15 11:17 messages_raw.json
-rw-r--r-- 1 fgras-ca fgras-ca 575 Apr 15 11:17 structure.json
-rw-r--r-- 1 fgras-ca fgras-ca 1588 Apr 15 11:17 ticket_info.json
-rw-r--r-- 1 fgras-ca fgras-ca 1009 Apr 15 11:17 ticket_summary.json
fgras-ca@PC-DEV:~/llm-ticket3$
Le répertoire contient tous les fichiers nécessaires, mais il manque encore le fichier rapport.md mentionné dans la sortie. Voyons si le rapport a été créé dans un autre emplacement ou s'il y a encore un problème :
Cancelled
User
les rapports sont dans un sous répertoire qui a pour nom le code du ticket collé a "_rapports"
Assistant
C'est vrai, j'ai remarqué que les rapports sont générés dans un sous-répertoire nommé avec le code du ticket suivi de "_rapports" (par exemple, "T11163_rapports"). Cela n'est pas cohérent avec le comportement de l'extraction d'un ticket unique.
Vérifions maintenant la structure du répertoire avec la commande suivante :
cd /home/fgras-ca/llm-ticket3 && ls -la output/T11163_20250415_111739/T11163_rapports/
<ca/llm-ticket3 && ls -la output/T11163_20250415_111739/T11163_rapports/
total 16
drwxr-xr-x 2 fgras-ca fgras-ca 4096 Apr 15 11:17 .
drwxr-xr-x 4 fgras-ca fgras-ca 4096 Apr 15 11:17 ..
-rw-r--r-- 1 fgras-ca fgras-ca 1062 Apr 15 11:17 T11163_rapport.json
-rw-r--r-- 1 fgras-ca fgras-ca 1138 Apr 15 11:17 T11163_rapport.md
fgras-ca@PC-DEV:~/llm-ticket3$
Pour maintenir une cohérence avec l'extraction d'un ticket unique, nous devons modifier le code pour que les rapports soient générés directement dans le répertoire principal du ticket, et non dans un sous-répertoire spécifique.
Read file: odoo/ticket_manager.py
Pour résoudre le problème des rapports générés dans un sous-répertoire, je vais chercher d'abord où ce sous-répertoire est créé. Je vais examiner les fichiers liés à la création des rapports :
Cancelled
User
non pas la peine je veux qu'ils soient dans ce répertoire rien a modifier
Assistant
D'accord, si vous souhaitez que les rapports restent dans le sous-répertoire nommé avec le code du ticket suivi de "_rapports", il n'est pas nécessaire de modifier le code pour changer leur emplacement.
Si vous avez d'autres questions ou si vous avez besoin d'aide supplémentaire concernant l'extraction des tickets ou la génération des rapports, n'hésitez pas à demander !
User
autre chose concernant les répertoire de création retrieve_ticket.py pour la récupération d'un ticket @ticket_T9656 créé un répertoire ticket_T9656 avec le code du ticket et ensuite un répertoire avec code ticket et dateheure de creation je voudrai reproduire la même chose avec mon extracteur par lot
Assistant
Read file: odoo/retrieve_ticket.py
Read file: odoo/batch_ticket_manager.py
Pour reproduire la même structure de répertoires que celle créée par retrieve_ticket.py dans votre extracteur par lot, je vais modifier le fichier batch_ticket_manager.py. Voici les modifications à faire :
# ... existing code ...
logging.info(f"Traitement du ticket {ticket_code}...")
# Créer un répertoire parent pour ce ticket
ticket_parent_dir = os.path.join(base_output_dir, f"ticket_{ticket_code}")
ensure_dir(ticket_parent_dir)
# Créer un répertoire spécifique pour ce ticket avec timestamp
timestamp_ticket = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(ticket_parent_dir, f"{ticket_code}_{timestamp_ticket}")
ensure_dir(ticket_dir)
try:
# Extraire les données
# ... existing code ...
Cette modification crée d'abord un répertoire parent nommé ticket_T9656 puis un sous-répertoire avec le format T9656_20250415_112801 à l'intérieur, exactement comme dans le cas de retrieve_ticket.py.
User
je voudrai ne pas git les répertoires output, reports, csv et les fichiers config a ajouter dans mon gitignore
Assistant
Pour ignorer les répertoires output, reports, csv et les fichiers de configuration dans votre dépôt Git, vous devez ajouter les lignes suivantes à votre fichier .gitignore :
# Environnement virtuel
# Ignorer les répertoires de sortie et les fichiers de configuration
output/
reports/
csv/
*.json
*.yml
*.yaml
*.config
Assurez-vous que chaque répertoire ou fichier que vous souhaitez ignorer est bien spécifié. Après avoir modifié le fichier .gitignore, n'oubliez pas de valider les changements dans votre dépôt Git. Si ces répertoires ou fichiers étaient déjà suivis par Git, vous devrez les retirer de l'index avec la commande suivante :
git rm -r --cached output reports csv
Cela supprimera les répertoires de l'index tout en les laissant sur votre disque. Ensuite, vous pouvez valider les modifications de votre .gitignore.
User
peux tu être plus précis sur l'emplacement des modifications a effectuer dans batch_ticket_maanger.py # ... existing code ...
logging.info(f"Traitement du ticket {ticket_code}...")
# Créer un répertoire parent pour ce ticket
ticket_parent_dir = os.path.join(base_output_dir, f"ticket_{ticket_code}")
ensure_dir(ticket_parent_dir)
# Créer un répertoire spécifique pour ce ticket avec timestamp
timestamp_ticket = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(ticket_parent_dir, f"{ticket_code}_{timestamp_ticket}")
ensure_dir(ticket_dir)
try:
# Extraire les données
... existing code ...
Assistant
Pour effectuer les modifications dans le fichier batch_ticket_manager.py, vous devez les insérer dans la méthode extract_tickets_batch, juste avant l'extraction des données du ticket. Voici les étapes précises :
-
Localisez la méthode
extract_tickets_batchdansbatch_ticket_manager.py. Vous devriez trouver cette méthode à partir de la ligne 185. -
Ajoutez les modifications juste après la ligne où vous traitez chaque ticket, c'est-à-dire après la ligne qui contient
logging.info(f"Traitement du ticket {ticket_code}...").
Voici à quoi cela devrait ressembler :
# ... existing code ...
logging.info(f"Traitement du ticket {ticket_code}...")
# Créer un répertoire parent pour ce ticket
ticket_parent_dir = os.path.join(base_output_dir, f"ticket_{ticket_code}")
ensure_dir(ticket_parent_dir)
# Créer un répertoire spécifique pour ce ticket avec timestamp
timestamp_ticket = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(ticket_parent_dir, f"{ticket_code}_{timestamp_ticket}")
ensure_dir(ticket_dir)
try:
# Extraire les données
result = self.ticket_manager.extract_ticket_data(ticket_code, ticket_dir)
# ... existing code ...
Résumé des modifications :
- Création d'un répertoire parent :
ticket_parent_dirpour chaque ticket, qui contiendra le code du ticket. - Création d'un sous-répertoire :
ticket_diravec le code du ticket et un timestamp pour stocker les données extraites.
Ces modifications garantiront que chaque ticket extrait a sa propre structure de répertoire, similaire à celle que vous avez dans retrieve_ticket.py.
User
le répertoire ticket_Tcode sont bien créés mais le contenu est toujours dans output et non pas dans son répertoire de ticket as tu compris le problème?
Assistant
Je vois le problème. Les répertoires ticket_Tcode sont créés mais les fichiers sont toujours placés dans le répertoire output directement. Pour résoudre ce problème, il faut examiner l'emplacement exact du code où les répertoires sont créés et où les données sont extraites.
Voici la modification précise à apporter dans odoo/batch_ticket_manager.py aux alentours de la ligne 257 :
logging.info(f"Traitement du ticket {ticket_code}...")
# Créer un répertoire parent pour ce ticket
ticket_parent_dir = os.path.join(base_output_dir, f"ticket_{ticket_code}")
ensure_dir(ticket_parent_dir)
# Créer un répertoire spécifique pour ce ticket avec timestamp
timestamp_ticket = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(ticket_parent_dir, f"{ticket_code}_{timestamp_ticket}")
ensure_dir(ticket_dir)
try:
# Extraire les données
result = self.ticket_manager.extract_ticket_data(ticket_code, ticket_dir)
D'après les logs que vous avez partagés, je constate que les fichiers sont toujours placés dans des répertoires comme output/T11130_20250415_114643/ au lieu de output/ticket_T11130/T11130_20250415_114643/.
Le problème semble être que les noms de répertoires que nous avons définis dans notre modification ne sont pas repris dans le reste du code. Il faut donc s'assurer que toutes les références au répertoire du ticket utilisent la nouvelle variable ticket_dir.
Vérifiez également que la modification est faite dans le bon fichier et au bon endroit. Les logs montrent que le code continue à créer les répertoires directement dans output/.
User
peux tu m'aider a corriger ce problème
Assistant
Je vais vous aider à corriger ce problème. Il semble que les répertoires ticket_Tcode sont bien créés, mais les fichiers sont toujours placés dans le mauvais chemin. Examinons la structure exacte du code autour de la ligne 254 dans odoo/batch_ticket_manager.py.
Read file: odoo/batch_ticket_manager.py
Je vois le problème ! Bien que vous créiez le répertoire parent correctement, vous placez toujours les fichiers directement dans output. La ligne problématique est :
ticket_dir = os.path.join(base_output_dir, f"{ticket_code}_{timestamp_ticket}")
Alors qu'elle devrait utiliser le répertoire parent comme base :
ticket_dir = os.path.join(ticket_parent_dir, f"{ticket_code}_{timestamp_ticket}")
Voici la correction à apporter à odoo/batch_ticket_manager.py :
logging.info(f"Traitement du ticket {ticket_code}...")
# Créer un répertoire parent pour ce ticket
ticket_parent_dir = os.path.join(base_output_dir, f"ticket_{ticket_code}")
ensure_dir(ticket_parent_dir)
# Créer un répertoire spécifique pour ce ticket avec timestamp
timestamp_ticket = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(ticket_parent_dir, f"{ticket_code}_{timestamp_ticket}")
ensure_dir(ticket_dir)
try:
# Extraire les données
result = self.ticket_manager.extract_ticket_data(ticket_code, ticket_dir)
Cette modification garantira que les fichiers sont placés dans le répertoire ticket_Tcode/Tcode_timestamp/ plutôt que directement dans output/Tcode_timestamp/.
User
je voudrai centraliser ma méthode d'identification odoo j'appelle mon identification dans plusieurs fichier il serait préferable de centraliser cela. Je voudrai que tu m'aides pas à pas pour réaliser cela. En m'indiquant avec précision où supprimer ou ajouter du code pour le réaliser
Assistant
Je vais vous aider à centraliser votre méthode d'identification Odoo pas à pas. Actuellement, plusieurs fichiers initialisent leur propre connexion à Odoo. Nous allons créer une fonction centralisée et l'utiliser partout.
Étape 1: Créer un nouveau fichier pour centraliser l'authentification
Read file: odoo/auth_manager.py
Créons d'abord un nouveau fichier pour centraliser l'authentification :
"""
Module pour centraliser la connexion à Odoo.
Fournit des fonctions pour obtenir une connexion authentifiée de manière cohérente.
"""
import os
import json
import logging
from typing import Optional, Dict, Any
from .auth_manager import AuthManager
# Variable globale pour stocker l'instance du gestionnaire d'authentification
_auth_manager_instance = None
def load_config(config_file: str = "config.json") -> Dict[str, Any]:
"""
Charge le fichier de configuration.
Args:
config_file: Chemin vers le fichier de configuration
Returns:
Dictionnaire contenant la configuration
"""
try:
with open(config_file, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logging.error(f"Erreur lors du chargement du fichier de configuration: {e}")
return {}
def get_auth_manager(config_file: str = "config.json", force_new: bool = False) -> Optional[AuthManager]:
"""
Obtient une instance unique du gestionnaire d'authentification Odoo.
Args:
config_file: Chemin vers le fichier de configuration
force_new: Force la création d'une nouvelle instance
Returns:
Instance du AuthManager ou None en cas d'erreur
"""
global _auth_manager_instance
# Si une instance existe déjà et qu'on ne force pas la création, la retourner
if _auth_manager_instance is not None and not force_new:
return _auth_manager_instance
# Charger la configuration
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]):
logging.error("Informations de connexion Odoo manquantes dans le fichier de configuration")
return None
# Créer une nouvelle instance
try:
auth_manager = AuthManager(
url=url,
db=db,
username=username,
api_key=api_key
)
# Se connecter à Odoo
if not auth_manager.login():
logging.error("Échec de l'authentification à Odoo")
return None
# Stocker l'instance pour les appels futurs
_auth_manager_instance = auth_manager
return auth_manager
except Exception as e:
logging.exception(f"Erreur lors de l'initialisation du gestionnaire d'authentification: {e}")
return None
def get_output_dir(config_file: str = "config.json", subdir: Optional[str] = None) -> str:
"""
Obtient le répertoire de sortie à partir de la configuration.
Args:
config_file: Chemin vers le fichier de configuration
subdir: Sous-répertoire à ajouter au chemin (optionnel)
Returns:
Chemin du répertoire de sortie
"""
config = load_config(config_file)
output_dir = config.get("output_dir", "output")
if subdir:
return os.path.join(output_dir, subdir)
return output_dir
Étape 2: Modifier les fichiers utilisant l'authentification
A. D'abord, examinons retrieve_ticket.py:
Read file: odoo/retrieve_ticket.py
B. Puis retrieve_tickets_batch.py:
Read file: odoo/retrieve_tickets_batch.py
Étape 3: Modification des fichiers pour utiliser le connecteur centralisé
A. Mettons à jour retrieve_ticket.py:
#!/usr/bin/env python3
import os
import sys
import json
import logging
import argparse
from datetime import datetime
from .ticket_manager import TicketManager
from .odoo_connector import get_auth_manager, get_output_dir
from core.utils import setup_logging, log_separator
def retrieve_ticket(ticket_code, output=None, config_file="config.json", verbose=False):
# Configurer la journalisation
log_level = logging.DEBUG if verbose else logging.INFO
setup_logging(log_level, "retrieve_ticket.log")
# Obtenir le gestionnaire d'authentification
auth_manager = get_auth_manager(config_file)
if not auth_manager:
logging.error("Impossible d'obtenir le gestionnaire d'authentification Odoo")
return None
# Définir le répertoire de sortie
output_base = output or get_output_dir(config_file)
output_dir = os.path.join(output_base, f"ticket_{ticket_code}")
# Créer le répertoire de sortie spécifique au ticket
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(output_dir, f"{ticket_code}_{timestamp}")
os.makedirs(ticket_dir, exist_ok=True)
logging.info(f"Extraction du ticket {ticket_code}")
log_separator()
try:
# Extraire les données du ticket
ticket_manager = TicketManager(auth_manager)
result = ticket_manager.extract_ticket_data(ticket_code, ticket_dir)
if not result:
logging.error(f"Échec de l'extraction du ticket {ticket_code}")
return None
# Afficher le résumé
log_separator()
logging.info(f"Extraction terminée avec succès")
logging.info(f"Ticket: {ticket_code}")
logging.info(f"Répertoire: {ticket_dir}")
logging.info(f"Messages traités: {result.get('messages_count', 0)}")
logging.info(f"Pièces jointes: {result.get('attachments_count', 0)}")
log_separator()
# Générer un rapport de fin
summary = {
"timestamp": timestamp,
"ticket_code": ticket_code,
"output_directory": ticket_dir,
"message_count": result.get("messages_count", 0),
"attachment_count": result.get("attachments_count", 0),
"files_created": [
os.path.basename(result.get("ticket_info", "")),
os.path.basename(result.get("ticket_summary", "")),
os.path.basename(result.get("messages_file", "")),
os.path.basename(result.get("ticket_data_file", ""))
]
}
summary_path = os.path.join(ticket_dir, "extraction_summary.json")
with open(summary_path, 'w', encoding='utf-8') as f:
json.dump(summary, f, indent=2, ensure_ascii=False)
print(f"\nExtraction du ticket {ticket_code} terminée avec succès.")
print(f"Les données ont été sauvegardées dans: {ticket_dir}")
return ticket_dir
except Exception as e:
logging.exception(f"Une erreur est survenue: {e}")
return None
def parse_arguments():
parser = argparse.ArgumentParser(description="Récupère un ticket Odoo par son code et extrait ses données.")
parser.add_argument("ticket_code", help="Code du ticket à extraire")
parser.add_argument("--output", "-o", help="Répertoire de sortie", default=None)
parser.add_argument("--config", "-c", help="Fichier de configuration", default="config.json")
parser.add_argument("--verbose", "-v", action="store_true", help="Mode verbeux")
return parser.parse_args()
def main():
args = parse_arguments()
result = retrieve_ticket(
ticket_code=args.ticket_code,
output=args.output,
config_file=args.config,
verbose=args.verbose
)
if not result:
sys.exit(1)
if __name__ == "__main__":
main()
B. Mettons à jour retrieve_tickets_batch.py:
#!/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 .ticket_manager import TicketManager
from .batch_ticket_manager import BatchTicketManager
from .odoo_connector import get_auth_manager, get_output_dir, 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
"""
# Configurer la journalisation
log_level = logging.DEBUG if verbose else logging.INFO
setup_logging(log_level, "retrieve_tickets_batch.log")
# Obtenir le gestionnaire d'authentification
auth_manager = get_auth_manager(config_file)
if not auth_manager:
logging.error("Impossible d'obtenir le gestionnaire d'authentification Odoo")
return None
# Définir le répertoire de sortie
base_output_dir = output or get_output_dir(config_file)
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
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"Tickets exclus par tag 'BRG-LAB WIN': {result.get('excluded_by_tag', 0)}")
logging.info(f"Répertoire: {result.get('batch_dir', '')}")
log_separator()
# Afficher les tickets exclus à cause du tag "BRG-LAB WIN"
excluded_tickets = result.get('excluded_tickets', [])
if excluded_tickets:
print("\nLes tickets suivants ont été exclus car ils possèdent le tag 'BRG-LAB WIN':")
for ticket in excluded_tickets:
print(f"- {ticket.get('code', 'Code inconnu')}: {ticket.get('name', 'Nom inconnu')}")
print(f"Total: {len(excluded_tickets)} ticket(s) exclu(s)")
print("Ces tickets sont exclus de l'extraction conformément à la politique.")
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
"""
# Obtenir le gestionnaire d'authentification
auth_manager = get_auth_manager(config_file)
if not auth_manager:
print("Impossible d'obtenir le gestionnaire d'authentification Odoo")
return None
try:
# 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
"""
# Obtenir le gestionnaire d'authentification
auth_manager = get_auth_manager(config_file)
if not auth_manager:
print("Impossible d'obtenir le gestionnaire d'authentification Odoo")
return None
try:
# 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
# [Le reste du fichier reste inchangé]
C. Mettons à jour odoo_extractor.py:
Read file: odoo_extractor.py
Voici la version mise à jour de odoo_extractor.py :
"""
Script pour récupérer les tickets depuis odoo.
Extraction d'un ticket unique ou d'un groupe de tickets.
"""
import os
import sys
import json
import argparse
from datetime import datetime
from core.utils import setup_logging, log_separator
from formatters.json_to_markdown import create_markdown_from_json
from odoo.retrieve_ticket import retrieve_ticket
from odoo.retrieve_tickets_batch import retrieve_tickets_batch, parse_domain, list_projects, list_stages
from odoo.odoo_connector import get_auth_manager, load_config
#importation de l'extracteur d'images HTML (optionnel)
try:
from utils.image_extractor import extract_images_from_ticket
from utils.image_extractor.extract_all_images import enhance_ticket_data_with_images
HTML_IMAGE_EXTRACTOR_AVAILABLE = True
except ImportError:
HTML_IMAGE_EXTRACTOR_AVAILABLE = False
def parse_arguments():
"""Parse les arguments de ligne de commande."""
parser = argparse.ArgumentParser(description="Extrait des données depuis Odoo (ticket unique ou par lots).")
# Paramètres communs
parser.add_argument("--config", "-c", help="Fichier de configuration", default="config.json")
parser.add_argument("--verbose", "-v", action="store_true", help="Mode verbeux")
parser.add_argument("--output", "-o", help="Répertoire de sortie", default=None)
parser.add_argument("--no-md", action="store_true", help="Désactiver la génération automatique du fichier Markdown")
parser.add_argument("--extract-html-images", action="store_true", help="Activer l'extraction des images intégrées dans le HTML")
# Sous-parseurs pour les différentes commandes
subparsers = parser.add_subparsers(dest="command", help="Commande à exécuter")
# Commande pour extraire un ticket unique
single_parser = subparsers.add_parser("ticket", help="Extrait un ticket unique par son code")
single_parser.add_argument("ticket_code", help="Code du ticket à extraire")
# 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", type=int, default=0, help="Index de départ pour la pagination")
batch_parser.add_argument("--include-existing", action="store_true", help="Inclure les tickets déjà extraits")
# Commande pour lister les projets
projects_parser = subparsers.add_parser("projects", help="Liste les projets disponibles")
# Commande pour lister les étapes/statuts
stages_parser = subparsers.add_parser("stages", help="Liste les étapes/statuts disponibles")
return parser.parse_args()
def main():
"""Point d'entrée principal du script."""
args = parse_arguments()
# Vérifier si le fichier de configuration existe
if not os.path.exists(args.config):
print(f"Erreur: Fichier de configuration '{args.config}' introuvable.")
sys.exit(1)
# Configurer la journalisation
log_level = "DEBUG" if args.verbose else "INFO"
setup_logging(log_level)
# Vérifier la connexion Odoo une seule fois
if not get_auth_manager(args.config):
print("Impossible de se connecter à Odoo. Vérifiez vos informations de connexion.")
sys.exit(1)
# Traiter la commande appropriée
if args.command == "ticket":
# Extraction d'un ticket unique
result = retrieve_ticket(
ticket_code=args.ticket_code,
output=args.output,
config_file=args.config,
verbose=args.verbose
)
if not result:
print(f"Echec de l'extraction du ticket {args.ticket_code}")
sys.exit(1)
if not args.no_md:
# Génération du rapport Markdown
json_file = os.path.join(result, "all_messages.json")
if os.path.exists(json_file):
md_file_path = os.path.join(result, "rapport.md")
print(f"Génération du rapport Markdown...")
if create_markdown_from_json(json_file, md_file_path):
print(f"Rapport Markdown créé: {md_file_path}")
else:
print("Echec de la génération du rapport Markdown.")
elif args.command == "batch":
# Extraction par lot
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])
print(f"Démarrage de l'extraction par lot avec les critères: {domain}")
print(f"Limite: {args.limit} tickets, offset: {args.offset}")
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":
print("Echec de l'extraction par lots")
sys.exit(1)
# Afficher un résumé des résultats
print(f"Extraction par lot terminée")
print(f"Tickets traités: {result.get('processed', 0)}")
print(f"Tickets ignorés: {result.get('skipped', 0)}")
# Générer des rapports Markdown pour chaque ticket extrait
if not args.no_md:
print("Génération des rapports Markdown pour les tickets extraits...")
processed_tickets = result.get("processed_tickets", [])
for ticket_info in processed_tickets:
ticket_dir = ticket_info.get("output_dir")
if ticket_dir and os.path.exists(ticket_dir):
json_file = os.path.join(ticket_dir, "all_messages.json")
if os.path.exists(json_file):
md_file_path = os.path.join(ticket_dir, "rapport.md")
print(f"Génération du rapport Markdown pour {ticket_info.get('code')}...")
if create_markdown_from_json(json_file, md_file_path):
print(f"Rapport Markdown créé: {md_file_path}")
else:
print(f"Echec de la génération du rapport Markdown pour {ticket_info.get('code')}")
else:
print(f"Fichier de messages introuvable pour {ticket_info.get('code')}")
else:
print(f"Répertoire introuvable pour {ticket_info.get('code')}")
elif args.command == "projects":
# Lister les projets
list_projects(args.config)
elif args.command == "stages":
# Lister les étapes/statuts
list_stages(args.config)
else:
parser = argparse.ArgumentParser(description="Extrait des données depuis Odoo (ticket unique ou par lots).")
parser.print_help()
sys.exit(1)
if __name__ == "__main__":
main()
Étape 4: Vérification des modifications
Voici un résumé des modifications effectuées:
-
Nouveau fichier
odoo/odoo_connector.py:- Contient les fonctions pour obtenir une instance unique du gestionnaire d'authentification
- Encapsule la logique de lecture de configuration et d'initialisation
- Fournit des fonctions utilitaires comme
get_output_dirpour la cohérence
-
Modifications dans
retrieve_ticket.py:- Suppression de la logique de connexion Odoo
- Utilisation des fonctions du nouveau module
odoo_connector
-
Modifications dans
retrieve_tickets_batch.py:- Suppression des initialisations redondantes du gestionnaire d'authentification
- Utilisation des fonctions du nouveau module
odoo_connector
-
Modifications dans
odoo_extractor.py:- Simplification des imports
- Utilisation des fonctions centralisées pour l'authentification
Ces modifications garantissent que:
- L'authentification est centralisée dans un seul endroit
- Une seule instance d'AuthManager est utilisée par le programme
- Le code est plus maintenu, évitant les duplications
La prochaine fois que vous devrez modifier la logique d'authentification, vous n'aurez qu'à le faire dans odoo_connector.py et tous les fichiers qui l'utilisent bénéficieront automatiquement des changements.
User
j'ai déjà il me semble un fichier auth_manager.py qui s'occupe de l'authentification il faudrait se baser sur lui pour réaliser les modifications voulus
Assistant
Vous avez raison, votre fichier auth_manager.py gère déjà parfaitement l'authentification à Odoo. Au lieu de créer un nouveau fichier, nous allons plutôt étendre ce fichier existant pour centraliser la création des instances d'authentification.
Voici comment procéder:
Étape 1: Modifier auth_manager.py pour ajouter la centralisation
Plutôt que de créer un nouveau fichier, nous allons ajouter des fonctions au fichier auth_manager.py existant:
import json
import logging
import os
import requests
from typing import Dict, Any, Optional
# Variable globale pour stocker l'instance du gestionnaire d'authentification
_auth_manager_instance = None
class AuthManager:
"""
Gestionnaire d'authentification pour l'API Odoo.
Gère la connexion et les appels RPC à l'API Odoo.
"""
def __init__(self, url: str, db: str, username: str, api_key: str):
"""
Initialise le gestionnaire d'authentification.
Args:
url: URL de l'instance Odoo
db: Nom de la base de données Odoo
username: Nom d'utilisateur pour la connexion
api_key: Clé API ou mot de passe pour l'authentification
"""
self.url = url.rstrip('/')
self.db = db
self.username = username
self.api_key = api_key
self.uid = None
self.session = requests.Session()
self.session.headers.update({
'Content-Type': 'application/json',
'Accept': 'application/json'
})
self.max_retries = 3
self.timeout = 30 # secondes
def login(self) -> bool:
"""
Se connecte à l'API Odoo en utilisant les identifiants fournis.
Returns:
True si l'authentification réussie, False sinon
"""
try:
logging.info(f"Tentative de connexion à {self.url} avec l'utilisateur {self.username}")
endpoint = '/web/session/authenticate'
payload = {
"jsonrpc": "2.0",
"params": {
"db": self.db,
"login": self.username,
"password": self.api_key
}
}
response = self.session.post(
f"{self.url}{endpoint}",
data=json.dumps(payload),
timeout=self.timeout
)
response.raise_for_status()
result = response.json()
if 'error' in result:
error = result['error']
logging.error(f"Erreur d'authentification: {error.get('message', 'Erreur inconnue')}")
return False
self.uid = result.get('result', {}).get('uid')
if not self.uid:
logging.error("Erreur: UID non trouvé dans la réponse d'authentification")
return False
logging.info(f"Authentification réussie. UID: {self.uid}")
return True
except requests.RequestException as e:
logging.error(f"Erreur de connexion à l'API Odoo: {e}")
return False
except json.JSONDecodeError as e:
logging.error(f"Erreur de décodage JSON: {e}")
return False
except Exception as e:
logging.error(f"Erreur inattendue lors de l'authentification: {e}")
return False
def _rpc_call(self, endpoint: str, params: Dict[str, Any], retry_count: int = 0) -> Any:
"""
Effectue un appel RPC à l'API Odoo.
Args:
endpoint: Point de terminaison de l'API
params: Paramètres de l'appel
retry_count: Nombre de tentatives actuelles (pour les nouvelles tentatives)
Returns:
Résultat de l'appel RPC ou None en cas d'erreur
"""
if not self.uid and endpoint != '/web/session/authenticate':
logging.warning("Tentative d'appel RPC sans être authentifié. Reconnexion...")
if not self.login():
logging.error("Échec de la reconnexion")
return None
try:
payload = {
"jsonrpc": "2.0",
"params": params
}
response = self.session.post(
f"{self.url}{endpoint}",
data=json.dumps(payload),
timeout=self.timeout
)
response.raise_for_status()
result = response.json()
if 'error' in result:
error = result['error']
error_msg = error.get('message', 'Erreur inconnue')
error_data = error.get('data', {})
error_name = error_data.get('name', 'UnknownError')
logging.error(f"Erreur RPC: {error_name} - {error_msg}")
# Gérer les erreurs d'authentification
if "session expired" in error_msg or "Access denied" in error_msg:
if retry_count < self.max_retries:
logging.info("Session expirée, nouvelle tentative d'authentification...")
if self.login():
return self._rpc_call(endpoint, params, retry_count + 1)
return None
return result.get('result')
except requests.RequestException as e:
logging.error(f"Erreur de requête RPC: {e}")
if retry_count < self.max_retries:
logging.info(f"Nouvelle tentative ({retry_count + 1}/{self.max_retries})...")
return self._rpc_call(endpoint, params, retry_count + 1)
return None
except json.JSONDecodeError as e:
logging.error(f"Erreur de décodage JSON dans la réponse RPC: {e}")
return None
except Exception as e:
logging.error(f"Erreur inattendue lors de l'appel RPC: {e}")
return None
def search_read(self, model: str, domain: list, fields: list, **kwargs) -> list:
"""
Effectue une recherche et lecture sur le modèle spécifié.
Args:
model: Nom du modèle Odoo
domain: Domaine de recherche (filtres)
fields: Liste des champs à récupérer
**kwargs: Arguments supplémentaires (limit, offset, etc.)
Returns:
Liste des enregistrements trouvés
"""
params = {
"model": model,
"method": "search_read",
"args": [domain, fields],
"kwargs": kwargs
}
return self._rpc_call("/web/dataset/call_kw", params) or []
def read(self, model: str, ids: list, fields: list) -> list:
"""
Lit les enregistrements spécifiés par leurs IDs.
Args:
model: Nom du modèle Odoo
ids: Liste des IDs des enregistrements à lire
fields: Liste des champs à récupérer
Returns:
Liste des enregistrements lus
"""
if not ids:
return []
params = {
"model": model,
"method": "read",
"args": [ids, fields],
"kwargs": {}
}
return self._rpc_call("/web/dataset/call_kw", params) or []
def get_fields(self, model: str) -> Dict[str, Any]:
"""
Récupère les informations sur les champs d'un modèle.
Args:
model: Nom du modèle Odoo
Returns:
Dictionnaire avec les informations sur les champs
"""
params = {
"model": model,
"method": "fields_get",
"args": [],
"kwargs": {}
}
return self._rpc_call("/web/dataset/call_kw", params) or {}
# Fonctions d'aide pour centraliser l'authentification
def load_config(config_file: str = "config.json") -> Dict[str, Any]:
"""
Charge le fichier de configuration.
Args:
config_file: Chemin vers le fichier de configuration
Returns:
Dictionnaire contenant la configuration
"""
try:
with open(config_file, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
logging.error(f"Erreur lors du chargement du fichier de configuration: {e}")
return {}
def get_auth_manager(config_file: str = "config.json", force_new: bool = False) -> Optional[AuthManager]:
"""
Obtient une instance unique du gestionnaire d'authentification Odoo.
Args:
config_file: Chemin vers le fichier de configuration
force_new: Force la création d'une nouvelle instance
Returns:
Instance du AuthManager ou None en cas d'erreur
"""
global _auth_manager_instance
# Si une instance existe déjà et qu'on ne force pas la création, la retourner
if _auth_manager_instance is not None and not force_new:
return _auth_manager_instance
# Charger la configuration
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]):
logging.error("Informations de connexion Odoo manquantes dans le fichier de configuration")
return None
# Créer une nouvelle instance
try:
auth_manager = AuthManager(
url=url,
db=db,
username=username,
api_key=api_key
)
# Se connecter à Odoo
if not auth_manager.login():
logging.error("Échec de l'authentification à Odoo")
return None
# Stocker l'instance pour les appels futurs
_auth_manager_instance = auth_manager
return auth_manager
except Exception as e:
logging.exception(f"Erreur lors de l'initialisation du gestionnaire d'authentification: {e}")
return None
def get_output_dir(config_file: str = "config.json", subdir: Optional[str] = None) -> str:
"""
Obtient le répertoire de sortie à partir de la configuration.
Args:
config_file: Chemin vers le fichier de configuration
subdir: Sous-répertoire à ajouter au chemin (optionnel)
Returns:
Chemin du répertoire de sortie
"""
config = load_config(config_file)
output_dir = config.get("output_dir", "output")
if subdir:
return os.path.join(output_dir, subdir)
return output_dir
Étape 2: Modifier retrieve_ticket.py
#!/usr/bin/env python3
import os
import sys
import json
import logging
import argparse
from datetime import datetime
from .ticket_manager import TicketManager
from .auth_manager import get_auth_manager, get_output_dir, load_config
from core.utils import setup_logging, log_separator
def retrieve_ticket(ticket_code, output=None, config_file="config.json", verbose=False):
# Configurer la journalisation
log_level = logging.DEBUG if verbose else logging.INFO
setup_logging(log_level, "retrieve_ticket.log")
# Obtenir le gestionnaire d'authentification
auth_manager = get_auth_manager(config_file)
if not auth_manager:
logging.error("Impossible d'obtenir le gestionnaire d'authentification Odoo")
return None
# Définir le répertoire de sortie
output_base = output or get_output_dir(config_file)
output_dir = os.path.join(output_base, f"ticket_{ticket_code}")
# Créer le répertoire de sortie spécifique au ticket
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
ticket_dir = os.path.join(output_dir, f"{ticket_code}_{timestamp}")
os.makedirs(ticket_dir, exist_ok=True)
logging.info(f"Extraction du ticket {ticket_code}")
log_separator()
try:
# Extraire les données du ticket
ticket_manager = TicketManager(auth_manager)
result = ticket_manager.extract_ticket_data(ticket_code, ticket_dir)
if not result:
logging.error(f"Échec de l'extraction du ticket {ticket_code}")
return None
# Afficher le résumé
log_separator()
logging.info(f"Extraction terminée avec succès")
logging.info(f"Ticket: {ticket_code}")
logging.info(f"Répertoire: {ticket_dir}")
logging.info(f"Messages traités: {result.get('messages_count', 0)}")
logging.info(f"Pièces jointes: {result.get('attachments_count', 0)}")
log_separator()
# Générer un rapport de fin
summary = {
"timestamp": timestamp,
"ticket_code": ticket_code,
"output_directory": ticket_dir,
"message_count": result.get("messages_count", 0),
"attachment_count": result.get("attachments_count", 0),
"files_created": [
os.path.basename(result.get("ticket_info", "")),
os.path.basename(result.get("ticket_summary", "")),
os.path.basename(result.get("messages_file", "")),
os.path.basename(result.get("ticket_data_file", ""))
]
}
summary_path = os.path.join(ticket_dir, "extraction_summary.json")
with open(summary_path, 'w', encoding='utf-8') as f:
json.dump(summary, f, indent=2, ensure_ascii=False)
print(f"\nExtraction du ticket {ticket_code} terminée avec succès.")
print(f"Les données ont été sauvegardées dans: {ticket_dir}")
return ticket_dir
except Exception as e:
logging.exception(f"Une erreur est survenue: {e}")
return None
def parse_arguments():
parser = argparse.ArgumentParser(description="Récupère un ticket Odoo par son code et extrait ses données.")
parser.add_argument("ticket_code", help="Code du ticket à extraire")
parser.add_argument("--output", "-o", help="Répertoire de sortie", default=None)
parser.add_argument("--config", "-c", help="Fichier de configuration", default="config.json")
parser.add_argument("--verbose", "-v", action="store_true", help="Mode verbeux")
return parser.parse_args()
def main():
args = parse_arguments()
result = retrieve_ticket(
ticket_code=args.ticket_code,
output=args.output,
config_file=args.config,
verbose=args.verbose
)
if not result:
sys.exit(1)
if __name__ == "__main__":
main()
Étape 3: Modifier retrieve_tickets_batch.py
#!/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 .ticket_manager import TicketManager
from .batch_ticket_manager import BatchTicketManager
from .auth_manager import get_auth_manager, get_output_dir, 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
"""
# Configurer la journalisation
log_level = logging.DEBUG if verbose else logging.INFO
setup_logging(log_level, "retrieve_tickets_batch.log")
# Obtenir le gestionnaire d'authentification
auth_manager = get_auth_manager(config_file)
if not auth_manager:
logging.error("Impossible d'obtenir le gestionnaire d'authentification Odoo")
return None
# Définir le répertoire de sortie
base_output_dir = output or get_output_dir(config_file)
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
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"Tickets exclus par tag 'BRG-LAB WIN': {result.get('excluded_by_tag', 0)}")
logging.info(f"Répertoire: {result.get('batch_dir', '')}")
log_separator()
# Afficher les tickets exclus à cause du tag "BRG-LAB WIN"
excluded_tickets = result.get('excluded_tickets', [])
if excluded_tickets:
print("\nLes tickets suivants ont été exclus car ils possèdent le tag 'BRG-LAB WIN':")
for ticket in excluded_tickets:
print(f"- {ticket.get('code', 'Code inconnu')}: {ticket.get('name', 'Nom inconnu')}")
print(f"Total: {len(excluded_tickets)} ticket(s) exclu(s)")
print("Ces tickets sont exclus de l'extraction conformément à la politique.")
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
"""
# Obtenir le gestionnaire d'authentification
auth_manager = get_auth_manager(config_file)
if not auth_manager:
print("Impossible d'obtenir le gestionnaire d'authentification Odoo")
return None
try:
# 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
"""
# Obtenir le gestionnaire d'authentification
auth_manager = get_auth_manager(config_file)
if not auth_manager:
print("Impossible d'obtenir le gestionnaire d'authentification Odoo")
return None
try:
# 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
# [Le reste du fichier reste inchangé]
Étape 4: Modifier odoo_extractor.py
"""
Script pour récupérer les tickets depuis odoo.
Extraction d'un ticket unique ou d'un groupe de tickets.
"""
import os
import sys
import json
import argparse
from datetime import datetime
from core.utils import setup_logging, log_separator
from formatters.json_to_markdown import create_markdown_from_json
from odoo.retrieve_ticket import retrieve_ticket
from odoo.retrieve_tickets_batch import retrieve_tickets_batch, parse_domain, list_projects, list_stages
from odoo.auth_manager import get_auth_manager, load_config
#importation de l'extracteur d'images HTML (optionnel)
try:
from utils.image_extractor import extract_images_from_ticket
from utils.image_extractor.extract_all_images import enhance_ticket_data_with_images
HTML_IMAGE_EXTRACTOR_AVAILABLE = True
except ImportError:
HTML_IMAGE_EXTRACTOR_AVAILABLE = False
def parse_arguments():
"""Parse les arguments de ligne de commande."""
parser = argparse.ArgumentParser(description="Extrait des données depuis Odoo (ticket unique ou par lots).")
# Paramètres communs
parser.add_argument("--config", "-c", help="Fichier de configuration", default="config.json")
parser.add_argument("--verbose", "-v", action="store_true", help="Mode verbeux")
parser.add_argument("--output", "-o", help="Répertoire de sortie", default=None)
parser.add_argument("--no-md", action="store_true", help="Désactiver la génération automatique du fichier Markdown")
parser.add_argument("--extract-html-images", action="store_true", help="Activer l'extraction des images intégrées dans le HTML")
# Sous-parseurs pour les différentes commandes
subparsers = parser.add_subparsers(dest="command", help="Commande à exécuter")
# Commande pour extraire un ticket unique
single_parser = subparsers.add_parser("ticket", help="Extrait un ticket unique par son code")
single_parser.add_argument("ticket_code", help="Code du ticket à extraire")
# 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", type=int, default=0, help="Index de départ pour la pagination")
batch_parser.add_argument("--include-existing", action="store_true", help="Inclure les tickets déjà extraits")
# Commande pour lister les projets
projects_parser = subparsers.add_parser("projects", help="Liste les projets disponibles")
# Commande pour lister les étapes/statuts
stages_parser = subparsers.add_parser("stages", help="Liste les étapes/statuts disponibles")
return parser.parse_args()
def main():
"""Point d'entrée principal du script."""
args = parse_arguments()
# Vérifier si le fichier de configuration existe
if not os.path.exists(args.config):
print(f"Erreur: Fichier de configuration '{args.config}' introuvable.")
sys.exit(1)
# Configurer la journalisation
log_level = "DEBUG" if args.verbose else "INFO"
setup_logging(log_level)
# Vérifier la connexion Odoo une seule fois
if not get_auth_manager(args.config):
print("Impossible de se connecter à Odoo. Vérifiez vos informations de connexion.")
sys.exit(1)
# Traiter la commande appropriée
if args.command == "ticket":
# Extraction d'un ticket unique
result = retrieve_ticket(
ticket_code=args.ticket_code,
output=args.output,
config_file=args.config,
verbose=args.verbose
)
if not result:
print(f"Echec de l'extraction du ticket {args.ticket_code}")
sys.exit(1)
if not args.no_md:
# Génération du rapport Markdown
json_file = os.path.join(result, "all_messages.json")
if os.path.exists(json_file):
md_file_path = os.path.join(result, "rapport.md")
print(f"Génération du rapport Markdown...")
if create_markdown_from_json(json_file, md_file_path):
print(f"Rapport Markdown créé: {md_file_path}")
else:
print("Echec de la génération du rapport Markdown.")
elif args.command == "batch":
# [LE RESTE DU CODE RESTE INCHANGÉ]
Résumé des modifications
1. Modification de auth_manager.py:
- Ajout d'une variable globale
_auth_manager_instancepour stocker une instance unique - Ajout de fonctions utilitaires :
load_config,get_auth_manager,get_output_dir
2. Modification de retrieve_ticket.py:
- Suppression de la création directe d'une instance
AuthManager - Utilisation de
get_auth_managerpour obtenir une instance partagée - Utilisation de
get_output_dirpour obtenir le répertoire de sortie
3. Modification de retrieve_tickets_batch.py:
- Idem, utilisation des fonctions centralisées au lieu de créer une instance à chaque fois
4. Modification de odoo_extractor.py:
- Simplification des imports
- Utilisation des fonctions centralisées
Avantages de cette approche:
- Une seule instance d'
AuthManagerest utilisée par toute l'application - Le code de connexion est centralisé et facile à modifier
- Le pattern Singleton évite les connexions multiples et améliore les performances
- Le fichier
auth_manager.pyreste le point central pour tout ce qui est lié à l'authentification
Ce modèle respecte votre structure de code existante tout en centralisant l'authentification.
User
peux tu effectuer les modifcations
Assistant
Je vais vous aider à effectuer les modifications nécessaires pour centraliser l'authentification Odoo. D'après les erreurs du linter, il y a quelques problèmes dans le fichier auth_manager.py que vous avez déjà commencé à modifier. Je vais corriger ces problèmes et effectuer les modifications dans tous les fichiers concernés.
Commençons par corriger le fichier auth_manager.py :
Cancelled