diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py index 20382737529..89f935dc7a2 100644 --- a/openerp/addons/base/tests/test_base.py +++ b/openerp/addons/base/tests/test_base.py @@ -289,6 +289,7 @@ class test_base(common.TransactionCase): {'name': 'Alice', 'login': 'alice', 'color': 1, 'function': 'Friend'}, {'name': 'Bob', 'login': 'bob', 'color': 2, 'function': 'Friend'}, {'name': 'Eve', 'login': 'eve', 'color': 3, 'function': 'Eavesdropper'}, + {'name': 'Nab', 'login': 'nab', 'color': 2, 'function': '5$ Wrench'}, ]: self.res_users.create(cr, uid, user_data) @@ -298,6 +299,14 @@ class test_base(common.TransactionCase): self.assertIn('color', group_data, "Aggregated data for the column 'color' is not present in read_group return values") self.assertEqual(group_data['color'], 3, "Incorrect sum for aggregated data for the column 'color'") + groups_data = self.res_users.read_group(cr, uid, domain=[('login', 'in', ('alice', 'bob', 'eve'))], fields=['name', 'color'], groupby='name', orderby='name DESC, color asc') + self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field") + self.assertEqual([user['name'] for user in groups_data], ['Eve', 'Bob', 'Alice'], 'Incorrect ordering of the list') + + groups_data = self.res_users.read_group(cr, uid, domain=[('login', 'in', ('alice', 'bob', 'eve', 'nab'))], fields=['function', 'color'], groupby='function', orderby='color ASC') + self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field") + self.assertEqual(groups_data, sorted(groups_data, key=lambda x: x['color']), 'Incorrect ordering of the list') + class test_partner_recursion(common.TransactionCase): def setUp(self): diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 49c436c69d4..400f2c439ea 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1424,11 +1424,9 @@ class property(function): def _get_by_id(self, obj, cr, uid, prop_name, ids, context=None): prop = obj.pool.get('ir.property') vids = [obj._name + ',' + str(oid) for oid in ids] - def_id = self._field_get(cr, uid, obj._name, prop_name[0]) - company = obj.pool.get('res.company') - cid = company._company_default_get(cr, uid, obj._name, def_id, context=context) - domain = [('fields_id.model', '=', obj._name), ('fields_id.name', 'in', prop_name), ('company_id', '=', cid)] - #domain = prop._get_domain(cr, uid, prop_name, obj._name, context) + domain = [('fields_id.model', '=', obj._name), ('fields_id.name', 'in', prop_name)] + if context and context.get('company_id'): + domain += [('company_id', '=', context.get('company_id'))] if vids: domain = [('res_id', 'in', vids)] + domain return prop.search(cr, uid, domain, context=context) @@ -1438,7 +1436,12 @@ class property(function): if context is None: context = {} - nids = self._get_by_id(obj, cr, uid, [prop_name], [id], context) + def_id = self._field_get(cr, uid, obj._name, prop_name) + company = obj.pool.get('res.company') + cid = company._company_default_get(cr, uid, obj._name, def_id, context=context) + # TODO for trunk: add new parameter company_id to _get_by_id method + context_company = dict(context, company_id=cid) + nids = self._get_by_id(obj, cr, uid, [prop_name], [id], context_company) if nids: cr.execute('DELETE FROM ir_property WHERE id IN %s', (tuple(nids),)) @@ -1452,10 +1455,6 @@ class property(function): property_create = True if property_create: - def_id = self._field_get(cr, uid, obj._name, prop_name) - company = obj.pool.get('res.company') - cid = company._company_default_get(cr, uid, obj._name, def_id, - context=context) propdef = obj.pool.get('ir.model.fields').browse(cr, uid, def_id, context=context) prop = obj.pool.get('ir.property') diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index b8c4cad158d..377914c9c20 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -770,8 +770,6 @@ class BaseModel(object): (name_id, context['module'], 'ir.model', model_id) ) - cr.commit() - cr.execute("SELECT * FROM ir_model_fields WHERE model=%s", (self._name,)) cols = {} for rec in cr.dictfetchall(): @@ -838,7 +836,6 @@ class BaseModel(object): for key, val in vals.items(): if cols[k][key] != vals[key]: cr.execute('update ir_model_fields set field_description=%s where model=%s and name=%s', (vals['field_description'], vals['model'], vals['name'])) - cr.commit() cr.execute("""UPDATE ir_model_fields SET model_id=%s, field_description=%s, ttype=%s, relation=%s, select_level=%s, readonly=%s ,required=%s, selectable=%s, relation_field=%s, translate=%s, serialization_field_id=%s @@ -849,7 +846,6 @@ class BaseModel(object): vals['select_level'], bool(vals['readonly']), bool(vals['required']), bool(vals['selectable']), vals['relation_field'], bool(vals['translate']), vals['serialization_field_id'], vals['model'], vals['name'] )) break - cr.commit() # # Goal: try to apply inheritance at the instanciation level and @@ -2608,6 +2604,32 @@ class BaseModel(object): r['__fold'] = folded.get(r[groupby] and r[groupby][0], False) return result + def _read_group_generate_order_by(self, orderby, aggregated_fields, groupby, query): + """ + Generates the ORDER BY sql clause for the read group method. Adds the missing JOIN clause + to the query if order should be computed against m2o field. + :param orderby: the orderby definition in the form "%(field)s %(order)s" + :param aggregated_fields: list of aggregated fields in the query + :param groupby: the current groupby field name + :param query: the query object used to construct the query afterwards + """ + orderby_list = [] + ob = '' + for order_splits in orderby.split(','): + order_split = order_splits.split() + orderby_field = order_split[0] + orderby_dir = len(order_split) == 2 and order_split[1].upper() == 'ASC' and 'ASC' or 'DESC' + if orderby_field == groupby: + ob = self._generate_order_by(order_splits, query).replace('ORDER BY ', '') + orderby_list.append(ob) + elif orderby_field in aggregated_fields: + orderby_list.append('%s %s' % (orderby_field,orderby_dir)) + + if orderby_list: + return ' ORDER BY %s' % (','.join(orderby_list)), ob and ob.split()[0] or '' + else: + return '', '' + def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False): """ Get the list of records in list view grouped by the given ``groupby`` fields @@ -2713,6 +2735,12 @@ class BaseModel(object): qualified_field = self._inherits_join_calc(f, query) flist += "%s(%s) AS %s" % (group_operator, qualified_field, f) + order = orderby or groupby + orderby_clause = '' + ob = '' + if order: + orderby_clause, ob = self._read_group_generate_order_by(order, aggregated_fields, groupby, query) + gb = groupby and (' GROUP BY ' + qualified_groupby_field) or '' from_clause, where_clause, where_clause_params = query.get_sql() @@ -2723,20 +2751,21 @@ class BaseModel(object): offset_str = offset and ' offset %d' % offset or '' if len(groupby_list) < 2 and context.get('group_by_no_leaf'): group_count = '_' - cr.execute('SELECT min(%s.id) AS id, count(%s.id) AS %s_count' % (self._table, self._table, group_count) + (flist and ',') + flist + ' FROM ' + from_clause + where_clause + gb + limit_str + offset_str, where_clause_params) + cr.execute('SELECT min(%s.id) AS id, count(%s.id) AS %s_count' % (self._table, self._table, group_count) + (flist and ',') + flist + ' FROM ' + from_clause + where_clause + gb + (ob and ',') + ob + orderby_clause + limit_str + offset_str, where_clause_params) alldata = {} groupby = group_by - for r in cr.dictfetchall(): + + fetched_data = cr.dictfetchall() + + data_ids = [] + for r in fetched_data: for fld, val in r.items(): if val is None: r[fld] = False alldata[r['id']] = r + data_ids.append(r['id']) del r['id'] - order = orderby or groupby - data_ids = self.search(cr, uid, [('id', 'in', alldata.keys())], order=order, context=context) - # the IDs of records that have groupby field value = False or '' should be included too - data_ids += set(alldata.keys()).difference(data_ids) if groupby: data = self.read(cr, uid, data_ids, [groupby], context=context) diff --git a/openerp/service/db.py b/openerp/service/db.py index 395689947a5..c18bb7f6afb 100644 --- a/openerp/service/db.py +++ b/openerp/service/db.py @@ -333,7 +333,7 @@ def exp_list(document=False): cr.execute("select datname from pg_database where datdba=(select usesysid from pg_user where usename=%s) and datname not in %s order by datname", (db_user, templates_list)) else: cr.execute("select datname from pg_database where datname not in %s order by datname", (templates_list,)) - res = [str(name) for (name,) in cr.fetchall()] + res = [tools.ustr(name) for (name,) in cr.fetchall()] except Exception: res = [] finally: diff --git a/openerp/tests/test_fields.py b/openerp/tests/test_fields.py index 774bbf41fb2..cb05861d301 100644 --- a/openerp/tests/test_fields.py +++ b/openerp/tests/test_fields.py @@ -121,4 +121,62 @@ class TestRelatedField(common.TransactionCase): # restore res.partner fields self.partner._columns = old_columns -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + +class TestPropertyField(common.TransactionCase): + + def setUp(self): + super(TestPropertyField, self).setUp() + self.user = self.registry('res.users') + self.partner = self.registry('res.partner') + self.company = self.registry('res.company') + self.country = self.registry('res.country') + self.property = self.registry('ir.property') + self.imd = self.registry('ir.model.data') + + def test_1_property_multicompany(self): + cr, uid = self.cr, self.uid + + parent_company_id = self.imd.get_object_reference(cr, uid, 'base', 'main_company')[1] + country_be = self.imd.get_object_reference(cr, uid, 'base', 'be')[1] + country_fr = self.imd.get_object_reference(cr, uid, 'base', 'fr')[1] + group_partner_manager = self.imd.get_object_reference(cr, uid, 'base', 'group_partner_manager')[1] + group_multi_company = self.imd.get_object_reference(cr, uid, 'base', 'group_multi_company')[1] + + sub_company = self.company.create(cr, uid, {'name': 'MegaCorp', 'parent_id': parent_company_id}) + alice = self.user.create(cr, uid, {'name': 'Alice', + 'login':'alice', + 'email':'alice@youcompany.com', + 'company_id':parent_company_id, + 'company_ids':[(6, 0, [parent_company_id, sub_company])], + 'country_id':country_be, + 'groups_id': [(6, 0, [group_partner_manager, group_multi_company])] + }) + bob = self.user.create(cr, uid, {'name': 'Bob', + 'login':'bob', + 'email':'bob@megacorp.com', + 'company_id':sub_company, + 'company_ids':[(6, 0, [parent_company_id, sub_company])], + 'country_id':country_fr, + 'groups_id': [(6, 0, [group_partner_manager, group_multi_company])] + }) + + self.partner._columns = dict(self.partner._columns) + self.partner._columns.update({ + 'property_country': fields.property(type='many2one', relation="res.country", string="Country by company"), + }) + self.partner._all_columns.update({ + 'property_country': fields.column_info('property_country', self.partner._columns['property_country'], None, None, None), + }) + self.partner._field_create(cr) + + partner_id = self.partner.create(cr, alice, { + 'name': 'An International Partner', + 'email': 'partner@example.com', + 'company_id': parent_company_id, + }) + self.partner.write(cr, bob, [partner_id], {'property_country': country_fr}) + self.assertEqual(self.partner.browse(cr, bob, partner_id).property_country.id, country_fr, "Bob does not see the value he has set on the property field") + + self.partner.write(cr, alice, [partner_id], {'property_country': country_be}) + self.assertEqual(self.partner.browse(cr, alice, partner_id).property_country.id, country_be, "Alice does not see the value he has set on the property field") + self.assertEqual(self.partner.browse(cr, bob, partner_id).property_country.id, country_fr, "Changes made by Alice have overwritten Bob's value") diff --git a/openerp/tools/image.py b/openerp/tools/image.py index 5e5055f252d..196ace2da60 100644 --- a/openerp/tools/image.py +++ b/openerp/tools/image.py @@ -25,7 +25,7 @@ except ImportError: import StringIO from PIL import Image -from PIL import ImageOps +from PIL import ImageEnhance from random import randint # ---------------------------------------- @@ -81,8 +81,13 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file return base64_source if image.size != size: - # If you need faster thumbnails you may use use Image.NEAREST - image = ImageOps.fit(image, size, Image.ANTIALIAS) + # create a thumbnail: will resize and keep ratios, then sharpen for better looking result + image.thumbnail(size, Image.ANTIALIAS) + sharpener = ImageEnhance.Sharpness(image.convert('RGBA')) + resized_image = sharpener.enhance(2.0) + # create a transparent image for background and paste the image on it + image = Image.new('RGBA', size, (255, 255, 255, 0)) + image.paste(resized_image, ((size[0] - resized_image.size[0]) / 2, (size[1] - resized_image.size[1]) / 2)) if image.mode not in ["1", "L", "P", "RGB", "RGBA"]: image = image.convert("RGB")