From 0ddff4eba7d18c2691f58f19cda4740312fb3e3d Mon Sep 17 00:00:00 2001 From: Cedric Collins Date: Fri, 26 Mar 2021 15:25:43 -0500 Subject: [PATCH] [IMP] sale_exception_portal: add tests and use safe_eval H5654 --- sale_exception_portal/models/sale.py | 8 +++- sale_exception_portal/tests/__init__.py | 1 + .../tests/test_check_so_exceptions.py | 43 +++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 sale_exception_portal/tests/__init__.py create mode 100644 sale_exception_portal/tests/test_check_so_exceptions.py diff --git a/sale_exception_portal/models/sale.py b/sale_exception_portal/models/sale.py index ae37d0b8..03c88689 100644 --- a/sale_exception_portal/models/sale.py +++ b/sale_exception_portal/models/sale.py @@ -1,5 +1,6 @@ import time from odoo import fields, models +from odoo.tools.safe_eval import safe_eval class ExceptionRule(models.Model): @@ -24,8 +25,11 @@ class SaleOrder(models.Model): # Locals() can be used instead of defined params, but can also cause buggy behavior on return params = {'sale': self, 'exception': ex, 'time': time} try: - exec(ex.code, globals(), params) - if 'failed' in params: + safe_eval(ex.code, + params, + mode='exec', + nocopy=True) # nocopy allows to return 'result' + if params.get('failed', False): desc = ex.website_description or ex.description message = {'title': ex.name, 'description': desc} reasons.append(message) diff --git a/sale_exception_portal/tests/__init__.py b/sale_exception_portal/tests/__init__.py new file mode 100644 index 00000000..0098975e --- /dev/null +++ b/sale_exception_portal/tests/__init__.py @@ -0,0 +1 @@ +from . import test_check_so_exceptions diff --git a/sale_exception_portal/tests/test_check_so_exceptions.py b/sale_exception_portal/tests/test_check_so_exceptions.py new file mode 100644 index 00000000..870ad1be --- /dev/null +++ b/sale_exception_portal/tests/test_check_so_exceptions.py @@ -0,0 +1,43 @@ +from odoo.tests.common import TransactionCase + + +class TestCheckSOExceptions(TransactionCase): + def setUp(self): + super(TestCheckSOExceptions, self).setUp() + + self.azure_customer = self.browse_ref('base.res_partner_12') + + self.exception_rule = self.env['exception.rule'].create({ + 'name': 'No Azure', + 'description': 'No sales to Azure', + 'active': True, + 'model': 'sale.order', + 'exception_type': 'by_py_code', + 'code': 'failed = sale.partner_id and sale.partner_id.id == %d' % self.azure_customer.id + }) + + self.sale_product = self.browse_ref('product.product_product_5') + self.sale_product.standard_price = 100.0 + + def test_00_check_so_exceptions(self): + sale_order = self.env['sale.order'].create({ + 'partner_id': self.azure_customer.id, + 'order_line': [(0, 0, { + 'product_id': self.sale_product.id, + 'product_uom_qty': 1.0, + 'price_unit': 50.0, # Set lower than 100.0 to trigger the exception + })], + }) + + exceptions = sale_order._check_sale_order_exceptions() + self.assertEqual(len(exceptions), 1) + self.assertEqual(exceptions[0].get('description'), 'No sales to Azure') + + self.exception_rule.website_description = 'Different message for website' + exceptions = sale_order._check_sale_order_exceptions() + self.assertEqual(len(exceptions), 1) + self.assertEqual(exceptions[0].get('description'), 'Different message for website') + + self.exception_rule.active = False + exceptions = sale_order._check_sale_order_exceptions() + self.assertEqual(len(exceptions), 0)