[MERGE] Latest bugfixes from 6.1

bzr revid: odo@openerp.com-20120322150506-vo7r1k65phlotaa2
This commit is contained in:
Olivier Dony 2012-03-22 16:05:06 +01:00
commit 975c65860f
9 changed files with 100 additions and 52 deletions

View File

@ -1373,7 +1373,7 @@
<record id="INR" model="res.currency">
<field name="name">INR</field>
<field name="symbol">Rs</field>
<field name="symbol"></field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field name="company_id" ref="main_company"/>

View File

@ -22,6 +22,7 @@
from email.MIMEText import MIMEText
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.Charset import Charset
from email.Header import Header
from email.Utils import formatdate, make_msgid, COMMASPACE
from email import Encoders
@ -97,6 +98,26 @@ def encode_header(header_text):
return header_text_ascii if header_text_ascii\
else Header(header_text_utf8, 'utf-8')
def encode_header_param(param_text):
"""Returns an appropriate RFC2047 encoded representation of the given
header parameter value, suitable for direct assignation as the
param value (e.g. via Message.set_param() or Message.add_header())
RFC2822 assumes that headers contain only 7-bit characters,
so we ensure it is the case, using RFC2047 encoding when needed.
:param param_text: unicode or utf-8 encoded string with header value
:rtype: string
:return: if ``param_text`` represents a plain ASCII string,
return the same 7-bit string, otherwise returns an
ASCII string containing the RFC2047 encoded text.
"""
# For details see the encode_header() method that uses the same logic
if not param_text: return ""
param_text_utf8 = tools.ustr(param_text).encode('utf-8')
param_text_ascii = try_coerce_ascii(param_text_utf8)
return param_text_ascii if param_text_ascii\
else Charset('utf8').header_encode(param_text_utf8)
name_with_email_pattern = re.compile(r'("[^<@>]+")\s*<([^ ,<@]+@[^> ,]+)>')
address_pattern = re.compile(r'([^ ,<@]+@[^> ,]+)')
@ -309,7 +330,7 @@ class ir_mail_server(osv.osv):
msg['Cc'] = encode_rfc2822_address_header(COMMASPACE.join(email_cc))
if email_bcc:
msg['Bcc'] = encode_rfc2822_address_header(COMMASPACE.join(email_bcc))
msg['Date'] = formatdate(localtime=True)
msg['Date'] = formatdate()
# Custom headers may override normal headers or provide additional ones
for key, value in headers.iteritems():
msg[ustr(key).encode('utf-8')] = encode_header(value)
@ -334,14 +355,16 @@ class ir_mail_server(osv.osv):
if attachments:
for (fname, fcontent) in attachments:
filename_utf8 = ustr(fname).encode('utf-8')
filename_rfc2047 = encode_header_param(fname)
part = MIMEBase('application', "octet-stream")
# The default RFC2231 encoding of Message.add_header() works in Thunderbird but not GMail
# so we fix it by using RFC2047 encoding for the filename instead.
part.set_param('name', filename_rfc2047)
part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047)
part.set_payload(fcontent)
Encoders.encode_base64(part)
# Force RFC2231 encoding for attachment filename
# See email.message.Message.add_header doc
part.add_header('Content-Disposition', 'attachment',
filename=('utf-8',None,filename_utf8))
msg.attach(part)
return msg

View File

