diff --git a/edi_oca/README.rst b/edi_oca/README.rst index 65507fa579..b46fe387d4 100644 --- a/edi_oca/README.rst +++ b/edi_oca/README.rst @@ -60,7 +60,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/models/edi_exchange_record.py b/edi_oca/models/edi_exchange_record.py index 13b3c94322..e49bc6c6ce 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 @@ -112,6 +113,10 @@ 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 = [ ("identifier_uniq", "unique(identifier)", "The identifier must be unique."), @@ -620,3 +625,33 @@ def _inverse_res_id(self): }) except (KeyError, ValueError, MissingError): continue + + 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.ref(xmlid).read()[0] + # 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 9a2a834fc9..de8331ad77 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 90b3461145..a398ca8269 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 ac23a298ad..e0f70a4909 100644 --- a/edi_oca/tests/test_backend_jobs.py +++ b/edi_oca/tests/test_backend_jobs.py @@ -16,6 +16,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 = { @@ -30,6 +36,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( @@ -48,6 +56,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_cache() + self.assertEqual(created, self._get_related_jobs(record)) def test_output_fail_retry(self): job_counter = self.job_counter() @@ -76,6 +87,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( @@ -115,3 +128,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_cache() + 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 84bcc4e05b..b6dda46426 100644 --- a/edi_oca/tests/test_security.py +++ b/edi_oca/tests/test_security.py @@ -49,7 +49,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 aa2d022fa0..67d9097bba 100644 --- a/edi_oca/views/edi_exchange_record_views.xml +++ b/edi_oca/views/edi_exchange_record_views.xml @@ -87,6 +87,23 @@ /> +
+ +