[MIG] base_exception: Migration to 11.0

pull/2463/head
Mourad Elhadj Mimoune 2017-10-13 10:00:13 +02:00 committed by matiasperalta1
parent 401b114771
commit 877487608e
13 changed files with 318 additions and 125 deletions

View File

@ -1,19 +1,24 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
==============
Base Exception
==============
This module provide an abstract model to manage customizable exceptions to be applied on different models (sale order, invoice, ...). It is not usefull for itself. You can see an example of implementation in the 'sale_exception' module. (sale-workflow repository).
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).
Usage
=====
.. 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/10.0
:target: https://runbot.odoo-community.org/runbot/149/11.0
Bug Tracker
@ -22,11 +27,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/server-tools/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
<https://github.com/OCA/
server-tools/issues/new?body=module:%20
base_exception%0Aversion:%20
10.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
help us smash it by providing detailed and welcomed feedback.
Images
------

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# © 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# Copyright 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import wizard, models
from .tests import test_tmp_model

View File

@ -1,13 +1,17 @@
# -*- coding: utf-8 -*-
# © 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# Copyright 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# Copyright 2017 Akretion (http://www.akretion.com)
# Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{'name': 'Exception Rule',
'version': '10.0.1.0.0',
{
'name': 'Exception Rule',
'version': '11.0.1.0.0',
'category': 'Generic Modules',
'summary': """This module provide an abstract model to manage customizable
'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)",
'author':
"Akretion, Sodexis, Camptocamp, Odoo Community Association (OCA)",
'website': 'http://www.akretion.com',
'depends': ['base_setup'],
'license': 'AGPL-3',
@ -18,4 +22,4 @@
'views/base_exception_view.xml',
],
'installable': True,
}
}

View File

@ -1,5 +1,2 @@
# -*- coding: utf-8 -*-
# © 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import base_exception

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# © 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# Copyright 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# Copyright 2017 Akretion (http://www.akretion.com)
# Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import time
from functools import wraps
@ -42,6 +43,12 @@ class ExceptionRule(models.Model):
selection=[],
string='Apply on', required=True)
active = fields.Boolean('Active')
next_state = fields.Char(
'Next state',
help="If we detect exception we set de 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 "
@ -63,6 +70,26 @@ class ExceptionRule(models.Model):
# - context: current context
""")
@api.constrains('next_state')
def _check_next_state_value(self):
""" Ensure that the next_state value is in the state values of
destination model """
for rule in self:
if rule.next_state:
select_vals = self.env[
rule.model].fields_get()[
'state']['selection']
if rule.next_state\
not in [s[0] for s in select_vals]:
raise ValidationError(
_('The value "%s" you chose 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'
@ -182,7 +209,7 @@ class BaseException(models.AbstractModel):
space,
mode='exec',
nocopy=True) # nocopy allows to return 'result'
except Exception, e:
except Exception as e:
raise UserError(
_('Error when evaluating the exception.rule '
'rule:\n %s \n(%s)') % (rule.name, e))
@ -193,9 +220,16 @@ class BaseException(models.AbstractModel):
sub_exceptions):
self.ensure_one()
exception_ids = []
next_state_rule = False
for rule in model_exceptions:
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:
next_state_rule = rule
if sub_exceptions:
for obj_line in self._get_lines():
for rule in sub_exceptions:
@ -207,6 +241,9 @@ class BaseException(models.AbstractModel):
group_line = self.rule_group + '_line'
if self._rule_eval(rule, group_line, obj_line):
exception_ids.append(rule.id)
# set object to next state
if next_state_rule:
self.state = next_state_rule.next_state
return exception_ids
@implemented_by_base_exception

View File

@ -1,5 +1,7 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_exception_rule","base.exception","model_exception_rule","base.group_user",1,0,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
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_exception_rule,base.exception,model_exception_rule,base.group_user,1,0,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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_exception_rule base.exception model_exception_rule base.group_user 1 0 0 0
3 access_exception_rule_manager base.exception model_exception_rule base_exception.group_exception_rule_manager 1 1 1 1
4 access_base_exception base.exception model_base_exception base.group_user 1 0 0 0
5 access_base_exception_manager base.exception model_base_exception base_exception.group_exception_rule_manager 1 1 1 1
6 access_base_exception_test_purchase access_base_exception_test_purchase model_base_exception_test_purchase base.group_system 1 1 1 1
7 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

View File

@ -0,0 +1,3 @@
from . import test_tmp_model
from . import test_base_exception

