Browse Source

[MIG] base_exception: Migration to 11.0

pull/1025/head
Mourad Elhadj Mimoune 7 years ago
committed by Mourad
parent
commit
2102134b1b
  1. 7
      .travis.yml
  2. 1
      base_exception/__init__.py
  3. 39
      base_exception/__manifest__.py
  4. 40
      base_exception/models/base_exception.py
  5. 12
      base_exception/security/ir.model.access.csv
  6. 4
      base_exception/tests/__init__.py
  7. 84
      base_exception/tests/test_base_exception.py
  8. 72
      base_exception/tests/test_tmp_model.py
  9. 83
      base_exception/views/base_exception_view.xml
  10. 2
      base_exception/wizard/base_exception_confirm.py
  11. 64
      base_exception/wizard/base_exception_confirm_view.xml

7
.travis.yml

@ -12,14 +12,10 @@ addons:
packages:
- expect-dev # provides unbuffer utility
- python-lxml # because pip installation is slow
- unixodbc-dev
- python-mysqldb
env:
global:
- VERSION="11.0" TESTS="0" LINT_CHECK="0" TRANSIFEX="0"
- TRANSIFEX_USER='transbot@odoo-community.org'
- secure: Z06mZCN+Hm3myqHSOZpOOk1pd4oq1epAWZv6m9OX2bTNHbhyOVOGK6JWWsnDm/3DUCN1ZeLtSGOl9bvQfMa8ahQHA80MkLL16YlTvQV59Lh+L2gAYmxX+ogJCJgeQSVAXlGLscgkADCu/HzDlmatrDeROMtULn5i23j2qcyUNyM=
matrix:
- LINT_CHECK="1"
@ -30,7 +26,6 @@ env:
# - TESTS="1" ODOO_REPO="OCA/OCB" INCLUDE="database_cleanup"
# - TESTS="1" ODOO_REPO="odoo/odoo" INCLUDE="database_cleanup"
before_install:
- "export PATH=$PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64/bin:$PATH"
- "if [ $(phantomjs --version) != '2.1.1' ]; then rm -rf $PWD/travis_phantomjs; mkdir -p $PWD/travis_phantomjs; fi"
@ -47,4 +42,4 @@ script:
- travis_run_tests
after_success:
- travis_after_tests_success
- travis_after_tests_success

1
base_exception/__init__.py

@ -3,3 +3,4 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import wizard, models
from .tests import test_tmp_model

39
base_exception/__manifest__.py

@ -1,21 +1,26 @@
# -*- coding: utf-8 -*-
# © 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# © 2017 Akretion (http://www.akretion.com)
# Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{'name': 'Exception Rule',
'version': '10.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'],
'license': 'AGPL-3',
'data': [
'security/base_exception_security.xml',
'security/ir.model.access.csv',
'wizard/base_exception_confirm_view.xml',
'views/base_exception_view.xml',
],
'installable': True,
}
{
'name': 'Exception Rule',
'version': '11.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'],
'license': 'AGPL-3',
'data': [
'security/base_exception_security.xml',
'security/ir.model.access.csv',
'wizard/base_exception_confirm_view.xml',
'views/base_exception_view.xml',
],
'installable': True,
}

40
base_exception/models/base_exception.py

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
# © 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
# © 2017 Akretion (http://www.akretion.com)
# Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import time
@ -42,6 +44,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 +71,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 +210,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 +221,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 +242,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

12
base_exception/security/ir.model.access.csv

@ -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

4
base_exception/tests/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import test_tmp_model
from . import test_base_exception

84
base_exception/tests/test_base_exception.py

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
# © 2016 Akretion Mourad EL HADJ MIMOUNE
# License AGPL-3.0 or later (http://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)

72
base_exception/tests/test_tmp_model.py

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# © 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()

83
base_exception/views/base_exception_view.xml

@ -1,51 +1,50 @@
<?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>
<field name="arch" type="xml">
<tree string="Exception Rule">
<field name="active"/>
<field name="name"/>
<field name="description"/>
<field name="model"/>
<field name="sequence"/>
</tree>
</field>
</record>
<record id="view_exception_rule_tree" model="ir.ui.view">
<field name="name">exception.rule.tree</field>
<field name="model">exception.rule</field>
<field name="arch" type="xml">
<tree string="Exception Rule">
<field name="active"/>
<record id="view_exception_rule_form" model="ir.ui.view">
<field name="name">exception.rule.form</field>
<field name="model">exception.rule</field>
<field name="arch" type="xml">
<form string="Exception Rule Setup" name="exception_rule">
<group colspan="4" col="2">
<field name="name"/>
<field name="description"/>
<field name="model"/>
</group>
<group colspan="4" groups="base_exception.group_exception_rule_manager">
<field name="active"/>
<field name="sequence"/>
</tree>
</field>
</record>
<record id="view_exception_rule_form" model="ir.ui.view">
<field name="name">exception.rule.form</field>
<field name="model">exception.rule</field>
<field name="arch" type="xml">
<form string="Exception Rule Setup" name="exception_rule">
<group colspan="4" col="2">
<field name="name"/>
<field name="description"/>
</group>
<group colspan="4" groups="base_exception.group_exception_rule_manager">
<field name="active"/>
<field name="sequence"/>
</group>
<group colspan="4" col="2" groups="base.group_system">
<field name="rule_group"/>
<field name="model"/>
<field name="code"/>
</group>
</form>
</field>
</record>
<record id="action_exception_rule_tree" model="ir.actions.act_window">
<field name="name">Exception Rules</field>
<field name="res_model">exception.rule</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_exception_rule_tree"/>
<field name="context">{'active_test': False}</field>
</record>
</group>
<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>
</field>
</record>
<menuitem action="action_exception_rule_tree" id="menu_action_exception" parent="base.menu_custom" sequence="90" />
<record id="action_exception_rule_tree" model="ir.actions.act_window">
<field name="name">Exception Rules</field>
<field name="res_model">exception.rule</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_exception_rule_tree"/>
<field name="context">{'active_test': False}</field>
</record>
<menuitem action="action_exception_rule_tree" id="menu_action_exception" parent="base.menu_custom" sequence="90" />
</odoo>

2
base_exception/wizard/base_exception_confirm.py

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

64
base_exception/wizard/base_exception_confirm_view.xml

@ -1,39 +1,35 @@
<?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">
<group>
<field name="exception_ids" nolabel="1" colspan="4">
<tree string="Exceptions Rules">
<field name="name"/>
<field name="description"/>
</tree>
</field>
<newline/>
<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" />
</footer>
</form>
</field>
</record>
<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">
<group>
<field name="exception_ids" nolabel="1" colspan="4">
<tree string="Exceptions Rules">
<field name="name"/>
<field name="description"/>
</tree>
</field>
<newline/>
<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" />
</footer>
</form>
</field>
<record id="action_exception_rule_confirm" model="ir.actions.act_window">
<field name="name">Blocked in draft due to exceptions</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">exception.rule.confirm</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_exception_rule_confirm"/>
<field name="target">new</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="type">ir.actions.act_window</field>
<field name="res_model">exception.rule.confirm</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_exception_rule_confirm"/>
<field name="target">new</field>
</record>
</data>
</odoo>
Loading…
Cancel
Save