From edcbf067d65910c58f08e1e64f9aec2decd4d5aa Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 10 Mar 2015 19:16:07 +0100 Subject: [PATCH 1/7] [FIX] workflow.workitem: deleting a subflow should never cascade to workitems It's always dangerous because (cascade-)deleting workitems has a great chance of killing the workflow instances they belong to, putting the records in the workflow limbo permanently. (They will appear stuck as they don't have enough workitems anymore) In addition, in some rare cases a subflow activity is converted into a regular activity during an update, and nullifying the `subflow_id` column is all there is to fixing the corresponding workitems. It will simply take them out of their subflow, and back into the main flow. This is the case for the modification of the purchase.order workflow in Odoo 8 (saas-5), for the picking subflow. --- openerp/addons/base/ir/workflow/workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/workflow/workflow.py b/openerp/addons/base/ir/workflow/workflow.py index cfef52a7b88..dc1fc9afb79 100644 --- a/openerp/addons/base/ir/workflow/workflow.py +++ b/openerp/addons/base/ir/workflow/workflow.py @@ -157,7 +157,7 @@ class wkf_workitem(osv.osv): _columns = { 'act_id': fields.many2one('workflow.activity', 'Activity', required=True, ondelete="cascade", select=True), 'wkf_id': fields.related('act_id','wkf_id', type='many2one', relation='workflow', string='Workflow'), - 'subflow_id': fields.many2one('workflow.instance', 'Subflow', ondelete="cascade", select=True), + 'subflow_id': fields.many2one('workflow.instance', 'Subflow', ondelete="set null", select=True), 'inst_id': fields.many2one('workflow.instance', 'Instance', required=True, ondelete="cascade", select=True), 'state': fields.char('Status', size=64, select=True), } From 2275af4b775c548804dd784d3034cb46dc8c4e14 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Tue, 10 Mar 2015 13:36:13 +0100 Subject: [PATCH 2/7] [FIX] base: ir sequence number is now reset to the requested value when calling the write method opw: 626974 --- openerp/addons/base/ir/ir_sequence.py | 2 +- openerp/addons/base/tests/__init__.py | 2 ++ openerp/addons/base/tests/test_ir_sequence.py | 35 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 openerp/addons/base/tests/test_ir_sequence.py diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index 0f505814c0c..9e9e0696cbe 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -198,7 +198,7 @@ class ir_sequence(openerp.osv.osv.osv): if new_implementation in ('standard', None): # Implementation has NOT changed. # Only change sequence if really requested. - if row['number_next'] != n: + if values.get('number_next'): self._alter_sequence(cr, row['id'], i, n) else: # Just in case only increment changed diff --git a/openerp/addons/base/tests/__init__.py b/openerp/addons/base/tests/__init__.py index 3c6029c49ea..d1438de25f7 100644 --- a/openerp/addons/base/tests/__init__.py +++ b/openerp/addons/base/tests/__init__.py @@ -6,6 +6,7 @@ import test_ir_values import test_menu import test_search import test_views +import test_ir_sequence checks = [ test_base, @@ -16,4 +17,5 @@ checks = [ test_menu, test_search, test_views, + test_ir_sequence, ] diff --git a/openerp/addons/base/tests/test_ir_sequence.py b/openerp/addons/base/tests/test_ir_sequence.py new file mode 100644 index 00000000000..85ae21bb8cc --- /dev/null +++ b/openerp/addons/base/tests/test_ir_sequence.py @@ -0,0 +1,35 @@ +import unittest2 + +import openerp.tests.common as common + + +class Test_ir_sequence(common.TransactionCase): + + def test_00(self): + registry, cr, uid = self.registry, self.cr, self.uid + + # test if read statement return the good number_next value (from postgreSQL sequence and not ir_sequence value) + sequence = registry('ir.sequence') + # first creation of sequence (normal) + values = {'number_next': 1, + 'company_id': 1, + 'padding': 4, + 'number_increment': 1, + 'implementation': 'standard', + 'name': 'test-sequence-00'} + seq_id = sequence.create(cr, uid, values) + # Call get next 4 times + sequence.next_by_id(cr, uid, seq_id) + sequence.next_by_id(cr, uid, seq_id) + sequence.next_by_id(cr, uid, seq_id) + read_sequence = sequence.next_by_id(cr, uid, seq_id) + # Read the value of the current sequence + assert read_sequence == "0004", 'The actual sequence value must be 4. reading : %s' % read_sequence + # reset sequence to 1 by write method calling + sequence.write(cr, uid, [seq_id], {'number_next': 1}) + # Read the value of the current sequence + read_sequence = sequence.next_by_id(cr, uid, seq_id) + assert read_sequence == "0001", 'The actual sequence value must be 1. reading : %s' % read_sequence + +if __name__ == "__main__": + unittest2.main() From 4530faae8ba8ecb80ae2765129302fd6c9718442 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Fri, 13 Mar 2015 10:35:48 +0100 Subject: [PATCH 3/7] [FIX] account_payment: compute amount to pay compute the amount_to_pay with function field amount_residual on account.move.line opw:628903, 628428 --- addons/account_payment/account_move_line.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/addons/account_payment/account_move_line.py b/addons/account_payment/account_move_line.py index e8d67e6dd89..9068d8b729c 100644 --- a/addons/account_payment/account_move_line.py +++ b/addons/account_payment/account_move_line.py @@ -29,16 +29,14 @@ class account_move_line(osv.osv): def amount_to_pay(self, cr, uid, ids, name, arg=None, context=None): """ Return the amount still to pay regarding all the payemnt orders (excepting cancelled orders)""" + res = {} if not ids: - return {} - res = dict.fromkeys(ids, 0.0) - cr.execute("""SELECT ml.id, - (SELECT sum(coalesce(residual, 0)) - FROM account_invoice - WHERE move_id = ml.move_id) - FROM account_move_line ml - WHERE id IN %s""", (tuple(ids),)) - res.update(cr.fetchall()) + return res + for ml in self.browse(cr, uid, ids, context=context): + if ml.amount_currency: + res[ml.id] = ml.amount_residual_currency + else: + res[ml.id] = ml.amount_residual return res def _to_pay_search(self, cr, uid, obj, name, args, context=None): From 2606e37b18c92f02331c05620f5c0edc7b9f14ad Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Mon, 16 Mar 2015 08:55:04 +0100 Subject: [PATCH 4/7] [FIX] account_asset: currency problem with depreciation in asset management The amount used to create an account asset depreciation line must be in the currency of the asset. opw: 628663 --- addons/account_asset/account_asset.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py index 9cf4c14fff2..59a3bdc825b 100644 --- a/addons/account_asset/account_asset.py +++ b/addons/account_asset/account_asset.py @@ -172,10 +172,6 @@ class account_asset_asset(osv.osv): for x in range(len(posted_depreciation_line_ids), undone_dotation_number): i = x + 1 amount = self._compute_board_amount(cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=context) - company_currency = asset.company_id.currency_id.id - current_currency = asset.currency_id.id - # compute amount into company currency - amount = currency_obj.compute(cr, uid, current_currency, company_currency, amount, context=context) residual_amount -= amount vals = { 'amount': amount, From 373b56051101b8d4b87579a741ce552142d82410 Mon Sep 17 00:00:00 2001 From: David Monjoie Date: Mon, 16 Mar 2015 10:33:03 +0100 Subject: [PATCH 5/7] [FIX] account: added check if country has a code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible, if the user created a new country by himself, to have a country without a code, we then need to check that. Fixes opw 629891, where the customer wrote "Belgie" trying to find "Belgiƫ", didn't find it and created a new "Belgie" country without code. --- addons/account/account_pre_install.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/account_pre_install.yml b/addons/account/account_pre_install.yml index e295989e698..798c0d954a5 100644 --- a/addons/account/account_pre_install.yml +++ b/addons/account/account_pre_install.yml @@ -7,7 +7,7 @@ wiz = wizards.browse(cr, uid, ref('account.account_configuration_installer_todo')) part = self.pool.get('res.partner').browse(cr, uid, ref('base.main_partner')) # if we know the country and the wizard has not yet been executed, we do it - if (part.country_id.id) and (wiz.state=='open'): + if (part.country_id.id) and (part.country_id.code) and (wiz.state=='open'): mod = 'l10n_'+part.country_id.code.lower() ids = modules.search(cr, uid, [ ('name','=',mod) ], context=context) if ids: From e2ccc5709b1b4909eb857d77ebb2e21c9a5c7fb9 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Mon, 16 Mar 2015 09:49:41 +0100 Subject: [PATCH 6/7] [FIX] account_asset: wrong currency to compute the residual amount of an asset The result of the residual amount of an asset is : asset.purchase_value - amount - asset.salvage_value where purchase_value and asset.salvage_value are in the currency of the asset. Amount is the difference between debit and credit of an account move line expressed in the currency of the company. This is why the amount must be convert in the currency of the asset. --- addons/account_asset/account_asset.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py index 59a3bdc825b..ffa0b75dc8c 100644 --- a/addons/account_asset/account_asset.py +++ b/addons/account_asset/account_asset.py @@ -212,7 +212,10 @@ class account_asset_asset(osv.osv): l.asset_id IN %s GROUP BY l.asset_id """, (tuple(ids),)) res=dict(cr.fetchall()) for asset in self.browse(cr, uid, ids, context): - res[asset.id] = asset.purchase_value - res.get(asset.id, 0.0) - asset.salvage_value + company_currency = asset.company_id.currency_id.id + current_currency = asset.currency_id.id + amount = self.pool['res.currency'].compute(cr, uid, company_currency, current_currency, res.get(asset.id, 0.0), context=context) + res[asset.id] = asset.purchase_value - amount - asset.salvage_value for id in ids: res.setdefault(id, 0.0) return res From e1daaff8e0711f4fc39a8360ace01f8529a4754e Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Tue, 10 Mar 2015 11:13:45 +0100 Subject: [PATCH 7/7] [FIX] kanban: propagate context of many2many field Propagate the context in kanban view when displaying a many2many field. fixes #5623, closes #5681 opw-629698 --- addons/web_kanban/static/src/js/kanban.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 23fa4923277..bdc0d539d25 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -28,6 +28,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.group_by_field = {}; this.grouped_by_m2o = false; this.many2manys = []; + this.m2m_context = {}; this.state = { groups : {}, records : {} @@ -115,6 +116,10 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.aggregates[node.attrs.name] = node.attrs[this.group_operators[j]]; break; } + }; + var ftype = node.attrs.widget || this.fields_view.fields[node.attrs.name].type; + if(ftype == "many2many" && "context" in node.attrs) { + this.m2m_context[node.attrs.name] = node.attrs.context; } }, transform_qweb_template: function(node) { @@ -490,7 +495,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ var field = record.record[name]; var $el = record.$('.oe_form_field.oe_tags[name=' + name + ']').empty(); if (!relations[field.relation]) { - relations[field.relation] = { ids: [], elements: {}}; + relations[field.relation] = { ids: [], elements: {}, context: self.m2m_context[name]}; } var rel = relations[field.relation]; field.raw_value.forEach(function(id) { @@ -504,7 +509,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ }); }); _.each(relations, function(rel, rel_name) { - var dataset = new instance.web.DataSetSearch(self, rel_name, self.dataset.get_context()); + var dataset = new instance.web.DataSetSearch(self, rel_name, self.dataset.get_context(rel.context)); dataset.name_get(_.uniq(rel.ids)).done(function(result) { result.forEach(function(nameget) { $(rel.elements[nameget[0]]).append('' + _.str.escapeHTML(nameget[1]) + '');