View File

@ -0,0 +1,83 @@
# Copyright 2016 Akretion Mourad EL HADJ MIMOUNE
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo.tests import common
import logging
_logger = logging.getLogger(__name__)
# @common.at_install(False)
# @common.post_install(True)
class TestBaseException(common.TransactionCase):
def setUp(self):
super(TestBaseException, self).setUp()
self.base_exception = self.env['base.exception']
self.exception_rule = self.env['exception.rule']
self.exception_confirm = self.env['exception.rule.confirm']
self.exception_rule._fields['rule_group'].selection.append(
('test_base', 'test base exception')
)
self.exception_rule._fields['model'].selection.append(
('base.exception.test.purchase',
'base.exception.test.purchase')
)
self.exception_rule._fields['model'].selection.append(
('base.exception.test.purchase.line',
'base.exception.test.purchase.line')
)
self.exceptionnozip = self.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""",
})
self.exceptionno_minorder = self.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""",
})
self.exceptionno_lineqty = self.env['exception.rule'].create({
'name': "Qty > 0",
'sequence': 10,
'rule_group': "test_base",
'model': "base.exception.test.purchase.line",
'code': """if test_base_line.qty <= 0:
failed=True"""})
def test_sale_order_exception(self):
partner = self.env.ref('base.res_partner_1')
partner.zip = False
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})],
})
potest1.button_confirm()
# Set ignore_exception flag (Done after ignore is selected at wizard)
potest1.ignore_exception = True
potest1.button_confirm()
self.assertTrue(potest1.state == 'purchase')
# Simulation the opening of the wizard exception_confirm and
# set ignore_exception to True
except_confirm = self.exception_confirm.with_context(
{
'active_id': potest1.id,
'active_ids': [potest1.id],
'active_model': potest1._name
}).new({'ignore': True})
except_confirm.action_confirm()
self.assertTrue(potest1.ignore_exception)

View File

@ -0,0 +1,71 @@
# Copyright 2017 Akretion (http://www.akretion.com)
# Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
from odoo import fields, models, api
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.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.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_draft(self):
self.write({'state': 'draft'})
return {}
@api.multi
def button_confirm(self):
self.write({'state': 'purchase'})
return True
@api.multi
def button_cancel(self):
self.write({'state': 'cancel'})
def test_base_get_lines(self):
self.ensure_one()
return self.line_ids
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()

View File

@ -1,6 +1,5 @@
<?xml version="1.0" ?>
<odoo>
<record id="view_exception_rule_tree" model="ir.ui.view">
<field name="name">exception.rule.tree</field>
<field name="model">exception.rule</field>
@ -31,6 +30,7 @@
<group colspan="4" col="2" groups="base.group_system">
<field name="rule_group"/>
<field name="model"/>
<field name="next_state"/>
<field name="code"/>
</group>
</form>
@ -47,5 +47,4 @@
</record>
<menuitem action="action_exception_rule_tree" id="menu_action_exception" parent="base.menu_custom" sequence="90" />
</odoo>

View File

@ -1,5 +1,2 @@
# -*- coding: utf-8 -*-
# © 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import base_exception_confirm

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# © 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# Copyright 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# Copyright 2017 Akretion (http://www.akretion.com)
# Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models

View File

@ -1,12 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_exception_rule_confirm" model="ir.ui.view">
<field name="name">Exceptions Rules</field>
<field name="model">exception.rule.confirm</field>
<field name="arch" type="xml">
<form string="Blocked in draft due to exceptions" version="7.0">
<form string="Outstanding exceptions to manager" version="7.0">
<group>
<field name="exception_ids" nolabel="1" colspan="4">
<tree string="Exceptions Rules">
@ -15,18 +13,20 @@
</tree>
</field>
<newline/>
</group>
<group>
<field name="ignore" groups='base_exception.group_exception_rule_manager'/>
</group>
<footer>
<button name="action_confirm" string="_Close"
colspan="1" type="object" icon="gtk-ok" />
colspan="1" type="object" class="btn-primary"/>
</footer>
</form>
</field>
</record>
<record id="action_exception_rule_confirm" model="ir.actions.act_window">
<field name="name">Blocked in draft due to exceptions</field>
<field name="name">Outstanding exceptions to manage</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">exception.rule.confirm</field>
<field name="view_type">form</field>
@ -34,6 +34,4 @@
<field name="view_id" ref="view_exception_rule_confirm"/>
<field name="target">new</field>
</record>
</data>
</odoo>