From db180b340fe1bbece729b434818073770a83817c Mon Sep 17 00:00:00 2001 From: Ladebeze66 Date: Thu, 3 Apr 2025 10:45:52 +0200 Subject: [PATCH] ajust --- output/ticket_T11067/all_messages.json | 56 +++ output/ticket_T11067/messages_raw.json | 83 ++++ output/ticket_T11067/structure.json | 9 + output/ticket_T11067/ticket_info.json | 1 + .../ticket_manager2.cpython-312.pyc | Bin 15801 -> 7675 bytes utils/ticket_manager2.py | 413 ++++++------------ 6 files changed, 273 insertions(+), 289 deletions(-) create mode 100644 output/ticket_T11067/all_messages.json create mode 100644 output/ticket_T11067/messages_raw.json create mode 100644 output/ticket_T11067/structure.json create mode 100644 output/ticket_T11067/ticket_info.json diff --git a/output/ticket_T11067/all_messages.json b/output/ticket_T11067/all_messages.json new file mode 100644 index 0000000..380f45d --- /dev/null +++ b/output/ticket_T11067/all_messages.json @@ -0,0 +1,56 @@ +[ + { + "message_id": 228803, + "sender": "Romuald GRUSON", + "timestamp": "2025-04-02 07:16:48", + "content": "" + }, + { + "message_id": 227733, + "sender": "Romuald GRUSON", + "timestamp": "2025-03-18 14:19:29", + "content": "" + }, + { + "message_id": 227732, + "sender": "Romuald GRUSON", + "timestamp": "2025-03-18 14:19:29", + "content": "" + }, + { + "message_id": 227731, + "sender": "Romuald GRUSON", + "timestamp": "2025-03-18 14:18:51", + "content": "Bonjour,Effectivement, il y a une anomalie lors du changement du nom d'un poste de production. Les mises à jour déployées ce soir et demain devraient vous permettre d’effectuer cette modification. Pour cela, il faut éditer le nom du poste de production d’enrobée, l’enregistrer dans la fiche générale, puis cliquer sur la petite flèche à droite du nom et le modifier.Je reste à votre entière disposition pour toute information complémentaire.Cordialement,---Support technique \"CBAO Afin d'assurer une meilleure traçabilité et vous garantir une prise en charge optimale, nous vous invitons à envoyer vos demandes d'assistance technique à support@cbao.frL'objectif du Support Technique est de vous aider : si vous rencontrez une difficulté, ou pour nous soumettre une ou des suggestions d'amélioration de nos logiciels ou de nos méthodes. Notre service est ouvert du lundi au vendredi de 9h à 12h et de 14h à 18h. Dès réception, un technicien prendra en charge votre demande et au besoin vous rappellera.Confidentialité : Ce courriel contient des informations confidentielles exclusivement réservées au destinataire mentionné. Si vous deviez recevoir cet e-mail par erreur, merci d’en avertir immédiatement l’expéditeur et de le supprimer de votre système informatique. Au cas où vous ne seriez pas destinataire de ce message, veuillez noter que sa divulgation, sa copie ou tout acte en rapport avec la communication du contenu des informations est strictement interdit." + }, + { + "message_id": 227730, + "sender": "Romuald GRUSON", + "timestamp": "2025-03-18 13:42:15", + "content": "" + }, + { + "message_id": 227728, + "sender": "Romuald GRUSON", + "timestamp": "2025-03-18 13:42:04", + "content": "" + }, + { + "message_id": 227726, + "sender": "OdooBot", + "timestamp": "2025-03-18 13:22:28", + "content": "" + }, + { + "message_id": 227725, + "sender": "CONSEIL DEPARTEMENTAL DU MORBIHAN (56), Dominique CARVAL", + "timestamp": "2025-03-18 13:18:31", + "content": "Bonjour, 3 centrales d’enrobage ont changé de nom. Comment faire ce changement sur BRG-LAB ? (ici ARMOR ENROBÉS devient BREIZH ENROBÉS sur 3 sites) Bonne réception Dominique CARVAL Responsable du pôle Laboratoire Routier Direction des Infrastructures et des mobilités (DIM) Service d’Appui aux Politiques d’Aménagement / Pôle Laboratoire Routier (SAPA/PLR) 115, rue du commerce – 56000 VANNES tél : 02 97 54 71 14 - mobile : 06 98 32 88 30 – dominique.carval@morbihan.fr Droit à la déconnexion : Si vous recevez ce message en dehors de vos heures de travail ou pendant vos congés, vous n’êtes pas tenu de répondre immédiatement, sauf en cas d’urgence exceptionnelle. Ce message électronique et tous les fichiers attachés qu'il contient peuvent être confidentiels, contenir des données personnelles ou sensibles et être soumis au secret professionnel. Il est destiné exclusivement à l'usage du ou des destinataires. Si vous recevez ce message par erreur et/ou si vous n'êtes pas le destinataire désigné de ce message, le département du Morbihan vous remercie d'avertir immédiatement l'expéditeur et de le détruire ainsi que toutes les pièces jointes s'y rattachant. La publication, l'usage, la distribution, l'impression ou la copie non autorisée de ce message et des attachements qu'il contient sont strictement interdits. Tout message électronique est susceptible d'altération." + }, + { + "message_id": 227724, + "sender": "OdooBot", + "timestamp": "2025-03-18 13:22:28", + "content": "" + } +] \ No newline at end of file diff --git a/output/ticket_T11067/messages_raw.json b/output/ticket_T11067/messages_raw.json new file mode 100644 index 0000000..f9a3332 --- /dev/null +++ b/output/ticket_T11067/messages_raw.json @@ -0,0 +1,83 @@ +[ + { + "id": 228803, + "body": "", + "author_id": [ + 32165, + "Romuald GRUSON" + ], + "date": "2025-04-02 07:16:48" + }, + { + "id": 227733, + "body": "", + "author_id": [ + 32165, + "Romuald GRUSON" + ], + "date": "2025-03-18 14:19:29" + }, + { + "id": 227732, + "body": "", + "author_id": [ + 32165, + "Romuald GRUSON" + ], + "date": "2025-03-18 14:19:29" + }, + { + "id": 227731, + "body": "

Bonjour,

Effectivement, il y a une anomalie lors du changement du nom d'un poste de production. Les mises à jour déployées ce soir et demain devraient vous permettre d’effectuer cette modification.

\n

Pour cela, il faut éditer le nom du poste de production d’enrobée, l’enregistrer dans la fiche générale, puis cliquer sur la petite flèche à droite du nom et le modifier.

\"image.png\"


Je reste à votre entière disposition pour toute information complémentaire.

Cordialement,

---

Support technique
 

\n

\"CBAO

\n

Afin d'assurer une meilleure traçabilité et vous garantir une prise en charge optimale, nous vous invitons à envoyer vos demandes d'assistance technique à support@cbao.fr
L'objectif du Support Technique est de vous aider : si vous rencontrez une difficulté, ou pour nous soumettre une ou des suggestions d'amélioration de nos logiciels ou de nos méthodes. Notre service est ouvert du lundi au vendredi de 9h à 12h et de 14h à 18h. Dès réception, un technicien prendra en charge votre demande et au besoin vous rappellera.

Confidentialité : Ce courriel contient des informations confidentielles exclusivement réservées au destinataire mentionné. Si vous deviez recevoir cet e-mail par erreur, merci d’en avertir immédiatement l’expéditeur et de le supprimer de votre système informatique. Au cas où vous ne seriez pas destinataire de ce message, veuillez noter que sa divulgation, sa copie ou tout acte en rapport avec la communication du contenu des informations est strictement interdit.

", + "author_id": [ + 32165, + "Romuald GRUSON" + ], + "date": "2025-03-18 14:18:51" + }, + { + "id": 227730, + "body": "", + "author_id": [ + 32165, + "Romuald GRUSON" + ], + "date": "2025-03-18 13:42:15" + }, + { + "id": 227728, + "body": "", + "author_id": [ + 32165, + "Romuald GRUSON" + ], + "date": "2025-03-18 13:42:04" + }, + { + "id": 227726, + "body": "", + "author_id": [ + 2, + "OdooBot" + ], + "date": "2025-03-18 13:22:28" + }, + { + "id": 227725, + "body": "

\r\n\r\n

\r\n
\r\n

Bonjour,\r\n

\r\n

 

\r\n

3 centrales d’enrobage ont changé de nom.

\r\n

 

\r\n

Comment faire ce changement sur BRG-LAB ?

\r\n

 

\r\n

(ici ARMOR ENROBÉS devient BREIZH ENROBÉS sur 3 sites)

\r\n

 

\r\n

\r\n

 

\r\n

Bonne réception

\r\n

 

\r\n

\"cid:image004.png@01D8D425.0F95E5B0\"

\r\n

 

\r\n

Dominique CARVAL

\r\n

 

\r\n

Responsable du pôle Laboratoire Routier

\r\n

Direction des Infrastructures et des mobilités (DIM)

\r\n

Service d’Appui aux Politiques d’Aménagement / Pôle Laboratoire Routier (SAPA/PLR)

\r\n

115, rue du commerce – 56000 VANNES

\r\n

 

\r\n

tél : 02 97 54 71 14 - mobile : 06 98 32 88 30 –\r\ndominique.carval@morbihan.fr\r\n 

\r\n

 

\r\n

 

\r\n

 

\r\n
\r\n
\r\n
Droit à la déconnexion : Si vous recevez ce message en dehors de vos heures de travail ou pendant vos congés, vous n’êtes pas tenu de répondre immédiatement, sauf en cas d’urgence exceptionnelle.\r\n
\r\nCe message électronique et tous les fichiers attachés qu'il contient peuvent être confidentiels, contenir des données personnelles ou sensibles et être soumis au secret professionnel. Il est destiné exclusivement à l'usage du ou des destinataires. Si vous recevez\r\n ce message par erreur et/ou si vous n'êtes pas le destinataire désigné de ce message, le département du Morbihan vous remercie d'avertir immédiatement l'expéditeur et de le détruire ainsi que toutes les pièces jointes s'y rattachant. La publication, l'usage,\r\n la distribution, l'impression ou la copie non autorisée de ce message et des attachements qu'il contient sont strictement interdits. Tout message électronique est susceptible d'altération.
\r\n\r\n", + "author_id": [ + 5144, + "CONSEIL DEPARTEMENTAL DU MORBIHAN (56), Dominique CARVAL" + ], + "date": "2025-03-18 13:18:31" + }, + { + "id": 227724, + "body": "", + "author_id": [ + 2, + "OdooBot" + ], + "date": "2025-03-18 13:22:28" + } +] \ No newline at end of file diff --git a/output/ticket_T11067/structure.json b/output/ticket_T11067/structure.json new file mode 100644 index 0000000..0040323 --- /dev/null +++ b/output/ticket_T11067/structure.json @@ -0,0 +1,9 @@ +{ + "date_extraction": "2025-04-03T10:44:16.768543", + "ticket_dir": "output/ticket_T11067", + "fichiers_json": [ + "ticket_info.json", + "messages_raw.json", + "all_messages.json" + ] +} \ No newline at end of file diff --git a/output/ticket_T11067/ticket_info.json b/output/ticket_T11067/ticket_info.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/output/ticket_T11067/ticket_info.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/utils/__pycache__/ticket_manager2.cpython-312.pyc b/utils/__pycache__/ticket_manager2.cpython-312.pyc index a0ebe38aaf0c2f093e609bca5701f5dde5a9aaa9..6940b6aa023a54811ff0663f89c1aebf3e283be2 100644 GIT binary patch literal 7675 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 literal 15801 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 JDMs<@{y#wc(qI4p diff --git a/utils/ticket_manager2.py b/utils/ticket_manager2.py index 6ccd324..2515c80 100644 --- a/utils/ticket_manager2.py +++ b/utils/ticket_manager2.py @@ -1,18 +1,11 @@ import os import json import base64 -from typing import Dict, List, Any, Optional import requests -import re -from html import unescape +from typing import Dict, List, Any, Optional from datetime import datetime - class TicketManager: - """ - Gestionnaire de tickets pour extraire des données depuis Odoo. - """ - def __init__(self, url: str, db: str, username: str, api_key: str): self.url = url self.db = db @@ -21,309 +14,151 @@ class TicketManager: self.uid = None self.session_id = None self.model_name = "project.task" - + def login(self) -> bool: - try: - login_url = f"{self.url}/web/session/authenticate" - login_data = { - "jsonrpc": "2.0", - "params": { - "db": self.db, - "login": self.username, - "password": self.api_key - } + login_url = f"{self.url}/web/session/authenticate" + login_data = { + "jsonrpc": "2.0", + "params": { + "db": self.db, + "login": self.username, + "password": self.api_key } - response = requests.post(login_url, json=login_data) - response.raise_for_status() - - result = response.json() - if result.get("error"): - print(f"Erreur de connexion: {result['error']['message']}") - return False - - self.uid = result.get("result", {}).get("uid") - self.session_id = response.cookies.get("session_id") - if not self.uid: - print("Erreur: Impossible de récupérer l'ID utilisateur") - return False - - print(f"Connecté avec succès à {self.url} (User ID: {self.uid})") - return True - except Exception as e: - print(f"Erreur de connexion: {str(e)}") + } + response = requests.post(login_url, json=login_data) + result = response.json() + + if result.get("error"): + print(f"Erreur de connexion: {result['error']['message']}") return False - + + self.uid = result.get("result", {}).get("uid") + self.session_id = response.cookies.get("session_id") + return True if self.uid else False + def _rpc_call(self, endpoint: str, params: Dict[str, Any]) -> Dict[str, Any]: - if not self.uid and not self.login(): - return {"error": "Non connecté"} - - try: - full_url = f"{self.url}{endpoint}" - headers = {"Content-Type": "application/json"} - data = {"jsonrpc": "2.0", "method": "call", "params": params} - - response = requests.post( - full_url, - json=data, - headers=headers, - cookies={"session_id": self.session_id} if self.session_id else None - ) - response.raise_for_status() - result = response.json() - if result.get("error"): - return {"error": result["error"]["message"]} - return result.get("result", {}) - except Exception as e: - return {"error": str(e)} - - def search_read(self, model: str, domain: List, fields: List[str], order: Optional[str] = None, limit: Optional[int] = None) -> List[Dict[str, Any]]: + full_url = f"{self.url}{endpoint}" + headers = {"Content-Type": "application/json"} + data = {"jsonrpc": "2.0", "method": "call", "params": params} + + response = requests.post(full_url, json=data, headers=headers, cookies={"session_id": self.session_id}) + return response.json().get("result", {}) + + def get_ticket(self, ticket_id: int) -> Dict[str, Any]: params = { - "model": model, - "method": "search_read", - "args": [domain, fields], + "model": self.model_name, + "method": "read", + "args": [[ticket_id]], "kwargs": {} } - - if order is not None: - params["kwargs"]["order"] = order - if limit is not None: - params["kwargs"]["limit"] = limit - - result = self._rpc_call("/web/dataset/call_kw", params) - return result if isinstance(result, list) else [] - - def read(self, model: str, ids: List[int], fields: List[str]) -> List[Dict[str, Any]]: - params = {"model": model, "method": "read", "args": [ids, fields], "kwargs": {}} - result = self._rpc_call("/web/dataset/call_kw", params) - return result if isinstance(result, list) else [] - - def get_ticket_by_code(self, ticket_code: str) -> Dict[str, Any]: - tickets = self.search_read(self.model_name, [("code", "=", ticket_code)], ["id"]) - if not tickets: - return {} - return self.get_ticket_by_id(tickets[0]["id"]) - - def get_ticket_by_id(self, ticket_id: int) -> Dict[str, Any]: - ticket_fields = [ - "id", "name", "description", "stage_id", "user_id", "partner_id", - "create_date", "write_date", "date_deadline", "priority", - "tag_ids", "code", "project_id", "kanban_state", "color", - "active", "company_id", "display_name" - ] - tickets = self.read(self.model_name, [ticket_id], ticket_fields) - return tickets[0] if tickets else {} - + return self._rpc_call("/web/dataset/call_kw", params) + def get_ticket_messages(self, ticket_id: int) -> List[Dict[str, Any]]: - messages = self.search_read( - "mail.message", - [ - ("res_id", "=", ticket_id), - ("model", "=", self.model_name), - ("message_type", "in", ["comment", "notification", "email"]) - ], - ["id", "body", "date", "author_id", "email_from", "message_type", "parent_id", "subtype_id", "tracking_value_ids"], - order="date asc" - ) - return self._clean_messages(messages) - - def _clean_messages(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]: - cleaned_messages = [] - for message in messages: - if message.get("body"): - body = message["body"] - body = unescape(body) - # Stocker la version HTML - message["body_html"] = body - # Créer une version texte nettoyée - body_text = re.sub(r'.*?', '', body, flags=re.DOTALL) - body_text = re.sub(r'.*?', '', body_text, flags=re.DOTALL) - body_text = re.sub(r'<[^>]+>', ' ', body_text) - body_text = re.sub(r'\s+', ' ', body_text).strip() - message["body_text"] = body_text - - # Organiser les messages en fils de discussion - if message.get("parent_id"): - parent_id = message["parent_id"][0] if isinstance(message["parent_id"], (list, tuple)) else message["parent_id"] - message["parent_id"] = parent_id - - cleaned_messages.append(message) - return cleaned_messages - - def get_ticket_attachments(self, ticket_id: int) -> List[Dict[str, Any]]: + messages = self._rpc_call("/web/dataset/call_kw", { + "model": "mail.message", + "method": "search_read", + "args": [[["res_id", "=", ticket_id], ["model", "=", "project.task"]]], + "kwargs": {"fields": ["id", "body", "author_id", "date"]} + }) + return messages + + def get_ticket_by_code(self, ticket_code: str) -> Dict[str, Any]: """ - Récupère les pièces jointes associées à un ticket. - - Args: - ticket_id: ID du ticket - - Returns: - Liste des pièces jointes avec leurs métadonnées. - """ - attachments = self.search_read( - "ir.attachment", - [ - ("res_id", "=", ticket_id), - ("res_model", "=", self.model_name) - ], - ["id", "name", "mimetype", "file_size", "create_date", "create_uid", "datas", "description"] - ) - return attachments - - def download_attachment(self, attachment: Dict[str, Any], output_dir: str) -> str: - """ - Télécharge et sauvegarde une pièce jointe dans le répertoire spécifié. - - Args: - attachment: Dictionnaire contenant les métadonnées de la pièce jointe - output_dir: Répertoire où sauvegarder la pièce jointe - - Returns: - Chemin du fichier sauvegardé - """ - if not attachment.get("datas"): - return "" - - # Créer le dossier attachments s'il n'existe pas - attachments_dir = os.path.join(output_dir, "attachments") - os.makedirs(attachments_dir, exist_ok=True) - - # Construire un nom de fichier sécurisé - filename = re.sub(r'[^\w\.-]', '_', attachment["name"]) - file_path = os.path.join(attachments_dir, filename) - - # Décoder et sauvegarder le contenu - try: - file_content = base64.b64decode(attachment["datas"]) - with open(file_path, "wb") as f: - f.write(file_content) - return file_path - except Exception as e: - print(f"Erreur lors du téléchargement de la pièce jointe {attachment['name']}: {str(e)}") - return "" - - def organize_messages_by_thread(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]: - """ - Organise les messages en fils de discussion. - - Args: - messages: Liste des messages à organiser - - Returns: - Liste des messages racines avec leurs réponses imbriquées. - """ - # Créer un dictionnaire pour stocker tous les messages par ID - messages_by_id = {msg["id"]: {**msg, "replies": []} for msg in messages} - - # Identifier les messages racines et ajouter les réponses aux parents - root_messages = [] - for msg_id, msg in messages_by_id.items(): - if not msg.get("parent_id") or msg["parent_id"] == 0: - root_messages.append(msg) - else: - parent_id = msg["parent_id"] - if parent_id in messages_by_id: - messages_by_id[parent_id]["replies"].append(msg) - - # Trier les messages racines par date - root_messages.sort(key=lambda m: m.get("date", "")) - return root_messages - - def extract_ticket_data(self, ticket_id: int, output_dir: str) -> Dict[str, Any]: - """ - Extrait toutes les données d'un ticket, y compris messages et pièces jointes. - - Args: - ticket_id: ID du ticket - output_dir: Répertoire de sortie - - Returns: - Dictionnaire contenant les chemins des fichiers créés. + Récupère un ticket par son code unique. + + Args: + ticket_code: Code du ticket à récupérer (par exemple, T11067) + + Returns: + Dictionnaire contenant les informations du ticket ou une erreur si non trouvé """ + # Recherche du ticket par code + params = { + "model": self.model_name, + "method": "search_read", + "args": [[["code", "=", ticket_code]], ["id", "name", "description", "stage_id"]], + "kwargs": {"limit": 1} + } + + result = self._rpc_call("/web/dataset/call_kw", params) + + if not result: + print(f"Aucun ticket trouvé avec le code {ticket_code}") + return {} + + # Retourne le premier ticket trouvé + return result[0] if isinstance(result, list) and len(result) > 0 else {} + + def save_json(self, data: Any, path: str): + with open(path, "w", encoding="utf-8") as f: + json.dump(data, f, indent=2, ensure_ascii=False) + + def extract_ticket_data(self, ticket_id: int, output_dir: str): os.makedirs(output_dir, exist_ok=True) - ticket = self.get_ticket_by_id(ticket_id) - if not ticket: - return {"error": f"Ticket {ticket_id} non trouvé"} - - # Récupération des messages associés au ticket + ticket_data = self.get_ticket(ticket_id) + self.save_json(ticket_data, os.path.join(output_dir, "ticket_info.json")) + messages = self.get_ticket_messages(ticket_id) - # Organisation des messages en fils de discussion - thread_messages = self.organize_messages_by_thread(messages) + # Save messages in raw and cleaned formats + self.save_json(messages, os.path.join(output_dir, "messages_raw.json")) - # Récupération des pièces jointes - attachments = self.get_ticket_attachments(ticket_id) - attachment_files = [] + cleaned_messages = [] + for msg in messages: + cleaned_messages.append({ + "message_id": msg["id"], + "sender": msg["author_id"][1] if msg["author_id"] else "Unknown", + "timestamp": msg["date"], + "content": self.clean_html(msg["body"]) + }) - # Téléchargement des pièces jointes - for attachment in attachments: - file_path = self.download_attachment(attachment, output_dir) - if file_path: - # Supprimer les données binaires avant de sauvegarder dans le JSON - attachment_info = {k: v for k, v in attachment.items() if k != "datas"} - attachment_info["local_path"] = file_path - attachment_files.append(attachment_info) + self.save_json(cleaned_messages, os.path.join(output_dir, "all_messages.json")) - # Constitution des données complètes du ticket - ticket_data = { - **ticket, - "messages": messages, - "threads": thread_messages, - "attachments": attachment_files + # Generate structure.json + structure = { + "date_extraction": datetime.now().isoformat(), + "ticket_dir": output_dir, + "fichiers_json": [ + "ticket_info.json", + "messages_raw.json", + "all_messages.json" + ] } - - # Sauvegarde des données du ticket dans un fichier JSON - ticket_path = os.path.join(output_dir, "ticket_data.json") - with open(ticket_path, "w", encoding="utf-8") as f: - json.dump(ticket_data, f, indent=2, ensure_ascii=False) + self.save_json(structure, os.path.join(output_dir, "structure.json")) + + def clean_html(self, html_content: str) -> str: + import re + from html import unescape - # Sauvegarder séparément les messages pour compatibilité - messages_path = os.path.join(output_dir, "messages.json") - with open(messages_path, "w", encoding="utf-8") as f: - json.dump({"ticket": ticket, "messages": messages}, f, indent=2, ensure_ascii=False) + text = re.sub(r'<.*?>', '', html_content) + text = unescape(text) + text = re.sub(r'\s+', ' ', text).strip() - # Journal d'extraction pour référence - log_path = os.path.join(output_dir, "extraction_log.txt") - with open(log_path, "w", encoding="utf-8") as f: - f.write(f"Extraction du ticket {ticket_id} le {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") - f.write(f"Nom du ticket: {ticket.get('name', 'N/A')}\n") - f.write(f"Nombre de messages: {len(messages)}\n") - f.write(f"Nombre de pièces jointes: {len(attachments)}\n") - - print(f"Données complètes sauvegardées dans {ticket_path}") - print(f"Pièces jointes ({len(attachment_files)}) sauvegardées dans {os.path.join(output_dir, 'attachments')}") - - # Retourner un dictionnaire contenant les informations du ticket - return { - "ticket_info": ticket, - "messages_file": messages_path, - "ticket_data_file": ticket_path, - "attachments": attachment_files, - "log_file": log_path - } + return text if __name__ == "__main__": import sys - + if len(sys.argv) < 2: - print("Usage: python retrieve_ticket.py ") + print("Usage: python ticket_manager2.py ") sys.exit(1) - - ticket_code = sys.argv[1] - output_dir = f"output/ticket_{ticket_code}" - - config = { - "url": "https://odoo.example.com", - "db": "your_db_name", - "username": "your_username", - "api_key": "your_api_key" - } - - manager = TicketManager(config["url"], config["db"], config["username"], config["api_key"]) - if manager.login(): - ticket = manager.get_ticket_by_code(ticket_code) - if ticket: - result = manager.extract_ticket_data(ticket["id"], output_dir) - print(f"Extraction terminée. Données disponibles dans {output_dir}") - else: - print(f"Ticket avec code {ticket_code} non trouvé.") + + ticket_id = int(sys.argv[1]) + + # Configuration Odoo + url = "https://odoo.cbao.fr" + db = "database_name" + username = "username" + api_key = "api_key" + + manager = TicketManager(url, db, username, api_key) + + if not manager.login(): + print("Échec de connexion à Odoo") + sys.exit(1) + + output_dir = f"T11067_analysis/ticket_structure" + manager.extract_ticket_data(ticket_id, output_dir) + + print("Extraction terminée avec succès.")