From 23778030cd344a9674d56d738ecf4013a40a7009 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 29 Jan 2014 11:35:38 +0100 Subject: [PATCH 1/9] [FIX] forbid dropping templates databases bzr revid: chs@openerp.com-20140129103538-qbm054m29y5r4hu4 --- openerp/service/web_services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index ea905d91a4b..35ca4c4613d 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -196,7 +196,7 @@ class db(netsvc.ExportService): raise Exception, e def exp_drop(self, db_name): - if not self.exp_db_exist(db_name): + if db_name not in self.exp_list(True): return False openerp.modules.registry.RegistryManager.delete(db_name) sql_db.close_db(db_name) From 05ec12692f99b69924765fd0ce384632547f03f9 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 29 Jan 2014 11:55:48 +0100 Subject: [PATCH 2/9] [FIX] res_partner: name_search search in one pass The original query did two passes (SQL query and orm search). This was a problem due to the limit parameter where the second query could reduce the number of results to a smaller number than the asked limit. This code reproduces the orm _search behaviour to execute only one SQL query mixing both the ACL clauses and the complexe name_search without degrading the performances (removing the limit in the first query would have). lp bug: https://launchpad.net/bugs/1203727 fixed bzr revid: mat@openerp.com-20140129105548-dd6zmy9uc2cuowpq --- openerp/addons/base/res/res_partner.py | 40 ++++++++++++++++---------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 98a60690887..46ecbbe4d32 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -596,40 +596,50 @@ class res_partner(osv.osv, format_address): if not args: args = [] if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'): + + self.check_access_rights(cr, uid, 'read') + where_query = self._where_calc(cr, uid, args, context=context) + self._apply_ir_rules(cr, uid, where_query, 'read', context=context) + from_clause, where_clause, where_clause_params = where_query.get_sql() + where_str = where_clause and (" WHERE %s" % where_clause) or '' + # search on the name of the contacts and of its company search_name = name if operator in ('ilike', 'like'): search_name = '%%%s%%' % name if operator in ('=ilike', '=like'): operator = operator[1:] - query_args = {'name': search_name} + # TODO: simplify this in trunk with `display_name`, once it is stored # Perf note: a CTE expression (WITH ...) seems to have an even higher cost # than this query with duplicated CASE expressions. The bulk of # the cost is the ORDER BY, and it is inevitable if we want # relevant results for the next step, otherwise we'd return # a random selection of `limit` results. - query = ('''SELECT partner.id FROM res_partner partner + query = ('''SELECT res_partner.id FROM res_partner LEFT JOIN res_partner company - ON partner.parent_id = company.id - WHERE partner.email ''' + operator + ''' %(name)s OR + ON res_partner.parent_id = company.id''' + + where_str + + ''' AND res_partner.email ''' + operator + ''' %s OR CASE - WHEN company.id IS NULL OR partner.is_company - THEN partner.name - ELSE company.name || ', ' || partner.name - END ''' + operator + ''' %(name)s + WHEN company.id IS NULL OR res_partner.is_company + THEN res_partner.name + ELSE company.name || ', ' || res_partner.name + END ''' + operator + ''' %s ORDER BY CASE - WHEN company.id IS NULL OR partner.is_company - THEN partner.name - ELSE company.name || ', ' || partner.name + WHEN company.id IS NULL OR res_partner.is_company + THEN res_partner.name + ELSE company.name || ', ' || res_partner.name END''') + + where_clause_params += [search_name, search_name] if limit: - query += ' limit %(limit)s' - query_args['limit'] = limit - cr.execute(query, query_args) + query += ' limit %s' + where_clause_params.append(limit) + cr.execute(query, where_clause_params) ids = map(lambda x: x[0], cr.fetchall()) - ids = self.search(cr, uid, [('id', 'in', ids)] + args, limit=limit, context=context) + if ids: return self.name_get(cr, uid, ids, context) return super(res_partner,self).name_search(cr, uid, name, args, operator=operator, context=context, limit=limit) From 7dedf4ec4575f210d1eb29927480d1a3ac918adc Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 29 Jan 2014 12:19:59 +0100 Subject: [PATCH 3/9] [IMP] remove useless variable, where_clause at least '' as created from a str.join() bzr revid: mat@openerp.com-20140129111959-7y9su01ooneu0mco --- openerp/addons/base/res/res_partner.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 46ecbbe4d32..d3d88049fb2 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -601,7 +601,6 @@ class res_partner(osv.osv, format_address): where_query = self._where_calc(cr, uid, args, context=context) self._apply_ir_rules(cr, uid, where_query, 'read', context=context) from_clause, where_clause, where_clause_params = where_query.get_sql() - where_str = where_clause and (" WHERE %s" % where_clause) or '' # search on the name of the contacts and of its company search_name = name @@ -618,8 +617,8 @@ class res_partner(osv.osv, format_address): # a random selection of `limit` results. query = ('''SELECT res_partner.id FROM res_partner LEFT JOIN res_partner company - ON res_partner.parent_id = company.id''' - + where_str + + ON res_partner.parent_id = company.id + WHERE ''' + where_clause + ''' AND res_partner.email ''' + operator + ''' %s OR CASE WHEN company.id IS NULL OR res_partner.is_company @@ -639,7 +638,6 @@ class res_partner(osv.osv, format_address): where_clause_params.append(limit) cr.execute(query, where_clause_params) ids = map(lambda x: x[0], cr.fetchall()) - if ids: return self.name_get(cr, uid, ids, context) return super(res_partner,self).name_search(cr, uid, name, args, operator=operator, context=context, limit=limit) From 5d38e40e6bd68d44a8ed7ccc06326ffad2774644 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 29 Jan 2014 12:39:38 +0100 Subject: [PATCH 4/9] [FIX] revert previous rev for better where and add test bzr revid: mat@openerp.com-20140129113938-517gqfi1kzcf64fz --- openerp/addons/base/res/res_partner.py | 8 +++++--- openerp/addons/base/tests/test_base.py | 8 ++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index d3d88049fb2..21d70e1502a 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -601,6 +601,7 @@ class res_partner(osv.osv, format_address): where_query = self._where_calc(cr, uid, args, context=context) self._apply_ir_rules(cr, uid, where_query, 'read', context=context) from_clause, where_clause, where_clause_params = where_query.get_sql() + where_str = where_clause and (" WHERE %s AND " % where_clause) or ' WHERE ' # search on the name of the contacts and of its company search_name = name @@ -617,9 +618,9 @@ class res_partner(osv.osv, format_address): # a random selection of `limit` results. query = ('''SELECT res_partner.id FROM res_partner LEFT JOIN res_partner company - ON res_partner.parent_id = company.id - WHERE ''' + where_clause + - ''' AND res_partner.email ''' + operator + ''' %s OR + ON res_partner.parent_id = company.id''' + + where_str + + ''' res_partner.email ''' + operator + ''' %s OR CASE WHEN company.id IS NULL OR res_partner.is_company THEN res_partner.name @@ -638,6 +639,7 @@ class res_partner(osv.osv, format_address): where_clause_params.append(limit) cr.execute(query, where_clause_params) ids = map(lambda x: x[0], cr.fetchall()) + if ids: return self.name_get(cr, uid, ids, context) return super(res_partner,self).name_search(cr, uid, name, args, operator=operator, context=context, limit=limit) diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py index 1ca66f57943..02ce3b09688 100644 --- a/openerp/addons/base/tests/test_base.py +++ b/openerp/addons/base/tests/test_base.py @@ -39,6 +39,14 @@ class test_base(common.TransactionCase): new_id2 = self.res_partner.find_or_create(cr, uid, self.samples[2][0]) self.assertTrue(new_id2 > new_id, 'find_or_create failed - should have created new one again') + def test_15_res_partner_name_search(self): + cr,uid = self.cr, self.uid + for text, name, mail in self.samples: + partner_id, dummy = self.res_partner.name_create(cr, uid, text) + partners = self.res_partner.name_search(cr, uid, 'Raoul') + self.assertEqual(len(partners), 3, 'Incorrect search number result for name_search') + partners = self.res_partner.name_search(cr, uid, 'Raoul', limit=1) + self.assertEqual(len(partners), 1, 'Incorrect search number result for name_search with a limit') def test_20_res_partner_address_sync(self): cr, uid = self.cr, self.uid From f71a381b816561274d1124de9f80e7c8095b83dd Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 29 Jan 2014 12:41:02 +0100 Subject: [PATCH 5/9] [ref] move up! bzr revid: mat@openerp.com-20140129114102-tk4fotnb28mtaz9x --- openerp/addons/base/res/res_partner.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 21d70e1502a..d337b3c0a10 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -619,8 +619,7 @@ class res_partner(osv.osv, format_address): query = ('''SELECT res_partner.id FROM res_partner LEFT JOIN res_partner company ON res_partner.parent_id = company.id''' - + where_str + - ''' res_partner.email ''' + operator + ''' %s OR + + where_str + ''' res_partner.email ''' + operator + ''' %s OR CASE WHEN company.id IS NULL OR res_partner.is_company THEN res_partner.name From e6ee1947f86066e0779a76c6a77eea1b5ed3e6e7 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 29 Jan 2014 13:34:04 +0100 Subject: [PATCH 6/9] [FIX] better test, add missing parentheses in query, return empty list in case of no idea (instead of triggering super) bzr revid: mat@openerp.com-20140129123404-8hs786n64briqyta --- openerp/addons/base/res/res_partner.py | 6 ++++-- openerp/addons/base/tests/test_base.py | 12 +++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index d337b3c0a10..d66c69daaa7 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -619,12 +619,12 @@ class res_partner(osv.osv, format_address): query = ('''SELECT res_partner.id FROM res_partner LEFT JOIN res_partner company ON res_partner.parent_id = company.id''' - + where_str + ''' res_partner.email ''' + operator + ''' %s OR + + where_str + ''' (res_partner.email ''' + operator + ''' %s OR CASE WHEN company.id IS NULL OR res_partner.is_company THEN res_partner.name ELSE company.name || ', ' || res_partner.name - END ''' + operator + ''' %s + END ''' + operator + ''' %s) ORDER BY CASE WHEN company.id IS NULL OR res_partner.is_company @@ -641,6 +641,8 @@ class res_partner(osv.osv, format_address): if ids: return self.name_get(cr, uid, ids, context) + else: + return [] return super(res_partner,self).name_search(cr, uid, name, args, operator=operator, context=context, limit=limit) def find_or_create(self, cr, uid, email, context=None): diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py index 02ce3b09688..b1453b5e372 100644 --- a/openerp/addons/base/tests/test_base.py +++ b/openerp/addons/base/tests/test_base.py @@ -41,12 +41,18 @@ class test_base(common.TransactionCase): def test_15_res_partner_name_search(self): cr,uid = self.cr, self.uid - for text, name, mail in self.samples: - partner_id, dummy = self.res_partner.name_create(cr, uid, text) + for name, active in [ + ('"A Raoul Grosbedon" ', False), + ('ryu+giga-Sushi@aizubange.fukushima.jp', True), + ('Raoul chirurgiens-dentistes.fr', True), + (" Raoul O'hara ", True) + ]: + partner_id, dummy = self.res_partner.name_create(cr, uid, name, context={'default_active': active}) partners = self.res_partner.name_search(cr, uid, 'Raoul') - self.assertEqual(len(partners), 3, 'Incorrect search number result for name_search') + self.assertEqual(len(partners), 2, 'Incorrect search number result for name_search') partners = self.res_partner.name_search(cr, uid, 'Raoul', limit=1) self.assertEqual(len(partners), 1, 'Incorrect search number result for name_search with a limit') + self.assertEqual(partners[0][1], 'Raoul chirurgiens-dentistes.fr', 'Incorrect partner returned, should be the first active') def test_20_res_partner_address_sync(self): cr, uid = self.cr, self.uid From cb4ce12d3a4ce3ed53dfb3f19ce76744142d9eb0 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 29 Jan 2014 13:48:06 +0100 Subject: [PATCH 7/9] [IMP] make sure the records will be in right order (and trigger chirurgiens-dentistes.fr for the second name_search) bzr revid: mat@openerp.com-20140129124806-dq56o7r1yt38nb08 --- openerp/addons/base/tests/test_base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py index b1453b5e372..7403c884410 100644 --- a/openerp/addons/base/tests/test_base.py +++ b/openerp/addons/base/tests/test_base.py @@ -43,16 +43,16 @@ class test_base(common.TransactionCase): cr,uid = self.cr, self.uid for name, active in [ ('"A Raoul Grosbedon" ', False), + ('B Raoul chirurgiens-dentistes.fr', True), + ("C Raoul O'hara ", True), ('ryu+giga-Sushi@aizubange.fukushima.jp', True), - ('Raoul chirurgiens-dentistes.fr', True), - (" Raoul O'hara ", True) ]: partner_id, dummy = self.res_partner.name_create(cr, uid, name, context={'default_active': active}) partners = self.res_partner.name_search(cr, uid, 'Raoul') self.assertEqual(len(partners), 2, 'Incorrect search number result for name_search') partners = self.res_partner.name_search(cr, uid, 'Raoul', limit=1) self.assertEqual(len(partners), 1, 'Incorrect search number result for name_search with a limit') - self.assertEqual(partners[0][1], 'Raoul chirurgiens-dentistes.fr', 'Incorrect partner returned, should be the first active') + self.assertEqual(partners[0][1], 'B Raoul chirurgiens-dentistes.fr', 'Incorrect partner returned, should be the first active') def test_20_res_partner_address_sync(self): cr, uid = self.cr, self.uid From 3a07e0a012a6914a532dfba7072c2a65e0c3627a Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Wed, 29 Jan 2014 15:14:38 +0100 Subject: [PATCH 8/9] [FIX] attachement: display error message (removed inexistant template) and redraw the window (to avoid getting stucked) bzr revid: mat@openerp.com-20140129141438-3883hhzdiwyoo19t --- addons/web/static/src/js/views.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 21ff627c544..1c5850d6151 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -1217,7 +1217,8 @@ instance.web.Sidebar = instance.web.Widget.extend({ this.dataset = dataset; this.model_id = model_id; if (args && args[0].error) { - this.do_warn( instance.web.qweb.render('message_error_uploading'), args[0].error); + this.do_warn(_t('Upload Error'), args[0].error); + self.redraw(); } if (!model_id) { this.on_attachments_loaded([]); From 08dfda9ec677d11556d3a218cb04af6f799646a0 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 29 Jan 2014 17:32:38 +0100 Subject: [PATCH 9/9] [FIX] purchase: on po confirm, avoid to write location_id on the chained stock move if the move is done On purchase order confirmation, if the order_line comes from a procurement order created by a sale order, it tried to write on the location_id, whatever the move state was, even done. Or, sometimes, the stock move associated to the procurement order (from the so) was already done, for example because we forced the availability of the stock move. It makes sense to not write the location_id if the move is already done, because the location_id is already good. bzr revid: dle@openerp.com-20140129163238-1s1t9oc814z4z7f3 --- addons/purchase/purchase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 1cee51eb8dd..8102ef6b469 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -693,7 +693,7 @@ class purchase_order(osv.osv): continue if order_line.product_id.type in ('product', 'consu'): move = stock_move.create(cr, uid, self._prepare_order_line_move(cr, uid, order, order_line, picking_id, context=context)) - if order_line.move_dest_id: + if order_line.move_dest_id and order_line.move_dest_id.state != 'done': order_line.move_dest_id.write({'location_id': order.location_id.id}) todo_moves.append(move) stock_move.action_confirm(cr, uid, todo_moves)