From 1088f5c3ae0cb96ac486df4af5377d0d8fb073a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Todorovich?= Date: Tue, 9 Apr 2019 11:47:13 +0000 Subject: [PATCH] [MIG] base_exception: Migration to 12.0 --- base_exception/README.rst | 78 ++-- base_exception/__init__.py | 1 - base_exception/__manifest__.py | 9 +- base_exception/models/base_exception.py | 129 ++---- base_exception/readme/CONTRIBUTORS.rst | 8 + base_exception/readme/DESCRIPTION.rst | 6 + base_exception/readme/ROADMAP.rst | 1 + base_exception/static/description/index.html | 437 ++++++++++++++++++ base_exception/tests/test_base_exception.py | 35 +- base_exception/views/base_exception_view.xml | 34 +- .../wizard/base_exception_confirm.py | 11 +- .../wizard/base_exception_confirm_view.xml | 2 + 12 files changed, 612 insertions(+), 139 deletions(-) create mode 100644 base_exception/readme/CONTRIBUTORS.rst create mode 100644 base_exception/readme/DESCRIPTION.rst create mode 100644 base_exception/readme/ROADMAP.rst create mode 100644 base_exception/static/description/index.html diff --git a/base_exception/README.rst b/base_exception/README.rst index 4c390d7f0..480047307 100644 --- a/base_exception/README.rst +++ b/base_exception/README.rst @@ -1,11 +1,30 @@ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html - :alt: License: AGPL-3 - ============== -Base Exception +Exception Rule ============== +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github + :target: https://github.com/OCA/server-tools/tree/12.0/base_exception + :alt: OCA/server-tools +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-tools-12-0/server-tools-12-0-base_exception + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/149/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + This module provide an abstract model to manage customizable exceptions to be applied on different models (sale order, invoice, ...). @@ -13,34 +32,38 @@ It is not useful for itself. You can see an example of implementation in the 'sale_exception' module. (sale-workflow repository) or 'purchase_exception' module (purchase-workflow repository). -Usage -===== +**Table of contents** -.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas - :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/149/11.0 +.. contents:: + :local: +Known issues / Roadmap +====================== + +Terms used in old api like `pool`, `cr`, `uid` must be removed porting this module in version 12. Bug Tracker =========== -Bugs are tracked on `GitHub Issues -`_. In case of trouble, please -check there if your issue has already been reported. If you spotted it first, -help us smash it by providing detailed and welcomed feedback. +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. -Roadmap -------- -Terms used in old api like `pool`, `cr`, `uid` must be removed porting this module in version 12. +Do not contact contributors directly about support or help with technical issues. +Credits +======= -Images ------- +Authors +~~~~~~~ -* Odoo Community Association: `Icon `_. +* Akretion +* Sodexis +* Camptocamp Contributors ------------- +~~~~~~~~~~~~ * Raphaël Valyi * Renato Lima @@ -49,18 +72,21 @@ Contributors * Yannick Vaucher * SodexisTeam * Mourad EL HADJ MIMOUNE +* Iván Todorovich -Maintainer ----------- +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. .. image:: https://odoo-community.org/logo.png :alt: Odoo Community Association :target: https://odoo-community.org -This module is maintained by the OCA. - OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -To contribute to this module, please visit https://odoo-community.org. +This module is part of the `OCA/server-tools `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_exception/__init__.py b/base_exception/__init__.py index 75a695531..e415ab28a 100644 --- a/base_exception/__init__.py +++ b/base_exception/__init__.py @@ -1,2 +1 @@ - from . import wizard, models diff --git a/base_exception/__manifest__.py b/base_exception/__manifest__.py index 61a0eee02..ad9c55106 100644 --- a/base_exception/__manifest__.py +++ b/base_exception/__manifest__.py @@ -2,18 +2,19 @@ # Copyright 2017 Akretion (http://www.akretion.com) # Mourad EL HADJ MIMOUNE # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). - { 'name': 'Exception Rule', - 'version': '11.0.1.1.0', + 'version': '12.0.1.0.0', 'category': 'Generic Modules', 'summary': """ This module provide an abstract model to manage customizable exceptions to be applied on different models (sale order, invoice, ...)""", 'author': "Akretion, Sodexis, Camptocamp, Odoo Community Association (OCA)", - 'website': 'http://www.akretion.com', - 'depends': ['base_setup'], + 'website': 'https://github.com/OCA/server-tools', + 'depends': [ + 'base_setup', + ], 'license': 'AGPL-3', 'data': [ 'security/base_exception_security.xml', diff --git a/base_exception/models/base_exception.py b/base_exception/models/base_exception.py index 29c187d7b..b6b0d6fb0 100644 --- a/base_exception/models/base_exception.py +++ b/base_exception/models/base_exception.py @@ -6,13 +6,9 @@ import time from functools import wraps from odoo import api, fields, models, _ -import logging - from odoo.exceptions import UserError, ValidationError from odoo.tools.safe_eval import safe_eval -_logger = logging.getLogger(__name__) - def implemented_by_base_exception(func): """Call a prefixed function based on 'namespace'.""" @@ -28,50 +24,36 @@ def implemented_by_base_exception(func): class ExceptionRule(models.Model): _name = 'exception.rule' - _description = "Exception Rules" + _description = 'Exception Rule' _order = 'active desc, sequence asc' name = fields.Char('Exception Name', required=True, translate=True) description = fields.Text('Description', translate=True) sequence = fields.Integer( string='Sequence', - help="Gives the sequence order when applying the test") + help="Gives the sequence order when applying the test", + ) rule_group = fields.Selection( selection=[], help="Rule group is used to group the rules that must validated " "at same time for a target object. Ex: " "validate sale.order.line rules with sale order rules.", - required=True) - model = fields.Selection( - selection=[], - string='Apply on', required=True) + required=True, + ) + model = fields.Selection(selection=[], string='Apply on', required=True) active = fields.Boolean('Active') next_state = fields.Char( 'Next state', help="If we detect exception we set the state of object (ex purchase) " "to the next_state (ex 'to approve'). If there are more than one " "exception detected and all have a value for next_state, we use" - "the exception having the smallest sequence value") + "the exception having the smallest sequence value", + ) code = fields.Text( 'Python Code', help="Python code executed to check if the exception apply or " "not. Use failed = True to block the exception", - default=""" -# Python code. Use failed = True to block the base.exception. -# You can use the following variables : -# - self: ORM model of the record which is checked -# - "rule_group" or "rule_group_"line: -# browse_record of the base.exception or -# base.exception line (ex rule_group = sale for sale order) -# - object: same as order or line, browse_record of the base.exception or -# base.exception line -# - obj: same as object -# - env: Odoo Environment (i.e. self.env) -# - time: Python time module -# - cr: database cursor -# - uid: current user id -# - context: current context -""") + ) @api.constrains('next_state') def _check_next_state_value(self): @@ -84,60 +66,55 @@ class ExceptionRule(models.Model): 'state']['selection'] select_vals_code = [s[0] for s in select_vals] if rule.next_state not in select_vals_code: - raise ValidationError( - _('The value "%s" you choose for the "next state" ' - 'field state of "%s" is wrong.' - ' Value must be in this list %s') - % (rule.next_state, - rule.model, - select_vals) - ) + raise ValidationError(_( + 'The value "%s" you choose for the "next state" ' + 'field state of "%s" is wrong.' + ' Value must be in this list %s' + ) % ( + rule.next_state, + rule.model, + select_vals + )) class BaseException(models.AbstractModel): _name = 'base.exception' - _order = 'main_exception_id asc' + _description = 'Exception' main_exception_id = fields.Many2one( 'exception.rule', compute='_compute_main_error', string='Main Exception', - store=True) - rule_group = fields.Selection( - [], - readonly=True, + store=True, ) - exception_ids = fields.Many2many( - 'exception.rule', - string='Exceptions') + rule_group = fields.Selection([], readonly=True) + exception_ids = fields.Many2many('exception.rule', string='Exceptions') ignore_exception = fields.Boolean('Ignore Exceptions', copy=False) @api.depends('exception_ids', 'ignore_exception') def _compute_main_error(self): - for obj in self: - if not obj.ignore_exception and obj.exception_ids: - obj.main_exception_id = obj.exception_ids[0] + for rec in self: + if not rec.ignore_exception and rec.exception_ids: + rec.main_exception_id = rec.exception_ids[0] else: - obj.main_exception_id = False + rec.main_exception_id = False @api.multi def _popup_exceptions(self): - action = self._get_popup_action() - action_data = action.read()[0] - action_data.update({ + action = self._get_popup_action().read()[0] + action.update({ 'context': { 'active_id': self.ids[0], 'active_ids': self.ids, 'active_model': self._name, } }) - return action_data + return action @api.model def _get_popup_action(self): - action = self.env.ref('base_exception.action_exception_rule_confirm') - return action + return self.env.ref('base_exception.action_exception_rule_confirm') @api.multi def _check_exception(self): @@ -191,36 +168,32 @@ class BaseException(models.AbstractModel): @api.model def _exception_rule_eval_context(self, obj_name, rec): - return {obj_name: rec, - 'self': self.env[rec._name], - 'object': rec, - 'obj': rec, - 'env': self.env, - 'cr': self.env.cr, - 'uid': self.env.uid, - 'user': self.env.user, - 'time': time, - # copy context to prevent side-effects of eval - 'context': self.env.context.copy()} + return { + 'time': time, + 'self': rec, + # obj_name, object, obj: deprecated. + # should be removed in future migrations + obj_name: rec, + 'object': rec, + 'obj': rec, + # copy context to prevent side-effects of eval + # should be deprecated too, accesible through self. + 'context': self.env.context.copy() + } @api.model def _rule_eval(self, rule, obj_name, rec): - expr = rule.code - space = self._exception_rule_eval_context(obj_name, rec) + eval_ctx = self._exception_rule_eval_context(obj_name, rec) try: - safe_eval(expr, - space, - mode='exec', - nocopy=True) # nocopy allows to return 'result' + safe_eval(rule.code, eval_ctx, mode='exec', nocopy=True) except Exception as e: - raise UserError( - _('Error when evaluating the exception.rule ' - 'rule:\n %s \n(%s)') % (rule.name, e)) - return space.get('failed', False) + raise UserError(_( + 'Error when evaluating the exception.rule: ' + '%s\n(%s)') % (rule.name, e)) + return eval_ctx.get('failed', False) @api.multi - def _detect_exceptions(self, model_exceptions, - sub_exceptions): + def _detect_exceptions(self, model_exceptions, sub_exceptions): self.ensure_one() exception_ids = [] next_state_rule = False @@ -228,8 +201,8 @@ class BaseException(models.AbstractModel): if self._rule_eval(rule, self.rule_group, self): exception_ids.append(rule.id) if rule.next_state: - if not next_state_rule or\ - rule.sequence < next_state_rule.sequence: + if not next_state_rule or \ + rule.sequence < next_state_rule.sequence: next_state_rule = rule if sub_exceptions: for obj_line in self._get_lines(): diff --git a/base_exception/readme/CONTRIBUTORS.rst b/base_exception/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..f1fe41bf8 --- /dev/null +++ b/base_exception/readme/CONTRIBUTORS.rst @@ -0,0 +1,8 @@ +* Raphaël Valyi +* Renato Lima +* Sébastien BEAU +* Guewen Baconnier +* Yannick Vaucher +* SodexisTeam +* Mourad EL HADJ MIMOUNE +* Iván Todorovich diff --git a/base_exception/readme/DESCRIPTION.rst b/base_exception/readme/DESCRIPTION.rst new file mode 100644 index 000000000..30fe35746 --- /dev/null +++ b/base_exception/readme/DESCRIPTION.rst @@ -0,0 +1,6 @@ +This module provide an abstract model to manage customizable +exceptions to be applied on different models (sale order, invoice, ...). + +It is not useful for itself. You can see an example of implementation +in the 'sale_exception' module. (sale-workflow repository) or +'purchase_exception' module (purchase-workflow repository). diff --git a/base_exception/readme/ROADMAP.rst b/base_exception/readme/ROADMAP.rst new file mode 100644 index 000000000..846343f9c --- /dev/null +++ b/base_exception/readme/ROADMAP.rst @@ -0,0 +1 @@ +Terms used in old api like `pool`, `cr`, `uid` must be removed porting this module in version 12. diff --git a/base_exception/static/description/index.html b/base_exception/static/description/index.html new file mode 100644 index 000000000..bfa0ddf39 --- /dev/null +++ b/base_exception/static/description/index.html @@ -0,0 +1,437 @@ + + + + + + +Exception Rule + + + +
+

