diff --git a/base_exception/models/base_exception.py b/base_exception/models/base_exception.py index 1e29af359..45c153276 100644 --- a/base_exception/models/base_exception.py +++ b/base_exception/models/base_exception.py @@ -47,13 +47,16 @@ class ExceptionRule(models.Model): "not. Use failed = True to block the exception", ) - @api.constrains("exception_type", "domain", "code") + @api.constrains("exception_type", "domain", "code", "model") def check_exception_type_consistency(self): for rule in self: if ( (rule.exception_type == "by_py_code" and not rule.code) or (rule.exception_type == "by_domain" and not rule.domain) - or (rule.exception_type == "by_method" and not rule.method) + or ( + rule.exception_type == "by_method" + and not self._check_method_valid(rule.method, rule.model) + ) ): raise ValidationError( _( @@ -63,6 +66,13 @@ class ExceptionRule(models.Model): ) ) + def _check_method_valid(self, method_name, model_name): + model = self.env[model_name] + method = getattr(model, method_name) + if method and callable(method): + return True + return False + @api.multi def _get_domain(self): """ override me to customize domains according exceptions cases """ diff --git a/base_exception/tests/purchase_test.py b/base_exception/tests/purchase_test.py index 3b5d806ed..c7c4dfe4d 100644 --- a/base_exception/tests/purchase_test.py +++ b/base_exception/tests/purchase_test.py @@ -62,6 +62,13 @@ class PurchaseTest(models.Model): def _reverse_field(self): return "test_purchase_ids" + def exception_method_no_zip(self): + records_fail = self.env["base.exception.test.purchase"] + for rec in self: + if not rec.partner_id.zip: + records_fail += rec + return records_fail + class LineTest(models.Model): _name = "base.exception.test.purchase.line" diff --git a/base_exception/tests/test_base_exception.py b/base_exception/tests/test_base_exception.py index 0a73f0250..e67f05e16 100644 --- a/base_exception/tests/test_base_exception.py +++ b/base_exception/tests/test_base_exception.py @@ -33,51 +33,81 @@ class TestBaseException(common.SavepointCase): ("base.exception.test.purchase.line", "Purchase Order Line") ) - cls.exceptionnozip = cls.env["exception.rule"].create( + cls.partner = cls.env.ref("base.res_partner_1") + cls.partner.zip = False + cls.potest1 = cls.env["base.exception.test.purchase"].create( { - "name": "No ZIP code on destination", - "sequence": 10, - "model": "base.exception.test.purchase", - "code": "if not obj.partner_id.zip: failed=True", + "name": "Test base exception to basic purchase", + "partner_id": cls.partner.id, + "line_ids": [ + (0, 0, {"name": "line test", "amount": 120.0, "qty": 1.5}) + ], } ) - cls.exceptionno_minorder = cls.env["exception.rule"].create( + def test_purchase_order_valid(self): + self.potest1.button_confirm() + self.assertFalse(self.potest1.exception_ids) + + def test_purchase_order_exception_invalid_amt_total(self): + self.exception_amount_total = self.env["exception.rule"].create( { "name": "Min order except", "sequence": 10, "model": "base.exception.test.purchase", "code": "if obj.amount_total <= 200.0: failed=True", + "exception_type": "by_py_code", } ) + with self.assertRaises(ValidationError): + self.potest1.button_confirm() + self.assertTrue(self.potest1.exception_ids) - cls.exceptionno_lineqty = cls.env["exception.rule"].create( + def test_purchase_order_exception_invalid_partner_zip(self): + self.exception_partner_no_zip = self.env["exception.rule"].create( { - "name": "Qty > 0", + "name": "No ZIP code on destination", "sequence": 10, - "model": "base.exception.test.purchase.line", - "code": "if obj.qty <= 0: failed=True", + "model": "base.exception.test.purchase", + "code": "if not obj.partner_id.zip: failed=True", + "exception_type": "by_py_code", } ) + with self.assertRaises(ValidationError): + self.potest1.button_confirm() + self.assertTrue(self.potest1.exception_ids) - def test_purchase_order_exception(self): - partner = self.env.ref("base.res_partner_1") - partner.zip = False - potest1 = self.env["base.exception.test.purchase"].create( + def test_purchase_order_exception_name(self): + self.exception_no_name = self.env["exception.rule"].create( { - "name": "Test base exception to basic purchase", - "partner_id": partner.id, - "line_ids": [ - (0, 0, {"name": "line test", "amount": 120.0, "qty": 1.5}) - ], + "name": "No name", + "sequence": 10, + "model": "base.exception.test.purchase", + "method": "exception_method_no_zip", + "exception_type": "by_method", + } + ) + with self.assertRaises(ValidationError): + self.potest1.button_confirm() + self.assertTrue(self.potest1.exception_ids) + + def test_ignore_exception(self): + # same as 1st test + self.exception_amount_total = self.env["exception.rule"].create( + { + "name": "Min order except", + "sequence": 10, + "model": "base.exception.test.purchase", + "code": "if obj.amount_total <= 200.0: failed=True", + "exception_type": "by_py_code", } ) # Block because of exception during validation with self.assertRaises(ValidationError): - potest1.button_confirm() + self.potest1.button_confirm() # Test that we have linked exceptions - self.assertTrue(potest1.exception_ids) + self.assertTrue(self.potest1.exception_ids) # Test ignore exeception make possible for the po to validate - potest1.ignore_exception = True - potest1.button_confirm() - self.assertTrue(potest1.state == "purchase") + self.potest1.ignore_exception = True + self.potest1.button_confirm() + self.assertTrue(self.potest1.state == "purchase")