From 332154444df450489ea01522bf1360c0446f91fb Mon Sep 17 00:00:00 2001 From: Samus CTO Date: Fri, 7 Nov 2014 16:11:15 +0100 Subject: [PATCH 01/24] [FIX] Can not search using a string operator on column id --- openerp/addons/test_impex/tests/test_load.py | 11 +++++------ openerp/osv/expression.py | 4 ---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/openerp/addons/test_impex/tests/test_load.py b/openerp/addons/test_impex/tests/test_load.py index d9cbd5b100a..2fcf6dc2ad6 100644 --- a/openerp/addons/test_impex/tests/test_load.py +++ b/openerp/addons/test_impex/tests/test_load.py @@ -642,12 +642,11 @@ class test_m2o(ImporterCase): @mute_logger('openerp.sql_db') def test_fail_id_mistype(self): result = self.import_(['value/.id'], [["foo"]]) - - self.assertEqual(result['messages'], [ - message(u"Invalid database id 'foo' for the field 'unknown'", - moreinfo=moreaction(res_model='ir.model.data', - domain=[('model','=','export.integer')])) - ]) + try: + int("foo") + except ValueError, exc: + expected_message = unicode(exc) + self.assertEqual(result['messages'], [message(expected_message)]) self.assertIs(result['ids'], False) def test_sub_field(self): diff --git a/openerp/osv/expression.py b/openerp/osv/expression.py index 0298bd3a90a..53ba5a2e8ae 100644 --- a/openerp/osv/expression.py +++ b/openerp/osv/expression.py @@ -1195,10 +1195,6 @@ class expression(object): query, params = self.__leaf_to_sql( create_substitution_leaf(eleaf, (left, '=', right), model)) - elif left == 'id': - query = '%s.id %s %%s' % (table_alias, operator) - params = right - else: need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike') sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator) From acd7d84da474eae3d64e0c5c6369c0dfb1deb395 Mon Sep 17 00:00:00 2001 From: Samus CTO Date: Wed, 7 Jan 2015 16:45:02 +0100 Subject: [PATCH 02/24] [IMP] make name_search() use '=' if col _rec_name is an integer When looking for an issue number, it's more useful to match the word in the whole string instead of just a part of it. --- openerp/models.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openerp/models.py b/openerp/models.py index 23c967e07f1..78b6aaaaf32 100644 --- a/openerp/models.py +++ b/openerp/models.py @@ -1707,7 +1707,7 @@ class BaseModel(object): return False @api.model - def name_search(self, name='', args=None, operator='ilike', limit=100): + def name_search(self, name='', args=None, operator=None, limit=100): """ name_search(name='', args=None, operator='ilike', limit=100) -> records Search for records that have a display name matching the given @@ -1733,7 +1733,7 @@ class BaseModel(object): """ return self._name_search(name, args, operator, limit=limit) - def _name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100, name_get_uid=None): + def _name_search(self, cr, user, name='', args=None, operator=None, context=None, limit=100, name_get_uid=None): # private implementation of name_search, allows passing a dedicated user # for the name_get part to solve some access rights issues args = list(args or []) @@ -1741,6 +1741,9 @@ class BaseModel(object): if not self._rec_name: _logger.warning("Cannot execute name_search, no _rec_name defined on %s", self._name) elif not (name == '' and operator == 'ilike'): + if operator is None: + field = self._fields[self._rec_name] + operator = ('=' if field.type == 'integer' else 'ilike') args += [(self._rec_name, operator, name)] access_rights_uid = name_get_uid or user ids = self._search(cr, user, args, limit=limit, context=context, access_rights_uid=access_rights_uid) From 0cbba7c222eca8a306f2ff042904e2a7fee187c7 Mon Sep 17 00:00:00 2001 From: qdp-odoo Date: Mon, 19 Jan 2015 15:23:59 +0100 Subject: [PATCH 03/24] [FIX] stock: display the pack operations in the same order than the stock move (if possible) --- addons/stock/stock.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 260b953f034..a9a56e7b4b2 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1084,6 +1084,7 @@ class stock_picking(osv.osv): # Create the necessary operations for the grouped quants and remaining qtys uom_obj = self.pool.get('product.uom') + prevals = {} for key, qty in qtys_grouped.items(): product = self.pool.get("product.product").browse(cr, uid, key[0], context=context) uom_id = product.uom_id.id @@ -1091,7 +1092,7 @@ class stock_picking(osv.osv): if product_uom.get(key[0]): uom_id = product_uom[key[0]].id qty_uom = uom_obj._compute_qty(cr, uid, product.uom_id.id, qty, uom_id) - vals.append({ + val_dict = { 'picking_id': picking.id, 'product_qty': qty_uom, 'product_id': key[0], @@ -1101,7 +1102,17 @@ class stock_picking(osv.osv): 'location_id': key[4], 'location_dest_id': key[5], 'product_uom_id': uom_id, - }) + } + if key[0] in prevals: + prevals[key[0]].append(val_dict) + else: + prevals[key[0]] = [val_dict] + # prevals var holds the operations in order to create them in the same order than the picking stock moves if possible + processed_products = set() + for move in picking.move_lines: + if move.product_id.id not in processed_products: + vals += prevals.get(move.product_id.id, []) + processed_products.add(move.product_id.id) return vals @api.cr_uid_ids_context From fb4c8220009d167c594acb93816014c48bed6cb2 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 20 Jan 2015 12:11:51 +0100 Subject: [PATCH 04/24] [FIX] account_asset: using attrs to hide method_* fields In order to hide fields method_number and method_period to hide them according to the asset, fields_view_get method was overriden. An issue was present: if a search view on model account.asset.asset was added, and did not contain these method_* fields, this overriden fields_view_get was applied, and tried to hide method_* fields, while they were not present in the search view, which leaded to a crash. I could have solved this the easy way, to not apply the invisbility if the fields were not present in the view, or if the view was something else than form, but I prefered to solve this the cleanest way. --- .../wizard/account_asset_change_duration.py | 39 +++++-------------- .../account_asset_change_duration_view.xml | 5 ++- 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/addons/account_asset/wizard/account_asset_change_duration.py b/addons/account_asset/wizard/account_asset_change_duration.py index 19782c76367..7b256e47391 100644 --- a/addons/account_asset/wizard/account_asset_change_duration.py +++ b/addons/account_asset/wizard/account_asset_change_duration.py @@ -27,43 +27,22 @@ class asset_modify(osv.osv_memory): _name = 'asset.modify' _description = 'Modify Asset' + def _get_asset_method_time(self, cr, uid, ids, field_name, arg, context=None): + if ids and len(ids) == 1 and context.get('active_id'): + asset = self.pool['account.asset.asset'].browse(cr, uid, context.get('active_id'), context=context) + return {ids[0]: asset.method_time} + else: + return dict.fromkeys(ids, False) + _columns = { 'name': fields.char('Reason', size=64, required=True), 'method_number': fields.integer('Number of Depreciations', required=True), 'method_period': fields.integer('Period Length'), 'method_end': fields.date('Ending date'), 'note': fields.text('Notes'), + 'asset_method_time': fields.function(_get_asset_method_time, type='char', string='Asset Method Time', readonly=True), } - def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): - """ Returns views and fields for current model. - @param cr: A database cursor - @param user: ID of the user currently logged in - @param view_id: list of fields, which required to read signatures - @param view_type: defines a view type. it can be one of (form, tree, graph, calender, gantt, search, mdx) - @param context: context arguments, like lang, time zone - @param toolbar: contains a list of reports, wizards, and links related to current model - - @return: Returns a dictionary that contains definition for fields, views, and toolbars - """ - if not context: - context = {} - asset_obj = self.pool.get('account.asset.asset') - result = super(asset_modify, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu) - asset_id = context.get('active_id', False) - active_model = context.get('active_model', '') - if active_model == 'account.asset.asset' and asset_id: - asset = asset_obj.browse(cr, uid, asset_id, context=context) - doc = etree.XML(result['arch']) - if asset.method_time == 'number': - node = doc.xpath("//field[@name='method_end']")[0] - node.set('invisible', '1') - elif asset.method_time == 'end': - node = doc.xpath("//field[@name='method_number']")[0] - node.set('invisible', '1') - result['arch'] = etree.tostring(doc) - return result - def default_get(self, cr, uid, fields, context=None): """ To get default values for the object. @param self: The object pointer. @@ -87,6 +66,8 @@ class asset_modify(osv.osv_memory): res.update({'method_period': asset.method_period}) if 'method_end' in fields and asset.method_time == 'end': res.update({'method_end': asset.method_end}) + if context.get('active_id'): + res['asset_method_time'] = self._get_asset_method_time(cr, uid, [0], 'asset_method_time', [], context=context)[0] return res def modify(self, cr, uid, ids, context=None): diff --git a/addons/account_asset/wizard/account_asset_change_duration_view.xml b/addons/account_asset/wizard/account_asset_change_duration_view.xml index bb848e6db5d..e7dd7e134fd 100644 --- a/addons/account_asset/wizard/account_asset_change_duration_view.xml +++ b/addons/account_asset/wizard/account_asset_change_duration_view.xml @@ -7,13 +7,14 @@ asset.modify
+ - + - +