Exception Rule

+ + +

Beta License: AGPL-3 OCA/server-tools Translate me on Weblate Try me on Runbot

+

This module provide an abstract model to manage customizable +exceptions to be applied on different models (sale order, invoice, …).

+

It is not useful for itself. You can see an example of implementation +in the ‘sale_exception’ module. (sale-workflow repository) or +‘purchase_exception’ module (purchase-workflow repository).

+

Table of contents

+ +
+

Known issues / Roadmap

+

Terms used in old api like pool, cr, uid must be removed porting this module in version 12.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
  • Sodexis
  • +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/server-tools project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/base_exception/tests/test_base_exception.py b/base_exception/tests/test_base_exception.py index c0442731d..90fe6a9bb 100644 --- a/base_exception/tests/test_base_exception.py +++ b/base_exception/tests/test_base_exception.py @@ -13,8 +13,6 @@ _logger = logging.getLogger(__name__) @common.post_install(True) class TestBaseException(common.SavepointCase): - # pylint: disable=missing-return - @classmethod def setUpClass(cls): super(TestBaseException, cls).setUpClass() @@ -25,31 +23,28 @@ class TestBaseException(common.SavepointCase): cls.exception_confirm = cls.env['exception.rule.confirm'] cls.exception_rule._fields['rule_group'].selection.append( - ('test_base', 'test base exception') - ) + ('test_base', 'Test Base Exception')) + cls.exception_rule._fields['model'].selection.append( - ('base.exception.test.purchase', - 'base.exception.test.purchase') - ) + ('base.exception.test.purchase', 'Purchase Order')) + cls.exception_rule._fields['model'].selection.append( - ('base.exception.test.purchase.line', - 'base.exception.test.purchase.line') - ) + ('base.exception.test.purchase.line', 'Purchase Order Line')) + cls.exceptionnozip = cls.env['exception.rule'].create({ 'name': "No ZIP code on destination", 'sequence': 10, 'rule_group': "test_base", 'model': "base.exception.test.purchase", - 'code': """if not test_base.partner_id.zip: - failed=True""", + 'code': "if not test_base.partner_id.zip: failed=True", }) + cls.exceptionno_minorder = cls.env['exception.rule'].create({ 'name': "Min order except", 'sequence': 10, 'rule_group': "test_base", 'model': "base.exception.test.purchase", - 'code': """if test_base.amount_total <= 200.0: - failed=True""", + 'code': "if test_base.amount_total <= 200.0: failed=True", }) cls.exceptionno_lineqty = cls.env['exception.rule'].create({ @@ -57,8 +52,8 @@ class TestBaseException(common.SavepointCase): 'sequence': 10, 'rule_group': "test_base", 'model': "base.exception.test.purchase.line", - 'code': """if test_base_line.qty <= 0: - failed=True"""}) + 'code': "if test_base_line.qty <= 0: failed=True" + }) def test_purchase_order_exception(self): partner = self.env.ref('base.res_partner_1') @@ -66,9 +61,11 @@ class TestBaseException(common.SavepointCase): potest1 = self.env['base.exception.test.purchase'].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})], + 'line_ids': [(0, 0, { + 'name': "line test", + 'amount': 120.0, + 'qty': 1.5, + })], }) potest1.button_confirm() diff --git a/base_exception/views/base_exception_view.xml b/base_exception/views/base_exception_view.xml index 384bb939e..9526db774 100644 --- a/base_exception/views/base_exception_view.xml +++ b/base_exception/views/base_exception_view.xml @@ -1,5 +1,6 @@ + exception.rule.tree exception.rule @@ -20,24 +21,45 @@
