This commit is contained in:
Ladebeze66 2025-04-03 11:11:13 +02:00
parent db180b340f
commit ea257c737e
11 changed files with 149 additions and 769 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

View File

@ -1,4 +0,0 @@
Extraction du ticket 11046 le 2025-04-03 10:22:59
Nom du ticket: changement nom centrale d'enrobage
Nombre de messages: 9
Nombre de pièces jointes: 3

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{ {
"date_extraction": "2025-04-03T10:44:16.768543", "date_extraction": "2025-04-03T11:09:41.473063",
"ticket_dir": "output/ticket_T11067", "ticket_dir": "output/ticket_T11067",
"fichiers_json": [ "fichiers_json": [
"ticket_info.json", "ticket_info.json",

File diff suppressed because one or more lines are too long

View File

@ -1 +1,6 @@
{} {
"id": 11046,
"name": "changement nom centrale d'enrobage",
"description": "<p><br></p>",
"stage_id": "Clôturé"
}

View File

@ -4,6 +4,8 @@ import base64
import requests import requests
from typing import Dict, List, Any, Optional from typing import Dict, List, Any, Optional
from datetime import datetime from datetime import datetime
import re
from html import unescape
class TicketManager: class TicketManager:
def __init__(self, url: str, db: str, username: str, api_key: str): def __init__(self, url: str, db: str, username: str, api_key: str):
@ -49,9 +51,20 @@ class TicketManager:
"model": self.model_name, "model": self.model_name,
"method": "read", "method": "read",
"args": [[ticket_id]], "args": [[ticket_id]],
"kwargs": {} "kwargs": {"fields": ["id", "name", "description", "stage_id", "user_id", "partner_id",
"create_date", "write_date", "date_deadline", "priority",
"tag_ids", "code", "project_id"]}
} }
return self._rpc_call("/web/dataset/call_kw", params) result = self._rpc_call("/web/dataset/call_kw", params)
# Afficher le résultat brut pour le débogage
print(f"Réponse brute de l'appel RPC pour le ticket ID {ticket_id} : {result}")
if isinstance(result, list) and len(result) > 0:
return result[0]
else:
print(f"Aucun ticket trouvé avec l'ID {ticket_id} ou une erreur est survenue.")
return {}
def get_ticket_messages(self, ticket_id: int) -> List[Dict[str, Any]]: def get_ticket_messages(self, ticket_id: int) -> List[Dict[str, Any]]:
messages = self._rpc_call("/web/dataset/call_kw", { messages = self._rpc_call("/web/dataset/call_kw", {
@ -63,32 +76,24 @@ class TicketManager:
return messages return messages
def get_ticket_by_code(self, ticket_code: str) -> Dict[str, Any]: def get_ticket_by_code(self, ticket_code: str) -> Dict[str, Any]:
"""
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 = { params = {
"model": self.model_name, "model": self.model_name,
"method": "search_read", "method": "search_read",
"args": [[["code", "=", ticket_code]], ["id", "name", "description", "stage_id"]], "args": [[["code", "=", ticket_code]]],
"kwargs": {"limit": 1} "kwargs": {"fields": ["id", "name", "description", "stage_id", "user_id",
"partner_id", "create_date", "write_date"], "limit": 1}
} }
print(f"Recherche du ticket avec code: {ticket_code}")
result = self._rpc_call("/web/dataset/call_kw", params) result = self._rpc_call("/web/dataset/call_kw", params)
if not result: if result and len(result) > 0:
print(f"Ticket trouvé avec le code {ticket_code}: ID={result[0]['id']}")
return result[0]
else:
print(f"Aucun ticket trouvé avec le code {ticket_code}") print(f"Aucun ticket trouvé avec le code {ticket_code}")
return {} 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): def save_json(self, data: Any, path: str):
with open(path, "w", encoding="utf-8") as f: with open(path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False) json.dump(data, f, indent=2, ensure_ascii=False)
@ -97,25 +102,31 @@ class TicketManager:
os.makedirs(output_dir, exist_ok=True) os.makedirs(output_dir, exist_ok=True)
ticket_data = self.get_ticket(ticket_id) ticket_data = self.get_ticket(ticket_id)
self.save_json(ticket_data, os.path.join(output_dir, "ticket_info.json"))
# Vérifier si le ticket a bien été trouvé
if not ticket_data or "id" not in ticket_data:
print(f"Impossible d'extraire les données pour le ticket ID {ticket_id}")
return {"error": "Ticket non trouvé", "ticket_info": None, "messages_file": None, "ticket_data_file": None, "attachments": []}
ticket_info = {
"id": ticket_data["id"],
"name": ticket_data["name"],
"description": ticket_data.get("description", ""),
"stage_id": ticket_data.get("stage_id", ["", ""])[1] if ticket_data.get("stage_id") else "Non défini"
}
self.save_json(ticket_info, os.path.join(output_dir, "ticket_info.json"))
messages = self.get_ticket_messages(ticket_id) messages = self.get_ticket_messages(ticket_id)
# Save messages in raw and cleaned formats # Sauvegarde brute des messages
self.save_json(messages, os.path.join(output_dir, "messages_raw.json")) self.save_json(messages, os.path.join(output_dir, "messages_raw.json"))
cleaned_messages = [] # Nettoyage des messages
for msg in messages: cleaned_messages = self._clean_messages(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"])
})
self.save_json(cleaned_messages, os.path.join(output_dir, "all_messages.json")) self.save_json(cleaned_messages, os.path.join(output_dir, "all_messages.json"))
# Generate structure.json # Génération de structure.json
structure = { structure = {
"date_extraction": datetime.now().isoformat(), "date_extraction": datetime.now().isoformat(),
"ticket_dir": output_dir, "ticket_dir": output_dir,
@ -126,39 +137,41 @@ class TicketManager:
] ]
} }
self.save_json(structure, os.path.join(output_dir, "structure.json")) self.save_json(structure, os.path.join(output_dir, "structure.json"))
return {
"ticket_info": os.path.join(output_dir, "ticket_info.json"),
"messages_file": os.path.join(output_dir, "all_messages.json"),
"ticket_data_file": os.path.join(output_dir, "structure.json"),
"attachments": [] # Si vous implémentez la gestion des pièces jointes
}
def clean_html(self, html_content: str) -> str: def _clean_messages(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
import re signatures = [
from html import unescape r'Droit à la déconnexion.*',
r'Ce message électronique et tous les fichiers attachés.*',
text = re.sub(r'<.*?>', '', html_content) r'Direction des Infrastructures.*',
text = unescape(text) r'Service d\'Appui aux Politiques d\'Aménagement.*',
text = re.sub(r'\s+', ' ', text).strip() r'tél :.*',
r'mobile :.*',
return text r'email :.*',
r'Cordialement,.*',
r'Bonne réception.*',
r'---.*'
]
cleaned_messages = []
for msg in messages:
body = msg.get("body", "")
body = re.sub(r'<.*?>', '', body)
body = unescape(body)
body = re.sub(r'\s+', ' ', body).strip()
# Supprime les signatures courantes
for signature in signatures:
body = re.sub(signature, '', body, flags=re.IGNORECASE | re.DOTALL)
msg["body"] = body
cleaned_messages.append(msg)
return cleaned_messages
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Usage: python ticket_manager2.py <ticket_id>")
sys.exit(1)
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.")