[IMP] res_partner: default image and gravatar

Try to find the gravatar of partners based on their email. Better computation
of the default image.

The default image is not computed as a default anymore. Indeed due to the
color of the default avatar it is not possible to know if the user has changed
the partner iamge or not.

An onchange on the email field allow to search for the gravatar. If no image is
given when creating a partner, the values are updated with a default image
coming from the contact type, whether the partner is a company or has a parent
with an image.

Many thanks to Yti and Rim that are waiting for this task to use their fancy
gravatar.
This commit is contained in:
Deep Bundela
2015-11-26 16:47:30 +01:00
committed by Thibault Delavallée
parent 284d82623f
commit 66d4de7a0f
3 changed files with 47 additions and 10 deletions
+44 -10
View File
@@ -1,10 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details. # Part of Odoo. See LICENSE file for full copyright and licensing details.
import base64
import datetime import datetime
import hashlib
from lxml import etree from lxml import etree
import math import math
import pytz import pytz
import urllib2
import urlparse import urlparse
import openerp import openerp
@@ -14,6 +17,7 @@ from openerp.osv.expression import get_unaccent_wrapper
from openerp.tools.translate import _ from openerp.tools.translate import _
from openerp.exceptions import UserError from openerp.exceptions import UserError
ADDRESS_FORMAT_LAYOUTS = { ADDRESS_FORMAT_LAYOUTS = {
'%(city)s %(state_code)s\n%(zip)s': """ '%(city)s %(state_code)s\n%(zip)s': """
<div class="address_format"> <div class="address_format">
@@ -268,8 +272,7 @@ class res_partner(osv.Model, format_address):
# image: all image fields are base64 encoded and PIL-supported # image: all image fields are base64 encoded and PIL-supported
image = openerp.fields.Binary("Image", attachment=True, image = openerp.fields.Binary("Image", attachment=True,
help="This field holds the image used as avatar for this contact, limited to 1024x1024px", help="This field holds the image used as avatar for this contact, limited to 1024x1024px",)
default=lambda self: self._get_default_image(False, True))
image_medium = openerp.fields.Binary("Medium-sized image", image_medium = openerp.fields.Binary("Medium-sized image",
compute='_compute_images', inverse='_inverse_image_medium', store=True, attachment=True, compute='_compute_images', inverse='_inverse_image_medium', store=True, attachment=True,
help="Medium-sized image of this contact. It is automatically "\ help="Medium-sized image of this contact. It is automatically "\
@@ -301,14 +304,26 @@ class res_partner(osv.Model, format_address):
return [category_id] if category_id else False return [category_id] if category_id else False
@api.model @api.model
def _get_default_image(self, is_company, colorize=False): def _get_default_image(self, partner_type, is_company, parent_id):
img_path = openerp.modules.get_module_resource( colorize, img_path, image = False, False, False
'base', 'static/src/img', 'company_image.png' if is_company else 'avatar.png')
with open(img_path, 'rb') as f:
image = f.read()
# colorize user avatars if partner_type in ['contact', 'other'] and parent_id:
if not is_company: image = self.browse(parent_id).image.decode('base64')
if not image and partner_type == 'invoice':
img_path = openerp.modules.get_module_resource('base', 'static/src/img', 'money.png')
elif not image and partner_type == 'delivery':
img_path = openerp.modules.get_module_resource('base', 'static/src/img', 'truck.png')
elif not image and is_company:
img_path = openerp.modules.get_module_resource('base', 'static/src/img', 'company_image.png')
elif not image:
img_path = openerp.modules.get_module_resource('base', 'static/src/img', 'avatar.png')
colorize = True
if img_path:
with open(img_path, 'rb') as f:
image = f.read()
if image and colorize:
image = tools.image_colorize(image) image = tools.image_colorize(image)
return tools.image_resize_image_big(image.encode('base64')) return tools.image_resize_image_big(image.encode('base64'))
@@ -336,7 +351,6 @@ class res_partner(osv.Model, format_address):
'is_company': False, 'is_company': False,
'company_type': 'person', 'company_type': 'person',
'type': 'contact', 'type': 'contact',
'image': False,
} }
_constraints = [ _constraints = [
@@ -386,6 +400,11 @@ class res_partner(osv.Model, format_address):
return {'value': {'country_id': state.country_id.id}} return {'value': {'country_id': state.country_id.id}}
return {'value': {}} return {'value': {}}
@api.onchange('email')
def onchange_email(self):
if not self.image and not self.env.context.get('yaml_onchange') and self.email:
self.image = self._get_gravatar_image(self.email)
@api.multi @api.multi
def on_change_company_type(self, company_type): def on_change_company_type(self, company_type):
return {'value': {'is_company': company_type == 'company'}} return {'value': {'is_company': company_type == 'company'}}
@@ -545,6 +564,10 @@ class res_partner(osv.Model, format_address):
# migrating to the new API # migrating to the new API
c_type = vals.get('company_type', self._context.get('default_company_type')) c_type = vals.get('company_type', self._context.get('default_company_type'))
is_company = vals.get('is_company', self._context.get('default_is_company')) is_company = vals.get('is_company', self._context.get('default_is_company'))
# compute default image in create, because computing gravatar in the onchange
# cannot be easily performed if default images are in the way
if not vals.get('image'):
vals['image'] = self._get_default_image(vals.get('type'), vals.get('is_company'), vals.get('parent_id'))
if c_type: if c_type:
vals['is_company'] = c_type == 'company' vals['is_company'] = c_type == 'company'
else: else:
@@ -704,6 +727,17 @@ class res_partner(osv.Model, format_address):
return self.name_create(cr, uid, email, context=context)[0] return self.name_create(cr, uid, email, context=context)[0]
return ids[0] return ids[0]
def _get_gravatar_image(self, email):
gravatar_image = False
email_hash = hashlib.md5(email.lower()).hexdigest()
url = "https://www.gravatar.com/avatar/" + email_hash
try:
image_content = urllib2.urlopen(url + "?d=404&s=128", timeout=5).read()
gravatar_image = base64.b64encode(image_content)
except Exception:
pass
return gravatar_image
def _email_send(self, cr, uid, ids, email_from, subject, body, on_error=None): def _email_send(self, cr, uid, ids, email_from, subject, body, on_error=None):
partners = self.browse(cr, uid, ids) partners = self.browse(cr, uid, ids)
for partner in partners: for partner in partners:
@@ -299,6 +299,7 @@
<field name="supplier" invisible="True"/> <field name="supplier" invisible="True"/>
<field name="customer" invisible="True"/> <field name="customer" invisible="True"/>
<field name="lang" invisible="True"/> <field name="lang" invisible="True"/>
<field name="image" invisible="True"/>
</sheet> </sheet>
</form> </form>
</field> </field>
+2
View File
@@ -348,6 +348,7 @@ class YamlInterpreter(object):
:return: dictionary mapping the field names and their values, ready to use when calling the create() function :return: dictionary mapping the field names and their values, ready to use when calling the create() function
:rtype: dict :rtype: dict
""" """
class dotdict(dict): class dotdict(dict):
""" Dictionary class that allow to access a dictionary value by using '.'. This is needed to eval correctly """ Dictionary class that allow to access a dictionary value by using '.'. This is needed to eval correctly
statements like 'parent.fieldname' in context. statements like 'parent.fieldname' in context.
@@ -455,6 +456,7 @@ class YamlInterpreter(object):
if el.attrib['on_change'] in ('1', 'true'): if el.attrib['on_change'] in ('1', 'true'):
# New-style on_change # New-style on_change
self.context['yaml_onchange'] = True
recs = model.browse(self.cr, SUPERUSER_ID, [], self.context) recs = model.browse(self.cr, SUPERUSER_ID, [], self.context)
result = recs.onchange(record_dict, field_name, onchange_spec) result = recs.onchange(record_dict, field_name, onchange_spec)