feat: restore compact ticket notification format

This commit is contained in:
2026-07-24 10:10:33 +02:00
parent 93b6947feb
commit b0fb879914
6 changed files with 86 additions and 21 deletions
+8 -8
View File
@@ -57,6 +57,7 @@ timeout = 30
[notification] [notification]
max_tickets = 50 max_tickets = 50
ticket_url_template = {odoo_url}/web#id={id}&model={model}&view_type=form
``` ```
Au deploiement, `install()` copie ce modele vers `WAPT.private_dir/ticketing.ini` uniquement si le fichier n'existe pas deja. Il faut ensuite renseigner le fichier prive sur la machine cible. Les mises a jour du paquet n'ecrasent donc pas une configuration deja remplie. Au deploiement, `install()` copie ce modele vers `WAPT.private_dir/ticketing.ini` uniquement si le fichier n'existe pas deja. Il faut ensuite renseigner le fichier prive sur la machine cible. Les mises a jour du paquet n'ecrasent donc pas une configuration deja remplie.
@@ -92,7 +93,7 @@ La cle API est utilisee comme mot de passe d'API Odoo pour authentifier `usernam
`odoo.fields` controle les champs recuperes depuis Odoo pour enrichir la notification. Les champs `id` et `write_date` sont toujours ajoutes s'ils sont absents, car ils sont necessaires a la comparaison d'etat. `odoo.fields` controle les champs recuperes depuis Odoo pour enrichir la notification. Les champs `id` et `write_date` sont toujours ajoutes s'ils sont absents, car ils sont necessaires a la comparaison d'etat.
`notification.max_tickets` limite le nombre de lignes detaillees envoyees dans Rocket.Chat. Le message indique toujours le nombre total de tickets modifies. `notification.max_tickets` limite le nombre de tickets affiches dans Rocket.Chat. `notification.ticket_url_template` controle le lien d'ouverture du ticket ; les variables disponibles sont `{odoo_url}`, `{id}` et `{model}`.
## Protocole Odoo ## Protocole Odoo
@@ -132,17 +133,16 @@ Lecture des tickets :
Quand des tickets changent, Rocket.Chat recoit un message avec : Quand des tickets changent, Rocket.Chat recoit un message avec :
- le nombre total de tickets modifies ; - une ligne compacte par ticket affiche, limitee par `notification.max_tickets` ;
- une ligne par ticket affiche, limitee par `notification.max_tickets` ; - l'ID, le sujet, la personne assignee et un lien d'ouverture direct dans Odoo ;
- l'ID, le titre, le type de changement, le statut, le client, l'assigne, la nouvelle date de modification et l'ancienne date quand elle existe. - une ligne de resume si tous les tickets modifies ne sont pas affiches.
Exemple : Exemple :
```text ```text
Tickets Odoo mis a jour depuis la derniere verification : 2 Les tickets suivants ont ete mis a jour depuis la derniere verification :
187 : Sujet : Probleme imprimante gere par Support : [cliquer ici pour ouvrir le ticket](https://odoo.example.test/web#id=187&model=helpdesk.ticket&view_type=form)
- #187 | Probleme imprimante | type: modifie | statut: En cours | client: Comitari | assigne: Support | date: 2026-07-24 10:00:00 | ancienne date: 2026-07-24 09:00:00 251 : Sujet : Nouveau ticket gere par Personne : [cliquer ici pour ouvrir le ticket](https://odoo.example.test/web#id=251&model=helpdesk.ticket&view_type=form)
- #251 | Nouveau ticket | type: nouveau | statut: - | client: - | assigne: - | date: 2026-07-24 11:00:00
``` ```
## Tests ## Tests
+8
View File
@@ -120,3 +120,11 @@ Ce fichier consigne les interventions Codex sur le projet afin de garder une tra
- Ajout de l'option `notification.max_tickets` pour limiter le nombre de lignes detaillees dans Rocket.Chat. - Ajout de l'option `notification.max_tickets` pour limiter le nombre de lignes detaillees dans Rocket.Chat.
- Remplacement du message brut contenant seulement une liste d'IDs par un message avec nombre total, titre, statut, client, assigne, date courante et ancienne date quand disponible. - Remplacement du message brut contenant seulement une liste d'IDs par un message avec nombre total, titre, statut, client, assigne, date courante et ancienne date quand disponible.
- Incrementation de la version WAPT locale de `0.1-11` a `0.1-12`. - Incrementation de la version WAPT locale de `0.1-11` a `0.1-12`.
### Alignement format historique Rocket.Chat
- Remplacement du format detaille par un format compact proche de l'ancien rendu :
`ID : Sujet : titre gere par personne : cliquer ici pour ouvrir le ticket`.
- Ajout d'un lien Markdown vers Odoo pour chaque ticket.
- Ajout de l'option `notification.ticket_url_template` avec les variables `{odoo_url}`, `{id}` et `{model}`.
- Incrementation de la version WAPT de `0.1-12` a `0.1-13`.
+1 -1
View File
@@ -1,5 +1,5 @@
package : comi-odoo-ticketing package : comi-odoo-ticketing
version : 0.1-12 version : 0.1-13
architecture : all architecture : all
section : base section : base
priority : optional priority : optional
+37 -6
View File
@@ -14,6 +14,7 @@ STATE_FILE = "tickets_state.json"
DEFAULT_TIMEOUT = 30 DEFAULT_TIMEOUT = 30
DEFAULT_TICKET_FIELDS = ["id", "name", "stage_id", "partner_id", "user_id", "write_date"] DEFAULT_TICKET_FIELDS = ["id", "name", "stage_id", "partner_id", "user_id", "write_date"]
DEFAULT_MAX_NOTIFIED_TICKETS = 50 DEFAULT_MAX_NOTIFIED_TICKETS = 50
DEFAULT_TICKET_URL_TEMPLATE = "{odoo_url}/web#id={id}&model={model}&view_type=form"
def get_config_path(): def get_config_path():
@@ -40,6 +41,9 @@ def audit():
tickets_updated, tickets_updated,
previous_tickets_state, previous_tickets_state,
get_max_notified_tickets(conf_wapt), get_max_notified_tickets(conf_wapt),
get_ticket_url_template(conf_wapt),
conf_wapt.get("odoo", "url").rstrip("/"),
conf_wapt.get("odoo", "model", fallback="helpdesk.ticket"),
) )
send_to_rocket(message, conf_wapt=conf_wapt) send_to_rocket(message, conf_wapt=conf_wapt)
@@ -110,6 +114,10 @@ def get_max_notified_tickets(conf_wapt):
return conf_wapt.getint("notification", "max_tickets", fallback=DEFAULT_MAX_NOTIFIED_TICKETS) return conf_wapt.getint("notification", "max_tickets", fallback=DEFAULT_MAX_NOTIFIED_TICKETS)
def get_ticket_url_template(conf_wapt):
return conf_wapt.get("notification", "ticket_url_template", fallback=DEFAULT_TICKET_URL_TEMPLATE)
def build_odoo_payload(service, method, args): def build_odoo_payload(service, method, args):
return { return {
"jsonrpc": "2.0", "jsonrpc": "2.0",
@@ -235,7 +243,28 @@ def display_odoo_value(value):
return str(value) return str(value)
def format_ticket_line(ticket, previous_tickets_state): def build_ticket_url(ticket, ticket_url_template, odoo_url, model):
return ticket_url_template.format(
id=ticket["id"],
odoo_url=odoo_url,
model=model,
)
def format_ticket_line(ticket, ticket_url_template, odoo_url, model):
assignee = display_odoo_value(ticket.get("user_id"))
if assignee == "-":
assignee = "Personne"
return "%s : Sujet : %s gere par %s : [cliquer ici pour ouvrir le ticket](%s)" % (
ticket["id"],
display_odoo_value(ticket.get("name", "Sans titre")),
assignee,
build_ticket_url(ticket, ticket_url_template, odoo_url, model),
)
def format_detailed_ticket_line(ticket, previous_tickets_state):
ticket_id = str(ticket["id"]) ticket_id = str(ticket["id"])
previous_write_date = previous_tickets_state.get(ticket_id) previous_write_date = previous_tickets_state.get(ticket_id)
change_type = "nouveau" if previous_write_date is None else "modifie" change_type = "nouveau" if previous_write_date is None else "modifie"
@@ -253,25 +282,27 @@ def format_ticket_line(ticket, previous_tickets_state):
return "- " + " | ".join(parts) return "- " + " | ".join(parts)
def build_notification_message(tickets_updated, previous_tickets_state, max_tickets): def build_notification_message(tickets_updated, previous_tickets_state, max_tickets, ticket_url_template, odoo_url, model):
if not tickets_updated: if not tickets_updated:
return "Aucun ticket n'a ete mis a jour depuis la derniere verification." return "Aucun ticket n'a ete mis a jour depuis la derniere verification."
displayed_tickets = tickets_updated[:max_tickets] displayed_tickets = tickets_updated[:max_tickets]
hidden_count = len(tickets_updated) - len(displayed_tickets) hidden_count = len(tickets_updated) - len(displayed_tickets)
lines = [ lines = [
"Tickets Odoo mis a jour depuis la derniere verification : %s" % len(tickets_updated), "Les tickets suivants ont ete mis a jour depuis la derniere verification :",
"",
] ]
lines.extend([ lines.extend([
format_ticket_line(ticket, previous_tickets_state) format_ticket_line(ticket, ticket_url_template, odoo_url, model)
for ticket in displayed_tickets for ticket in displayed_tickets
]) ])
if hidden_count > 0: if hidden_count > 0:
lines.extend([ lines.extend([
"", "",
"... %s ticket(s) supplementaire(s) non affiche(s)." % hidden_count, "... %s ticket(s) supplementaire(s) non affiche(s) sur %s au total." % (
hidden_count,
len(tickets_updated),
),
]) ])
return "\n".join(lines) return "\n".join(lines)
+31 -6
View File
@@ -92,15 +92,40 @@ class TicketingStateTest(unittest.TestCase):
}, },
] ]
message = ticketing.build_notification_message(tickets, previous_state, 1) message = ticketing.build_notification_message(
tickets,
previous_state,
1,
"{odoo_url}/web#id={id}&model={model}&view_type=form",
"https://odoo.example.test",
"helpdesk.ticket",
)
self.assertIn("Tickets Odoo mis a jour depuis la derniere verification : 2", message) self.assertIn("Les tickets suivants ont ete mis a jour depuis la derniere verification :", message)
self.assertIn("#1 | Probleme imprimante | type: modifie", message) self.assertIn(
self.assertIn("statut: En cours", message) "1 : Sujet : Probleme imprimante gere par Support : "
self.assertIn("ancienne date: 2026-07-24 09:00:00", message) "[cliquer ici pour ouvrir le ticket]"
self.assertIn("1 ticket(s) supplementaire(s) non affiche(s)", message) "(https://odoo.example.test/web#id=1&model=helpdesk.ticket&view_type=form)",
message,
)
self.assertIn("1 ticket(s) supplementaire(s) non affiche(s) sur 2 au total", message)
self.assertNotIn("Nouveau ticket", message) self.assertNotIn("Nouveau ticket", message)
def test_format_ticket_line_uses_personne_when_no_assignee(self):
line = ticketing.format_ticket_line(
{"id": 2, "name": "Nouveau ticket", "user_id": False},
"{odoo_url}/web#id={id}&model={model}&view_type=form",
"https://odoo.example.test",
"helpdesk.ticket",
)
self.assertEqual(
line,
"2 : Sujet : Nouveau ticket gere par Personne : "
"[cliquer ici pour ouvrir le ticket]"
"(https://odoo.example.test/web#id=2&model=helpdesk.ticket&view_type=form)",
)
def test_load_tickets_state_returns_empty_dict_when_file_is_missing(self): def test_load_tickets_state_returns_empty_dict_when_file_is_missing(self):
missing_path = os.path.join(tempfile.gettempdir(), "missing-ticket-state.json") missing_path = os.path.join(tempfile.gettempdir(), "missing-ticket-state.json")
+1
View File
@@ -14,3 +14,4 @@ timeout = 30
[notification] [notification]
max_tickets = 50 max_tickets = 50
ticket_url_template = {odoo_url}/web#id={id}&model={model}&view_type=form