@ -404,7 +404,7 @@ class ir_values(osv.osv):
results[action['name']] = (action['id'], action['name'], action_def)
except except_orm, e:
continue
return results.values()
return sorted(results.values())
def _map_legacy_model_list(self, model_list, map_fn, merge_results=False):
"""Apply map_fn to the various models passed, according to

View File

@ -452,6 +452,7 @@ class module(osv.osv):
'sequence': terp.get('sequence', 100),
'application': terp.get('application', False),
'auto_install': terp.get('auto_install', False),
'icon': terp.get('icon', False),
}
# update the list of available packages

View File

@ -346,21 +346,35 @@ class res_partner_address(osv.osv):
def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=100):
if not args:
args=[]
if not context:
context={}
if context.get('contact_display', 'contact')=='partner ' or context.get('contact_display', 'contact')=='partner_address ' :
ids = self.search(cr, user, [('partner_id',operator,name)], limit=limit, context=context)
args = []
if context is None:
context = {}
if not name:
ids = self.search(cr, user, args, limit=limit, context=context)
elif context.get('contact_display', 'contact') == 'partner':
ids = self.search(cr, user, [('partner_id', operator, name)] + args, limit=limit, context=context)
else:
if not name:
ids = self.search(cr, user, args, limit=limit, context=context)
# first lookup zip code, as it is a common and efficient way to search on these data
ids = self.search(cr, user, [('zip', '=', name)] + args, limit=limit, context=context)
# then search on other fields:
if context.get('contact_display', 'contact') == 'partner_address':
fields = ['partner_id', 'name', 'country_id', 'city', 'street']
else:
ids = self.search(cr, user, [('zip','=',name)] + args, limit=limit, context=context)
if not ids:
ids = self.search(cr, user, [('city',operator,name)] + args, limit=limit, context=context)
if name:
ids += self.search(cr, user, [('name',operator,name)] + args, limit=limit, context=context)
ids += self.search(cr, user, [('partner_id',operator,name)] + args, limit=limit, context=context)
fields = ['name', 'country_id', 'city', 'street']
# Here we have to search the records that satisfy the domain:
# OR([[(f, operator, name)] for f in fields])) + args
# Searching on such a domain can be dramatically inefficient, due to the expansion made
# for field translations, and the handling of the disjunction by the DB engine itself.
# So instead, we search field by field until the search limit is reached.
while len(ids) < limit and fields:
f = fields.pop(0)
new_ids = self.search(cr, user, [(f, operator, name)] + args, limit=limit, context=context)
# extend ids with the ones in new_ids that are not in ids yet (and keep order)
old_ids = set(ids)
ids.extend([id for id in new_ids if id not in old_ids])
ids = ids[:limit]
return self.name_get(cr, user, ids, context=context)
def get_city(self, cr, uid, id):

View File

@ -35,8 +35,8 @@
<field name="name">user rule</field>
<field model="ir.model" name="model_id" ref="model_res_users"/>
<field eval="True" name="global"/>
<field name="domain_force">['|',('company_id.child_ids','child_of',[user.company_id.id]),('company_id','child_of',[user.company_id.id])]</field>
<field name="domain_force">[('company_ids','child_of',[user.company_id.id])]</field>
</record>
</data>
</data>
</openerp>

View File

@ -34,6 +34,9 @@ from service import security
from tools.translate import _
import openerp
import openerp.exceptions
from lxml import etree
from lxml.builder import E
_logger = logging.getLogger(__name__)
@ -743,29 +746,27 @@ class groups_view(osv.osv):
# and introduces the reified group fields
view = self.get_user_groups_view(cr, uid, context)
if view:
xml = u"""<?xml version="1.0" encoding="utf-8"?>
<!-- GENERATED AUTOMATICALLY BY GROUPS -->
<field name="groups_id" position="replace">
%s
%s
</field>
"""
xml1, xml2 = [], []
xml1.append('<separator string="%s" colspan="4"/>' % _('Applications'))
xml1.append(E.separator(string=_('Application'), colspan="4"))
for app, kind, gs in self.get_groups_by_application(cr, uid, context):
if kind == 'selection':
# application name with a selection field
field_name = name_selection_groups(map(int, gs))
xml1.append('<field name="%s"/>' % field_name)
xml1.append('<newline/>')
xml1.append(E.field(name=field_name))
xml1.append(E.newline())
else:
# application separator with boolean fields
app_name = app and app.name or _('Other')
xml2.append('<separator string="%s" colspan="4"/>' % app_name)
xml2.append(E.separator(string=app_name, colspan="4"))
for g in gs:
field_name = name_boolean_group(g.id)
xml2.append('<field name="%s"/>' % field_name)
view.write({'arch': xml % ('\n'.join(xml1), '\n'.join(xml2))})
xml2.append(E.field(name=field_name))
xml = E.field(*(xml1 + xml2), name="groups_id", position="replace")
xml.addprevious(etree.Comment("GENERATED AUTOMATICALLY BY GROUPS"))
xml_content = etree.tostring(xml, pretty_print=True, xml_declaration=True, encoding="utf-8")
view.write({'arch': xml_content})
return True
def get_user_groups_view(self, cr, uid, context=None):

View File

@ -173,6 +173,8 @@ class db(netsvc.ExportService):
raise Exception, e
def exp_drop(self, db_name):
if not self.exp_db_exist(db_name):
return False
openerp.modules.registry.RegistryManager.delete(db_name)
sql_db.close_db(db_name)
@ -180,6 +182,17 @@ class db(netsvc.ExportService):
cr = db.cursor()
cr.autocommit(True) # avoid transaction block
try:
# Try to terminate all other connections that might prevent
# dropping the database
try:
cr.execute("""SELECT pg_terminate_backend(procpid)
FROM pg_stat_activity
WHERE datname = %s AND
procpid != pg_backend_pid()""",
(db_name,))
except Exception:
pass
try:
cr.execute('DROP DATABASE "%s"' % db_name)
except Exception, e:

View File

@ -313,7 +313,8 @@ class graph(object):
self.order[level] = self.order[level]+1
for sec_end in self.transitions.get(node, []):
self.init_order(sec_end, self.result[sec_end]['x'])
if node!=sec_end:
self.init_order(sec_end, self.result[sec_end]['x'])
def order_heuristic(self):
@ -438,33 +439,27 @@ class graph(object):
l.reverse()
no = len(l)
if no%2==0:
first_half = l[no/2:]
factor = 1
else:
first_half = l[no/2+1:]
factor = 0
rest = no%2
first_half = l[no/2+rest:]
last_half = l[:no/2]
i=1
for child in first_half:
self.result[child]['y'] = mid_pos - (i - (factor * 0.5))
i += 1
for i, child in enumerate(first_half):
self.result[child]['y'] = mid_pos - (i+1 - (0 if rest else 0.5))
if self.transitions.get(child, False):
if last:
self.result[child]['y'] = last + len(self.transitions[child])/2 + 1
last = self.tree_order(child, last)
if no%2:
if rest:
mid_node = l[no/2]
self.result[mid_node]['y'] = mid_pos
if self.transitions.get((mid_node), False):
if last:
self.result[mid_node]['y'] = last + len(self.transitions[mid_node])/2 + 1
last = self.tree_order(mid_node)
if node!=mid_node:
last = self.tree_order(mid_node)
else:
if last:
self.result[mid_node]['y'] = last + 1
@ -474,13 +469,14 @@ class graph(object):
i=1
last_child = None
for child in last_half:
self.result[child]['y'] = mid_pos + (i - (factor * 0.5))
self.result[child]['y'] = mid_pos + (i - (0 if rest else 0.5))
last_child = child
i += 1
if self.transitions.get(child, False):
if last:
self.result[child]['y'] = last + len(self.transitions[child])/2 + 1
last = self.tree_order(child, last)
if node!=child:
last = self.tree_order(child, last)
if last_child:
last = self.result[last_child]['y']