From f7dfcd5d9816a2841c3ab3bb71feb3ab71520ae1 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 22 Jul 2014 16:38:52 +0200 Subject: [PATCH 01/29] [FIX] delivery: use unit of measure and not unit of stock to compute price of delivery The computation expects uom and it was wrongly passing uos qunatities. --- addons/delivery/delivery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/delivery/delivery.py b/addons/delivery/delivery.py index c6deb3147a3..62d513c8bff 100644 --- a/addons/delivery/delivery.py +++ b/addons/delivery/delivery.py @@ -196,7 +196,7 @@ class delivery_grid(osv.osv): for line in order.order_line: if not line.product_id: continue - q = product_uom_obj._compute_qty(cr, uid, line.product_uom.id, line.product_uos_qty, line.product_id.uom_id.id) + q = product_uom_obj._compute_qty(cr, uid, line.product_uom.id, line.product_uom_qty, line.product_id.uom_id.id) total += line.price_subtotal or 0.0 weight += (line.product_id.weight or 0.0) * q volume += (line.product_id.volume or 0.0) * q From 9a20018166d0633c6b3cee2f13ec5c65c215df60 Mon Sep 17 00:00:00 2001 From: Hardik Ansodariya Date: Wed, 23 Jul 2014 10:03:40 +0200 Subject: [PATCH 02/29] [FIX] stock: allow same serial number for different products Bug lp:1222289, opw 597639 --- addons/stock/stock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 3b1e70646f1..c14819f9f5f 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1487,7 +1487,7 @@ class stock_production_lot(osv.osv): 'product_id': lambda x, y, z, c: c.get('product_id', False), } _sql_constraints = [ - ('name_ref_uniq', 'unique (name, ref)', 'The combination of Serial Number and internal reference must be unique !'), + ('name_ref_uniq', 'unique (name, ref, product_id, company_id)', 'The combination of Serial Number, internal reference, Product and Company must be unique !'), ] def action_traceability(self, cr, uid, ids, context=None): """ It traces the information of a product From f9d43e83c67691f84f352b2594977a05cbf3d50c Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 23 Jul 2014 12:19:51 +0200 Subject: [PATCH 03/29] [FIX] web: correct rev 680f955 Missing backport of commit f652402 for buffered dataset Again, should not be forwardported --- addons/web/static/src/js/data.js | 28 ++++++++++++++++++++++----- addons/web/static/src/js/view_form.js | 15 ++++++-------- addons/web/static/src/js/view_list.js | 9 +++++---- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index ee24c481a3a..6ae69fbe67b 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -430,12 +430,30 @@ instance.web.DataSet = instance.web.Class.extend(instance.web.PropertiesMixin, read_ids: function (ids, fields, options) { if (_.isEmpty(ids)) return $.Deferred().resolve([]); - + options = options || {}; - // TODO: reorder results to match ids list - return this._model.call('read', - [ids, fields || false], - {context: this.get_context(options.context)}); + var method = 'read'; + var ids_arg = ids; + var context = this.get_context(options.context); + if (options.check_access_rule === true){ + method = 'search_read'; + ids_arg = [['id', 'in', ids]]; + context = new instance.web.CompoundContext(context, {active_test: false}); + } + return this._model.call(method, + [ids_arg, fields || false], + {context: context}) + .then(function (records) { + if (records.length <= 1) { return records; } + var indexes = {}; + for (var i = 0; i < ids.length; i++) { + indexes[ids[i]] = i; + } + records.sort(function (a, b) { + return indexes[a.id] - indexes[b.id]; + }); + return records; + }); }, /** * Read a slice of the records represented by this DataSet, based on its diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 790fa88caa5..e91955e0a4e 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -957,20 +957,17 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM } else { var fields = _.keys(self.fields_view.fields); fields.push('display_name'); - // Use of search_read instead of read to check if we can still read the record (security rules) - return self.dataset.call('search_read', [[['id', '=', self.dataset.ids[self.dataset.index]]], fields], + return self.dataset.read_index(fields, { context: { 'bin_size': true, 'future_display_name': true - } + }, + check_access_rule: true }).then(function(r) { - if (_.isEmpty(r)){ - self.do_action('history_back'); - } - else{ - self.trigger('load_record', r[0]); - } + self.trigger('load_record', r); + }).fail(function (){ + self.do_action('history_back'); }); } }); diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 9d4c781b785..54f7946a9a3 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -529,13 +529,14 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi reload_record: function (record) { var self = this; // Use of search_read instead of read to check if we can still read the record (security rules) - return this.dataset.call('search_read', [ - [['id', '=', record.get('id')]], + return this.dataset.read_ids( + [record.get('id')], _.pluck(_(this.columns).filter(function (r) { return r.tag === 'field'; - }), 'name')] + }), 'name'), + {check_access_rule: true} ).done(function (records) { - var values = _.isEmpty(records) ? undefined : records[0]; + var values = records[0]; if (!values) { self.records.remove(record); return; From 67cca3f1e5489a81996d1ba20586749490d8665a Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Tue, 15 Jul 2014 16:17:36 -0400 Subject: [PATCH 04/29] [FIX] mail: display translated model name at record creation When a record is created, if it inherits from mail.thread, a message 'OBJECT created' is posted. 'created' is translated but the name of the model wasn't. This fix uses the name of the linked ir.model which is already a translatable field. lp:1262000, opw 611043 --- addons/mail/mail_thread.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 384fc6d6642..5691cb9ac73 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -253,7 +253,10 @@ class mail_thread(osv.AbstractModel): # automatic logging unless asked not to (mainly for various testing purpose) if not context.get('mail_create_nolog'): - self.message_post(cr, uid, thread_id, body=_('%s created') % (self._description), context=context) + ir_model_pool = self.pool['ir.model'] + ids = ir_model_pool.search(cr, uid, [('model', '=', self._name)], context=context) + name = ir_model_pool.read(cr, uid, ids, ['name'], context=context)[0]['name'] + self.message_post(cr, uid, thread_id, body=_('%s created') % name, context=context) # auto_subscribe: take values and defaults into account create_values = dict(values) From 330808b2cfadaa922994e92835b6b2df1f05c914 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Wed, 23 Jul 2014 16:21:53 +0200 Subject: [PATCH 05/29] [FIX] website.snippet: display snippet editor button inline insead of 2 lines for the small boxes --- addons/website/static/src/css/snippets.css | 7 +++++++ addons/website/static/src/css/snippets.sass | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/addons/website/static/src/css/snippets.css b/addons/website/static/src/css/snippets.css index a19baa33fd6..bd3ca21a367 100644 --- a/addons/website/static/src/css/snippets.css +++ b/addons/website/static/src/css/snippets.css @@ -356,6 +356,13 @@ } .oe_overlay .oe_overlay_options > .btn-group { left: -50%; + white-space: nowrap; +} +.oe_overlay .oe_overlay_options > .btn-group > a { + cursor: pointer; + display: inline-block; + float: none; + margin: 0 -3px; } .oe_overlay .oe_overlay_options .btn, .oe_overlay .oe_overlay_options a { cursor: pointer; diff --git a/addons/website/static/src/css/snippets.sass b/addons/website/static/src/css/snippets.sass index afdb261a2a5..bbdf34c8c61 100644 --- a/addons/website/static/src/css/snippets.sass +++ b/addons/website/static/src/css/snippets.sass @@ -264,6 +264,12 @@ z-index: 1002 > .btn-group left: -50% + white-space: nowrap + > a + cursor: pointer + display: inline-block + float: none + margin: 0 -3px .btn, a cursor: pointer .dropdown From 3d53306ccc4229ed6b1ee7c908f83c90acf24977 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 24 Jul 2014 08:50:48 +0200 Subject: [PATCH 06/29] [FIX] gamification: why is there a button here ? do you need a button ? I don't think so... --- addons/gamification/views/badge.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/gamification/views/badge.xml b/addons/gamification/views/badge.xml index 0b37e62051d..ad0aee76b07 100644 --- a/addons/gamification/views/badge.xml +++ b/addons/gamification/views/badge.xml @@ -40,7 +40,6 @@
From 1acf76bfc2b89af50ffe7f3e41c0b1c984ee418f Mon Sep 17 00:00:00 2001 From: Ravi Gohil Date: Mon, 9 Jun 2014 12:47:54 +0530 Subject: [PATCH 07/29] [FIX] purchase_analytic_plans: keep reference to analytic distribution Purchase orders created with invoice policy 'Based on incoming shipments' were not keeping the reference to the account analytic distribution when invoiced. opw 607577 --- .../purchase_analytic_plans/purchase_analytic_plans.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/addons/purchase_analytic_plans/purchase_analytic_plans.py b/addons/purchase_analytic_plans/purchase_analytic_plans.py index c80beddd20f..ae359f64b1a 100644 --- a/addons/purchase_analytic_plans/purchase_analytic_plans.py +++ b/addons/purchase_analytic_plans/purchase_analytic_plans.py @@ -42,4 +42,14 @@ class purchase_order(osv.osv): purchase_order() +class stock_picking(osv.osv): + _name='stock.picking' + _inherit='stock.picking' + + def _prepare_invoice_line(self, cr, uid, group, picking, move_line, invoice_id, invoice_vals, context=None): + res = super(stock_picking, self)._prepare_invoice_line(cr, uid, group, picking, move_line, invoice_id, invoice_vals, context=context) + if move_line.purchase_line_id and move_line.purchase_line_id.analytics_id: + res['analytics_id'] = move_line.purchase_line_id.analytics_id.id + return res + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 951a51df3f7696bf69a5bb0f3fc82a802219bf19 Mon Sep 17 00:00:00 2001 From: Yannick Vaucher Date: Thu, 24 Jul 2014 12:21:34 +0200 Subject: [PATCH 08/29] [IMP] account: do not offer closed analytic accounts on invoices lp:1223922, opw 609656 --- addons/account/account_invoice_view.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 2c768115e2a..f353877dd21 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -61,7 +61,7 @@ - + @@ -95,7 +95,7 @@ - + @@ -200,7 +200,7 @@ domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '=', 'other')]" on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)"/> + domain="[('type','!=','view'), ('company_id', '=', parent.company_id), ('state','not in',('close','cancelled'))]"/> @@ -357,7 +357,7 @@ domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '=', 'other')]" on_change="onchange_account_id(product_id, parent.partner_id, parent.type, parent.fiscal_position,account_id)"/> + domain="[('type','!=','view'), ('company_id', '=', parent.company_id), ('state','not in',('close','cancelled'))]"/> From de34d66860a4f586f456819974d0b38c81505cc2 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 24 Jul 2014 19:41:15 +0200 Subject: [PATCH 09/29] [FIX] project: remove state field from task analys The state has been replaced by stage_id in the view, so the state is no longer used Moreover, when doing an advanced search, the field state is visible and if used -> Traceback (because not available in the report sql table) opw-609984 --- addons/project/report/project_report.py | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/project/report/project_report.py b/addons/project/report/project_report.py index 5a473469b2d..30a61106d76 100644 --- a/addons/project/report/project_report.py +++ b/addons/project/report/project_report.py @@ -50,7 +50,6 @@ class report_project_task_user(osv.osv): 'nbr': fields.integer('# of tasks', readonly=True), 'priority': fields.selection([('4', 'Very Low'), ('3', 'Low'), ('2', 'Medium'), ('1', 'Urgent'), ('0', 'Very urgent')], string='Priority', readonly=True), - 'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')],'Status', readonly=True), 'company_id': fields.many2one('res.company', 'Company', readonly=True), 'partner_id': fields.many2one('res.partner', 'Contact', readonly=True), 'stage_id': fields.many2one('project.task.type', 'Stage'), From a5531c1d291786e76974e6bd6c2481fa5483e803 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 24 Jul 2014 20:42:21 +0200 Subject: [PATCH 10/29] [FIX] stock: do not set user_id on prepare_invoice_group The user_id is already set by the prepare_invoice method, which is called before the prepare_invoice_group (the user_id is already set, thus) Besides, _prepare_invoice is overriden in sale_stock, to set the picking sale order salesman as user_id, and, without this correct, grouping invoicse by partner re-set the user_id to uid, which is wrong. --- addons/stock/stock.py | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index c14819f9f5f..d363275b7fa 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1011,7 +1011,6 @@ class stock_picking(osv.osv): 'origin': (invoice.origin or '') + ', ' + (picking.name or '') + (picking.origin and (':' + picking.origin) or ''), 'comment': (comment and (invoice.comment and invoice.comment + "\n" + comment or comment)) or (invoice.comment and invoice.comment or ''), 'date_invoice': context.get('date_inv', False), - 'user_id': uid, } def _prepare_invoice(self, cr, uid, picking, partner, inv_type, journal_id, context=None): From 10fce02eb0ee8c9eb9fa19c9ab0af8ef19b3ab2e Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 25 Jul 2014 10:57:30 +0200 Subject: [PATCH 11/29] [FIX] website_membership: access rules fixes When searching on memberships, we use domain clauses in the format 'partner.x = y' where partner is a many2one to res.partner. The object res.partner has strict security rules for public users and this search will return zero result if not done with SUPERUSER_ID. In addition, we need to access the list of products (membership_ids) in the domain to be sure we will retrieve only published membership (otherwise it would crash in the sort below). --- addons/website_membership/controllers/main.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/addons/website_membership/controllers/main.py b/addons/website_membership/controllers/main.py index a4932c1b46c..e8787978e43 100644 --- a/addons/website_membership/controllers/main.py +++ b/addons/website_membership/controllers/main.py @@ -50,7 +50,7 @@ class WebsiteMembership(http.Controller): ('partner.website_description', 'ilike', post_name)] # group by country, based on all customers (base domain) - membership_line_ids = membership_line_obj.search(cr, uid, base_line_domain, context=context) + membership_line_ids = membership_line_obj.search(cr, SUPERUSER_ID, base_line_domain, context=context) countries = partner_obj.read_group( cr, uid, [('member_lines', 'in', membership_line_ids), ("website_published", "=", True)], ["id", "country_id"], groupby="country_id", orderby="country_id", context=request.context) @@ -72,8 +72,14 @@ class WebsiteMembership(http.Controller): 'country_id': (0, _("All Countries")) }) + # format domain for group_by and memberships + membership_ids = product_obj.search(cr, uid, [('membership', '=', True)], order="website_sequence", context=context) + memberships = product_obj.browse(cr, uid, membership_ids, context=context) + # make sure we don't access to lines with unpublished membershipts + line_domain.append(('membership_id', 'in', membership_ids)) + # displayed membership lines - membership_line_ids = membership_line_obj.search(cr, uid, line_domain, context=context) + membership_line_ids = membership_line_obj.search(cr, SUPERUSER_ID, line_domain, context=context) membership_lines = membership_line_obj.browse(cr, uid, membership_line_ids, context=context) membership_lines.sort(key=lambda x: x.membership_id.website_sequence) partner_ids = [m.partner and m.partner.id for m in membership_lines] @@ -83,10 +89,6 @@ class WebsiteMembership(http.Controller): for partner in partner_obj.read(cr, openerp.SUPERUSER_ID, partner_ids, request.website.get_partner_white_list_fields(), context=context): partners_data[partner.get("id")] = partner - # format domain for group_by and memberships - membership_ids = product_obj.search(cr, uid, [('membership', '=', True)], order="website_sequence", context=context) - memberships = product_obj.browse(cr, uid, membership_ids, context=context) - # request pager for lines pager = request.website.pager(url="/members/", total=len(membership_line_ids), page=page, step=self._references_per_page, scope=7, url_args=post) From 93127099c9b90964ab1d1b1e99c7fe1532365570 Mon Sep 17 00:00:00 2001 From: dsabrinarg Date: Thu, 24 Jul 2014 22:31:12 -0500 Subject: [PATCH 12/29] [ADD] base_vat: add VAT validation for Peruvian localization. --- addons/base_vat/base_vat.py | 38 ++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/addons/base_vat/base_vat.py b/addons/base_vat/base_vat.py index 374e910e6e6..5ecb321d3ba 100644 --- a/addons/base_vat/base_vat.py +++ b/addons/base_vat/base_vat.py @@ -63,6 +63,7 @@ _ref_vat = { 'mx': 'MXABC123456T1B', 'nl': 'NL123456782B90', 'no': 'NO123456785', + 'pe': 'PER10254824220 or PED10254824220', 'pl': 'PL1234567883', 'pt': 'PT123456789', 'ro': 'RO1234567897', @@ -219,7 +220,7 @@ class res_partner(osv.osv): return vat[7] == self._ie_check_char(vat[2:7] + vat[0] + vat[8]) return False - # Mexican VAT verification, contributed by + # Mexican VAT verification, contributed by Vauxoo # and Panos Christeas __check_vat_mx_re = re.compile(r"(?P[A-Za-z\xd1\xf1&]{3,4})" \ r"[ \-_]?" \ @@ -276,6 +277,41 @@ class res_partner(osv.osv): return False return check == int(vat[8]) + # Peruvian VAT validation, contributed by Vauxoo + def check_vat_pe(self, vat): + + vat_type,vat = vat and len(vat)>=2 and (vat[0], vat[1:]) or (False, False) + + if vat_type and vat_type.upper() == 'D': + #DNI + return True + elif vat_type and vat_type.upper() == 'R': + #verify RUC + factor = '5432765432' + sum = 0 + dig_check = False + if len(vat) != 11: + return False + try: + int(vat) + except ValueError: + return False + + for f in range(0,10): + sum += int(factor[f]) * int(vat[f]) + + subtraction = 11 - (sum % 11) + if subtraction == 10: + dig_check = 0 + elif subtraction == 11: + dig_check = 1 + else: + dig_check = subtraction + + return int(vat[10]) == dig_check + else: + return False + res_partner() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 133becd966ba1789f323487c4c2c67530965b1e5 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 25 Jul 2014 11:53:30 +0200 Subject: [PATCH 13/29] [FIX] ir_fields: allow accent on selection import If the selection label (not value) had accents, it wasn't possible to import it using the label having accents --- openerp/addons/base/ir/ir_fields.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/ir/ir_fields.py b/openerp/addons/base/ir/ir_fields.py index 0ed2cb3bf4e..f8a93730430 100644 --- a/openerp/addons/base/ir/ir_fields.py +++ b/openerp/addons/base/ir/ir_fields.py @@ -11,7 +11,8 @@ import pytz from openerp.osv import orm from openerp.tools.translate import _ from openerp.tools.misc import DEFAULT_SERVER_DATE_FORMAT,\ - DEFAULT_SERVER_DATETIME_FORMAT + DEFAULT_SERVER_DATETIME_FORMAT,\ + ustr from openerp.tools import html_sanitize REFERENCING_FIELDS = set([None, 'id', '.id']) @@ -256,6 +257,7 @@ class ir_fields_converter(orm.Model): # Or just copy context & remove lang? selection = selection(model, cr, uid, context=None) for item, label in selection: + label = ustr(label) labels = self._get_translations( cr, uid, ('selection', 'model', 'code'), label, context=context) labels.append(label) @@ -264,8 +266,8 @@ class ir_fields_converter(orm.Model): raise ValueError( _(u"Value '%s' not found in selection field '%%(field)s'") % ( value), { - 'moreinfo': [label or unicode(item) for item, label in selection - if label or item] + 'moreinfo': [_label or unicode(item) for item, _label in selection + if _label or item] }) From 46ef1356d6de734b96ab3f1d8a0892044989b5f9 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 25 Jul 2014 13:00:17 +0200 Subject: [PATCH 14/29] [ADD] safe_eval: UNPACK_SEQUENCE and Exception Allowing UNPACK_SEQUENCE allows the use of the "multi" assignation: a, b = [1,2] for a,b in items --- openerp/tools/safe_eval.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openerp/tools/safe_eval.py b/openerp/tools/safe_eval.py index 76987e278e6..0b9b2e7a8a3 100644 --- a/openerp/tools/safe_eval.py +++ b/openerp/tools/safe_eval.py @@ -67,7 +67,7 @@ _SAFE_OPCODES = _EXPR_OPCODES.union(set(opmap[x] for x in [ # New in Python 2.7 - http://bugs.python.org/issue4715 : 'JUMP_IF_FALSE_OR_POP', 'JUMP_IF_TRUE_OR_POP', 'POP_JUMP_IF_FALSE', 'POP_JUMP_IF_TRUE', 'SETUP_EXCEPT', 'END_FINALLY', - 'LOAD_FAST', 'STORE_FAST', 'DELETE_FAST', + 'LOAD_FAST', 'STORE_FAST', 'DELETE_FAST', 'UNPACK_SEQUENCE', 'LOAD_GLOBAL', # Only allows access to restricted globals ] if x in opmap)) @@ -278,7 +278,8 @@ def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=Fal 'filter': filter, 'round': round, 'len': len, - 'set' : set + 'set' : set, + 'Exception': Exception, } ) try: From ced585214405a62a06aba27ea4c5817914301bf8 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Fri, 25 Jul 2014 14:45:48 +0200 Subject: [PATCH 15/29] [FIX] hr_holidays: do not allow reduce remaining leaves In the Employee form, a remaining legal leaves field is available, which shows remaining validated leaves from allocation requests As this is not allowed to delete a validated allocation requets, it shouldn't be possible to reduce the validated remaining leaves of an employee. To reduce the remaining leaves of an employee, the user should cancel and remove the allocation request --- addons/hr_holidays/hr_holidays.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 793ab247a2d..fbe72a1898c 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -491,7 +491,7 @@ class hr_employee(osv.osv): if diff > 0: leave_id = holiday_obj.create(cr, uid, {'name': _('Allocation for %s') % employee.name, 'employee_id': employee.id, 'holiday_status_id': status_id, 'type': 'add', 'holiday_type': 'employee', 'number_of_days_temp': diff}, context=context) elif diff < 0: - leave_id = holiday_obj.create(cr, uid, {'name': _('Leave Request for %s') % employee.name, 'employee_id': employee.id, 'holiday_status_id': status_id, 'type': 'remove', 'holiday_type': 'employee', 'number_of_days_temp': abs(diff)}, context=context) + raise osv.except_osv(_('Warning!'), _('You cannot reduce validated allocation requests')) else: return False wf_service = netsvc.LocalService("workflow") From 40b1fccb2a422c46f4a9b2ae56eb9099c21eb1ef Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Fri, 25 Jul 2014 16:17:29 -0400 Subject: [PATCH 16/29] [FIX] translate: Fix debug print when parse path list to translate. --- openerp/tools/translate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/tools/translate.py b/openerp/tools/translate.py index 4dc49903730..b3bea678cf8 100644 --- a/openerp/tools/translate.py +++ b/openerp/tools/translate.py @@ -854,7 +854,7 @@ def trans_generate(lang, modules, cr): for bin_path in ['osv', 'report' ]: path_list.append(os.path.join(config.config['root_path'], bin_path)) - _logger.debug("Scanning modules at paths: ", path_list) + _logger.debug("Scanning modules at paths: %s", path_list) mod_paths = [] From 3fe508f200963122f1ee61072516c84b2022aa48 Mon Sep 17 00:00:00 2001 From: Humberto Arocha Date: Thu, 10 Jul 2014 15:25:01 -0430 Subject: [PATCH 17/29] [FIX] account: no journal items on consolidation accounts As for the view accounts, the consolidation accounts should not allow to create journal items. Fixes #1090 --- addons/account/account_move_line.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index bdc1941238d..b3f21eb1525 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -574,7 +574,7 @@ class account_move_line(osv.osv): def _check_no_view(self, cr, uid, ids, context=None): lines = self.browse(cr, uid, ids, context=context) for l in lines: - if l.account_id.type == 'view': + if l.account_id.type in ('view', 'consolidation'): return False return True @@ -626,7 +626,7 @@ class account_move_line(osv.osv): return True _constraints = [ - (_check_no_view, 'You cannot create journal items on an account of type view.', ['account_id']), + (_check_no_view, 'You cannot create journal items on an account of type view or consolidation.', ['account_id']), (_check_no_closed, 'You cannot create journal items on closed account.', ['account_id']), (_check_company_id, 'Account and Period must belong to the same company.', ['company_id']), (_check_date, 'The date of your Journal Entry is not in the defined period! You should change the date or remove this constraint from the journal.', ['date']), From cd013aa09a780291931323430f0c3c97ea6ab55d Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 28 Jul 2014 14:35:44 +0200 Subject: [PATCH 18/29] Revert 3dec090 "[FIX] ir_values: fallback when no condition" An ir.value without condition should not match when searching with a condition. When a field with change_default on it is modified, the method get_defaults is called with the new value. This means that manually modifying a field with this trigger would put back the default value (opw 611193). --- openerp/addons/base/ir/ir_values.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/ir/ir_values.py b/openerp/addons/base/ir/ir_values.py index 953d1aad0d4..bf0128dffd6 100644 --- a/openerp/addons/base/ir/ir_values.py +++ b/openerp/addons/base/ir/ir_values.py @@ -310,10 +310,10 @@ class ir_values(osv.osv): (SELECT company_id from res_users where id = %%s) ) %s - ORDER BY v.user_id, u.company_id, v.key2""" + ORDER BY v.user_id, u.company_id""" params = ('default', model, uid, uid) if condition: - query %= 'AND (v.key2 = %s OR v.key2 IS NULL)' + query %= 'AND v.key2 = %s' params += (condition[:200],) else: query %= 'AND v.key2 is NULL' From b91a75f7eff85edd5d51a91d10d6e3be8a409030 Mon Sep 17 00:00:00 2001 From: Ravi Gohil Date: Fri, 25 Jul 2014 12:45:40 +0530 Subject: [PATCH 19/29] [IMP] base_vat: differenciate VIES and classical VAT error Display a different error message so that users are aware if the test failed with VIES enabled or not (opw 609823) --- addons/base_vat/base_vat.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/base_vat/base_vat.py b/addons/base_vat/base_vat.py index 5ecb321d3ba..8ba25748317 100644 --- a/addons/base_vat/base_vat.py +++ b/addons/base_vat/base_vat.py @@ -150,6 +150,8 @@ class res_partner(osv.osv): vat_no = "'CC##' (CC=Country Code, ##=VAT Number)" if default_vat_check(vat_country, vat_number): vat_no = _ref_vat[vat_country] if vat_country in _ref_vat else vat_no + if self.pool['res.users'].browse(cr, uid, uid).company_id.vat_check_vies: + return '\n' + _('This VAT number either failed the VIES VAT validation check or did not respect the expected format %s.') % vat_no return '\n' + _('This VAT number does not seem to be valid.\nNote: the expected format is %s') % vat_no _constraints = [(check_vat, _construct_constraint_msg, ["vat"])] From 767d2ea9a63ceb6d8473766f52eb06f69b281ca1 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Mon, 28 Jul 2014 19:02:11 +0200 Subject: [PATCH 20/29] [FIX] web: on refresh, do search_read with fields passed --- addons/web/static/src/js/views.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 7677ddfb9f5..78accfd4da4 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -653,8 +653,8 @@ instance.web.ViewManager = instance.web.Widget.extend({ var container = this.$el.find("> .oe_view_manager_body > .oe_view_manager_view_" + view_type); var view_promise = controller.appendTo(container); this.views[view_type].controller = controller; - this.views[view_type].deferred.resolve(view_type); return $.when(view_promise).done(function() { + self.views[view_type].deferred.resolve(view_type); if (self.searchview && self.flags.auto_search && view.controller.searchable !== false) { @@ -1071,7 +1071,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ ); } - $.when(defs).done(function() { + $.when(this.views[this.active_view] ? this.views[this.active_view].deferred : $.when(), defs).done(function() { self.views[self.active_view].controller.do_load_state(state, warm); }); }, From bbb8d8f25a7a81c26965aa76b5085961a13132d6 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 29 Jul 2014 11:35:19 +0200 Subject: [PATCH 21/29] [MERGE] forward port of branch 7.0 up to 767d2ea9a63ceb6d8473766f52eb06f69b281ca1 --- addons/web/static/src/js/views.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 86fd61a244b..76fa67231be 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -694,8 +694,8 @@ instance.web.ViewManager = instance.web.Widget.extend({ var container = this.$el.find("> .oe_view_manager_body > .oe_view_manager_view_" + view_type); var view_promise = controller.appendTo(container); this.views[view_type].controller = controller; - this.views[view_type].deferred.resolve(view_type); return $.when(view_promise).done(function() { + self.views[view_type].deferred.resolve(view_type); if (self.searchview && self.flags.auto_search && view.controller.searchable !== false) { @@ -1109,7 +1109,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ ); } - $.when(defs).done(function() { + $.when(this.views[this.active_view] ? this.views[this.active_view].deferred : $.when(), defs).done(function() { self.views[self.active_view].controller.do_load_state(state, warm); }); }, From f9da53743f2c12bf12e93c6004c0107249962805 Mon Sep 17 00:00:00 2001 From: StefanRijnhart Date: Tue, 29 Jul 2014 12:17:38 +0200 Subject: [PATCH 22/29] [FIX] mail: reset of default_type in context When creating a new message, we need to reset the default_type key to avoid context propagation (e.g. invoice menu). However we used to compare the key in context (char) with the list of selections (tuple) so it was never matching and always reset. --- addons/mail/mail_message.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 3f491df82b7..8ac047fb77e 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -61,7 +61,8 @@ class mail_message(osv.Model): def default_get(self, cr, uid, fields, context=None): # protection for `default_type` values leaking from menu action context (e.g. for invoices) - if context and context.get('default_type') and context.get('default_type') not in self._columns['type'].selection: + if context and context.get('default_type') and context.get('default_type') not in [ + val[0] for val in self._columns['type'].selection]: context = dict(context, default_type=None) return super(mail_message, self).default_get(cr, uid, fields, context=context) From dd4d72d710ab9ffcc3143130a6b5feecf8ce7a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lionel=20Sausin=20=28Num=C3=A9rigraphe=29?= Date: Fri, 25 Jul 2014 11:54:36 +0200 Subject: [PATCH 23/29] [FIX] stock: partial deliveries switch on delivered picking Users don't care for the backorder picking precisely because they can't process it, whereas they may have to do some more things on the picking they processed: invoice it, print delivery orders or transportation stickers.. Refresh the browse record after changing the name to avoid the need to rebrowse. Fixes #1372 --- addons/stock/stock.py | 6 +++--- addons/stock/wizard/stock_partial_picking.py | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index d363275b7fa..64284f7c0c2 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1305,6 +1305,7 @@ class stock_picking(osv.osv): {'name': sequence_obj.get(cr, uid, 'stock.picking.%s'%(pick.type)), }) + pick.refresh() new_picking = self.copy(cr, uid, pick.id, { 'name': new_picking_name, @@ -1362,9 +1363,8 @@ class stock_picking(osv.osv): self.action_move(cr, uid, [new_picking], context=context) wf_service.trg_validate(uid, 'stock.picking', new_picking, 'button_done', cr) wf_service.trg_write(uid, 'stock.picking', pick.id, cr) - delivered_pack_id = pick.id - back_order_name = self.browse(cr, uid, delivered_pack_id, context=context).name - self.message_post(cr, uid, new_picking, body=_("Back order %s has been created.") % (back_order_name), context=context) + delivered_pack_id = new_picking + self.message_post(cr, uid, new_picking, body=_("Back order %s has been created.") % (pick.name), context=context) else: self.action_move(cr, uid, [pick.id], context=context) wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_done', cr) diff --git a/addons/stock/wizard/stock_partial_picking.py b/addons/stock/wizard/stock_partial_picking.py index ceedb682ed8..7358855924d 100644 --- a/addons/stock/wizard/stock_partial_picking.py +++ b/addons/stock/wizard/stock_partial_picking.py @@ -156,6 +156,8 @@ class stock_partial_picking(osv.osv_memory): return partial_move def do_partial(self, cr, uid, ids, context=None): + if context is None: + context = {} assert len(ids) == 1, 'Partial picking processing may only be done one at a time.' stock_picking = self.pool.get('stock.picking') stock_move = self.pool.get('stock.move') @@ -211,7 +213,19 @@ class stock_partial_picking(osv.osv_memory): if (picking_type == 'in') and (wizard_line.product_id.cost_method == 'average'): partial_data['move%s' % (wizard_line.move_id.id)].update(product_price=wizard_line.cost, product_currency=wizard_line.currency.id) - stock_picking.do_partial(cr, uid, [partial.picking_id.id], partial_data, context=context) - return {'type': 'ir.actions.act_window_close'} + + # Do the partial delivery and open the picking that was delivered + # We don't need to find which view is required, stock.picking does it. + done = stock_picking.do_partial( + cr, uid, [partial.picking_id.id], partial_data, context=context) + return { + 'type': 'ir.actions.act_window', + 'res_model': context.get('active_model', 'stock.picking'), + 'name': _('Partial Delivery'), + 'res_id': done[partial.picking_id.id]['delivered_picking'], + 'view_type': 'form', + 'view_mode': 'form,tree,calendar', + 'context': context, + } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From c6f91facbb44336de5d2278983b0a006ed3e014f Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 30 Jul 2014 15:10:22 +0200 Subject: [PATCH 24/29] [FIX] website: do not restore page views --- addons/website/controllers/main.py | 11 ++++++++--- addons/website/models/ir_http.py | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index 856ab6ecffc..4f2a2a3da4a 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -141,14 +141,19 @@ class Website(openerp.addons.web.controllers.main.Home): modules_to_update = [] for temp_id in templates: view = request.registry['ir.ui.view'].browse(request.cr, request.uid, int(temp_id), context=request.context) + if view.page: + continue view.model_data_id.write({ 'noupdate': False }) if view.model_data_id.module not in modules_to_update: modules_to_update.append(view.model_data_id.module) - module_obj = request.registry['ir.module.module'] - module_ids = module_obj.search(request.cr, request.uid, [('name', 'in', modules_to_update)], context=request.context) - module_obj.button_immediate_upgrade(request.cr, request.uid, module_ids, context=request.context) + + if modules_to_update: + module_obj = request.registry['ir.module.module'] + module_ids = module_obj.search(request.cr, request.uid, [('name', 'in', modules_to_update)], context=request.context) + if module_ids: + module_obj.button_immediate_upgrade(request.cr, request.uid, module_ids, context=request.context) return request.redirect(redirect) @http.route('/website/customize_template_toggle', type='json', auth='user', website=True) diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py index be6b4982819..a73e33cb824 100644 --- a/addons/website/models/ir_http.py +++ b/addons/website/models/ir_http.py @@ -137,7 +137,7 @@ class ir_http(orm.AbstractModel): if 'qweb_exception' in values: view = request.registry.get("ir.ui.view") views = view._views_get(request.cr, request.uid, exception.qweb['template'], request.context) - to_reset = [v for v in views if v.model_data_id.noupdate is True] + to_reset = [v for v in views if v.model_data_id.noupdate is True and not v.page] values['views'] = to_reset elif code == 403: logger.warn("403 Forbidden:\n\n%s", values['traceback']) From 873dc0370d7a006156cbfeb2ee793ddd67437777 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 30 Jul 2014 15:26:43 +0200 Subject: [PATCH 25/29] [FIX] sale: config, timesheet if module account_analytic_analysis In Settings > Sales, the onchange_timesheet ensure that if you check timesheet, it checks module_account_analytic_analysis. Therefore, if module_account_analytic_analysis is installed, timesheet should be checked by default Until now, it worked "luckily", because the onchange_timesheet of the field module_account_analytic_analysis was triggered before the onchange_timesheet of the timesheet field. Nevertheless, we shouldn't trust the onchange calls order. --- addons/sale/res_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/sale/res_config.py b/addons/sale/res_config.py index f4239b0e1a2..164213f1f59 100644 --- a/addons/sale/res_config.py +++ b/addons/sale/res_config.py @@ -91,6 +91,7 @@ Example: Product: this product is deprecated, do not purchase more than 5. except ValueError: # keep default value in that case _logger.warning("Product with xml_id 'product.product_product_consultant' not found") + res['timesheet'] = res.get('module_account_analytic_analysis') return res def _get_default_time_unit(self, cr, uid, context=None): From 8f0392b49099eaca6f4c5cdd0931da0821d73865 Mon Sep 17 00:00:00 2001 From: Ravi Gohil Date: Thu, 10 Jul 2014 17:09:15 +0530 Subject: [PATCH 26/29] [FIX] account_voucher: avoid trying unreconcile a move twice When we cancel a voucher, we may be trying to unlink a reconciliation that was already removed on another move (just looking at the version in cache). In such cases, the unlink would fail with traceback. opw 610287 --- addons/account_voucher/account_voucher.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py index ce080d9e446..a7c7646f6e1 100644 --- a/addons/account_voucher/account_voucher.py +++ b/addons/account_voucher/account_voucher.py @@ -957,6 +957,8 @@ class account_voucher(osv.osv): # refresh to make sure you don't unlink an already removed move voucher.refresh() for line in voucher.move_ids: + # refresh to make sure you don't unreconcile an already unreconciled entry + line.refresh() if line.reconcile_id: move_lines = [move_line.id for move_line in line.reconcile_id.line_id] move_lines.remove(line.id) From faa0df809fdbaa083e0562739ec045820a0b26e2 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 30 Jul 2014 15:27:58 +0200 Subject: [PATCH 27/29] [FIX] project_long_term: avoid bad duplication of phases When we duplicate a project, the related phases need to be duplicated as well but keeping references between each other. e.g. 'project 1' with 'phase A' follwed by 'phase B' should become 'project 1 (copy)' with 'phase A (copy)' followed by 'phase B (copy)'. Fixing bug lp:1212860, opw 607062 --- addons/project_long_term/project_long_term.py | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/addons/project_long_term/project_long_term.py b/addons/project_long_term/project_long_term.py index 109f0c03c6f..0758d4181e2 100644 --- a/addons/project_long_term/project_long_term.py +++ b/addons/project_long_term/project_long_term.py @@ -267,7 +267,44 @@ class project(osv.osv): 'date_end': p.end.strftime('%Y-%m-%d %H:%M:%S') }, context=context) return True -project() + + def map_phase(self, cr, uid, old_project_id, new_project_id, context=None): + """ copy and map phases from old to new project while keeping order relations """ + project_phase = self.pool['project.phase'] + project_task = self.pool['project.task'] + # mapping source and copy ids to recreate m2m links + phase_ids_mapping = {} + project = self.browse(cr, uid, old_project_id, context=context) + if project.phase_ids: + for phase in project.phase_ids: + phase_default = { + 'project_id': new_project_id, + 'previous_phase_ids': [], + 'next_phase_ids': [], + 'task_ids': [], + } + # adding relationships with already copied phases + for previous_phase in phase.previous_phase_ids: + if previous_phase.id in phase_ids_mapping: + phase_default['previous_phase_ids'].append((4, phase_ids_mapping[previous_phase.id])) + for next_phase in phase.next_phase_ids: + if next_phase.id in phase_ids_mapping: + phase_default['previous_phase_ids'].append((4, phase_ids_mapping[next_phase.id])) + phase_ids_mapping[phase.id] = project_phase.copy(cr, uid, phase.id, phase_default, context=context) + if project.tasks: + # if has copied tasks, need to update phase_id + for task in self.browse(cr, uid, new_project_id, context=context).tasks: + if task.phase_id and task.phase_id.id in phase_ids_mapping: + project_task.write(cr, uid, task.id, {'phase_id': phase_ids_mapping[phase.id]}, context=context) + return True + + def copy(self, cr, uid, id, default=None, context=None): + if default is None: + default = {} + default.update(phase_ids=[]) + new_project_id = super(project, self).copy(cr, uid, id, default, context) + self.map_phase(cr, uid, id, new_project_id, context=context) + return new_project_id class account_analytic_account(osv.osv): _inherit = 'account.analytic.account' From 0b947b26e19c8a293a54d788c253edf63b77c2b7 Mon Sep 17 00:00:00 2001 From: dhr-odoo Date: Mon, 7 Jul 2014 18:08:12 +0530 Subject: [PATCH 28/29] Passed default type while creating document page category from document page --- addons/document_page/document_page_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/document_page/document_page_view.xml b/addons/document_page/document_page_view.xml index 9d02b47d265..2ffc905946c 100644 --- a/addons/document_page/document_page_view.xml +++ b/addons/document_page/document_page_view.xml @@ -42,7 +42,7 @@

- + From 39f3e403293e51f1e6e544638831dd090bcc0847 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 9 Jul 2014 11:39:58 +0200 Subject: [PATCH 29/29] [FIX] sale: copy_quotation must propagate the context --- addons/sale/sale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index af62b014c05..264c2d9650f 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -281,7 +281,7 @@ class sale_order(osv.osv): return osv.osv.unlink(self, cr, uid, unlink_ids, context=context) def copy_quotation(self, cr, uid, ids, context=None): - id = self.copy(cr, uid, ids[0], context=None) + id = self.copy(cr, uid, ids[0], context=context) view_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'sale', 'view_order_form') view_id = view_ref and view_ref[1] or False, return {