[MERGE] forward port branch 11.0 up to 59a8a1cd8e

This commit is contained in:
Christophe Simonis
2018-05-17 13:19:49 +02:00
83 changed files with 417 additions and 88 deletions
+1 -1
View File
@@ -802,7 +802,7 @@ class AccountTax(models.Model):
tag_ids = fields.Many2many('account.account.tag', 'account_tax_account_tag', string='Tags', help="Optional tags you may want to assign for custom reporting")
tax_group_id = fields.Many2one('account.tax.group', string="Tax Group", default=_default_tax_group, required=True)
# Technical field to make the 'tax_exigibility' field invisible if the same named field is set to false in 'res.company' model
hide_tax_exigibility = fields.Boolean(string='Hide Use Cash Basis Option', related='company_id.tax_exigibility')
hide_tax_exigibility = fields.Boolean(string='Hide Use Cash Basis Option', related='company_id.tax_exigibility', readonly=True)
tax_exigibility = fields.Selection(
[('on_invoice', 'Based on Invoice'),
('on_payment', 'Based on Payment'),
@@ -804,6 +804,7 @@ var StatementModel = BasicModel.extend({
model: 'account.tax',
method: 'json_friendly_compute_all',
args: args,
context: $.extend(self.context || {}, {'round': true}),
})
.then(function (result) {
_.each(result.taxes, function(tax){
-1
View File
@@ -42,7 +42,6 @@ class AuthSignupHome(Home):
template.sudo().with_context(
lang=user_sudo.lang,
auth_login=werkzeug.url_encode({'auth_login': user_sudo.email}),
password=request.params.get('password')
).send_mail(user_sudo.id, force_send=True)
return super(AuthSignupHome, self).web_login(*args, **kw)
except UserError as e:
@@ -116,7 +116,6 @@
<p>
Your login: ${object.email}
<br/>
Your password: ${ctx['password']}
</p>
<p>
To gain access to your account, you can use the following link:
-1
View File
@@ -109,7 +109,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -115,7 +115,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -102,7 +102,6 @@ msgid "<div style=\"padding:0px;width:600px;margin:auto;background: #FFFFFF repe
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -109,7 +109,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -134,7 +134,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -111,7 +111,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -162,7 +162,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-2
View File
@@ -165,7 +165,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
@@ -199,7 +198,6 @@ msgstr ""
" <p>\n"
" Email/Όνομα χρήστη: ${object.email}\n"
" <br/>\n"
" Κωδικός Πρόσβασης: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" Για να αποκτήσετε πρόσβαση στο λογαριασμό σας, ακολουθήστε τον παρακάτω σύνδεσμο:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -174,7 +174,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -111,7 +111,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -111,7 +111,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -114,7 +114,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -105,7 +105,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -168,7 +168,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -144,7 +144,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -165,7 +165,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -112,7 +112,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -109,7 +109,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -165,7 +165,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -112,7 +112,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -105,7 +105,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -110,7 +110,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -105,7 +105,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-2
View File
@@ -167,7 +167,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
@@ -201,7 +200,6 @@ msgstr ""
" <p>\n"
" Uw login: ${object.email}\n"
" <br/>\n"
" Uw wachtwoord: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" Om toegang te krijgen tot uw account, kan u de volgende link gebruiken::\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -114,7 +114,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-2
View File
@@ -167,7 +167,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
@@ -201,7 +200,6 @@ msgstr ""
" <p>\n"
" Seu login: ${object.email}\n"
" <br/>\n"
" Sua senha: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" Para acessar sua conta, você pode acessar o seguinte link:\n"
-1
View File
@@ -139,7 +139,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -173,7 +173,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -105,7 +105,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -109,7 +109,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -109,7 +109,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -108,7 +108,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -171,7 +171,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -167,7 +167,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -109,7 +109,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -140,7 +140,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
-1
View File
@@ -109,7 +109,6 @@ msgid ""
" <p>\n"
" Your login: ${object.email}\n"
" <br/>\n"
" Your password: ${ctx['password']}\n"
" </p>\n"
" <p>\n"
" To gain access to your account, you can use the following link:\n"
+1
View File
@@ -32,6 +32,7 @@ class ResPartner(models.Model):
signup_url = fields.Char(compute='_compute_signup_url', string='Signup URL')
@api.multi
@api.depends('signup_token', 'signup_expiration')
def _compute_signup_valid(self):
dt = now()
for partner in self:
+47 -3
View File
@@ -4,7 +4,12 @@ from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, tools
from odoo.tools import exception_to_unicode
from odoo.tools.translate import _
import random
import logging
_logger = logging.getLogger(__name__)
_INTERVALS = {
'hours': lambda interval: relativedelta(hours=interval),
@@ -114,13 +119,52 @@ class EventMailScheduler(models.Model):
self.write({'mail_sent': True})
return True
@api.model
def _warn_template_error(self, scheduler, exception):
# We warn ~ once by hour ~ instead of every 10 min if the interval unit is more than 'hours'.
if random.random() < 0.1666 or scheduler.interval_unit in ('now', 'hours'):
ex_s = exception_to_unicode(exception)
try:
event, template = scheduler.event_id, scheduler.template_id
emails = list(set([event.organizer_id.email, event.user_id.email, template.write_uid.email]))
subject = _("WARNING: Event Scheduler Error for event: %s" % event.name)
body = _("""Event Scheduler for:
- Event: %s (%s)
- Scheduled: %s
- Template: %s (%s)
Failed with error:
- %s
You receive this email because you are:
- the organizer of the event,
- or the responsible of the event,
- or the last writer of the template."""
% (event.name, event.id, scheduler.scheduled_date, template.name, template.id, ex_s))
email = self.env['ir.mail_server'].build_email(
email_from=self.env.user.email,
email_to=emails,
subject=subject, body=body,
)
self.env['ir.mail_server'].send_email(email)
except Exception as e:
_logger.error("Exception while sending traceback by email: %s.\n Original Traceback:\n%s", e, exception)
pass
@api.model
def run(self, autocommit=False):
schedulers = self.search([('done', '=', False), ('scheduled_date', '<=', datetime.strftime(fields.datetime.now(), tools.DEFAULT_SERVER_DATETIME_FORMAT))])
for scheduler in schedulers:
scheduler.execute()
if autocommit:
self.env.cr.commit()
try:
with self.env.cr.savepoint():
scheduler.execute()
except Exception as e:
_logger.exception(e)
self.invalidate_cache()
self._warn_template_error(scheduler, e)
else:
if autocommit:
self.env.cr.commit()
return True
+11 -1
View File
@@ -412,8 +412,18 @@ class Message(models.Model):
subtypes = self.env['mail.message.subtype'].sudo().browse(subtype_ids).read(['internal', 'description','id'])
subtypes_dict = dict((subtype['id'], subtype) for subtype in subtypes)
xml_comment_id = self.env.ref('mail.mt_comment').id
# fetch notification status
notif_dict = {}
notifs = self.env['mail.notification'].sudo().search([('mail_message_id', 'in', list(mid for mid in message_tree)), ('is_read', '=', False)])
for notif in notifs:
mid = notif.mail_message_id.id
if not notif_dict.get(mid):
notif_dict[mid] = {'partner_id': list()}
notif_dict[mid]['partner_id'].append(notif.res_partner_id.id)
for message in message_values:
message['needaction_partner_ids'] = self.env['mail.notification'].sudo().search([('mail_message_id', '=', message['id']), ('is_read', '=', False)]).mapped('res_partner_id').ids
message['needaction_partner_ids'] = notif_dict.get(message['id'], dict()).get('partner_id', [])
message['is_note'] = message['subtype_id'] and subtypes_dict[message['subtype_id'][0]]['internal']
message['is_discussion'] = message['subtype_id'] and subtypes_dict[message['subtype_id'][0]]['id'] == xml_comment_id
message['subtype_description'] = message['subtype_id'] and subtypes_dict[message['subtype_id'][0]]['description']
+7 -1
View File
@@ -1366,7 +1366,13 @@ class MailThread(models.AbstractModel):
located in tools. """
if not body:
return body, attachments
root = lxml.html.fromstring(body)
try:
root = lxml.html.fromstring(body)
except ValueError:
# In case the email client sent XHTML, fromstring will fail because 'Unicode strings
# with encoding declaration are not supported'.
root = lxml.html.fromstring(body.encode('utf-8'))
postprocessed = False
to_remove = []
for node in root.iter():
+4 -1
View File
@@ -260,6 +260,7 @@ exports.PosModel = Backbone.Model.extend({
// we attribute a role to the user, 'cashier' or 'manager', depending
// on the group the user belongs.
var pos_users = [];
var current_cashier = self.get_cashier();
for (var i = 0; i < users.length; i++) {
var user = users[i];
for (var j = 0; j < user.groups_id.length; j++) {
@@ -277,6 +278,8 @@ exports.PosModel = Backbone.Model.extend({
// replace the current user with its updated version
if (user.id === self.user.id) {
self.user = user;
}
if (user.id === current_cashier.id) {
self.set_cashier(user);
}
}
@@ -630,7 +633,7 @@ exports.PosModel = Backbone.Model.extend({
// changes the current cashier
set_cashier: function(user){
this.set('cashier', user);
this.db.set_cashier(this.cashier);
this.db.set_cashier(this.get('cashier'));
},
//creates a new empty order and sets it as the current order
add_new_order: function(){
+3 -3
View File
@@ -425,10 +425,10 @@ class StockMove(models.Model):
if propagated_date_field:
current_date = datetime.strptime(move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT)
new_date = datetime.strptime(vals.get(propagated_date_field), DEFAULT_SERVER_DATETIME_FORMAT)
delta = relativedelta.relativedelta(new_date, current_date)
if abs(delta.days) >= move.company_id.propagation_minimum_delta:
delta_days = (new_date - current_date).total_seconds() / 86400
if abs(delta_days) >= move.company_id.propagation_minimum_delta:
old_move_date = datetime.strptime(move.move_dest_ids[0].date_expected, DEFAULT_SERVER_DATETIME_FORMAT)
new_move_date = (old_move_date + relativedelta.relativedelta(days=delta.days or 0)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
new_move_date = (old_move_date + relativedelta.relativedelta(days=delta_days or 0)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
propagated_changes_dict['date_expected'] = new_move_date
#For pushed moves as well as for pulled moves, propagate by recursive call of write().
#Note that, for pulled moves we intentionally don't propagate on the procurement.
+5 -3
View File
@@ -372,6 +372,7 @@ class StockMove(models.Model):
product_tot_qty_available = move.product_id.qty_available + tmpl_dict[move.product_id.id]
rounding = move.product_id.uom_id.rounding
qty_done = 0.0
if float_is_zero(product_tot_qty_available, precision_rounding=rounding):
new_std_price = move._get_price_unit()
elif float_is_zero(product_tot_qty_available + move.product_qty, precision_rounding=rounding):
@@ -379,10 +380,11 @@ class StockMove(models.Model):
else:
# Get the standard price
amount_unit = std_price_update.get((move.company_id.id, move.product_id.id)) or move.product_id.standard_price
qty = forced_qty or move.product_qty
new_std_price = ((amount_unit * product_tot_qty_available) + (move._get_price_unit() * qty)) / (product_tot_qty_available + move.product_qty)
qty_done = move.product_uom._compute_quantity(move.quantity_done, move.product_id.uom_id)
qty = forced_qty or qty_done
new_std_price = ((amount_unit * product_tot_qty_available) + (move._get_price_unit() * qty)) / (product_tot_qty_available + qty_done)
tmpl_dict[move.product_id.id] += move.product_qty
tmpl_dict[move.product_id.id] += qty_done
# Write the standard price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products
move.product_id.with_context(force_company=move.company_id.id).sudo().write({'standard_price': new_std_price})
std_price_update[move.company_id.id, move.product_id.id] = new_std_price
@@ -2489,6 +2489,39 @@ class TestStockValuation(TransactionCase):
move2.move_line_ids.qty_done = 0
self.assertEqual(self.product1.stock_value, -187.5)
def test_average_perpetual_4(self):
self.product1.product_tmpl_id.cost_method = 'average'
move1 = self.env['stock.move'].create({
'name': 'Receive 1 unit at 10',
'location_id': self.supplier_location.id,
'location_dest_id': self.stock_location.id,
'product_id': self.product1.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': 1.0,
'price_unit': 10,
})
move1._action_confirm()
move1._action_assign()
move1.move_line_ids.qty_done = 1.0
move1._action_done()
move2 = self.env['stock.move'].create({
'name': 'Receive 3 units at 5',
'location_id': self.supplier_location.id,
'location_dest_id': self.stock_location.id,
'product_id': self.product1.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': 3.0,
'price_unit': 5,
})
move2._action_confirm()
move2._action_assign()
move2.move_line_ids.qty_done = 1.0
move2._action_done()
self.assertAlmostEqual(self.product1.standard_price, 7.5)
def test_average_negative_1(self):
""" Test edit in the past. Receive 10, send 20, edit the second move to only send 10.
"""
+242
View File
@@ -432,3 +432,245 @@ Web: <a class="moz-txt-link-freetext" href="http://www.odoo.com">http://www.odoo
--------------1F2D18B1129FC2F0B9EECF50--
--------------A6B5FD5F68F4D73ECD739009--"""
MAIL_XHTML = """Return-Path: <xxxx@xxxx.com>
Received: from xxxx.internal (xxxx.xxxx.internal [1.1.1.1])
by xxxx (xxxx 1.1.1-111-g972eecc-slipenbois) with LMTPA;
Fri, 13 Apr 2018 22:11:52 -0400
X-Cyrus-Session-Id: sloti35d1t38-1111111-11111111111-5-11111111111111111111
X-Sieve: CMU Sieve 1.0
X-Spam-known-sender: no ("Email failed DMARC policy for domain"); in-addressbook
X-Spam-score: 0.0
X-Spam-hits: ALL_TRUSTED -1, BAYES_00 -1.9, FREEMAIL_FROM 0.001,
HTML_FONT_LOW_CONTRAST 0.001, HTML_MESSAGE 0.001, SPF_SOFTFAIL 0.665,
LANGUAGES en, BAYES_USED global, SA_VERSION 1.1.0
X-Spam-source: IP='1.1.1.1', Host='unk', Country='unk', FromHeader='com',
MailFrom='com'
X-Spam-charsets: plain='utf-8', html='utf-8'
X-IgnoreVacation: yes ("Email failed DMARC policy for domain")
X-Resolved-to: catchall@xxxx.xxxx
X-Delivered-to: catchall@xxxx.xxxx
X-Mail-from: xxxx@xxxx.com
Received: from mx4 ([1.1.1.1])
by xxxx.internal (LMTPProxy); Fri, 13 Apr 2018 22:11:52 -0400
Received: from xxxx.xxxx.com (localhost [127.0.0.1])
by xxxx.xxxx.internal (Postfix) with ESMTP id E1111C1111;
Fri, 13 Apr 2018 22:11:51 -0400 (EDT)
Received: from xxxx.xxxx.internal (localhost [127.0.0.1])
by xxxx.xxxx.com (Authentication Milter) with ESMTP
id BBDD1111D1A;
Fri, 13 Apr 2018 22:11:51 -0400
ARC-Authentication-Results: i=1; xxxx.xxxx.com; arc=none (no signatures found);
dkim=pass (2048-bit rsa key sha256) header.d=xxxx.com header.i=@xxxx.com header.b=P1aaAAaa x-bits=2048 x-keytype=rsa x-algorithm=sha256 x-selector=fm2;
dmarc=fail (p=none,d=none) header.from=xxxx.com;
iprev=pass policy.iprev=1.1.1.1 (out1-smtp.xxxx.com);
spf=softfail smtp.mailfrom=xxxx@xxxx.com smtp.helo=out1-smtp.xxxx.com;
x-aligned-from=pass (Address match);
x-cm=none score=0;
x-ptr=pass x-ptr-helo=out1-smtp.xxxx.com x-ptr-lookup=out1-smtp.xxxx.com;
x-return-mx=pass smtp.domain=xxxx.com smtp.result=pass smtp_is_org_domain=yes header.domain=xxxx.com header.result=pass header_is_org_domain=yes;
x-tls=pass version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128;
x-vs=clean score=0 state=0
Authentication-Results: xxxx.xxxx.com;
arc=none (no signatures found);
dkim=pass (2048-bit rsa key sha256) header.d=xxxx.com header.i=@xxxx.com header.b=P1awJPiy x-bits=2048 x-keytype=rsa x-algorithm=sha256 x-selector=fm2;
dmarc=fail (p=none,d=none) header.from=xxxx.com;
iprev=pass policy.iprev=66.111.4.25 (out1-smtp.xxxx.com);
spf=softfail smtp.mailfrom=xxxx@xxxx.com smtp.helo=out1-smtp.xxxx.com;
x-aligned-from=pass (Address match);
x-cm=none score=0;
x-ptr=pass x-ptr-helo=out1-smtp.xxxx.com x-ptr-lookup=out1-smtp.xxxx.com;
x-return-mx=pass smtp.domain=xxxx.com smtp.result=pass smtp_is_org_domain=yes header.domain=xxxx.com header.result=pass header_is_org_domain=yes;
x-tls=pass version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128;
x-vs=clean score=0 state=0
X-ME-VSCategory: clean
X-ME-CMScore: 0
X-ME-CMCategory: none
Received-SPF: softfail
(gmail.com ... _spf.xxxx.com: Sender is not authorized by default to use 'xxxx@xxxx.com' in 'mfrom' identity, however domain is not currently prepared for false failures (mechanism '~all' matched))
receiver=xxxx.xxxx.com;
identity=mailfrom;
envelope-from="xxxx@xxxx.com";
helo=out1-smtp.xxxx.com;
client-ip=1.1.1.1
Received: from xxxx.xxxx.internal (gateway1.xxxx.internal [1.1.1.1])
(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))
(No client certificate requested)
by xxxx.xxxx.internal (Postfix) with ESMTPS;
Fri, 13 Apr 2018 22:11:51 -0400 (EDT)
Received: from compute3.internal (xxxx.xxxx.internal [10.202.2.43])
by xxxx.xxxx.internal (Postfix) with ESMTP id 8BD5B21BBD;
Fri, 13 Apr 2018 22:11:51 -0400 (EDT)
Received: from xxxx ([10.202.2.163])
by xxxx.internal (MEProxy); Fri, 13 Apr 2018 22:11:51 -0400
X-ME-Sender: <xms:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>
Received: from [1.1.1.1] (unknown [1.1.1.1])
by mail.xxxx.com (Postfix) with ESMTPA id BF5E1111D
for <catchall@xxxx.xxxx>; Fri, 13 Apr 2018 22:11:50 -0400 (EDT)
From: "xxxx xxxx" <xxxx@xxxx.com>
To: "xxxx" <catchall@xxxx.xxxx>
Subject: Re: xxxx (Ref PO1)
Date: Sat, 14 Apr 2018 02:11:42 +0000
Message-Id: <em67f5c44a-xxxx-xxxx-xxxx-69f56d618a94@wswin7hg4n4l1ce>
In-Reply-To: <829228111124527.1111111602.256611118262939-openerp-129-xxxx.xxxx@ip-1-1-1-1>
References: <867911111953277.1523671337.187951111160400-openerp-129-xxxx.xxxx@ip-1-1-1-1>
<867911111953277.1523671337.256611118262939-openerp-129-xxxx.xxxx@ip-1-1-1-1>
Reply-To: "xxxx xxxx" <xxxx@xxxx.com>
User-Agent: eM_Client/7.0.26687.0
Mime-Version: 1.0
Content-Type: multipart/alternative;
boundary="------=_MB48E455BD-1111-42EC-1111-886CDF48905E"
--------=_MB48E455BD-1111-42EC-1111-886CDF48905E
Content-Type: text/plain; format=flowed; charset=utf-8
Content-Transfer-Encoding: quoted-printable
xxxx
------ Original Message ------
From: "xxxx" <xxxx@xxxx.com>
To: "xxxx" <xxxx@xxxx.com>
Sent: 4/13/2018 7:06:43 PM
Subject: xxxx
>xxxx
--------=_MB48E455BD-1111-42EC-1111-886CDF48905E
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
<?xml version=3D"1.0" encoding=3D"utf-16"?><html><head><style type=3D"text/=
css"><!--blockquote.cite
{margin-left: 5px; margin-right: 0px; padding-left: 10px; padding-right:=
0px; border-left-width: 1px; border-left-style: solid; border-left-color:=
rgb(204, 204, 204);}
blockquote.cite2
{margin-left: 5px; margin-right: 0px; padding-left: 10px; padding-right:=
0px; border-left-width: 1px; border-left-style: solid; border-left-color:=
rgb(204, 204, 204); margin-top: 3px; padding-top: 0px;}
a img
{border: 0px;}
body
{font-family: Tahoma; font-size: 12pt;}
--></style></head><body><div>this is a reply to PO200109 from emClient</div=
><div id=3D"signature_old"><div style=3D"font-family: Tahoma; font-size:=
12 pt;">-- <br /><span><span class=3D"__postbox-detected-content __postbox=
-detected-address" style=3D"TEXT-DECORATION: underline; COLOR: rgb(115,133,=
172); PADDING-BOTTOM: 0pt; PADDING-TOP: 0pt; PADDING-LEFT: 0pt; DISPLAY:=
inline; PADDING-RIGHT: 0pt" __postbox-detected-content=3D"__postbox-detect=
ed-address"></span>xxxx<br />xxxx<br /><b=
r />xxxx</span></=
div></div><div><br /></div><div><br /></div><div><br /></div>
<div>------ Original Message ------</div>
<div>From: "xxxx" &lt;<a href=3D"mailto:xxxx@xxxx.com">xxxx=
@xxxx.com</a>&gt;</div>
<div>To: "xxxx" &lt;<a href=3D"mailto:xxxx@xxxx.com">a=
xxxx@xxxx.com</a>&gt;</div>
<div>Sent: 4/13/2018 7:06:43 PM</div>
<div>Subject: xxxx</div><div><br /></div=
>
<div id=3D"x00b4101ba6e64ce"><blockquote cite=3D"829228972724527.1523671602=
.256660938262939-openerp-129-xxxx.xxxx@ip-1-1-1-1" type=3D"cite"=
class=3D"cite2">
<table border=3D"0" width=3D"100%" cellpadding=3D"0" bgcolor=3D"#ededed"=
style=3D"padding: 20px; background-color: #ededed" summary=3D"o_mail_notif=
ication">
<tbody>
<!-- HEADER -->
<tr>
<td align=3D"center" style=3D"min-width: 590px;">
<table width=3D"590" border=3D"0" cellpadding=3D=
"0" bgcolor=3D"#875A7B" style=3D"min-width: 590px; background-color: rgb(13=
5,90,123); padding: 20px;">
<tbody><tr>
<td valign=3D"middle">
<span style=3D"font-size:20px; color:whit=
e; font-weight: bold;">
mangez des saucisses
</span>
</td>
<td valign=3D"middle" align=3D"right">
<img src=3D"http://erp.xxxx.xxxx/logo.png=
" style=3D"padding: 0px; margin: 0px; height: auto; width: 80px;" alt=3D=
"xxxx" />
</td>
</tr>
</tbody></table>
</td>
</tr>
<!-- CONTENT -->
<tr>
<td align=3D"center" style=3D"min-width: 590px;">
<table width=3D"590" border=3D"0" cellpadding=3D=
"0" bgcolor=3D"#ffffff" style=3D"min-width: 590px; background-color: rgb(25=
5, 255, 255); padding: 20px;">
<tbody>
<tr><td valign=3D"top" style=3D"font-family:A=
rial,Helvetica,sans-serif; color: #555; font-size: 14px;">
<p style=3D"margin: 0px 0px 9px 0px; font-s=
ize: 13px; font-family: &quot;Lucida Grande&quot;, Helvetica, Verdana, Aria=
l, sans-serif">xxxx.=20
,</p>
<p style=3D"margin: 0px 0px 9px 0px; font-size: 13px; font-family: &quot;Lu=
cida Grande&quot;, Helvetica, Verdana, Arial, sans-serif">
xxxx.
</p>
<p style=3D"margin: 0px 0px 9px 0px; font-size: 13px; font-family: &quot;Lu=
cida Grande&quot;, Helvetica, Verdana, Arial, sans-serif">You can reply =
to this email if you have any questions.</p>
<p style=3D"margin: 0px 0px 9px 0px; font-size: 13px; font-family: &quot;Lu=
cida Grande&quot;, Helvetica, Verdana, Arial, sans-serif">Thank you,</p>
</td>
</tr></tbody>
</table>
</td>
</tr>
<!-- FOOTER -->
<tr>
<td align=3D"center" style=3D"min-width: 590px;">
<table width=3D"590" border=3D"0" cellpadding=3D=
"0" bgcolor=3D"#875A7B" style=3D"min-width: 590px; background-color: rgb(13=
5,90,123); padding: 20px;">
<tbody><tr>
<td valign=3D"middle" align=3D"left" style=
=3D"color: #fff; padding-top: 10px; padding-bottom: 10px; font-size: 12px;"=
>
xxxx<br />
+1-801-980-4240
</td>
<td valign=3D"middle" align=3D"right" style=
=3D"color: #fff; padding-top: 10px; padding-bottom: 10px; font-size: 12px;"=
>
<a href=3D"http://erp.xxxx.xxxx/info@xxxx-a=
aa.com" style=3D"text-decoration:none; color: white;">info@aust-mfg.com</a>=
<br />
<a href=3D"http://www.xxxx=
.com" style=3D"text-decoration:none; color: white;">
http://www.xxxx.com
</a>
</td>
</tr>
</tbody></table>
</td>
</tr>
<tr>
<td align=3D"center">
Powered by <a href=3D"https://www.odoo.com">Odo=
o</a>.
</td>
</tr>
</tbody>
</table>
=20
<pre style=3D"white-space: pre-wrap">xxxx.
</pre>
</blockquote></div>
</body></html>
--------=_MB48E455BD-2850-42EC-B1CA-886CDF48905E--"""
+7 -1
View File
@@ -7,7 +7,7 @@ from email.utils import formataddr
from odoo.addons.test_mail.data.test_mail_data import \
MAIL_TEMPLATE, MAIL_TEMPLATE_PLAINTEXT, MAIL_MULTIPART_MIXED, MAIL_MULTIPART_MIXED_TWO, \
MAIL_MULTIPART_IMAGE, MAIL_SINGLE_BINARY, MAIL_EML_ATTACHMENT
MAIL_MULTIPART_IMAGE, MAIL_SINGLE_BINARY, MAIL_EML_ATTACHMENT, MAIL_XHTML
from odoo.addons.test_mail.tests.common import BaseFunctionalTest, MockEmails
from odoo.tools import mute_logger
@@ -84,6 +84,12 @@ class TestMailgateway(BaseFunctionalTest, MockEmails):
"""
self.env['mail.thread'].message_process('mail.channel', MAIL_EML_ATTACHMENT)
@mute_logger('odoo.addons.mail.models.mail_thread')
def test_message_parse_xhtml(self):
""" Test that the parsing of mail with embedded emails as eml(msg) which generates empty attachments, can be processed.
"""
self.env['mail.thread'].message_process('mail.channel', MAIL_XHTML)
@mute_logger('odoo.addons.mail.models.mail_thread')
def test_message_process_cid(self):
record = self.format_and_process(MAIL_MULTIPART_IMAGE, to='groups@example.com')
@@ -4105,10 +4105,20 @@ var BasicModel = AbstractModel.extend({
var r2 = self.localData[record2ID];
var data1 = _.extend({}, r1.data, r1._changes);
var data2 = _.extend({}, r2.data, r2._changes);
if (data1[order.name] < data2[order.name]) {
// Default value to sort against: the value of the field
var orderData1 = data1[order.name];
var orderData2 = data2[order.name];
// If the field is a relation, sort on the display_name of those records
if (list.fields[order.name].type === 'many2one') {
orderData1 = orderData1 ? self.localData[orderData1].data.display_name : "";
orderData2 = orderData2 ? self.localData[orderData2].data.display_name : "";
}
if (orderData1 < orderData2) {
return order.asc ? -1 : 1;
}
if (data1[order.name] > data2[order.name]) {
if (orderData1 > orderData2) {
return order.asc ? 1 : -1;
}
return compareRecords(record1ID, record2ID, level + 1);
@@ -2272,6 +2272,43 @@ QUnit.module('relational_fields', {
form.destroy();
});
QUnit.test('x2many list sorted by many2one', function (assert) {
assert.expect(3);
this.data.partner.records[0].p = [1, 2, 4];
this.data.partner.fields.trululu.sortable = true;
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form>' +
'<field name="p">' +
'<tree>' +
'<field name="id"/>' +
'<field name="trululu"/>' +
'</tree>' +
'</field>' +
'</form>',
res_id: 1,
});
assert.strictEqual(form.$('.o_data_row .o_list_number').text(), '124',
"should have correct order initially");
form.$('.o_list_view thead th:nth(1)').click();
assert.strictEqual(form.$('.o_data_row .o_list_number').text(), '412',
"should have correct order (ASC)");
form.$('.o_list_view thead th:nth(1)').click();
assert.strictEqual(form.$('.o_data_row .o_list_number').text(), '214',
"should have correct order (DESC)");
form.destroy();
});
QUnit.test('many2many list add *many* records, remove, re-add', function (assert) {
assert.expect(5);
+6 -1
View File
@@ -14,6 +14,7 @@ from hashlib import sha256
from odoo import api, fields, models, tools, SUPERUSER_ID, _
from odoo.exceptions import AccessDenied, AccessError, UserError, ValidationError
from odoo.http import request
from odoo.osv import expression
from odoo.service.db import check_super
from odoo.tools import partition, pycompat
@@ -466,8 +467,12 @@ class Users(models.Model):
user.sudo(user_id).check_credentials(password)
user.sudo(user_id)._update_last_login()
except AccessDenied:
_logger.info("Login failed for db:%s login:%s", db, login)
user_id = False
status = "successful" if user_id else "failed"
ip = request.httprequest.environ['REMOTE_ADDR'] if request else 'n/a'
_logger.info("Login %s for db:%s login:%s from %s", status, db, login, ip)
return user_id
@classmethod