diff --git a/edi_oca/models/edi_exchange_record.py b/edi_oca/models/edi_exchange_record.py index af5623cd9..d15a2ad53 100644 --- a/edi_oca/models/edi_exchange_record.py +++ b/edi_oca/models/edi_exchange_record.py @@ -5,6 +5,7 @@ import base64 import logging +from ast import literal_eval from collections import defaultdict from odoo import _, api, exceptions, fields, models @@ -113,6 +114,9 @@ class EDIExchangeRecord(models.Model): compute="_compute_retryable", help="The record state can be rolled back manually in case of failure.", ) + related_queue_jobs_count = fields.Integer( + compute="_compute_related_queue_jobs_count" + ) company_id = fields.Many2one("res.company", string="Company") _sql_constraints = [ @@ -610,3 +614,32 @@ def delayable(self, **kw): def _job_retry_params(self): return {} + + def _compute_related_queue_jobs_count(self): + for rec in self: + # TODO: We should refactor the object field on queue_job to use jsonb field + # so that we can search directly into it. + rec.related_queue_jobs_count = rec.env["queue.job"].search_count( + [("func_string", "like", str(rec))] + ) + + def action_view_related_queue_jobs(self): + self.ensure_one() + xmlid = "queue_job.action_queue_job" + action = self.env["ir.actions.act_window"]._for_xml_id(xmlid) + # Searching based on task name. Ex: `edi.exchange.record(1,).action_exchange_send()` + # TODO: We should refactor the object field on queue_job to use jsonb field + # so that we can search directly into it. + action["domain"] = [("func_string", "like", str(self))] + # Purge default search filters from ctx to avoid hiding records + ctx = action.get("context", {}) + if isinstance(ctx, str): + ctx = literal_eval(ctx) + # Update the current contexts + ctx.update(self.env.context) + action["context"] = { + k: v for k, v in ctx.items() if not k.startswith("search_default_") + } + # Drop ID otherwise the context will be loaded from the action's record + action.pop("id") + return action diff --git a/edi_oca/readme/CONFIGURE.rst b/edi_oca/readme/CONFIGURE.rst index 24a1cede1..2a8047b9f 100644 --- a/edi_oca/readme/CONFIGURE.rst +++ b/edi_oca/readme/CONFIGURE.rst @@ -11,7 +11,7 @@ In order to define a new Exchange Record, we need to configure: * Components Jobs -~~~~~~~~~~~~~~~~~~~~ +~~~~ * (1) **Internal User**: might be an EDI user without even knowing about it, triggering EDI flows by some of his actions on business records; does not need access to related queue jobs. diff --git a/edi_oca/security/ir_model_access.xml b/edi_oca/security/ir_model_access.xml index 7920b0906..6a80a34bf 100644 --- a/edi_oca/security/ir_model_access.xml +++ b/edi_oca/security/ir_model_access.xml @@ -45,6 +45,18 @@ + + + + access_queue_job edi user + + + + + + + + access_edi_backend_type user diff --git a/edi_oca/tests/test_backend_jobs.py b/edi_oca/tests/test_backend_jobs.py index aa5893018..58b4b0025 100644 --- a/edi_oca/tests/test_backend_jobs.py +++ b/edi_oca/tests/test_backend_jobs.py @@ -17,6 +17,12 @@ class EDIBackendTestJobsCase(EDIBackendCommonTestCase, JobMixin): def _setup_context(cls): return dict(super()._setup_context(), test_queue_job_no_delay=None) + def _get_related_jobs(self, record): + # Use domain in action to find all related jobs + record.ensure_one() + action = record.action_view_related_queue_jobs() + return self.env["queue.job"].search(action["domain"]) + def test_output(self): job_counter = self.job_counter() vals = { @@ -31,6 +37,8 @@ def test_output(self): self.assertEqual( created.name, "Generate output content for given exchange record." ) + # Check related jobs + self.assertEqual(created, self._get_related_jobs(record)) with mock.patch.object( type(self.backend), "_exchange_generate" ) as mocked_generate, mock.patch.object( @@ -49,6 +57,9 @@ def test_output(self): self.assertEqual(res, "Exchange sent") self.assertEqual(record.edi_exchange_state, "output_sent") self.assertEqual(created[0].name, "Send exchange file.") + # Check related jobs + record.invalidate_recordset() + self.assertEqual(created, self._get_related_jobs(record)) def test_output_fail_retry(self): job_counter = self.job_counter() @@ -77,6 +88,8 @@ def test_input(self): created = job_counter.search_created() self.assertEqual(len(created), 1) self.assertEqual(created.name, "Retrieve an incoming document.") + # Check related jobs + self.assertEqual(created, self._get_related_jobs(record)) with mock.patch.object( type(self.backend), "_exchange_receive" ) as mocked_receive, mock.patch.object( @@ -116,3 +129,6 @@ def test_input_processed_error(self): new_created = job_counter.search_created() - created # Should not create new job self.assertEqual(len(new_created), 0) + # Check related jobs + record.invalidate_recordset() + self.assertEqual(created, self._get_related_jobs(record)) diff --git a/edi_oca/tests/test_security.py b/edi_oca/tests/test_security.py index 390c40352..40addb9e5 100644 --- a/edi_oca/tests/test_security.py +++ b/edi_oca/tests/test_security.py @@ -55,7 +55,7 @@ def _setup_records(cls): "name": "Poor Partner (not integrating one)", "email": "poor.partner@ododo.com", "login": "poorpartner", - "groups_id": [(6, 0, [cls.env.ref("base.group_user").id])], + "groups_id": [(6, 0, [cls.env.ref("base_edi.group_edi_user").id])], } ) ) diff --git a/edi_oca/views/edi_exchange_record_views.xml b/edi_oca/views/edi_exchange_record_views.xml index 23b0d9e7e..93a275a4c 100644 --- a/edi_oca/views/edi_exchange_record_views.xml +++ b/edi_oca/views/edi_exchange_record_views.xml @@ -94,6 +94,23 @@ /> +
+ +