From 4c6f0b2afd412d3c7057d0f377487cb794ebec4e Mon Sep 17 00:00:00 2001 From: Mourad Date: Fri, 24 Nov 2017 10:17:01 +0100 Subject: [PATCH] [FIX] temp model test access rule & fix OCA remarks --- base_exception/__manifest__.py | 1 + base_exception/models/base_exception.py | 69 ++++++---- base_exception/security/ir.model.access.csv | 2 - .../security/tmp_test_model_access_rule.xml | 8 ++ base_exception/tests/test_tmp_model.py | 120 +++++++++--------- .../wizard/base_exception_confirm.py | 13 +- .../wizard/base_exception_confirm_view.xml | 2 +- 7 files changed, 128 insertions(+), 87 deletions(-) create mode 100644 base_exception/security/tmp_test_model_access_rule.xml diff --git a/base_exception/__manifest__.py b/base_exception/__manifest__.py index 35e2c0be2..a7539eef7 100644 --- a/base_exception/__manifest__.py +++ b/base_exception/__manifest__.py @@ -18,6 +18,7 @@ 'data': [ 'security/base_exception_security.xml', 'security/ir.model.access.csv', + 'security/tmp_test_model_access_rule.xml', 'wizard/base_exception_confirm_view.xml', 'views/base_exception_view.xml', ], diff --git a/base_exception/models/base_exception.py b/base_exception/models/base_exception.py index 0eebb72cf..c62fba6c8 100644 --- a/base_exception/models/base_exception.py +++ b/base_exception/models/base_exception.py @@ -5,11 +5,15 @@ import time from functools import wraps +import os +from odoo import api, fields, models, tools, _ +import logging -from odoo import api, models, fields, _ 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'.""" @@ -45,15 +49,14 @@ class ExceptionRule(models.Model): active = fields.Boolean('Active') next_state = fields.Char( 'Next state', - help="If we detect exception we set de state of object (ex purchase) " + 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") code = fields.Text( 'Python Code', help="Python code executed to check if the exception apply or " - "not. The code must apply block = True to apply the " - "exception.", + "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 : @@ -63,7 +66,7 @@ class ExceptionRule(models.Model): # 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 -# - pool: ORM model pool (i.e. self.pool) +# - env: Odoo Environment (i.e. self.env) # - time: Python time module # - cr: database cursor # - uid: current user id @@ -79,10 +82,10 @@ class ExceptionRule(models.Model): select_vals = self.env[ rule.model].fields_get()[ 'state']['selection'] - if rule.next_state\ - not in [s[0] for s in select_vals]: + 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 chose for the "next state" ' + _('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, @@ -121,14 +124,14 @@ class BaseException(models.AbstractModel): @api.multi def _popup_exceptions(self): action = self._get_popup_action() - action = action.read()[0] - action.update({ + action_data = action.read()[0] + action_data.update({ 'context': { 'active_id': self.ids[0], 'active_ids': self.ids } }) - return action + return action_data @api.model def _get_popup_action(self): @@ -187,18 +190,17 @@ class BaseException(models.AbstractModel): @api.model def _exception_rule_eval_context(self, obj_name, rec): - user = self.env['res.users'].browse(self._uid) return {obj_name: rec, - 'self': self.pool.get(rec._name), + 'self': self.env[rec._name], 'object': rec, 'obj': rec, - 'pool': self.pool, - 'cr': self._cr, - 'uid': self._uid, - 'user': user, + 'env': self.env, + 'cr': self.env.cr, + 'uid': self.env.user.id, + 'user': self.env.user, 'time': time, # copy context to prevent side-effects of eval - 'context': self._context.copy()} + 'context': self.env.context.copy()} @api.model def _rule_eval(self, rule, obj_name, rec): @@ -225,10 +227,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: - next_state_rule = rule - elif next_state_rule and\ - 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(): @@ -252,3 +252,28 @@ class BaseException(models.AbstractModel): def _default_get_lines(self): return [] + + @api.model + def _import_acl_for_tmp_test_model(self): + # import the access rule of temp test model only if testing + testing = tools.config.get('test_enable')\ + or os.environ.get('ODOO_TEST_ENABLE') + if testing: + header = ['id', 'name', 'model_id:id', 'group_id:id', + 'perm_read', 'perm_write', + 'perm_create', 'perm_unlink'] + IrModelAccess = self.env['ir.model.access'] + acl_data = [ + ['access_base_exception_test_purchase', + 'access_base_exception_test_purchase', + 'base_exception.model_base_exception_test_purchase', + 'base.group_system', '1', '1', '1', '1'], + ['access_base_exception_test_purchase_line', + 'access_base_exception_test_purchase_line', + 'base_exception.model_base_exception_test_purchase_line', + 'base.group_system', '1', '1', '1', '1'] + ] + + result = IrModelAccess.load(header, acl_data) + if result['messages']: + _logger.warning(result['messages']) diff --git a/base_exception/security/ir.model.access.csv b/base_exception/security/ir.model.access.csv index ad0cb33f9..38331a4f4 100644 --- a/base_exception/security/ir.model.access.csv +++ b/base_exception/security/ir.model.access.csv @@ -3,5 +3,3 @@ access_exception_rule,base.exception,model_exception_rule,base.group_user,1,0,0, access_exception_rule_manager,base.exception,model_exception_rule,base_exception.group_exception_rule_manager,1,1,1,1 access_base_exception,base.exception,model_base_exception,base.group_user,1,0,0,0 access_base_exception_manager,base.exception,model_base_exception,base_exception.group_exception_rule_manager,1,1,1,1 -access_base_exception_test_purchase,access_base_exception_test_purchase,model_base_exception_test_purchase,base.group_system,1,1,1,1 -access_base_exception_test_model_line,access_base_exception_test_model_line,model_base_exception_test_model_line,base.group_system,1,1,1,1 \ No newline at end of file diff --git a/base_exception/security/tmp_test_model_access_rule.xml b/base_exception/security/tmp_test_model_access_rule.xml new file mode 100644 index 000000000..d104ea432 --- /dev/null +++ b/base_exception/security/tmp_test_model_access_rule.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/base_exception/tests/test_tmp_model.py b/base_exception/tests/test_tmp_model.py index a07367878..8612b6d05 100644 --- a/base_exception/tests/test_tmp_model.py +++ b/base_exception/tests/test_tmp_model.py @@ -1,71 +1,77 @@ # Copyright 2017 Akretion (http://www.akretion.com) # Mourad EL HADJ MIMOUNE +import os +from odoo import api, fields, models, tools +import logging -from odoo import fields, models, api +_logger = logging.getLogger(__name__) +testing = tools.config.get('test_enable') or os.environ.get('ODOO_TEST_ENABLE') +if testing: + class PurchaseTest(models.Model): + _inherit = 'base.exception' + _name = "base.exception.test.purchase" + _description = "Base Ecxeption Test Model" -class PurchaseTest(models.Model): - _inherit = 'base.exception' - _name = "base.exception.test.purchase" - _description = "Base Ecxeption Test Model" + rule_group = fields.Selection( + selection_add=[('test_base', 'test')], + default='test_base', + ) + name = fields.Char(required=True) + user_id = fields.Many2one('res.users', string='Responsible') + state = fields.Selection( + [('draft', 'New'), ('cancel', 'Cancelled'), + ('purchase', 'Purchase'), + ('to approve', 'To approve'), ('done', 'Done')], + string="Status", readonly=True, default='draft') + active = fields.Boolean(default=True) + partner_id = fields.Many2one('res.partner', string='Partner') + line_ids = fields.One2many( + 'base.exception.test.purchase.line', 'lead_id') + amount_total = fields.Float( + compute='_compute_amount_total', store=True) - rule_group = fields.Selection( - selection_add=[('test_base', 'test')], - default='test_base', - ) - name = fields.Char(required=True) - user_id = fields.Many2one('res.users', string='Responsible') - state = fields.Selection( - [('draft', 'New'), ('cancel', 'Cancelled'), - ('purchase', 'Purchase'), - ('to approve', 'To approve'), ('done', 'Done')], - string="Status", readonly=True, default='draft') - active = fields.Boolean(default=True) - partner_id = fields.Many2one('res.partner', string='Partner') - line_ids = fields.One2many('base.exception.test.model.line', 'lead_id') - amount_total = fields.Float(compute='_compute_amount_total', store=True) + @api.depends('line_ids') + def _compute_amount_total(self): + for record in self: + for line in record.line_ids: + record.amount_total += line.amount * line.qty - @api.depends('line_ids') - def _compute_amount_total(self): - for record in self: - for line in record.line_ids: - record.amount_total += line.amount * line.qty + @api.constrains('ignore_exception', 'line_ids', 'state') + def test_purchase_check_exception(self): + orders = self.filtered(lambda s: s.state == 'purchase') + if orders: + orders._check_exception() - @api.constrains('ignore_exception', 'line_ids', 'state') - def test_purchase_check_exception(self): - orders = self.filtered(lambda s: s.state == 'purchase') - if orders: - orders._check_exception() + @api.multi + def button_approve(self, force=False): + self.write({'state': 'to approve'}) + return {} - @api.multi - def button_approve(self, force=False): - self.write({'state': 'to approve'}) - return {} + @api.multi + def button_draft(self): + self.write({'state': 'draft'}) + return {} - @api.multi - def button_draft(self): - self.write({'state': 'draft'}) - return {} + @api.multi + def button_confirm(self): + self.write({'state': 'purchase'}) + return True - @api.multi - def button_confirm(self): - self.write({'state': 'purchase'}) - return True + @api.multi + def button_cancel(self): + self.write({'state': 'cancel'}) - @api.multi - def button_cancel(self): - self.write({'state': 'cancel'}) + def test_base_get_lines(self): + self.ensure_one() + return self.line_ids - def test_base_get_lines(self): - self.ensure_one() - return self.line_ids + class LineTest(models.Model): + _name = "base.exception.test.purchase.line" + _description = "Base Ecxeption Test Model Line" - -class LineTest(models.Model): - _name = "base.exception.test.model.line" - _description = "Base Ecxeption Test Model Line" - - name = fields.Char() - lead_id = fields.Many2one('base.exception.test.model', ondelete='cascade') - qty = fields.Float() - amount = fields.Float() + name = fields.Char() + lead_id = fields.Many2one('base.exception.test.purchase', + ondelete='cascade') + qty = fields.Float() + amount = fields.Float() diff --git a/base_exception/wizard/base_exception_confirm.py b/base_exception/wizard/base_exception_confirm.py index 9cb207f62..4ab485b8f 100644 --- a/base_exception/wizard/base_exception_confirm.py +++ b/base_exception/wizard/base_exception_confirm.py @@ -3,7 +3,8 @@ # 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 import api, fields, models, _ +from odoo.exceptions import ValidationError class ExceptionRuleConfirm(models.AbstractModel): @@ -19,13 +20,15 @@ class ExceptionRuleConfirm(models.AbstractModel): @api.model def default_get(self, field_list): res = super(ExceptionRuleConfirm, self).default_get(field_list) - current_model = self._context.get('active_model') + current_model = self.env.context.get('active_model') model_except_obj = self.env[current_model] - active_ids = self._context.get('active_ids') - assert len(active_ids) == 1, "Only 1 ID accepted, got %r" % active_ids + active_ids = self.env.context.get('active_ids') + if len(active_ids) > 1: + raise ValidationError( + _('Only 1 ID accepted, got %r.') % active_ids) active_id = active_ids[0] related_model_except = model_except_obj.browse(active_id) - exception_ids = [e.id for e in related_model_except.exception_ids] + exception_ids = related_model_except.exception_ids.ids res.update({'exception_ids': [(6, 0, exception_ids)]}) res.update({'related_model_id': active_id}) return res diff --git a/base_exception/wizard/base_exception_confirm_view.xml b/base_exception/wizard/base_exception_confirm_view.xml index e100c7ac6..a8ece8e33 100644 --- a/base_exception/wizard/base_exception_confirm_view.xml +++ b/base_exception/wizard/base_exception_confirm_view.xml @@ -33,5 +33,5 @@ form new - +