+
+ +
+
+
- - - - - - + + + + + + +
+

Help with Python expressions

+

Various fields may use Python code or Python expressions. The following variables can be used:

+
    +
  • self: Record on which the rule is evaluated.
  • +
  • time: useful Python libraries
  • +
  • To block the exception use: failed = True
  • +
+
+
+
+
diff --git a/base_exception/wizard/base_exception_confirm.py b/base_exception/wizard/base_exception_confirm.py index 4ab485b8f..ecdd63b49 100644 --- a/base_exception/wizard/base_exception_confirm.py +++ b/base_exception/wizard/base_exception_confirm.py @@ -2,19 +2,20 @@ # Copyright 2017 Akretion (http://www.akretion.com) # Mourad EL HADJ MIMOUNE # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). - from odoo import api, fields, models, _ from odoo.exceptions import ValidationError class ExceptionRuleConfirm(models.AbstractModel): - _name = 'exception.rule.confirm' + _description = 'Exception Rule Confirm Wizard' related_model_id = fields.Many2one('base.exception',) - exception_ids = fields.Many2many('exception.rule', - string='Exceptions to resolve', - readonly=True) + exception_ids = fields.Many2many( + 'exception.rule', + string='Exceptions to resolve', + readonly=True, + ) ignore = fields.Boolean('Ignore Exceptions') @api.model diff --git a/base_exception/wizard/base_exception_confirm_view.xml b/base_exception/wizard/base_exception_confirm_view.xml index a8ece8e33..f0251d302 100644 --- a/base_exception/wizard/base_exception_confirm_view.xml +++ b/base_exception/wizard/base_exception_confirm_view.xml @@ -1,5 +1,6 @@ + Exceptions Rules exception.rule.confirm @@ -34,4 +35,5 @@ new +