X-Git-Url: http://git.inspyration.org/?a=blobdiff_plain;f=openerp%2Faddons%2Fbase%2Fres%2Fres_partner.py;h=41fbee1b78f2bb037637d8f74235aabe97ec4a4f;hb=c15f748be05b3709f5e16680569abdc2949468e2;hp=22cd4a8d66a7a44f7d42071532e33b5f91e73936;hpb=b00122ad995c1f0b80bf30dcd46580bef2422743;p=odoo%2Fodoo.git diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 22cd4a8..41fbee1 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -23,48 +23,47 @@ import datetime from lxml import etree import math import pytz -import re +import urlparse import openerp -from openerp import SUPERUSER_ID -from openerp import pooler, tools +from openerp import tools, api from openerp.osv import osv, fields from openerp.osv.expression import get_unaccent_wrapper from openerp.tools.translate import _ -from openerp.tools.yaml_import import is_comment + +ADDRESS_FORMAT_LAYOUTS = { + '%(city)s %(state_code)s\n%(zip)s': """ +
+ + +
+ +
+ """, + '%(zip)s %(city)s': """ +
+ + +
+ +
+ """, + '%(city)s\n%(state_name)s\n%(zip)s': """ +
+ + + +
+ """ +} + class format_address(object): - def fields_view_get_address(self, cr, uid, arch, context={}): - user_obj = self.pool.get('res.users') - fmt = user_obj.browse(cr, SUPERUSER_ID, uid, context).company_id.country_id - fmt = fmt and fmt.address_format - layouts = { - '%(city)s %(state_code)s\n%(zip)s': """ -
- - -
- -
- """, - '%(zip)s %(city)s': """ -
- - -
- -
- """, - '%(city)s\n%(state_name)s\n%(zip)s': """ -
- - - -
- """ - } - for k,v in layouts.items(): - if fmt and (k in fmt): + @api.model + def fields_view_get_address(self, arch): + fmt = self.env.user.company_id.country_id.address_format or '' + for k, v in ADDRESS_FORMAT_LAYOUTS.items(): + if k in fmt: doc = etree.fromstring(arch) for node in doc.xpath("//div[@class='address_format']"): tree = etree.fromstring(v) @@ -74,58 +73,58 @@ class format_address(object): return arch -def _tz_get(self,cr,uid, context=None): +@api.model +def _tz_get(self): # put POSIX 'Etc/*' entries at the end to avoid confusing users - see bug 1086728 return [(tz,tz) for tz in sorted(pytz.all_timezones, key=lambda tz: tz if not tz.startswith('Etc/') else '_')] -class res_partner_category(osv.osv): + +class res_partner_category(osv.Model): def name_get(self, cr, uid, ids, context=None): - """Return the categories' display name, including their direct - parent by default. - - :param dict context: the ``partner_category_display`` key can be - used to select the short version of the - category name (without the direct parent), - when set to ``'short'``. The default is - the long version.""" + """ Return the categories' display name, including their direct + parent by default. + + If ``context['partner_category_display']`` is ``'short'``, the short + version of the category name (without the direct parent) is used. + The default is the long version. + """ + if not isinstance(ids, list): + ids = [ids] if context is None: context = {} + if context.get('partner_category_display') == 'short': return super(res_partner_category, self).name_get(cr, uid, ids, context=context) - if isinstance(ids, (int, long)): - ids = [ids] - reads = self.read(cr, uid, ids, ['name', 'parent_id'], context=context) + res = [] - for record in reads: - name = record['name'] - if record['parent_id']: - name = record['parent_id'][1] + ' / ' + name - res.append((record['id'], name)) + for category in self.browse(cr, uid, ids, context=context): + names = [] + current = category + while current: + names.append(current.name) + current = current.parent_id + res.append((category.id, ' / '.join(reversed(names)))) return res - def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100): - if not args: - args = [] - if not context: - context = {} + @api.model + def name_search(self, name, args=None, operator='ilike', limit=100): + args = args or [] if name: # Be sure name_search is symetric to name_get name = name.split(' / ')[-1] - ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit, context=context) - else: - ids = self.search(cr, uid, args, limit=limit, context=context) - return self.name_get(cr, uid, ids, context) + args = [('name', operator, name)] + args + categories = self.search(args, limit=limit) + return categories.name_get() + @api.multi + def _name_get_fnc(self, field_name, arg): + return dict(self.name_get()) - def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None): - res = self.name_get(cr, uid, ids, context=context) - return dict(res) - - _description = 'Partner Categories' + _description = 'Partner Tags' _name = 'res.partner.category' _columns = { - 'name': fields.char('Category Name', required=True, size=64, translate=True), + 'name': fields.char('Category Name', required=True, translate=True), 'parent_id': fields.many2one('res.partner.category', 'Parent Category', select=True, ondelete='cascade'), 'complete_name': fields.function(_name_get_fnc, type="char", string='Full Name'), 'child_ids': fields.one2many('res.partner.category', 'parent_id', 'Child Categories'), @@ -144,29 +143,30 @@ class res_partner_category(osv.osv): _parent_order = 'name' _order = 'parent_left' + class res_partner_title(osv.osv): _name = 'res.partner.title' _order = 'name' _columns = { - 'name': fields.char('Title', required=True, size=46, translate=True), - 'shortcut': fields.char('Abbreviation', size=16, translate=True), - 'domain': fields.selection([('partner', 'Partner'), ('contact', 'Contact')], 'Domain', required=True, size=24) + 'name': fields.char('Title', required=True, translate=True), + 'shortcut': fields.char('Abbreviation', translate=True), + 'domain': fields.selection([('partner', 'Partner'), ('contact', 'Contact')], 'Domain', required=True) } _defaults = { 'domain': 'contact', } -def _lang_get(self, cr, uid, context=None): - lang_pool = self.pool.get('res.lang') - ids = lang_pool.search(cr, uid, [], context=context) - res = lang_pool.read(cr, uid, ids, ['code', 'name'], context) - return [(r['code'], r['name']) for r in res] + +@api.model +def _lang_get(self): + languages = self.env['res.lang'].search([]) + return [(language.code, language.name) for language in languages] # fields copy if 'use_parent_address' is checked ADDRESS_FIELDS = ('street', 'street2', 'zip', 'city', 'state_id', 'country_id') -POSTAL_ADDRESS_FIELDS = ADDRESS_FIELDS # deprecated, to remove after 7.0 -class res_partner(osv.osv, format_address): + +class res_partner(osv.Model, format_address): _description = 'Partner' _name = "res.partner" @@ -176,26 +176,23 @@ class res_partner(osv.osv, format_address): res[partner.id] = self._display_address(cr, uid, partner, context=context) return res - def _get_image(self, cr, uid, ids, name, args, context=None): - result = dict.fromkeys(ids, False) - for obj in self.browse(cr, uid, ids, context=context): - result[obj.id] = tools.image_get_resized_images(obj.image) - return result + @api.multi + def _get_tz_offset(self, name, args): + return dict( + (p.id, datetime.datetime.now(pytz.timezone(p.tz or 'GMT')).strftime('%z')) + for p in self) - def _get_tz_offset(self, cr, uid, ids, name, args, context=None): - result = dict.fromkeys(ids, False) - for obj in self.browse(cr, uid, ids, context=context): - result[obj.id] = datetime.datetime.now(pytz.timezone(obj.tz or 'GMT')).strftime('%z') - return result + @api.multi + def _get_image(self, name, args): + return dict((p.id, tools.image_get_resized_images(p.image)) for p in self) - def _set_image(self, cr, uid, id, name, value, args, context=None): - return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context) + @api.one + def _set_image(self, name, value, args): + return self.write({'image': tools.image_resize_image_big(value)}) - def _has_image(self, cr, uid, ids, name, args, context=None): - result = {} - for obj in self.browse(cr, uid, ids, context=context): - result[obj.id] = obj.image != False - return result + @api.multi + def _has_image(self, name, args): + return dict((p.id, bool(p.image)) for p in self) def _commercial_partner_compute(self, cr, uid, ids, name, args, context=None): """ Returns the partner that is considered the commercial @@ -209,18 +206,36 @@ class res_partner(osv.osv, format_address): result[partner.id] = current_partner.id return result - # indirection to avoid passing a copy of the overridable method when declaring the function field + def _display_name_compute(self, cr, uid, ids, name, args, context=None): + context = dict(context or {}) + context.pop('show_address', None) + context.pop('show_address_only', None) + context.pop('show_email', None) + return dict(self.name_get(cr, uid, ids, context=context)) + + # indirections to avoid passing a copy of the overridable method when declaring the function field _commercial_partner_id = lambda self, *args, **kwargs: self._commercial_partner_compute(*args, **kwargs) + _display_name = lambda self, *args, **kwargs: self._display_name_compute(*args, **kwargs) + + _commercial_partner_store_triggers = { + 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)], context=dict(active_test=False)), + ['parent_id', 'is_company'], 10) + } + _display_name_store_triggers = { + 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)], context=dict(active_test=False)), + ['parent_id', 'is_company', 'name'], 10) + } - _order = "name" + _order = "display_name" _columns = { - 'name': fields.char('Name', size=128, required=True, select=True), + 'name': fields.char('Name', required=True, select=True), + 'display_name': fields.function(_display_name, type='char', string='Name', store=_display_name_store_triggers, select=True), 'date': fields.date('Date', select=1), 'title': fields.many2one('res.partner.title', 'Title'), 'parent_id': fields.many2one('res.partner', 'Related Company', select=True), 'parent_name': fields.related('parent_id', 'name', type='char', readonly=True, string='Parent name'), - 'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts', domain=[('active','=',True)]), # force "active_test" domain to bypass _search() override - 'ref': fields.char('Reference', size=64, select=1), + 'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts', domain=[('active','=',True)]), # force "active_test" domain to bypass _search() override + 'ref': fields.char('Internal Reference', select=1), 'lang': fields.selection(_lang_get, 'Language', help="If the selected language is loaded in the system, all documents related to this contact will be printed in this language. If not, it will be English."), 'tz': fields.selection(_tz_get, 'Timezone', size=64, @@ -229,35 +244,33 @@ class res_partner(osv.osv, format_address): "that is otherwise used to pick and render date and time values: your computer's timezone."), 'tz_offset': fields.function(_get_tz_offset, type='char', size=5, string='Timezone offset', invisible=True), 'user_id': fields.many2one('res.users', 'Salesperson', help='The internal user that is in charge of communicating with this contact if any.'), - 'vat': fields.char('TIN', size=32, help="Tax Identification Number. Check the box if this contact is subjected to taxes. Used by the some of the legal statements."), + 'vat': fields.char('TIN', help="Tax Identification Number. Check the box if this contact is subjected to taxes. Used by the some of the legal statements."), 'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'), - 'website': fields.char('Website', size=64, help="Website of Partner or Company"), + 'website': fields.char('Website', help="Website of Partner or Company"), 'comment': fields.text('Notes'), 'category_id': fields.many2many('res.partner.category', id1='partner_id', id2='category_id', string='Tags'), 'credit_limit': fields.float(string='Credit Limit'), - 'ean13': fields.char('EAN13', size=13), + 'barcode': fields.char('Barcode', oldname='ean13'), 'active': fields.boolean('Active'), - 'customer': fields.boolean('Customer', help="Check this box if this contact is a customer."), - 'supplier': fields.boolean('Supplier', help="Check this box if this contact is a supplier. If it's not checked, purchase people will not see it when encoding a purchase order."), + 'customer': fields.boolean('Is a Customer', help="Check this box if this contact is a customer."), + 'supplier': fields.boolean('Is a Supplier', help="Check this box if this contact is a supplier. If it's not checked, purchase people will not see it when encoding a purchase order."), 'employee': fields.boolean('Employee', help="Check this box if this contact is an Employee."), - 'function': fields.char('Job Position', size=128), + 'function': fields.char('Job Position'), 'type': fields.selection([('default', 'Default'), ('invoice', 'Invoice'), ('delivery', 'Shipping'), ('contact', 'Contact'), ('other', 'Other')], 'Address Type', help="Used to select automatically the right address according to the context in sales and purchases documents."), - 'street': fields.char('Street', size=128), - 'street2': fields.char('Street2', size=128), - 'zip': fields.char('Zip', change_default=True, size=24), - 'city': fields.char('City', size=128), - 'state_id': fields.many2one("res.country.state", 'State'), - 'country_id': fields.many2one('res.country', 'Country'), - 'country': fields.related('country_id', type='many2one', relation='res.country', string='Country', - deprecated="This field will be removed as of OpenERP 7.1, use country_id instead"), - 'email': fields.char('Email', size=240), - 'phone': fields.char('Phone', size=64), - 'fax': fields.char('Fax', size=64), - 'mobile': fields.char('Mobile', size=64), - 'birthdate': fields.char('Birthdate', size=64), + 'street': fields.char('Street'), + 'street2': fields.char('Street2'), + 'zip': fields.char('Zip', size=24, change_default=True), + 'city': fields.char('City'), + 'state_id': fields.many2one("res.country.state", 'State', ondelete='restrict'), + 'country_id': fields.many2one('res.country', 'Country', ondelete='restrict'), + 'email': fields.char('Email'), + 'phone': fields.char('Phone'), + 'fax': fields.char('Fax'), + 'mobile': fields.char('Mobile'), + 'birthdate': fields.char('Birthdate'), 'is_company': fields.boolean('Is a Company', help="Check if the contact is a company, otherwise it is a person"), 'use_parent_address': fields.boolean('Use Company Address', help="Select this if you want to set company's address information for this contact"), # image: all image fields are base64 encoded and PIL-supported @@ -279,26 +292,25 @@ class res_partner(osv.osv, format_address): help="Small-sized image of this contact. It is automatically "\ "resized as a 64x64px image, with aspect ratio preserved. "\ "Use this field anywhere a small image is required."), - 'has_image': fields.function(_has_image, type="boolean"), + 'has_image': fields.function(_has_image, string="Has image", type="boolean"), 'company_id': fields.many2one('res.company', 'Company', select=1), 'color': fields.integer('Color Index'), 'user_ids': fields.one2many('res.users', 'partner_id', 'Users'), 'contact_address': fields.function(_address_display, type='char', string='Complete Address'), # technical field used for managing commercial fields - 'commercial_partner_id': fields.function(_commercial_partner_id, type='many2one', relation='res.partner', string='Commercial Entity') + 'commercial_partner_id': fields.function(_commercial_partner_id, type='many2one', relation='res.partner', string='Commercial Entity', store=_commercial_partner_store_triggers) } - def _default_category(self, cr, uid, context=None): - if context is None: - context = {} - if context.get('category_id'): - return [context['category_id']] - return False + @api.model + def _default_category(self): + category_id = self.env.context.get('category_id', False) + return [category_id] if category_id else False - def _get_default_image(self, cr, uid, is_company, context=None, colorize=False): - img_path = openerp.modules.get_module_resource('base', 'static/src/img', - ('company_image.png' if is_company else 'avatar.png')) + @api.model + def _get_default_image(self, is_company, colorize=False): + img_path = openerp.modules.get_module_resource( + 'base', 'static/src/img', 'company_image.png' if is_company else 'avatar.png') with open(img_path, 'rb') as f: image = f.read() @@ -310,19 +322,23 @@ class res_partner(osv.osv, format_address): def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): if (not view_id) and (view_type=='form') and context and context.get('force_email', False): - view_id = self.pool.get('ir.model.data').get_object_reference(cr, user, 'base', 'view_partner_simple_form')[1] + view_id = self.pool['ir.model.data'].get_object_reference(cr, user, 'base', 'view_partner_simple_form')[1] res = super(res_partner,self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu) if view_type == 'form': res['arch'] = self.fields_view_get_address(cr, user, res['arch'], context=context) return res + @api.model + def _default_company(self): + return self.env['res.company']._company_default_get('res.partner') + _defaults = { 'active': True, - 'lang': lambda self, cr, uid, ctx: ctx.get('lang', 'en_US'), - 'tz': lambda self, cr, uid, ctx: ctx.get('tz', False), + 'lang': api.model(lambda self: self.env.lang), + 'tz': api.model(lambda self: self.env.context.get('tz', False)), 'customer': True, 'category_id': _default_category, - 'company_id': lambda self, cr, uid, ctx: self.pool.get('res.company')._company_default_get(cr, uid, 'res.partner', context=ctx), + 'company_id': _default_company, 'color': 0, 'is_company': False, 'type': 'contact', # type 'default' is wildcard and thus inappropriate @@ -334,16 +350,15 @@ class res_partner(osv.osv, format_address): (osv.osv._check_recursion, 'You cannot create recursive Partner hierarchies.', ['parent_id']), ] - def copy(self, cr, uid, id, default=None, context=None): - if default is None: - default = {} - name = self.read(cr, uid, [id], ['name'], context)[0]['name'] - default.update({'name': _('%s (copy)') % name}) - return super(res_partner, self).copy(cr, uid, id, default, context) + @api.one + def copy(self, default=None): + default = dict(default or {}) + default['name'] = _('%s (copy)') % self.name + return super(res_partner, self).copy(default) - def onchange_type(self, cr, uid, ids, is_company, context=None): - value = {} - value['title'] = False + @api.multi + def onchange_type(self, is_company): + value = {'title': False} if is_company: value['use_parent_address'] = False domain = {'title': [('domain', '=', 'partner')]} @@ -373,43 +388,26 @@ class res_partner(osv.osv, format_address): result['value'] = {'use_parent_address': False} return result - def onchange_state(self, cr, uid, ids, state_id, context=None): + @api.multi + def onchange_state(self, state_id): if state_id: - country_id = self.pool.get('res.country.state').browse(cr, uid, state_id, context).country_id.id - return {'value':{'country_id':country_id}} + state = self.env['res.country.state'].browse(state_id) + return {'value': {'country_id': state.country_id.id}} return {} - def _check_ean_key(self, cr, uid, ids, context=None): - for partner_o in pooler.get_pool(cr.dbname).get('res.partner').read(cr, uid, ids, ['ean13',]): - thisean=partner_o['ean13'] - if thisean and thisean!='': - if len(thisean)!=13: - return False - sum=0 - for i in range(12): - if not (i % 2): - sum+=int(thisean[i]) - else: - sum+=3*int(thisean[i]) - if math.ceil(sum/10.0)*10-sum!=int(thisean[12]): - return False - return True - -# _constraints = [(_check_ean_key, 'Error: Invalid ean code', ['ean13'])] - def _update_fields_values(self, cr, uid, partner, fields, context=None): """ Returns dict of write() values for synchronizing ``fields`` """ values = {} - for field in fields: - column = self._all_columns[field].column - if column._type == 'one2many': + for fname in fields: + field = self._fields[fname] + if field.type == 'one2many': raise AssertionError('One2Many fields cannot be synchronized as part of `commercial_fields` or `address fields`') - if column._type == 'many2one': - values[field] = partner[field].id if partner[field] else False - elif column._type == 'many2many': - values[field] = [(6,0,[r.id for r in partner[field] or []])] + if field.type == 'many2one': + values[fname] = partner[fname].id if partner[fname] else False + elif field.type == 'many2many': + values[fname] = [(6,0,[r.id for r in partner[fname] or []])] else: - values[field] = partner[field] + values[fname] = partner[fname] return values def _address_fields(self, cr, uid, context=None): @@ -508,30 +506,52 @@ class res_partner(osv.osv, format_address): if not parent.is_company: parent.write({'is_company': True}) - def write(self, cr, uid, ids, vals, context=None): - if isinstance(ids, (int, long)): - ids = [ids] - #res.partner must only allow to set the company_id of a partner if it - #is the same as the company of all users that inherit from this partner - #(this is to allow the code from res_users to write to the partner!) or - #if setting the company_id to False (this is compatible with any user company) + def unlink(self, cr, uid, ids, context=None): + orphan_contact_ids = self.search(cr, uid, + [('parent_id', 'in', ids), ('id', 'not in', ids), ('use_parent_address', '=', True)], context=context) + if orphan_contact_ids: + # no longer have a parent address + self.write(cr, uid, orphan_contact_ids, {'use_parent_address': False}, context=context) + return super(res_partner, self).unlink(cr, uid, ids, context=context) + + def _clean_website(self, website): + (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(website) + if not scheme: + if not netloc: + netloc, path = path, '' + website = urlparse.urlunparse(('http', netloc, path, params, query, fragment)) + return website + + @api.multi + def write(self, vals): + # res.partner must only allow to set the company_id of a partner if it + # is the same as the company of all users that inherit from this partner + # (this is to allow the code from res_users to write to the partner!) or + # if setting the company_id to False (this is compatible with any user + # company) + if vals.get('website'): + vals['website'] = self._clean_website(vals['website']) if vals.get('company_id'): - for partner in self.browse(cr, uid, ids, context=context): + company = self.env['res.company'].browse(vals['company_id']) + for partner in self: if partner.user_ids: - user_companies = set([user.company_id.id for user in partner.user_ids]) - if len(user_companies) > 1 or vals['company_id'] not in user_companies: + companies = set(user.company_id for user in partner.user_ids) + if len(companies) > 1 or company not in companies: raise osv.except_osv(_("Warning"),_("You can not change the company as the partner/user has multiple user linked with different companies.")) - result = super(res_partner,self).write(cr, uid, ids, vals, context=context) - for partner in self.browse(cr, uid, ids, context=context): - self._fields_sync(cr, uid, partner, vals, context) + + result = super(res_partner, self).write(vals) + for partner in self: + self._fields_sync(partner, vals) return result - def create(self, cr, uid, vals, context=None): - new_id = super(res_partner, self).create(cr, uid, vals, context=context) - partner = self.browse(cr, uid, new_id, context=context) - self._fields_sync(cr, uid, partner, vals, context) - self._handle_first_contact_creation(cr, uid, partner, context) - return new_id + @api.model + def create(self, vals): + if vals.get('website'): + vals['website'] = self._clean_website(vals['website']) + partner = super(res_partner, self).create(vals) + self._fields_sync(partner, vals) + self._handle_first_contact_creation(partner) + return partner def open_commercial_entity(self, cr, uid, ids, context=None): """ Utility method used to add an "Open Company" button in partner views """ @@ -563,10 +583,12 @@ class res_partner(osv.osv, format_address): name = record.name if record.parent_id and not record.is_company: name = "%s, %s" % (record.parent_name, name) + if context.get('show_address_only'): + name = self._display_address(cr, uid, record, without_company=True, context=context) if context.get('show_address'): name = name + "\n" + self._display_address(cr, uid, record, without_company=True, context=context) - name = name.replace('\n\n','\n') - name = name.replace('\n\n','\n') + name = name.replace('\n\n','\n') + name = name.replace('\n\n','\n') if context.get('show_email') and record.email: name = "%s <%s>" % (name, record.email) res.append((record.id, name)) @@ -605,7 +627,8 @@ class res_partner(osv.osv, format_address): """ Override search() to always show inactive children when searching via ``child_of`` operator. The ORM will always call search() with a simple domain of the form [('parent_id', 'in', [ids])]. """ # a special ``domain`` is set on the ``child_ids`` o2m to bypass this logic, as it uses similar domain expressions - if len(args) == 1 and len(args[0]) == 3 and args[0][:2] == ('parent_id','in'): + if len(args) == 1 and len(args[0]) == 3 and args[0][:2] == ('parent_id','in') \ + and args[0][2] != [False]: context = dict(context or {}, active_test=False) return super(res_partner, self)._search(cr, user, args, offset=offset, limit=limit, order=order, context=context, count=count, access_rights_uid=access_rights_uid) @@ -630,30 +653,15 @@ class res_partner(osv.osv, format_address): unaccent = get_unaccent_wrapper(cr) - # 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. - - display_name = """CASE WHEN company.id IS NULL OR res_partner.is_company - THEN {partner_name} - ELSE {company_name} || ', ' || {partner_name} - END""".format(partner_name=unaccent('res_partner.name'), - company_name=unaccent('company.name')) - - query = """SELECT res_partner.id + query = """SELECT id FROM res_partner - LEFT JOIN res_partner company - ON res_partner.parent_id = company.id {where} ({email} {operator} {percent} OR {display_name} {operator} {percent}) ORDER BY {display_name} """.format(where=where_str, operator=operator, - email=unaccent('res_partner.email'), - percent=unaccent('%s'), - display_name=display_name) + email=unaccent('email'), + display_name=unaccent('display_name'), + percent=unaccent('%s')) where_clause_params += [search_name, search_name] if limit: @@ -692,7 +700,7 @@ class res_partner(osv.osv, format_address): def email_send(self, cr, uid, ids, email_from, subject, body, on_error=''): while len(ids): - self.pool.get('ir.cron').create(cr, uid, { + self.pool['ir.cron'].create(cr, uid, { 'name': 'Send Partner Emails', 'user_id': uid, 'model': 'res.partner', @@ -745,16 +753,13 @@ class res_partner(osv.osv, format_address): if res: return res if not context.get('category_id', False): return False - return _('Partners: ')+self.pool.get('res.partner.category').browse(cr, uid, context['category_id'], context).name + return _('Partners: ')+self.pool['res.partner.category'].browse(cr, uid, context['category_id'], context).name - def main_partner(self, cr, uid): - ''' Return the id of the main partner - ''' - model_data = self.pool.get('ir.model.data') - return model_data.browse(cr, uid, - model_data.search(cr, uid, [('module','=','base'), - ('name','=','main_partner')])[0], - ).res_id + @api.model + @api.returns('self') + def main_partner(self): + ''' Return the main partner ''' + return self.env.ref('base.main_partner') def _display_address(self, cr, uid, address, without_company=False, context=None): @@ -770,14 +775,14 @@ class res_partner(osv.osv, format_address): # get the information that will be injected into the display format # get the address format - address_format = address.country_id and address.country_id.address_format or \ + address_format = address.country_id.address_format or \ "%(street)s\n%(street2)s\n%(city)s %(state_code)s %(zip)s\n%(country_name)s" args = { - 'state_code': address.state_id and address.state_id.code or '', - 'state_name': address.state_id and address.state_id.name or '', - 'country_code': address.country_id and address.country_id.code or '', - 'country_name': address.country_id and address.country_id.name or '', - 'company_name': address.parent_id and address.parent_name or '', + 'state_code': address.state_id.code or '', + 'state_name': address.state_id.name or '', + 'country_code': address.country_id.code or '', + 'country_name': address.country_id.name or '', + 'company_name': address.parent_name or '', } for field in self._address_fields(cr, uid, context=context): args[field] = getattr(address, field) or ''