diff --git a/onchange_helper/README.rst b/onchange_helper/README.rst index 48cca771e..c30d33249 100644 --- a/onchange_helper/README.rst +++ b/onchange_helper/README.rst @@ -18,12 +18,23 @@ To use this module, you need to: Example if you want to create a sale order and you want to get the values relative to partner_id field (as if you fill the field from UI) - `vals = {'partner_id: 1'}` + `vals = {'partner_id': 1}` `vals = self.env['sale.order'].play_onchanges(vals, ['partner_id'])` Then, `vals` will be updated with partner_invoice_id, partner_shipping_id, pricelist_id, etc... +You can also use it on existing record for example: + + `vals = {'partner_shipping_id': 1}` + + `vals = sale.play_onchanges(vals, ['partner_shipping_id'])` + +Then the onchange will be played with the vals passed and the existing vals of the sale. `vals` will be updated with partner_invoice_id, pricelist_id, etc.. + + +Behind the scene, `play_onchanges` will execute **all the methods** registered for the list of changed fields, so you do not have to call manually each onchange. To avoid performance issue when the method is called on a record, the record will be transformed into a memory record before calling the registered methods to avoid to trigger SQL updates command when values are assigned to the record by the onchange + Bug Tracker =========== diff --git a/onchange_helper/models/__init__.py b/onchange_helper/models/__init__.py index 0f0f860f3..cde864bae 100644 --- a/onchange_helper/models/__init__.py +++ b/onchange_helper/models/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -from . import ir_rule +from . import models diff --git a/onchange_helper/models/ir_rule.py b/onchange_helper/models/ir_rule.py deleted file mode 100644 index b4f67af16..000000000 --- a/onchange_helper/models/ir_rule.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2016-2017 Akretion (http://www.akretion.com) -# © 2016-2017 Camptocamp (http://www.camptocamp.com/) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from odoo import api, models - - -def get_new_values(model, record, on_change_result): - vals = on_change_result.get('value', {}) - new_values = {} - for fieldname, value in vals.iteritems(): - if fieldname not in record: - column = model._fields[fieldname] - if value and column.type == 'many2one': - value = value[0] # many2one are tuple (id, name) - new_values[fieldname] = value - return new_values - - -@api.model -def play_onchanges(self, values, onchange_fields): - onchange_specs = self._onchange_spec() - # we need all fields in the dict even the empty ones - # otherwise 'onchange()' will not apply changes to them - all_values = values.copy() - for field in self._fields: - if field not in all_values: - all_values[field] = False - - # we work on a temporary record - new_record = self.new(all_values) - - new_values = {} - for field in onchange_fields: - onchange_values = new_record.onchange(all_values, - field, onchange_specs) - new_values.update(get_new_values(self, values, onchange_values)) - all_values.update(new_values) - - res = {f: v for f, v in all_values.iteritems() - if f in values or f in new_values} - return res - - -class IrRule(models.Model): - _inherit = 'ir.rule' - - def _setup_complete(self): - if not hasattr(models.BaseModel, 'play_onchanges'): - setattr(models.BaseModel, 'play_onchanges', play_onchanges) - return super(IrRule, self)._setup_complete() diff --git a/onchange_helper/models/models.py b/onchange_helper/models/models.py new file mode 100644 index 000000000..10ccee084 --- /dev/null +++ b/onchange_helper/models/models.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# © 2016-2017 Akretion (http://www.akretion.com) +# © 2016-2017 Camptocamp (http://www.camptocamp.com/) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, models + + +class Base(models.AbstractModel): + _inherit = 'base' + + @api.model + def _get_new_values(self, record, on_change_result): + vals = on_change_result.get('value', {}) + new_values = {} + for fieldname, value in vals.iteritems(): + if fieldname not in record: + column = self._fields[fieldname] + if value and column.type == 'many2one': + value = value[0] # many2one are tuple (id, name) + new_values[fieldname] = value + return new_values + + def play_onchanges(self, values, onchange_fields): + onchange_specs = self._onchange_spec() + # we need all fields in the dict even the empty ones + # otherwise 'onchange()' will not apply changes to them + all_values = values.copy() + + # If self is a record (play onchange on existing record) + # we take the value of the field + # If self is an empty record we will have an empty value + if self: + self.ensure_one() + record_values = self._convert_to_write(self.read()[0]) + else: + record_values = {} + for field in self._fields: + if field not in all_values: + all_values[field] = record_values.get(field, False) + + new_values = {} + for field in onchange_fields: + onchange_values = self.onchange(all_values, field, onchange_specs) + new_values.update(self._get_new_values(values, onchange_values)) + all_values.update(new_values) + + return { + f: v for f, v in all_values.iteritems() + if not self._fields[f].compute + and (f in values or f in new_values)} diff --git a/onchange_helper/tests/__init__.py b/onchange_helper/tests/__init__.py new file mode 100644 index 000000000..27ca25d37 --- /dev/null +++ b/onchange_helper/tests/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Akretion (http://www.akretion.com). +# @author Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_onchange diff --git a/onchange_helper/tests/test_onchange.py b/onchange_helper/tests/test_onchange.py new file mode 100644 index 000000000..22e155294 --- /dev/null +++ b/onchange_helper/tests/test_onchange.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Akretion (http://www.akretion.com). +# @author Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import openerp.tests.common as common + + +class TestOnchange(common.TransactionCase): + + def test_playing_onchange_on_model(self): + result = self.env['res.partner'].play_onchanges({ + 'company_type': 'company', + }, ['company_type']) + self.assertEqual(result['is_company'], True) + + def test_playing_onchange_on_record(self): + company = self.env.ref('base.main_company') + result = company.play_onchanges({ + 'email': 'contact@akretion.com'}, + ['email']) + self.assertEqual( + result['rml_footer'], + u'Phone: +1 555 123 8069 | Email: contact@akretion.com | ' + u'Website: http://www.example.com') + self.assertEqual(company.email, u'info@yourcompany.example.com')