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 @@
/>
+