This commit is contained in:
Ladebeze66 2025-04-03 11:17:36 +02:00
parent ea257c737e
commit 8b21e1d151
5 changed files with 61 additions and 263 deletions

View File

@ -1,83 +0,0 @@
[
{
"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 deffectuer cette modification. Pour cela, il faut éditer le nom du poste de production denrobée, lenregistrer 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.",
"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": "Bonjour, 3 centrales denrobage ont changé de nom. Comment faire ce changement sur BRG-LAB ? (ici ARMOR ENROBÉS devient BREIZH ENROBÉS sur 3 sites) ",
"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"
}
]

File diff suppressed because one or more lines are too long

View File

@ -1,9 +0,0 @@
{
"date_extraction": "2025-04-03T11:09:41.473063",
"ticket_dir": "output/ticket_T11067",
"fichiers_json": [
"ticket_info.json",
"messages_raw.json",
"all_messages.json"
]
}

View File

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

View File

@ -7,6 +7,11 @@ from datetime import datetime
import re
from html import unescape
try:
from bs4 import BeautifulSoup
except ImportError:
BeautifulSoup = None
class TicketManager:
def __init__(self, url: str, db: str, username: str, api_key: str):
self.url = url
@ -37,7 +42,7 @@ class TicketManager:
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]:
full_url = f"{self.url}{endpoint}"
headers = {"Content-Type": "application/json"}
@ -51,15 +56,10 @@ class TicketManager:
"model": self.model_name,
"method": "read",
"args": [[ticket_id]],
"kwargs": {"fields": ["id", "name", "description", "stage_id", "user_id", "partner_id",
"create_date", "write_date", "date_deadline", "priority",
"tag_ids", "code", "project_id"]}
"kwargs": {"fields": ["id", "name", "description", "stage_id", "user_id", "create_date"]}
}
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:
@ -75,103 +75,82 @@ class TicketManager:
})
return messages
def get_ticket_by_code(self, ticket_code: str) -> Dict[str, Any]:
params = {
"model": self.model_name,
def get_ticket_attachments(self, ticket_id: int) -> List[Dict[str, Any]]:
attachments = self._rpc_call("/web/dataset/call_kw", {
"model": "ir.attachment",
"method": "search_read",
"args": [[["code", "=", ticket_code]]],
"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)
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}")
return {}
"args": [[["res_id", "=", ticket_id], ["res_model", "=", self.model_name]]],
"kwargs": {"fields": ["id", "name", "datas"]}
})
return attachments
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 clean_html(self, html_content: str) -> str:
if BeautifulSoup:
soup = BeautifulSoup(html_content, "html.parser")
text = soup.get_text()
else:
text = re.sub(r'<.*?>', '', html_content)
text = unescape(text)
text = re.sub(r'\s+', ' ', text).strip()
return text
def extract_ticket_data(self, ticket_id: int, output_dir: str):
os.makedirs(output_dir, exist_ok=True)
ticket_data = self.get_ticket(ticket_id)
# 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": []}
print(f"Erreur: Ticket non trouvé.")
return
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"))
self.save_json(ticket_data, os.path.join(output_dir, "ticket_info.json"))
messages = self.get_ticket_messages(ticket_id)
cleaned_messages = []
# Sauvegarde brute des messages
self.save_json(messages, os.path.join(output_dir, "messages_raw.json"))
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"])
})
# Nettoyage des messages
cleaned_messages = self._clean_messages(messages)
self.save_json(cleaned_messages, os.path.join(output_dir, "all_messages.json"))
# Génération de structure.json
attachments = self.get_ticket_attachments(ticket_id)
attachment_list = []
for attachment in attachments:
if "datas" in attachment and attachment["datas"]:
file_name = f"{attachment['id']}_{attachment['name']}"
file_path = os.path.join(output_dir, "attachments", file_name)
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, "wb") as f:
f.write(base64.b64decode(attachment["datas"]))
attachment_list.append({
"id": attachment["id"],
"name": attachment["name"],
"file_path": file_path
})
self.save_json(attachment_list, os.path.join(output_dir, "attachments_info.json"))
structure = {
"date_extraction": datetime.now().isoformat(),
"ticket_dir": output_dir,
"fichiers_json": [
"ticket_info.json",
"messages_raw.json",
"all_messages.json"
"all_messages.json",
"attachments_info.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_messages(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
signatures = [
r'Droit à la déconnexion.*',
r'Ce message électronique et tous les fichiers attachés.*',
r'Direction des Infrastructures.*',
r'Service d\'Appui aux Politiques d\'Aménagement.*',
r'tél :.*',
r'mobile :.*',
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