Skip to content

Commit

Permalink
[BPRT] edi: Backport from 14.0
Browse files Browse the repository at this point in the history
  • Loading branch information
etobella authored and HviorForgeFlow committed Jul 26, 2023
1 parent f30c2f2 commit 5987259
Show file tree
Hide file tree
Showing 14 changed files with 90 additions and 73 deletions.
4 changes: 2 additions & 2 deletions edi_oca/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
Define backends, exchange types, exchange records,
basic automation and views for handling EDI exchanges.
""",
"version": "14.0.1.18.1",
"version": "12.0.1.0.0",
"website": "https://github.com/OCA/edi",
"development_status": "Beta",
"license": "LGPL-3",
Expand All @@ -22,7 +22,7 @@
"base_sparse_field",
"queue_job",
],
"external_dependencies": {"python": ["pyyaml"]},
"external_dependencies": {"python": ["yaml"]},
"data": [
"wizards/edi_exchange_record_create_wiz.xml",
"data/cron.xml",
Expand Down
5 changes: 1 addition & 4 deletions edi_oca/models/edi_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ def _create_record_prepare_values(self, type_code, values):
exchange_type = self.env["edi.exchange.type"].search(
self._get_exchange_type_domain(type_code), limit=1
)
assert exchange_type, f"Exchange type not found: {type_code}"
assert exchange_type, "Exchange type not found: {}".format(type_code)
res["type_id"] = exchange_type.id
res["backend_id"] = self.id
return res
Expand Down Expand Up @@ -473,9 +473,6 @@ def exchange_process(self, exchange_record):
{
"edi_exchange_state": state,
"exchange_error": error,
# FIXME: this should come from _compute_exchanged_on
# but somehow it's failing in send tests (in record tests it works).
"exchanged_on": fields.Datetime.now(),
}
)
if state == "input_processed_error":
Expand Down
4 changes: 3 additions & 1 deletion edi_oca/models/edi_backend_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ def _onchange_code(self):
def _inverse_code(self):
for rec in self:
# Make sure it's always normalized
rec.code = normalize_string(rec.code)
code = normalize_string(rec.code)
if code != rec.code:
rec.code = code
7 changes: 4 additions & 3 deletions edi_oca/models/edi_exchange_consumer_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class EDIExchangeConsumerMixin(models.AbstractModel):
exchange_record_ids = fields.One2many(
"edi.exchange.record",
inverse_name="res_id",
prefetch=False,
domain=lambda r: [("model", "=", r._name)],
)
exchange_record_count = fields.Integer(compute="_compute_exchange_record_count")
Expand All @@ -62,8 +63,8 @@ def _edi_get_exchange_type_config(self):
eval_ctx = dict(
self._get_eval_context(), record=self, exchange_type=exchange_type
)
domain = safe_eval.safe_eval(exchange_type.enable_domain or "[]", eval_ctx)
if not self.filtered_domain(domain):
domain = safe_eval(exchange_type.enable_domain or "[]", eval_ctx)
if not self.search(domain + [('id', 'in', self.ids)]):
continue
if exchange_type.enable_snippet:
safe_eval.safe_eval(
Expand All @@ -72,7 +73,7 @@ def _edi_get_exchange_type_config(self):
if not eval_ctx.get("result", False):
continue

result[exchange_type.id] = self._edi_get_exchange_type_conf(exchange_type)
result[str(exchange_type.id)] = self._edi_get_exchange_type_conf(exchange_type)
return result

@api.model
Expand Down
23 changes: 10 additions & 13 deletions edi_oca/models/edi_exchange_record.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from collections import defaultdict

from odoo import _, api, exceptions, fields, models
from odoo import SUPERUSER_ID

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -36,13 +37,11 @@ class EDIExchangeRecord(models.Model):
direction = fields.Selection(related="type_id.direction")
backend_id = fields.Many2one(comodel_name="edi.backend", required=True)
model = fields.Char(index=True, required=False, readonly=True)
res_id = fields.Many2oneReference(
string="Record",
res_id = fields.Integer(
string="Record ID",
index=True,
required=False,
readonly=True,
model_field="model",
copy=False,
)
related_record_exists = fields.Boolean(compute="_compute_related_record_exists")
related_name = fields.Char(compute="_compute_related_name", compute_sudo=True)
Expand All @@ -53,8 +52,6 @@ class EDIExchangeRecord(models.Model):
exchanged_on = fields.Datetime(
string="Exchanged on",
help="Sent or received on this date.",
compute="_compute_exchanged_on",
store=True,
readonly=False,
)
edi_exchange_state = fields.Selection(
Expand Down Expand Up @@ -125,15 +122,15 @@ def _compute_related_name(self):
related_record = rec.record
rec.related_name = related_record.display_name if related_record else ""

@api.depends("model", "type_id")
@api.depends("model", "type_id", "res_id")
def _compute_exchange_filename(self):
for rec in self:
if not rec.type_id:
continue
if not rec.exchange_filename:
rec.exchange_filename = rec.type_id._make_exchange_filename(rec)

@api.depends("edi_exchange_state")
@api.constrains("edi_exchange_state")
def _compute_exchanged_on(self):
for rec in self:
if rec.edi_exchange_state in ("input_received", "output_sent"):
Expand Down Expand Up @@ -372,7 +369,7 @@ def notify_action_complete(self, action, message=None):
self._notify_related_record(message)

# Trigger generic action complete event on exchange record
event_name = f"{action}_complete"
event_name = "{}_complete".format(action)
self._trigger_edi_event(event_name)
if self.related_record_exists:
# Trigger specific event on related record
Expand Down Expand Up @@ -453,8 +450,8 @@ def _search(
count=False,
access_rights_uid=access_rights_uid,
)
if self.env.is_system():
# restrictions do not apply to group "Settings"
if self._uid == SUPERUSER_ID:
# rules do not apply for the superuser
return len(ids) if count else ids

# TODO highlight orphaned EDI records in UI:
Expand Down Expand Up @@ -531,7 +528,7 @@ def check_access_rule(self, operation):
"""In order to check if we can access a record, we are checking if we can access
the related document"""
super(EDIExchangeRecord, self).check_access_rule(operation)
if self.env.is_superuser():
if self._uid == SUPERUSER_ID:
return
default_checker = self.env["edi.exchange.consumer.mixin"].get_edi_access
by_model_rec_ids = defaultdict(set)
Expand All @@ -546,7 +543,7 @@ def check_access_rule(self, operation):
)

for model, rec_ids in by_model_rec_ids.items():
records = self.env[model].browse(rec_ids).with_user(self._uid)
records = self.env[model].browse(rec_ids).sudo(self._uid)
checker = by_model_checker[model]
for record in records:
check_operation = checker(
Expand Down
2 changes: 1 addition & 1 deletion edi_oca/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def _setup_records(cls):
code="test_csv_output_ack",
direction="output",
exchange_file_ext="txt",
exchange_filename_pattern="{record.ref}-{type.code}-{dt}",
exchange_filename_pattern="{record.name}-{type.code}-{dt}",
)
cls.exchange_type_out.ack_type_id = cls.exchange_type_out_ack
cls.partner = cls.env.ref("base.res_partner_1")
Expand Down
1 change: 1 addition & 0 deletions edi_oca/tests/fake_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class EdiExchangeConsumerTest(models.Model):
_description = "Model used only for test"

name = fields.Char()
ref = fields.Char()

def _get_edi_exchange_record_name(self, exchange_record):
return self.id
13 changes: 6 additions & 7 deletions edi_oca/tests/test_backend_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

import base64

from freezegun import freeze_time

from odoo import fields
from odoo.exceptions import UserError
from odoo.tools import mute_logger
Expand Down Expand Up @@ -36,15 +34,16 @@ def setUp(self):

def test_process_record(self):
self.record.write({"edi_exchange_state": "input_received"})
with freeze_time("2020-10-22 10:00:00"):
self.record.action_exchange_process()
now = fields.Datetime.now()
self.record.action_exchange_process()
self.assertTrue(FakeInputProcess.check_called_for(self.record))
self.assertRecordValues(
self.record, [{"edi_exchange_state": "input_processed"}]
)
self.assertEqual(
fields.Datetime.to_string(self.record.exchanged_on), "2020-10-22 10:00:00"
)
self.record.refresh()
self.assertAlmostEqual(
(self.record.exchanged_on - now).total_seconds(),
0, places=2)

def test_process_record_with_error(self):
self.record.write({"edi_exchange_state": "input_received"})
Expand Down
60 changes: 37 additions & 23 deletions edi_oca/tests/test_security.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

from odoo_test_helper import FakeModelLoader

from odoo.exceptions import AccessError
from odoo.tools import mute_logger
from odoo.exceptions import AccessError, ValidationError

from .common import EDIBackendCommonTestCase

Expand Down Expand Up @@ -70,7 +70,10 @@ def create_record(self, user=False):
}
backend = self.backend
if user:
backend = backend.with_user(user)
if isinstance(user, int):
backend = backend.sudo(user)
else:
backend = backend.sudo(user.id)
return backend.create_record("test_csv_output", vals)

def test_superuser_create(self):
Expand All @@ -86,8 +89,8 @@ def test_group_create(self):
def test_rule_no_create(self):
self.user.write({"groups_id": [(4, self.group.id)]})
self.consumer_record.name = "no_rule"
with self.assertRaisesRegex(AccessError, "Exchange Record rule demo"):
self.create_record(self.user)
with self.assertRaises(ValidationError):
self.create_record(self.user.id)

@mute_logger("odoo.addons.base.models.ir_model")
def test_no_group_no_create(self):
Expand All @@ -98,43 +101,49 @@ def test_no_group_no_create(self):
def test_no_group_no_read(self):
exchange_record = self.create_record()
with self.assertRaisesRegex(AccessError, "You are not allowed to access"):
exchange_record.with_user(self.user).read()
exchange_record.sudo(self.user.id).read()

@mute_logger("odoo.addons.base.models.ir_rule")
def test_rule_no_read(self):
exchange_record = self.create_record()
self.user.write({"groups_id": [(4, self.group.id)]})
self.assertTrue(exchange_record.with_user(self.user).read())
self.assertTrue(exchange_record.sudo(self.user.id).read())
self.consumer_record.name = "no_rule"
with self.assertRaisesRegex(AccessError, "Exchange Record rule demo"):
exchange_record.with_user(self.user).read()
with self.assertRaisesRegex(
AccessError, "operation cannot be completed due to security"
):
exchange_record.sudo(self.user.id).read()

@mute_logger("odoo.addons.base.models.ir_model")
def test_no_group_no_unlink(self):
exchange_record = self.create_record()
with self.assertRaisesRegex(AccessError, "You are not allowed to modify"):
exchange_record.with_user(self.user).unlink()
exchange_record.sudo(self.user.id).unlink()

@mute_logger("odoo.models.unlink")
def test_group_unlink(self):
exchange_record = self.create_record()
self.user.write({"groups_id": [(4, self.group.id)]})
self.assertTrue(exchange_record.with_user(self.user).unlink())
exchange_record = exchange_record.sudo(self.user.id)
exchange_record.clear_caches()
self.assertTrue(exchange_record.unlink())

@mute_logger("odoo.addons.base.models.ir_rule")
def test_rule_no_unlink(self):
exchange_record = self.create_record()
self.user.write({"groups_id": [(4, self.group.id)]})
self.consumer_record.name = "no_rule"
with self.assertRaisesRegex(AccessError, "Exchange Record rule demo"):
exchange_record.with_user(self.user).unlink()
with self.assertRaisesRegex(
AccessError, "operation cannot be completed due to security"
):
exchange_record.sudo(self.user.id).unlink()

def test_no_group_no_search(self):
exchange_record = self.create_record()
self.assertEqual(
0,
self.env["edi.exchange.record"]
.with_user(self.user)
.sudo(self.user.id)
.search_count([("id", "=", exchange_record.id)]),
)

Expand All @@ -144,7 +153,7 @@ def test_group_search(self):
self.assertEqual(
1,
self.env["edi.exchange.record"]
.with_user(self.user)
.sudo(self.user.id)
.search_count([("id", "=", exchange_record.id)]),
)

Expand All @@ -155,7 +164,7 @@ def test_rule_no_search(self):
self.assertEqual(
0,
self.env["edi.exchange.record"]
.with_user(self.user)
.sudo(self.user.id)
.search_count([("id", "=", exchange_record.id)]),
)

Expand All @@ -167,9 +176,11 @@ def test_search_no_record(self):
self.user.write({"groups_id": [(4, self.group.id)]})
logger_name = "odoo.addons.edi_oca.models.edi_exchange_record"
expected_msg = (
f"WARNING:{logger_name}:"
f"Deleted record {exchange_record.model},{exchange_record.res_id} "
f"is referenced by edi.exchange.record [{exchange_record.id}]"
"WARNING:{}:"
"Deleted record {},{} "
"is referenced by edi.exchange.record [{}]".format(
logger_name, exchange_record.model, exchange_record.res_id, exchange_record.id
)
)
with self.assertLogs(logger_name, "WARNING") as watcher:
self.assertEqual(
Expand Down Expand Up @@ -197,19 +208,22 @@ def test_search_no_record_admin(self):
@mute_logger("odoo.addons.base.models.ir_model")
def test_no_group_no_write(self):
exchange_record = self.create_record()
with self.assertRaisesRegex(AccessError, "You are not allowed to modify"):
exchange_record.with_user(self.user).write({"external_identifier": "1234"})
with self.assertRaisesRegex(AccessError, "you are not allowed to modify"):
exchange_record.sudo(self.user.id).write({"external_identifier": "1234"})

def test_group_write(self):
exchange_record = self.create_record()
self.user.write({"groups_id": [(4, self.group.id)]})
exchange_record.with_user(self.user).write({"external_identifier": "1234"})
exchange_record.sudo(self.user.id).write({"external_identifier": "1234"})
self.assertEqual(exchange_record.external_identifier, "1234")

@mute_logger("odoo.addons.base.models.ir_rule")
def test_rule_no_write(self):
exchange_record = self.create_record()
self.user.write({"groups_id": [(4, self.group.id)]})
self.consumer_record.name = "no_rule"
with self.assertRaisesRegex(AccessError, "Exchange Record rule demo"):
exchange_record.with_user(self.user).write({"external_identifier": "1234"})
with self.assertRaisesRegex(
AccessError,
"operation cannot be completed due to security"
):
exchange_record.sudo(self.user.id).write({"external_identifier": "1234"})
20 changes: 9 additions & 11 deletions edi_oca/views/edi_exchange_record_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,20 @@
<record id="edi_exchange_record_view_tree" model="ir.ui.view">
<field name="model">edi.exchange.record</field>
<field name="arch" type="xml">
<tree string="EDI Exchange Record">
<tree string="EDI Exchange Record"
decoration-success="edi_exchange_state in ['output_sent_and_processed', 'input_processed']"
decoration-danger="edi_exchange_state in ['validate_error', 'output_error_on_send', 'output_sent_and_error', 'input_receive_error', 'input_processed_error']"
>
<field name="backend_id" />
<field name="type_id" />
<field name="identifier" />
<field name="external_identifier" optional="hide" />
<field name="related_name" optional="hide" />
<field name="res_id" groups="base.group_no_one" optional="hide" />
<field name="model" groups="base.group_no_one" optional="hide" />
<field name="external_identifier" />
<field name="related_name" />
<field name="res_id" groups="base.group_no_one" />
<field name="model" groups="base.group_no_one" />
<field name="exchanged_on" />
<field name="ack_received_on" />
<field
name="edi_exchange_state"
decoration-success="edi_exchange_state in ['output_sent_and_processed', 'input_processed']"
decoration-danger="edi_exchange_state in ['validate_error', 'output_error_on_send', 'output_sent_and_error', 'input_receive_error', 'input_processed_error']"
widget="badge"
/>
<field name="edi_exchange_state" />
</tree>
</field>
</record>
Expand Down
Loading

0 comments on commit 5987259

Please sign in to comment.