From 7c108154dfd525af5e4e5f5e2b0a88214df17ce7 Mon Sep 17 00:00:00 2001 From: pcosson Date: Fri, 24 Jul 2026 10:22:55 +0200 Subject: [PATCH] fix: fetch all odoo tickets deterministically --- README.md | 6 +++++- TRAVAIL.md | 7 +++++++ WAPT/control | 2 +- setup.py | 17 ++++++++++++++++- tests/test_ticketing.py | 4 ++++ ticketing.ini.example | 2 ++ 6 files changed, 35 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0989b1a..e0c535e 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ username = CHANGE_ME_ODOO_USERNAME api_key = CHANGE_ME_ODOO_API_KEY model = helpdesk.ticket fields = id,name,stage_id,partner_id,user_id,write_date +limit = 0 +order = id asc [http] timeout = 30 @@ -93,6 +95,8 @@ 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.limit = 0` force la recuperation de tous les tickets. `odoo.order = id asc` stabilise la comparaison avec l'etat local. + `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 @@ -123,7 +127,7 @@ Lecture des tickets : "params": { "service": "object", "method": "execute_kw", - "args": ["database", "uid", "api_key", "helpdesk.ticket", "search_read", [[]], {"fields": ["id", "name", "stage_id", "partner_id", "user_id", "write_date"]}] + "args": ["database", "uid", "api_key", "helpdesk.ticket", "search_read", [[]], {"fields": ["id", "name", "stage_id", "partner_id", "user_id", "write_date"], "limit": 0, "order": "id asc"}] }, "id": 1 } diff --git a/TRAVAIL.md b/TRAVAIL.md index f7f5fcf..03ec87f 100644 --- a/TRAVAIL.md +++ b/TRAVAIL.md @@ -128,3 +128,10 @@ Ce fichier consigne les interventions Codex sur le projet afin de garder une tra - 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`. + +### Fiabilisation detection des tickets + +- Ajout explicite de `limit = 0` sur `helpdesk.ticket.search_read` pour eviter une limite implicite cote Odoo. +- Ajout explicite de `order = id asc` pour stabiliser la liste des tickets comparee avec l'etat local. +- Ajout de logs d'audit indiquant le nombre de tickets recuperes et le nombre de tickets modifies detectes. +- Incrementation de la version WAPT de `0.1-13` a `0.1-14`. diff --git a/WAPT/control b/WAPT/control index 64c5598..e2aadaf 100644 --- a/WAPT/control +++ b/WAPT/control @@ -1,5 +1,5 @@ package : comi-odoo-ticketing -version : 0.1-13 +version : 0.1-14 architecture : all section : base priority : optional diff --git a/setup.py b/setup.py index 9feb943..6ccd433 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,7 @@ DEFAULT_TIMEOUT = 30 DEFAULT_TICKET_FIELDS = ["id", "name", "stage_id", "partner_id", "user_id", "write_date"] DEFAULT_MAX_NOTIFIED_TICKETS = 50 DEFAULT_TICKET_URL_TEMPLATE = "{odoo_url}/web#id={id}&model={model}&view_type=form" +DEFAULT_ODOO_ORDER = "id asc" def get_config_path(): @@ -37,6 +38,8 @@ def audit(): tickets = fetch_odoo_tickets(conf_wapt) previous_tickets_state = load_tickets_state(get_state_path()) tickets_updated = get_updated_tickets(tickets, previous_tickets_state) + print("Tickets recuperes depuis Odoo : %s" % len(tickets)) + print("Tickets modifies detectes : %s" % len(tickets_updated)) message = build_notification_message( tickets_updated, previous_tickets_state, @@ -118,6 +121,14 @@ def get_ticket_url_template(conf_wapt): return conf_wapt.get("notification", "ticket_url_template", fallback=DEFAULT_TICKET_URL_TEMPLATE) +def get_odoo_limit(conf_wapt): + return conf_wapt.getint("odoo", "limit", fallback=0) + + +def get_odoo_order(conf_wapt): + return conf_wapt.get("odoo", "order", fallback=DEFAULT_ODOO_ORDER) + + def build_odoo_payload(service, method, args): return { "jsonrpc": "2.0", @@ -186,7 +197,11 @@ def fetch_odoo_tickets(conf_wapt): conf_wapt.get("odoo", "model", fallback="helpdesk.ticket"), "search_read", [[]], - {"fields": get_odoo_fields(conf_wapt)}, + { + "fields": get_odoo_fields(conf_wapt), + "limit": get_odoo_limit(conf_wapt), + "order": get_odoo_order(conf_wapt), + }, ], ) diff --git a/tests/test_ticketing.py b/tests/test_ticketing.py index 16ac50a..63b7823 100644 --- a/tests/test_ticketing.py +++ b/tests/test_ticketing.py @@ -37,6 +37,8 @@ def make_config(): config.set("odoo", "username", "test@example.test") config.set("odoo", "api_key", "test-api-key") config.set("odoo", "model", "helpdesk.ticket") + config.set("odoo", "limit", "0") + config.set("odoo", "order", "id asc") config.add_section("rocket") config.set("rocket", "webhook_url", "https://rocket.example.test/webhook-test") config.add_section("http") @@ -163,6 +165,8 @@ class TicketingStateTest(unittest.TestCase): post.call_args.kwargs["json"]["params"]["args"][6]["fields"], ["id", "name", "stage_id", "partner_id", "user_id", "write_date"], ) + self.assertEqual(post.call_args.kwargs["json"]["params"]["args"][6]["limit"], 0) + self.assertEqual(post.call_args.kwargs["json"]["params"]["args"][6]["order"], "id asc") @patch("ticketing_setup.requests.post") def test_fetch_odoo_tickets_rejects_jsonrpc_error(self, post): diff --git a/ticketing.ini.example b/ticketing.ini.example index a07c51c..f1e2606 100644 --- a/ticketing.ini.example +++ b/ticketing.ini.example @@ -8,6 +8,8 @@ username = CHANGE_ME_ODOO_USERNAME api_key = CHANGE_ME_ODOO_API_KEY model = helpdesk.ticket fields = id,name,stage_id,partner_id,user_id,write_date +limit = 0 +order = id asc [http] timeout = 30