diff --git a/addons/account/report/account_invoice_report_view.xml b/addons/account/report/account_invoice_report_view.xml
index 66e17560bde..ed3649c300a 100644
--- a/addons/account/report/account_invoice_report_view.xml
+++ b/addons/account/report/account_invoice_report_view.xml
@@ -28,8 +28,7 @@
-
-
+
diff --git a/addons/account_asset/account_asset_demo.xml b/addons/account_asset/account_asset_demo.xml
index f81f3b7a63a..5b1a4b03be6 100644
--- a/addons/account_asset/account_asset_demo.xml
+++ b/addons/account_asset/account_asset_demo.xml
@@ -48,7 +48,7 @@
- 2014-08-11
+ endV6 Engine and 10 inches tires
@@ -63,7 +63,7 @@
open
- 2012-01-01
+ Office
diff --git a/addons/account_followup/account_followup.py b/addons/account_followup/account_followup.py
index 6587fbfd9d9..9821030df0b 100644
--- a/addons/account_followup/account_followup.py
+++ b/addons/account_followup/account_followup.py
@@ -280,19 +280,29 @@ class res_partner(osv.osv):
def do_button_print(self, cr, uid, ids, context=None):
assert(len(ids) == 1)
+ company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
+ #search if the partner has accounting entries to print. If not, it may not be present in the
+ #psql view the report is based on, so we need to stop the user here.
+ if not self.pool.get('account.move.line').search(cr, uid, [
+ ('partner_id', '=', ids[0]),
+ ('account_id.type', '=', 'receivable'),
+ ('reconcile_id', '=', False),
+ ('state', '!=', 'draft'),
+ ('company_id', '=', company_id),
+ ], context=context):
+ raise osv.except_osv(_('Error!'),_("The partner does not have any accounting entries to print in the overdue report for the current company."))
self.message_post(cr, uid, [ids[0]], body=_('Printed overdue payments report'), context=context)
- datas = {
- 'ids': ids,
- 'model': 'res.partner',
- 'form': self.read(cr, uid, ids[0], context=context)
+ #build the id of this partner in the psql view. Could be replaced by a search with [('company_id', '=', company_id),('partner_id', '=', ids[0])]
+ wizard_partner_ids = [ids[0] * 10000 + company_id]
+ followup_ids = self.pool.get('account_followup.followup').search(cr, uid, [('company_id', '=', company_id)], context=context)
+ if not followup_ids:
+ raise osv.except_osv(_('Error!'),_("There is no followup plan defined for the current company."))
+ data = {
+ 'date': fields.date.today(),
+ 'followup_id': followup_ids[0],
}
- return {
- 'type': 'ir.actions.report.xml',
- 'report_name': 'account.overdue',
- 'datas': datas,
- 'nodestroy' : True
- }
-
+ #call the print overdue report on this partner
+ return self.do_partner_print(cr, uid, wizard_partner_ids, data, context=context)
def _get_amounts_and_date(self, cr, uid, ids, name, arg, context=None):
'''
diff --git a/addons/account_followup/account_followup_view.xml b/addons/account_followup/account_followup_view.xml
index 5560ca822dc..e233feb489e 100644
--- a/addons/account_followup/account_followup_view.xml
+++ b/addons/account_followup/account_followup_view.xml
@@ -123,24 +123,10 @@
-
-
diff --git a/addons/account_followup/report/account_followup_print.py b/addons/account_followup/report/account_followup_print.py
index 0343fe023f9..16d88d69572 100644
--- a/addons/account_followup/report/account_followup_print.py
+++ b/addons/account_followup/report/account_followup_print.py
@@ -79,24 +79,29 @@ class report_rappel(report_sxw.rml_parse):
def _get_text(self, stat_line, followup_id, context=None):
if context is None:
context = {}
+ context.update({'lang': stat_line.partner_id.lang})
fp_obj = pooler.get_pool(self.cr.dbname).get('account_followup.followup')
- fp_line = fp_obj.browse(self.cr, self.uid, followup_id).followup_line
+ fp_line = fp_obj.browse(self.cr, self.uid, followup_id, context=context).followup_line
+ if not fp_line:
+ raise osv.except_osv(_('Error!'),_("The followup plan defined for the current company does not have any followup action."))
+ #the default text will be the first fp_line in the sequence with a description.
+ default_text = ''
li_delay = []
for line in fp_line:
+ if not default_text and line.description:
+ default_text = line.description
li_delay.append(line.delay)
li_delay.sort(reverse=True)
- text = ""
a = {}
- partner_line_ids = pooler.get_pool(self.cr.dbname).get('account.move.line').search(self.cr, self.uid, [('partner_id','=',stat_line.partner_id.id),('reconcile_id','=',False),('company_id','=',stat_line.company_id.id),('blocked','=',False)])
- partner_delay = []
- context.update({'lang': stat_line.partner_id.lang})
- for i in pooler.get_pool(self.cr.dbname).get('account.move.line').browse(self.cr, self.uid, partner_line_ids, context):
- for delay in li_delay:
- if i.followup_line_id and str(i.followup_line_id.delay)==str(delay):
- text = i.followup_line_id.description
- a[delay] = text
- partner_delay.append(delay)
- text = partner_delay and a[max(partner_delay)] or ''
+ #look into the lines of the partner that already have a followup level, and take the description of the higher level for which it is available
+ partner_line_ids = pooler.get_pool(self.cr.dbname).get('account.move.line').search(self.cr, self.uid, [('partner_id','=',stat_line.partner_id.id),('reconcile_id','=',False),('company_id','=',stat_line.company_id.id),('blocked','=',False),('state','!=','draft'),('debit','!=',False),('account_id.type','=','receivable'),('followup_line_id','!=',False)])
+ partner_max_delay = 0
+ partner_max_text = ''
+ for i in pooler.get_pool(self.cr.dbname).get('account.move.line').browse(self.cr, self.uid, partner_line_ids, context=context):
+ if i.followup_line_id.delay > partner_max_delay and i.followup_line_id.description:
+ partner_max_delay = i.followup_line_id.delay
+ partner_max_text = i.followup_line_id.description
+ text = partner_max_delay and partner_max_text or default_text
if text:
text = text % {
'partner_name': stat_line.partner_id.name,
diff --git a/addons/account_followup/test/account_followup.yml b/addons/account_followup/test/account_followup.yml
index 54dd3280984..ceb7ec2ea9b 100644
--- a/addons/account_followup/test/account_followup.yml
+++ b/addons/account_followup/test/account_followup.yml
@@ -3,7 +3,7 @@
-
!record {model: account.invoice, id: account.demo_invoice_0}:
check_total: 14.0
- date_invoice: 2012-06-2
+ date_invoice: !eval "'%s-06-2' %(datetime.now().year)"
invoice_line:
- account_id : account.a_sale
name: 'Test PC'
diff --git a/addons/account_voucher/account_voucher_data.xml b/addons/account_voucher/account_voucher_data.xml
index adfd6c8f228..440d1c5814a 100644
--- a/addons/account_voucher/account_voucher_data.xml
+++ b/addons/account_voucher/account_voucher_data.xml
@@ -17,7 +17,7 @@
Status Changeaccount.voucher
- Status <b>changed</b>
+ Status changed
diff --git a/addons/analytic/analytic_data.xml b/addons/analytic/analytic_data.xml
index 51c9d1471e0..26eb5ae3dd5 100644
--- a/addons/analytic/analytic_data.xml
+++ b/addons/analytic/analytic_data.xml
@@ -6,17 +6,17 @@
Contract to Renewaccount.analytic.account
- Contract <b>pending</b>
+ Contract pendingContract Finishedaccount.analytic.account
- Contract <b>closed</b>
+ Contract closedContract Openedaccount.analytic.account
- Stage <b>opened</b>
+ Contract opened
diff --git a/addons/auth_openid/controllers/main.py b/addons/auth_openid/controllers/main.py
index be59b9ae5b5..1fcc34c82a0 100644
--- a/addons/auth_openid/controllers/main.py
+++ b/addons/auth_openid/controllers/main.py
@@ -46,7 +46,18 @@ oidutil.log = _logger.debug
def get_system_user():
"""Return system user info string, such as USERNAME-EUID"""
- info = getpass.getuser()
+ try:
+ info = getpass.getuser()
+ except ImportError:
+ if os.name == 'nt':
+ # when there is no 'USERNAME' in environment, getpass.getuser()
+ # fail when trying to import 'pwd' module - which is unix only.
+ # In that case we have to fallback to real win32 API.
+ import win32api
+ info = win32api.GetUserName()
+ else:
+ raise
+
euid = getattr(os, 'geteuid', None) # Non available on some platforms
if euid is not None:
info = '%s-%d' % (info, euid())
diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py
index 233b3be6853..5c558ca68d7 100644
--- a/addons/auth_signup/res_users.py
+++ b/addons/auth_signup/res_users.py
@@ -252,12 +252,19 @@ class res_users(osv.Model):
raise osv.except_osv(_("Cannot send email: user has no email address."), user.name)
mail_id = self.pool.get('email.template').send_mail(cr, uid, template.id, user.id, True, context=context)
mail_state = mail_obj.read(cr, uid, mail_id, ['state'], context=context)
- if mail_state and mail_state == 'exception':
+ if mail_state and mail_state['state'] == 'exception':
raise osv.except_osv(_("Cannot send email: no outgoing email server configured.\nYou can configure it under Settings/General Settings."), user.name)
else:
- raise osv.except_osv(_("Mail sent to:"), user.email)
-
- return True
+ return {
+ 'type': 'ir.actions.client',
+ 'name': '_(Server Notification)',
+ 'tag': 'action_notify',
+ 'params': {
+ 'title': 'Mail Sent to: %s' % user.name,
+ 'text': 'You can reset the password by yourself using this link' % user.partner_id.signup_url,
+ 'sticky': True,
+ }
+ }
def create(self, cr, uid, values, context=None):
# overridden to automatically invite user to sign up
diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py
index a06bfd485bb..ab0d8d324b4 100644
--- a/addons/base_calendar/base_calendar.py
+++ b/addons/base_calendar/base_calendar.py
@@ -142,7 +142,7 @@ html_invitation = """
You are invited for %(company)s Event.
-
Below are the details of event:
+
Below are the details of event. Hours and dates expressed in %(timezone)s time.
@@ -427,12 +427,9 @@ property or property parameter."),
res = None
def ics_datetime(idate, short=False):
if idate:
- if short or len(idate)<=10:
- return date.fromtimestamp(time.mktime(time.strptime(idate, '%Y-%m-%d')))
- else:
- return datetime.strptime(idate, '%Y-%m-%d %H:%M:%S')
- else:
- return False
+ #returns the datetime as UTC, because it is stored as it in the database
+ return datetime.strptime(idate, '%Y-%m-%d %H:%M:%S').replace(tzinfo=pytz.timezone('UTC'))
+ return False
try:
# FIXME: why isn't this in CalDAV?
import vobject
@@ -516,9 +513,17 @@ property or property parameter."),
att_infos.append(((att2.user_id and att2.user_id.name) or \
(att2.partner_id and att2.partner_id.name) or \
att2.email) + ' - Status: ' + att2.state.title())
+ #dates and times are gonna be expressed in `tz` time (local timezone of the `uid`)
+ tz = context.get('tz', pytz.timezone('UTC'))
+ #res_obj.date and res_obj.date_deadline are in UTC in database so we use context_timestamp() to transform them in the `tz` timezone
+ date_start = fields.datetime.context_timestamp(cr, uid, datetime.strptime(res_obj.date, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context)
+ date_stop = False
+ if res_obj.date_deadline:
+ date_stop = fields.datetime.context_timestamp(cr, uid, datetime.strptime(res_obj.date_deadline, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context)
body_vals = {'name': res_obj.name,
- 'start_date': res_obj.date,
- 'end_date': res_obj.date_deadline or False,
+ 'start_date': date_start,
+ 'end_date': date_stop,
+ 'timezone': tz,
'description': res_obj.description or '-',
'location': res_obj.location or '-',
'attendees': ' '.join(att_infos),
@@ -623,7 +628,7 @@ property or property parameter."),
email = filter(lambda x:x.__contains__('@'), cnval)
vals['email'] = email and email[0] or ''
vals['cn'] = vals.get("cn")
- res = super(calendar_attendee, self).create(cr, uid, vals, context)
+ res = super(calendar_attendee, self).create(cr, uid, vals, context=context)
return res
calendar_attendee()
@@ -842,7 +847,7 @@ class calendar_alarm(osv.osv):
current_datetime = datetime.now()
alarm_ids = self.search(cr, uid, [('state', '!=', 'done')], context=context)
- mail_to = []
+ mail_to = ""
for alarm in self.browse(cr, uid, alarm_ids, context=context):
next_trigger_date = None
@@ -891,9 +896,9 @@ From:
""" % (alarm.name, alarm.trigger_date, alarm.description, \
alarm.user_id.name, alarm.user_id.signature)
- mail_to = [alarm.user_id.email]
+ mail_to = alarm.user_id.email
for att in alarm.attendee_ids:
- mail_to.append(att.user_id.email)
+ mail_to = mail_to + " " + att.user_id.email
if mail_to:
vals = {
'state': 'outgoing',
@@ -1117,7 +1122,7 @@ rule or repeating pattern of time to exclude from the recurring rule."),
for att in event.attendee_ids:
attendees[att.partner_id.id] = True
new_attendees = []
- mail_to = []
+ mail_to = ""
for partner in event.partner_ids:
if partner.id in attendees:
continue
@@ -1128,7 +1133,7 @@ rule or repeating pattern of time to exclude from the recurring rule."),
'email': partner.email
}, context=context)
if partner.email:
- mail_to.append(partner.email)
+ mail_to = mail_to + " " + partner.email
self.write(cr, uid, [event.id], {
'attendee_ids': [(4, att_id)]
}, context=context)
@@ -1136,7 +1141,7 @@ rule or repeating pattern of time to exclude from the recurring rule."),
if mail_to and current_user.email:
att_obj._send_mail(cr, uid, new_attendees, mail_to,
- email_from = current_user.email)
+ email_from = current_user.email, context=context)
return True
def default_organizer(self, cr, uid, context=None):
@@ -1747,57 +1752,4 @@ class virtual_report_spool(web_services.report_spool):
virtual_report_spool()
-class res_users(osv.osv):
- _inherit = 'res.users'
-
- def _get_user_avail(self, cr, uid, ids, context=None):
- """
- Get User Availability
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user's ID for security checks,
- @param ids: List of res user's IDs.
- @param context: A standard dictionary for contextual values
- """
-
- current_datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- res = {}
- attendee_obj = self.pool.get('calendar.attendee')
- attendee_ids = attendee_obj.search(cr, uid, [
- ('event_date', '<=', current_datetime), ('event_end_date', '<=', current_datetime),
- ('state', '=', 'accepted'), ('user_id', 'in', ids)
- ])
-
- for attendee_data in attendee_obj.read(cr, uid, attendee_ids, ['user_id']):
- user_id = attendee_data['user_id']
- status = 'busy'
- res.update({user_id:status})
-
- #TOCHECK: Delegated Event
- for user_id in ids:
- if user_id not in res:
- res[user_id] = 'free'
-
- return res
-
- def _get_user_avail_fun(self, cr, uid, ids, name, args, context=None):
- """
- Get User Availability Function
- @param self: The object pointer
- @param cr: the current row, from the database cursor,
- @param uid: the current user's ID for security checks,
- @param ids: List of res user's IDs.
- @param context: A standard dictionary for contextual values
- """
-
- return self._get_user_avail(cr, uid, ids, context=context)
-
- _columns = {
- 'availability': fields.function(_get_user_avail_fun, type='selection', \
- selection=[('free', 'Free'), ('busy', 'Busy')], \
- string='Free/Busy'),
- }
-
-res_users()
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_calendar/crm_meeting_view.xml b/addons/base_calendar/crm_meeting_view.xml
index 2efc76997cc..c2adc01cd54 100644
--- a/addons/base_calendar/crm_meeting_view.xml
+++ b/addons/base_calendar/crm_meeting_view.xml
@@ -181,10 +181,6 @@
-
-
-
-
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index bbd7e3a56b9..3fae85f311d 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -84,9 +84,20 @@ class crm_lead(base_stage, format_address, osv.osv):
},
}
+ def create(self, cr, uid, vals, context=None):
+ if context is None:
+ context = {}
+ if not vals.get('stage_id') and vals.get('section_id'):
+ ctx = context.copy()
+ ctx['default_section_id'] = vals['section_id']
+ vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
+ elif not vals.get('stage_id') and context.get('default_section_id'):
+ vals['stage_id'] = self._get_default_stage_id(cr, uid, context=context)
+ return super(crm_lead, self).create(cr, uid, vals, context=context)
+
def _get_default_section_id(self, cr, uid, context=None):
""" Gives default section by checking if present in the context """
- return (self._resolve_section_id_from_context(cr, uid, context=context) or False)
+ return self._resolve_section_id_from_context(cr, uid, context=context) or False
def _get_default_stage_id(self, cr, uid, context=None):
""" Gives default stage_id """
@@ -671,9 +682,9 @@ class crm_lead(base_stage, format_address, osv.osv):
section_id = lead.section_id and lead.section_id.id or False
if section_id:
- stage_ids = crm_stage.search(cr, uid, [('sequence','>=',1), ('section_ids','=', section_id)])
+ stage_ids = crm_stage.search(cr, uid, [('sequence', '>=', 1), ('section_ids', '=', section_id), ('probability', '>', 0)])
else:
- stage_ids = crm_stage.search(cr, uid, [('sequence','>=',1)])
+ stage_ids = crm_stage.search(cr, uid, [('sequence', '>=', 1), ('probability', '>', 0)])
stage_id = stage_ids and stage_ids[0] or False
return {
diff --git a/addons/crm/crm_lead_demo.xml b/addons/crm/crm_lead_demo.xml
index 86a944544ff..99fb0e895c2 100644
--- a/addons/crm/crm_lead_demo.xml
+++ b/addons/crm/crm_lead_demo.xml
@@ -402,9 +402,9 @@ Andrew
Leland Martinezinfo@deltapc.comDelta PC
- Fremont
+ London3661 Station Street
-
+
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index 2bab40ee457..24837cff586 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -156,7 +156,7 @@
-
+
@@ -421,8 +421,7 @@
-
+
diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml
index e070f8fd8d3..74b2ecd5069 100644
--- a/addons/crm/crm_phonecall_view.xml
+++ b/addons/crm/crm_phonecall_view.xml
@@ -36,11 +36,13 @@
diff --git a/addons/document/document.py b/addons/document/document.py
index 6cb2cabbf38..1671b6bc1ba 100644
--- a/addons/document/document.py
+++ b/addons/document/document.py
@@ -117,8 +117,22 @@ class document_file(osv.osv):
# take partner from uid
if vals.get('res_id', False) and vals.get('res_model', False) and not vals.get('partner_id', False):
vals['partner_id'] = self.__get_partner_id(cr, uid, vals['res_model'], vals['res_id'], context)
+ if vals.get('datas', False):
+ vals['file_type'], vals['index_content'] = self._index(cr, uid, vals['datas'].decode('base64'), vals.get('datas_fname', False), None)
return super(document_file, self).create(cr, uid, vals, context)
+ def write(self, cr, uid, ids, vals, context=None):
+ if context is None:
+ context = {}
+ if vals.get('datas', False):
+ vals['file_type'], vals['index_content'] = self._index(cr, uid, vals['datas'].decode('base64'), vals.get('datas_fname', False), None)
+ return super(document_file, self).write(cr, uid, ids, vals, context)
+
+ def _index(self, cr, uid, data, datas_fname, file_type):
+ mime, icont = cntIndex.doIndex(data, datas_fname, file_type or None, None)
+ icont_u = ustr(icont)
+ return mime, icont_u
+
def __get_partner_id(self, cr, uid, res_model, res_id, context=None):
""" A helper to retrieve the associated partner from any res_model+id
It is a hack that will try to discover if the mentioned record is
diff --git a/addons/document/document_view.xml b/addons/document/document_view.xml
index 4c2456de827..68f294b251c 100644
--- a/addons/document/document_view.xml
+++ b/addons/document/document_view.xml
@@ -167,7 +167,7 @@
-
+
diff --git a/addons/document_ftp/ftpserver/__init__.py b/addons/document_ftp/ftpserver/__init__.py
index b5ada070c84..3749a02a387 100644
--- a/addons/document_ftp/ftpserver/__init__.py
+++ b/addons/document_ftp/ftpserver/__init__.py
@@ -20,13 +20,20 @@
##############################################################################
import threading
-import ftpserver
+import logging
+
import authorizer
import abstracted_fs
-import logging
+import ftpserver
+
+import openerp
from openerp.tools import config
_logger = logging.getLogger(__name__)
+
def start_server():
+ if openerp.multi_process:
+ _logger.info("FTP disabled in multiprocess mode")
+ return
HOST = config.get('ftp_server_host', '127.0.0.1')
PORT = int(config.get('ftp_server_port', '8021'))
PASSIVE_PORTS = None
diff --git a/addons/email_template/tests/test_mail.py b/addons/email_template/tests/test_mail.py
index 80b9dcee5a2..2ee8bf10297 100644
--- a/addons/email_template/tests/test_mail.py
+++ b/addons/email_template/tests/test_mail.py
@@ -45,8 +45,8 @@ class test_message_compose(TestMailBase):
# Mail data
_subject1 = 'Pigs'
_subject2 = 'Bird'
- _body_html1 = 'Fans of Pigs, unite !\n
Admin
\n'
- _body_html2 = 'I am angry !\n
Admin
\n'
+ _body_html1 = '
Fans of Pigs, unite !\n
Admin
'
+ _body_html2 = '
I am angry !\n
Admin
'
_attachments = [
{'name': 'First', 'datas_fname': 'first.txt', 'datas': base64.b64encode('My first attachment')},
{'name': 'Second', 'datas_fname': 'second.txt', 'datas': base64.b64encode('My second attachment')}
@@ -147,7 +147,7 @@ class test_message_compose(TestMailBase):
message_pids = [partner.id for partner in compose.partner_ids]
partner_ids = [p_a_id]
self.assertEqual(compose.subject, '${object.name}', 'mail.compose.message subject incorrect')
- self.assertEqual(compose.body, '${object.description}', 'mail.compose.message body incorrect')
+ self.assertEqual(compose.body, '
${object.description}
', 'mail.compose.message body incorrect')
self.assertEqual(set(message_pids), set(partner_ids), 'mail.compose.message partner_ids incorrect')
# 2. Post the comment, get created message
diff --git a/addons/fleet/fleet_demo.xml b/addons/fleet/fleet_demo.xml
index a8d70eb06fa..a550ae78da5 100644
--- a/addons/fleet/fleet_demo.xml
+++ b/addons/fleet/fleet_demo.xml
@@ -32,7 +32,7 @@
BlackGrand-Rosiere5
-
+ kilometers
diff --git a/addons/google_docs/google_docs.py b/addons/google_docs/google_docs.py
index ac0cf68f3f6..4b98798c832 100644
--- a/addons/google_docs/google_docs.py
+++ b/addons/google_docs/google_docs.py
@@ -94,9 +94,9 @@ class google_docs_ir_attachment(osv.osv):
client = self._auth(cr, uid)
# fetch and copy the original document
try:
- original_resource = client.get_resource_by_id(gdoc_template_id)
+ doc = client.GetDoc(gdoc_template_id)
#copy the document you choose in the configuration
- copy_resource = client.copy_resource(original_resource, name_gdocs)
+ copy_resource = client.copy(doc, name_gdocs)
except:
raise osv.except_osv(_('Google Docs Error!'), _("Your resource id is not correct. You can find the id in the google docs URL."))
# create an ir.attachment
diff --git a/addons/google_docs/static/src/js/gdocs.js b/addons/google_docs/static/src/js/gdocs.js
index 45e1d09d42c..1cc511ef4d9 100644
--- a/addons/google_docs/static/src/js/gdocs.js
+++ b/addons/google_docs/static/src/js/gdocs.js
@@ -16,7 +16,7 @@ var _t = instance.web._t,
var view = self.getParent();
var ids = ( view.fields_view.type != "form" )? view.groups.get_selection().ids : [ view.datarecord.id ];
if( !_.isEmpty(ids) ){
- view.sidebar_context().done(function (context) {
+ view.sidebar_eval_context().done(function (context) {
var ds = new instance.web.DataSet(this, 'ir.attachment', context);
ds.call('google_doc_get', [view.dataset.model, ids, context]).done(function(r) {
if (r == 'False') {
diff --git a/addons/hr/hr.py b/addons/hr/hr.py
index c4727730464..92bde22086e 100644
--- a/addons/hr/hr.py
+++ b/addons/hr/hr.py
@@ -215,7 +215,9 @@ class hr_employee(osv.osv):
try:
(model, mail_group_id) = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'group_all_employees')
employee = self.browse(cr, uid, employee_id, context=context)
- self.pool.get('mail.group').message_post(cr, uid, [mail_group_id], body='Welcome to %s! Please help them take the first steps with OpenERP!' % (employee.name), context=context)
+ self.pool.get('mail.group').message_post(cr, uid, [mail_group_id],
+ body='Welcome to %s! Please help them take the first steps with OpenERP!' % (employee.name),
+ subtype='mail.mt_comment', context=context)
except:
pass # group deleted: do not push a message
return employee_id
diff --git a/addons/hr_evaluation/hr_evaluation_view.xml b/addons/hr_evaluation/hr_evaluation_view.xml
index 54baee5f538..52b288fdad5 100644
--- a/addons/hr_evaluation/hr_evaluation_view.xml
+++ b/addons/hr_evaluation/hr_evaluation_view.xml
@@ -140,7 +140,7 @@
-
+
diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py
index 0a693f50a3f..f61ecc8eb7d 100644
--- a/addons/lunch/lunch.py
+++ b/addons/lunch/lunch.py
@@ -94,9 +94,8 @@ class lunch_order(osv.Model):
"""
today = datetime.now().isoweekday()
assert 1 <= today <= 7, "Should be between 1 and 7"
- mapping = dict((idx, name) for idx, name in enumerate('monday tuestday wednesday thursday friday saturday sunday'.split()))
- if today in mapping:
- return mapping[today]
+ mapping = dict((idx, name) for idx, name in enumerate('days monday tuesday wednesday thursday friday saturday sunday'.split()))
+ return alert[mapping[today]]
def can_display_alert(self, alert):
"""
diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py
index e171c9cc14c..24aed942b1b 100644
--- a/addons/mail/mail_group.py
+++ b/addons/mail/mail_group.py
@@ -96,6 +96,16 @@ class mail_group(osv.Model):
'alias_domain': False, # always hide alias during creation
}
+ def _generate_header_description(self, cr, uid, group, context=None):
+ header = ''
+ if group.description:
+ header = '%s' % group.description
+ if group.alias_id and group.alias_id.alias_name and group.alias_id.alias_domain:
+ if header:
+ header = '%s ' % header
+ return '%sGroup email gateway: %s@%s' % (header, group.alias_id.alias_name, group.alias_id.alias_domain)
+ return header
+
def _subscribe_users(self, cr, uid, ids, context=None):
for mail_group in self.browse(cr, uid, ids, context=context):
partner_ids = []
@@ -126,6 +136,7 @@ class mail_group(osv.Model):
# Create group and alias
mail_group_id = super(mail_group, self).create(cr, uid, vals, context=context)
mail_alias.write(cr, uid, [vals['alias_id']], {"alias_force_thread_id": mail_group_id}, context)
+ group = self.browse(cr, uid, mail_group_id, context=context)
# Create client action for this group and link the menu to it
ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'action_mail_group_feeds')
@@ -137,11 +148,11 @@ class mail_group(osv.Model):
'context': {'default_model': 'mail.group', 'default_res_id': mail_group_id, 'search_default_message_unread': True},
'res_model': 'mail.message',
'thread_level': 1,
- 'header_description': vals.get('description'),
+ 'header_description': self._generate_header_description(cr, uid, group, context=context)
}
cobj = self.pool.get('ir.actions.client')
newref = cobj.copy(cr, SUPERUSER_ID, ref[1], default={'params': str(params), 'name': vals['name']}, context=context)
- mobj.write(cr, SUPERUSER_ID, menu_id, { 'action': 'ir.actions.client,' + str(newref), 'mail_group_id': mail_group_id}, context=context)
+ mobj.write(cr, SUPERUSER_ID, menu_id, {'action': 'ir.actions.client,' + str(newref), 'mail_group_id': mail_group_id}, context=context)
if vals.get('group_ids'):
self._subscribe_users(cr, uid, [mail_group_id], context=context)
@@ -164,18 +175,18 @@ class mail_group(osv.Model):
result = super(mail_group, self).write(cr, uid, ids, vals, context=context)
if vals.get('group_ids'):
self._subscribe_users(cr, uid, ids, context=context)
- # if description is changed: update client action
- if vals.get('description'):
+ # if description, name or alias is changed: update client action
+ if vals.get('description') or vals.get('name') or vals.get('alias_id') or vals.get('alias_name'):
cobj = self.pool.get('ir.actions.client')
for action in [group.menu_id.action for group in self.browse(cr, uid, ids, context=context)]:
new_params = action.params
- new_params['header_description'] = vals.get('description')
+ new_params['header_description'] = self._generate_header_description(cr, uid, group, context=context)
cobj.write(cr, SUPERUSER_ID, [action.id], {'params': str(new_params)}, context=context)
# if name is changed: update menu
if vals.get('name'):
mobj = self.pool.get('ir.ui.menu')
- mobj.write(cr, SUPERUSER_ID,
- [group.menu_id.id for group in self.browse(cr, uid, ids, context=context)],
+ mobj.write(cr, SUPERUSER_ID,
+ [group.menu_id.id for group in self.browse(cr, uid, ids, context=context)],
{'name': vals.get('name')}, context=context)
return result
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index f9406699190..be34153e316 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -309,13 +309,15 @@ class mail_thread(osv.AbstractModel):
def message_track(self, cr, uid, ids, tracked_fields, initial_values, context=None):
- def convert_for_display(value, field_obj):
+ def convert_for_display(value, col_info):
+ if not value and col_info['type'] == 'boolean':
+ return 'False'
if not value:
return ''
- if field_obj['type'] == 'many2one':
+ if col_info['type'] == 'many2one':
return value[1]
- if field_obj['type'] == 'selection':
- return dict(field_obj['selection'])[value]
+ if col_info['type'] == 'selection':
+ return dict(col_info['selection'])[value]
return value
def format_message(message_description, tracked_values):
@@ -489,7 +491,13 @@ class mail_thread(osv.AbstractModel):
for alias in mail_alias.browse(cr, uid, alias_ids, context=context):
user_id = alias.alias_user_id.id
if not user_id:
- user_id = self._message_find_user_id(cr, uid, message, context=context)
+ # TDE note: this could cause crashes, because no clue that the user
+ # that send the email has the right to create or modify a new document
+ # Fallback on user_id = uid
+ # Note: recognized partners will be added as followers anyway
+ # user_id = self._message_find_user_id(cr, uid, message, context=context)
+ user_id = uid
+ _logger.debug('No matching user_id for the alias %s', alias.alias_name)
routes.append((alias.alias_model_id.model, alias.alias_force_thread_id, \
eval(alias.alias_defaults), user_id))
_logger.debug('Routing mail with Message-Id %s: direct alias match: %r', message_id, routes)
@@ -959,7 +967,7 @@ class mail_thread(osv.AbstractModel):
# 3. Post message
return self.message_post(cr, uid, thread_id=thread_id, body=body,
type=msg_type, subtype=msg_subtype, parent_id=parent_id,
- attachment_ids=attachment_ids, partner_ids=partner_ids, context=context, **kwargs)
+ attachment_ids=attachment_ids, partner_ids=list(partner_ids), context=context, **kwargs)
#------------------------------------------------------
# Followers API
diff --git a/addons/mail/res_partner.py b/addons/mail/res_partner.py
index cfcb1106afc..77f680bcab2 100644
--- a/addons/mail/res_partner.py
+++ b/addons/mail/res_partner.py
@@ -51,9 +51,9 @@ class res_partner_mail(osv.Model):
"""
if isinstance(thread_id, (list, tuple)):
thread_id = thread_id[0]
- if type == 'email':
+ if kwargs.get('type') == 'email':
partner_ids = kwargs.get('partner_ids', [])
- if thread_id not in partner_ids:
+ if thread_id not in [command[1] for command in partner_ids]:
partner_ids.append((4, thread_id))
kwargs['partner_ids'] = partner_ids
thread_id = False
diff --git a/addons/mail/res_users.py b/addons/mail/res_users.py
index 160335fba2a..3f33f1dbca5 100644
--- a/addons/mail/res_users.py
+++ b/addons/mail/res_users.py
@@ -122,7 +122,7 @@ class res_users(osv.Model):
context['thread_model'] = 'res.partner'
if isinstance(thread_id, (list, tuple)):
thread_id = thread_id[0]
- return self.browse(cr, uid, thread_id).partner_id.id
+ return self.browse(cr, SUPERUSER_ID, thread_id).partner_id.id
def message_post_user_api(self, cr, uid, thread_id, context=None, **kwargs):
""" Redirect the posting of message on res.users to the related partner.
@@ -139,9 +139,16 @@ class res_users(osv.Model):
return self.pool.get('res.partner').message_post(cr, uid, partner_id, context=context, **kwargs)
def message_update(self, cr, uid, ids, msg_dict, update_vals=None, context=None):
- partner_id = self.browse(cr, uid, ids)[0].partner_id.id
- return self.pool.get('res.partner').message_update(cr, uid, [partner_id], msg_dict,
- update_vals=update_vals, context=context)
+ for id in ids:
+ partner_id = self.browse(cr, SUPERUSER_ID, id).partner_id.id
+ self.pool.get('res.partner').message_update(cr, uid, [partner_id], msg_dict, update_vals=update_vals, context=context)
+ return True
+
+ def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None):
+ for id in ids:
+ partner_id = self.browse(cr, SUPERUSER_ID, id).partner_id.id
+ self.pool.get('res.partner').message_subscribe(cr, uid, [partner_id], partner_ids, subtype_ids=subtype_ids, context=context)
+ return True
class res_users_mail_group(osv.Model):
diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css
index 54f97f448f4..e4e112cdfaf 100644
--- a/addons/mail/static/src/css/mail.css
+++ b/addons/mail/static/src/css/mail.css
@@ -59,6 +59,10 @@
left:0; top: 0; bottom: 0; width: 40px;
overflow: hidden;
}
+.openerp .oe_mail .oe_msg .oe_msg_left a,
+.openerp .oe_mail .oe_msg .oe_msg_left img{
+ border: 0;
+}
.openerp .oe_mail .oe_msg .oe_msg_icon{
width: 32px;
margin: 4px;
@@ -184,7 +188,7 @@
transition: all 0.1s linear;
}
.openerp .oe_mail .oe_msg .oe_msg_icons .oe_star:hover a{
- color: #FFF6C0;
+ color: #FFF670;
text-shadow: 0px 1px #FFA162,0px -1px #FFA162, -1px 0px #FFA162, 1px 0px #FFA162, 0px 3px 3px rgba(0,0,0,0.1);
}
.openerp .oe_mail .oe_msg .oe_msg_icons .oe_star.oe_starred a{
@@ -220,6 +224,21 @@
height: 24px;
width: 100%;
}
+.openerp .oe_mail .oe_msg.oe_msg_composer_compact .oe_compact{
+ height: 24px;
+ width: 100%;
+ padding: 2px 4px;
+ border: 1px solid #CCC;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ background: white;
+ font-size: 14px;
+ color: #AAA;
+ font-style: italic;
+ word-spacing: 3px;
+ cursor: text;
+}
/* d) I.E. tweaks for Message action icons */
@@ -585,6 +604,7 @@
.openerp .oe_followers .oe_partner {
height: 32px;
overflow: hidden;
+ white-space: nowrap;
}
.openerp .oe_followers .oe_partner img{
width: 32px;
@@ -593,7 +613,9 @@
}
.openerp .oe_followers .oe_remove_follower{
cursor: pointer;
- float: right;
+ position: absolute;
+ right: 0px;
+ line-height: 20px;
}
.openerp .oe_followers .oe_show_more{
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
index 29a2e076b19..f8643e94bb3 100644
--- a/addons/mail/static/src/js/mail.js
+++ b/addons/mail/static/src/js/mail.js
@@ -471,7 +471,7 @@ openerp.mail = function (session) {
bind_events: function () {
var self = this;
- this.$('textarea.oe_compact').on('focus', _.bind( this.on_compose_expandable, this));
+ this.$('.oe_compact').on('click', _.bind( this.on_compose_expandable, this));
// set the function called when attachments are added
this.$('input.oe_form_binary_file').on('change', _.bind( this.on_attachment_change, this) );
@@ -479,18 +479,16 @@ openerp.mail = function (session) {
this.$('.oe_cancel').on('click', _.bind( this.on_cancel, this) );
this.$('.oe_post').on('click', _.bind( this.on_message_post, this) );
this.$('.oe_full').on('click', _.bind( this.on_compose_fullmail, this, this.id ? 'reply' : 'comment') );
-
/* stack for don't close the compose form if the user click on a button */
this.$('.oe_msg_left, .oe_msg_center').on('mousedown', _.bind( function () { this.stay_open = true; }, this));
this.$('.oe_msg_left, .oe_msg_content').on('mouseup', _.bind( function () { this.$('textarea').focus(); }, this));
-
var ev_stay = {};
ev_stay.mouseup = ev_stay.keydown = ev_stay.focus = function () { self.stay_open = false; };
- this.$('textarea:not(.oe_compact)').on(ev_stay);
- this.$('textarea:not(.oe_compact)').autosize();
+ this.$('textarea').on(ev_stay);
+ this.$('textarea').autosize();
// auto close
- this.$('textarea:not(.oe_compact)').on('blur', _.bind( this.on_compose_expandable, this));
+ this.$('textarea').on('blur', _.bind( this.on_compose_expandable, this));
// event: delete child attachments off the oe_msg_attachment_list box
this.$(".oe_msg_attachment_list").on('click', '.oe_delete', this.on_attachment_delete);
@@ -567,11 +565,14 @@ openerp.mail = function (session) {
check_recipient_partners: function (emails) {
var self = this;
var deferreds = [];
+ for (var i = 0; i < emails.length; i++) {
+ deferreds.push($.Deferred());
+ }
var ds_partner = new session.web.DataSetSearch(this, 'res.partner');
_.each(emails, function (email) {
- ds_partner.call('search', [[['email', '=', email]]]).then(function (partner_ids) {
+ ds_partner.call('search', [[['email', 'ilike', email]]]).then(function (partner_ids) {
+ var deferred = deferreds[_.indexOf(emails, email)];
if (!partner_ids.length) {
- var deferred = $.Deferred();
var pop = new session.web.form.FormOpenPopup(this);
pop.show_element(
'res.partner',
@@ -588,11 +589,14 @@ openerp.mail = function (session) {
pop.on('write_completed, closed', self, function () {
deferred.resolve();
});
- deferreds.push(deferred);
}
+ else {
+ deferred.resolve();
+ }
+ return deferred;
});
});
- return $.when.apply( $, deferreds );
+ return $.when.apply( $, deferreds ).done();
},
on_message_post: function (event) {
diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js
index 1e481271eda..1fc93781039 100644
--- a/addons/mail/static/src/js/mail_followers.js
+++ b/addons/mail/static/src/js/mail_followers.js
@@ -218,7 +218,9 @@ openerp_mail_followers = function(session, mail) {
var subtype_list_ul = this.$('.oe_subtype_list');
subtype_list_ul.empty();
var records = data[this.view.datarecord.id || this.view.dataset.ids[0]].message_subtype_data;
- if (records.length > 1) {
+ var nb_subtype = 0;
+ _(records).each(function (record) {nb_subtype++;});
+ if (nb_subtype > 1) {
_(records).each(function (record, record_name) {
record.name = record_name;
record.followed = record.followed || undefined;
diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml
index d48665f684f..c1a32a2fe89 100644
--- a/addons/mail/static/src/xml/mail.xml
+++ b/addons/mail/static/src/xml/mail.xml
@@ -39,9 +39,11 @@
-
-
-
+
+
+ Write to the followers of this document...
+ Share with my followers...
+
\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n
\n',
+ self.assertEqual(new_mail.body, '
\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n
',
'plaintext mail incorrectly parsed')
# Do: post a new message, with a known partner
@@ -340,11 +340,11 @@ class test_mail(TestMailBase):
# Mail data
_subject = 'Pigs'
_mail_subject = '%s posted on %s' % (user_raoul.name, group_pigs.name)
- _body1 = 'Pigs rules'
- _mail_body1 = 'Pigs rules\n
'
_mail_bodyalt2 = 'Pigs rules\nRaoul'
_attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
@@ -487,7 +487,7 @@ class test_mail(TestMailBase):
message = group_pigs.message_ids[0]
# Test: mail.message: subject, body inside pre
self.assertEqual(message.subject, _subject, 'mail.message incorrect subject')
- self.assertEqual(message.body, _body, 'mail.message incorrect body')
+ self.assertEqual(message.body, '
%s
' % _body, 'mail.message incorrect body')
# Test: mail.message: notified_partner_ids = entries in mail.notification: group_pigs fans (a, b) + mail.compose.message partner_ids (c, d)
msg_pids = [partner.id for partner in message.notified_partner_ids]
test_pids = [p_b_id, p_c_id, p_d_id]
@@ -541,9 +541,9 @@ class test_mail(TestMailBase):
self.assertIn(message2.id, test_msg_ids, 'Bird did not receive its mass mailing message')
# Test: mail.message: subject, body
self.assertEqual(message1.subject, _subject, 'mail.message subject incorrect')
- self.assertEqual(message1.body, group_pigs.description, 'mail.message body incorrect')
+ self.assertEqual(message1.body, '
%s
' % group_pigs.description, 'mail.message body incorrect')
self.assertEqual(message2.subject, _subject, 'mail.message subject incorrect')
- self.assertEqual(message2.body, group_bird.description, 'mail.message body incorrect')
+ self.assertEqual(message2.body, '
%s
' % group_bird.description, 'mail.message body incorrect')
def test_30_needaction(self):
""" Tests for mail.message needaction. """
@@ -634,7 +634,7 @@ class test_mail(TestMailBase):
# Test: first produced message: no subtype, name change tracked
last_msg = self.group_pigs.message_ids[-1]
self.assertFalse(last_msg.subtype_id, 'tracked: message should not have been linked to a subtype')
- self.assertIn('SelectedGroupOnly→Public', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect')
+ self.assertIn(u'SelectedGroupOnly\u2192Public', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect')
self.assertIn('Pigs', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold always tracked field')
# Test: change name as supername, public as private -> 2 subtypes
@@ -645,13 +645,13 @@ class test_mail(TestMailBase):
last_msg = self.group_pigs.message_ids[-2]
self.assertEqual(last_msg.subtype_id.id, mt_private_id, 'tracked: message should be linked to mt_private subtype')
self.assertIn('Private public', last_msg.body, 'tracked: message body does not hold the subtype description')
- self.assertIn('Pigs→supername', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect')
+ self.assertIn(u'Pigs\u2192supername', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect')
# Test: second produced message: mt_name_supername
last_msg = self.group_pigs.message_ids[-3]
self.assertEqual(last_msg.subtype_id.id, mt_name_supername_id, 'tracked: message should be linked to mt_name_supername subtype')
self.assertIn('Supername name', last_msg.body, 'tracked: message body does not hold the subtype description')
- self.assertIn('Public→Private', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect')
- self.assertIn('Pigs→supername', _strip_string_spaces(last_msg.body), 'tracked feature: message body does not hold always tracked field')
+ self.assertIn(u'Public\u2192Private', _strip_string_spaces(last_msg.body), 'tracked: message body incorrect')
+ self.assertIn(u'Pigs\u2192supername', _strip_string_spaces(last_msg.body), 'tracked feature: message body does not hold always tracked field')
# Test: change public as public, group_public_id -> 1 subtype, name always tracked
self.mail_group.write(cr, self.user_raoul_id, [self.group_pigs_id], {'public': 'public', 'group_public_id': group_system_id})
@@ -661,8 +661,8 @@ class test_mail(TestMailBase):
last_msg = self.group_pigs.message_ids[-4]
self.assertEqual(last_msg.subtype_id.id, mt_group_public_id, 'tracked: message should not be linked to any subtype')
self.assertIn('Group changed', last_msg.body, 'tracked: message body does not hold the subtype description')
- self.assertIn('Private→Public', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold changed tracked field')
- self.assertIn('HumanResources/Employee→Administration/Settings', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold always tracked field')
+ self.assertIn(u'Private\u2192Public', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold changed tracked field')
+ self.assertIn(u'HumanResources/Employee\u2192Administration/Settings', _strip_string_spaces(last_msg.body), 'tracked: message body does not hold always tracked field')
# Test: change not tracked field, no tracking message
self.mail_group.write(cr, self.user_raoul_id, [self.group_pigs_id], {'description': 'Dummy'})
diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py
index ee3053014af..bcb60ba44c0 100644
--- a/addons/mail/wizard/invite.py
+++ b/addons/mail/wizard/invite.py
@@ -19,6 +19,7 @@
#
##############################################################################
+from openerp import tools
from openerp.osv import osv
from openerp.osv import fields
from openerp.tools.translate import _
@@ -60,6 +61,12 @@ class invite_wizard(osv.osv_memory):
# send an email
if wizard.message:
+ # add signature
+ user_id = self.pool.get("res.users").read(cr, uid, [uid], fields=["signature"], context=context)[0]
+ signature = user_id and user_id["signature"] or ''
+ if signature:
+ wizard.message = tools.append_content_to_html(wizard.message, signature, plaintext=True, container_tag='div')
+ # send mail to new followers
for follower_id in new_follower_ids:
mail_mail = self.pool.get('mail.mail')
# the invite wizard should create a private message not related to any object -> no model, no res_id
diff --git a/addons/portal_anonymous/static/src/js/portal_anonymous.js b/addons/portal_anonymous/static/src/js/portal_anonymous.js
index adaa51948b5..55326225403 100644
--- a/addons/portal_anonymous/static/src/js/portal_anonymous.js
+++ b/addons/portal_anonymous/static/src/js/portal_anonymous.js
@@ -1,12 +1,51 @@
openerp.portal_anonymous = function(instance) {
+ instance.web.Session.include({
+ load_translations: function() {
+ var self = this;
+ // browser_lang can contain 'xx' or 'xx_XX'
+ // we use the 'xx' to find matching languages installed in the DB
+ var browser_lang = (navigator.language || navigator.userLanguage).replace('-', '_');
+ // By default for anonymous session.user_context.lang === 'en_US',
+ // so do nothing if browser_lang is contained in 'en_US' (like 'en' or 'en_US')
+ if (this.username === 'anonymous' && this.user_context.lang.indexOf(browser_lang) === -1) {
+ return (new instance.web.Model('res.lang')).query(['code', 'iso_code'])
+ .filter([['code', 'like', browser_lang.substring(0, 2).toLowerCase()]]).all()
+ .then(function(langs) {
+ // If langs is empty (OpenERP doesn't support the language),
+ // then don't change session.user_context.lang
+ if (langs.length > 0) {
+ // Try to get the right user preference in the browser, else
+ // get the shortest language returned ('xx' country code) or
+ // just the first one
+ var l = _.filter(langs, function(lang) { return lang.code === browser_lang || lang.iso_code === browser_lang; });
+ if (!_.isEmpty(l)) {
+ self.user_context.lang = l[0].code;
+ } else {
+ l = _.filter(langs, function(lang) {
+ return lang.iso_code === _.pluck(langs, 'iso_code')
+ .sort(function(a, b) {
+ return a.length - b.length;
+ })[0];
+ });
+ self.user_context.lang = l[0].code;
+ }
+ }
+ return self.rpc('/web/webclient/translations', { mods: self.module_list, lang: self.user_context.lang }).done(function(trans) {
+ instance.web._t.database.set_bundle(trans);
+ });
+ });
+ }
+ return this._super();
+ },
+ });
+
instance.web.Login.include({
start: function() {
var self = this;
return $.when(this._super()).then(function() {
- var params = $.deparam($.param.querystring());
var dblist = self.db_list || [];
- if (!self.session.session_is_valid() && dblist.length === 1 && (!params.token || !params.login)) {
+ if (!self.session.session_is_valid() && dblist.length === 1 && _.isEmpty(self.params)) {
self.remember_credentials = false;
// XXX get login/pass from server (via a rpc call) ?
return self.do_login(dblist[0], 'anonymous', 'anonymous');
@@ -51,14 +90,6 @@ openerp.portal_anonymous = function(instance) {
}
return false;
},
- // Avoid browser preloading
- show_application: function() {
- var params = $.deparam($.param.querystring());
- if (!!params.token || !!params.login) {
- return this.show_login();
- }
- return this._super();
- },
});
};
diff --git a/addons/project/project.py b/addons/project/project.py
index 0534ad9a264..e98254d2fa1 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -1089,6 +1089,14 @@ class task(base_stage, osv.osv):
return True
def create(self, cr, uid, vals, context=None):
+ if context is None:
+ context = {}
+ if not vals.get('stage_id') and vals.get('project_id'):
+ ctx = context.copy()
+ ctx['default_project_id'] = vals['project_id']
+ vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
+ elif not vals.get('stage_id') and context.get('default_project_id'):
+ vals['stage_id'] = self._get_default_stage_id(cr, uid, context=context)
task_id = super(task, self).create(cr, uid, vals, context=context)
self._store_history(cr, uid, [task_id], context=context)
return task_id
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index 587faf295a1..ade07f7cebb 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -451,7 +451,6 @@
-
oe_kanban_text_red
diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py
index 0015bc3fa50..8b2afb130e1 100644
--- a/addons/project_issue/project_issue.py
+++ b/addons/project_issue/project_issue.py
@@ -64,6 +64,17 @@ class project_issue(base_stage, osv.osv):
},
}
+ def create(self, cr, uid, vals, context=None):
+ if context is None:
+ context = {}
+ if not vals.get('stage_id') and vals.get('project_id'):
+ ctx = context.copy()
+ ctx['default_project_id'] = vals['project_id']
+ vals['stage_id'] = self._get_default_stage_id(cr, uid, context=ctx)
+ elif not vals.get('stage_id') and context.get('default_project_id'):
+ vals['stage_id'] = self._get_default_stage_id(cr, uid, context=context)
+ return super(project_issue, self).create(cr, uid, vals, context=context)
+
def _get_default_project_id(self, cr, uid, context=None):
""" Gives default project by checking if present in the context """
return self._resolve_project_id_from_context(cr, uid, context=context)
@@ -514,7 +525,7 @@ class project_issue(base_stage, osv.osv):
}
for line in msg.get('body', '').split('\n'):
line = line.strip()
- res = tools.misc.command_re.match(line)
+ res = tools.command_re.match(line)
if res and maps.get(res.group(1).lower(), False):
key = maps.get(res.group(1).lower())
update_vals[key] = res.group(2).lower()
diff --git a/addons/sale/sale.py b/addons/sale/sale.py
index 78541efa989..66653c61849 100644
--- a/addons/sale/sale.py
+++ b/addons/sale/sale.py
@@ -178,6 +178,13 @@ class sale_order(osv.osv):
result[line.order_id.id] = True
return result.keys()
+ def _get_default_shop(self, cr, uid, context=None):
+ company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
+ shop_ids = self.pool.get('sale.shop').search(cr, uid, [('company_id','=',company_id)], context=context)
+ if not shop_ids:
+ raise osv.except_osv(_('Error!'), _('There is no default shop for the current user\'s company!'))
+ return shop_ids[0]
+
_columns = {
'name': fields.char('Order Reference', size=64, required=True,
readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, select=True),
@@ -251,6 +258,7 @@ class sale_order(osv.osv):
'user_id': lambda obj, cr, uid, context: uid,
'name': lambda obj, cr, uid, context: '/',
'invoice_quantity': 'order',
+ 'shop_id': _get_default_shop,
'partner_invoice_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').address_get(cr, uid, [context['partner_id']], ['invoice'])['invoice'],
'partner_shipping_id': lambda self, cr, uid, context: context.get('partner_id', False) and self.pool.get('res.partner').address_get(cr, uid, [context['partner_id']], ['delivery'])['delivery'],
}
diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml
index 0edda45b6d1..18fdb739923 100644
--- a/addons/sale/sale_view.xml
+++ b/addons/sale/sale_view.xml
@@ -156,7 +156,7 @@
-
+
@@ -246,7 +246,7 @@