diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index ad2fd5d25b4..dfd83aad1e9 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -1426,6 +1426,7 @@ class AccountInvoiceTax(models.Model):
base = fields.Monetary(string='Base', compute='_compute_base_amount', store=True)
# DO NOT FORWARD-PORT!!! ONLY FOR v10
+ @api.model
def create(self, vals):
inv_tax = super(AccountInvoiceTax, self).create(vals)
# Workaround to make sure the tax amount is rounded to the currency precision since the ORM
diff --git a/addons/account_cash_basis_base_account/__init__.py b/addons/account_cash_basis_base_account/__init__.py
new file mode 100644
index 00000000000..2971a2d9b7f
--- /dev/null
+++ b/addons/account_cash_basis_base_account/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import account_tax
+import account_partial_reconcile
diff --git a/addons/account_cash_basis_base_account/__manifest__.py b/addons/account_cash_basis_base_account/__manifest__.py
new file mode 100644
index 00000000000..331b3c812d7
--- /dev/null
+++ b/addons/account_cash_basis_base_account/__manifest__.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+{
+ 'name' : 'Tax Cash Basis Edit Base Account',
+ 'version' : '1.0',
+ 'summary': 'Add a custom account to handle base amount lines',
+ 'sequence': 5,
+ 'description': """
+Move the cash basis lines to another account.
+ """,
+ 'category': 'Accounting',
+ 'depends': ['account'],
+ 'data': [
+ 'views/account_tax_views.xml',
+ ],
+ 'installable': True,
+ 'auto_install': True,
+}
diff --git a/addons/account_cash_basis_base_account/account_partial_reconcile.py b/addons/account_cash_basis_base_account/account_partial_reconcile.py
new file mode 100644
index 00000000000..6e51ac61e7a
--- /dev/null
+++ b/addons/account_cash_basis_base_account/account_partial_reconcile.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from openerp import api, models
+
+
+class AccountPartialReconcileCashBasis(models.Model):
+ _inherit = 'account.partial.reconcile'
+
+ def _get_tax_cash_basis_base_account(self, line, tax):
+ if tax.cash_basis_base_account_id:
+ return tax.cash_basis_base_account_id
+ return super(AccountPartialReconcileCashBasis, self)._get_tax_cash_basis_base_account(line, tax)
diff --git a/addons/account_cash_basis_base_account/account_tax.py b/addons/account_cash_basis_base_account/account_tax.py
new file mode 100644
index 00000000000..d8b6c4ca87f
--- /dev/null
+++ b/addons/account_cash_basis_base_account/account_tax.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+
+from openerp import api, fields, models
+
+
+class AccountTax(models.Model):
+ _inherit = 'account.tax'
+
+ cash_basis_base_account_id = fields.Many2one('account.account', domain=[('deprecated', '=', False)],
+ string='Base Tax Received Account',
+ help='Account that will be set on lines created in cash basis journal entry and used to keep track of the tax base amount.')
diff --git a/addons/account_cash_basis_base_account/views/account_tax_views.xml b/addons/account_cash_basis_base_account/views/account_tax_views.xml
new file mode 100644
index 00000000000..1e9d1a814fc
--- /dev/null
+++ b/addons/account_cash_basis_base_account/views/account_tax_views.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ tax.form.cash.basis.base.account.inherit
+ account.tax
+
+
+
+
+
+
+
+
+
diff --git a/addons/account_voucher/models/account_voucher.py b/addons/account_voucher/models/account_voucher.py
index 2dfcd06835a..b9dce93cdc9 100644
--- a/addons/account_voucher/models/account_voucher.py
+++ b/addons/account_voucher/models/account_voucher.py
@@ -286,6 +286,9 @@ class AccountVoucher(models.Model):
#create one move line per voucher line where amount is not 0.0
if not line.price_subtotal:
continue
+ line_subtotal = line.price_subtotal
+ if self.voucher_type == 'sale':
+ line_subtotal = -1 * line.price_subtotal
# convert the amount set on the voucher line into the currency of the voucher's company
# this calls res_curreny.compute() with the right context,
# so that it will take either the rate on the voucher if it is relevant or will use the default behaviour
@@ -302,7 +305,7 @@ class AccountVoucher(models.Model):
'debit': abs(amount) if self.voucher_type == 'purchase' else 0.0,
'date': self.account_date,
'tax_ids': [(4,t.id) for t in line.tax_ids],
- 'amount_currency': line.price_subtotal if current_currency != company_currency else 0.0,
+ 'amount_currency': line_subtotal if current_currency != company_currency else 0.0,
'currency_id': company_currency != current_currency and current_currency or False,
'payment_id': self._context.get('payment_id'),
}
diff --git a/addons/hr_attendance/static/src/js/greeting_message.js b/addons/hr_attendance/static/src/js/greeting_message.js
index c0f120983ad..f2efc987d03 100644
--- a/addons/hr_attendance/static/src/js/greeting_message.js
+++ b/addons/hr_attendance/static/src/js/greeting_message.js
@@ -41,11 +41,18 @@ var GreetingMessage = Widget.extend(BarcodeHandlerMixin, {
if (this.next_action != 'hr_attendance.hr_attendance_action_kiosk_mode' && this.next_action.tag != 'hr_attendance_kiosk_mode') {
this.stop_listening();
}
+
this.attendance = action.attendance;
+ // We receive the check in/out times in UTC
+ // This widget only deals with display, which should be in browser's TimeZone
+ this.attendance.check_in = this.attendance.check_in && moment.utc(this.attendance.check_in).local();
+ this.attendance.check_out = this.attendance.check_out && moment.utc(this.attendance.check_out).local();
+ this.previous_attendance_change_date = action.previous_attendance_change_date && moment.utc(action.previous_attendance_change_date).local();
+
// check in/out times displayed in the greeting message template.
- this.attendance.check_in_time = (new Date((new Date(this.attendance.check_in)).valueOf() - (new Date()).getTimezoneOffset()*60*1000)).toTimeString().slice(0,8);
- this.attendance.check_out_time = this.attendance.check_out && (new Date((new Date(this.attendance.check_out)).valueOf() - (new Date()).getTimezoneOffset()*60*1000)).toTimeString().slice(0,8);
- this.previous_attendance_change_date = action.previous_attendance_change_date;
+ this.format_time = 'HH:mm:ss';
+ this.attendance.check_in_time = this.attendance.check_in && this.attendance.check_in.format(this.format_time);
+ this.attendance.check_out_time = this.attendance.check_out && this.attendance.check_out.format(this.format_time);
this.employee_name = action.employee_name;
},
@@ -57,13 +64,13 @@ var GreetingMessage = Widget.extend(BarcodeHandlerMixin, {
welcome_message: function() {
var self = this;
- var now = new Date((new Date(this.attendance.check_in)).valueOf() - (new Date()).getTimezoneOffset()*60*1000);
+ var now = this.attendance.check_in.clone();
this.return_to_main_menu = setTimeout( function() { self.do_action(self.next_action, {clear_breadcrumbs: true}); }, 5000);
- if (now.getHours() < 5) {
+ if (now.hours() < 5) {
this.$('.o_hr_attendance_message_message').append(_t("Good night"));
- } else if (now.getHours() < 12) {
- if (now.getHours() < 8 && Math.random() < 0.3) {
+ } else if (now.hours() < 12) {
+ if (now.hours() < 8 && Math.random() < 0.3) {
if (Math.random() < 0.75) {
this.$('.o_hr_attendance_message_message').append(_t("The early bird catches the worm"));
} else {
@@ -72,16 +79,16 @@ var GreetingMessage = Widget.extend(BarcodeHandlerMixin, {
} else {
this.$('.o_hr_attendance_message_message').append(_t("Good morning"));
}
- } else if (now.getHours() < 17){
+ } else if (now.hours() < 17){
this.$('.o_hr_attendance_message_message').append(_t("Good afternoon"));
- } else if (now.getHours() < 23){
+ } else if (now.hours() < 23){
this.$('.o_hr_attendance_message_message').append(_t("Good evening"));
} else {
this.$('.o_hr_attendance_message_message').append(_t("Good night"));
}
if(this.previous_attendance_change_date){
- var last_check_out_date = new Date((new Date(this.previous_attendance_change_date)).valueOf() - (new Date()).getTimezoneOffset()*60*1000);
- if(now.valueOf() - last_check_out_date.valueOf() > 1000*60*60*24*7){
+ var last_check_out_date = this.previous_attendance_change_date.clone();
+ if(now - last_check_out_date > 24*7*60*60*1000){
this.$('.o_hr_attendance_random_message').html(_t("Glad to have you back, it's been a while!"));
} else {
if(Math.random() < 0.02){
@@ -93,33 +100,33 @@ var GreetingMessage = Widget.extend(BarcodeHandlerMixin, {
farewell_message: function() {
var self = this;
- var now = new Date((new Date(this.attendance.check_out)).valueOf() - (new Date()).getTimezoneOffset()*60*1000);
+ var now = this.attendance.check_out.clone();
this.return_to_main_menu = setTimeout( function() { self.do_action(self.next_action, {clear_breadcrumbs: true}); }, 5000);
if(this.previous_attendance_change_date){
- var last_check_in_date = new Date((new Date(this.previous_attendance_change_date)).valueOf() - (new Date()).getTimezoneOffset()*60*1000);
- if(now.valueOf() - last_check_in_date.valueOf() > 1000*60*60*12){
+ var last_check_in_date = this.previous_attendance_change_date.clone();
+ if(now - last_check_in_date > 1000*60*60*12){
this.$('.o_hr_attendance_warning_message').append(_t("Warning! Last check in was over 12 hours ago. If this isn't right, please contact Human Resources."));
clearTimeout(this.return_to_main_menu);
this.stop_listening();
- } else if(now.valueOf() - last_check_in_date.valueOf() > 1000*60*60*8){
+ } else if(now - last_check_in_date > 1000*60*60*8){
this.$('.o_hr_attendance_random_message').html(_t("Another good day's work! See you soon!"));
}
}
- if (now.getHours() < 12) {
+ if (now.hours() < 12) {
this.$('.o_hr_attendance_message_message').append(_t("Have a good day!"));
- } else if (now.getHours() < 14) {
+ } else if (now.hours() < 14) {
this.$('.o_hr_attendance_message_message').append(_t("Have a nice lunch!"));
if (Math.random() < 0.05) {
this.$('.o_hr_attendance_random_message').html(_t("Eat breakfast as a king, lunch as a merchant and supper as a beggar"));
} else if (Math.random() < 0.06) {
this.$('.o_hr_attendance_random_message').html(_t("An apple a day keeps the doctor away"));
}
- } else if (now.getHours() < 17) {
+ } else if (now.hours() < 17) {
this.$('.o_hr_attendance_message_message').append(_t("Have a good afternoon"));
} else {
- if (now.getHours() < 18 && Math.random() < 0.2) {
+ if (now.hours() < 18 && Math.random() < 0.2) {
this.$('.o_hr_attendance_message_message').append(_t("Early to bed and early to rise, makes a man healthy, wealthy and wise"));
} else {
this.$('.o_hr_attendance_message_message').append(_t("Have a good evening"));
diff --git a/addons/hr_recruitment/data/hr_recruitment_data.xml b/addons/hr_recruitment/data/hr_recruitment_data.xml
index 0dc5b1b7b57..b1a7e9aed75 100644
--- a/addons/hr_recruitment/data/hr_recruitment_data.xml
+++ b/addons/hr_recruitment/data/hr_recruitment_data.xml
@@ -11,7 +11,7 @@
Applicant: RefuseApplication refused
- ${object.email_from}
+ ${object.email_from | safe}${object.partner_id and object.partner_id.id or ''}${object.partner_id and object.partner_id.lang or ''}
@@ -27,7 +27,7 @@ Unfortunately, your profile does not match with our needs
Applicant: InterestApplication approved
- ${object.email_from}
+ ${object.email_from | safe}${object.partner_id and object.partner_id.id or ''}${object.partner_id and object.partner_id.lang or ''}
diff --git a/addons/l10n_ca/data/l10n_ca_chart_data.xml b/addons/l10n_ca/data/l10n_ca_chart_data.xml
index 8610079a78f..64b7849d9f2 100644
--- a/addons/l10n_ca/data/l10n_ca_chart_data.xml
+++ b/addons/l10n_ca/data/l10n_ca_chart_data.xml
@@ -29,7 +29,7 @@
1181
-
+ GST receivable
@@ -37,7 +37,7 @@
1182
-
+ PST/QST receivable
@@ -45,7 +45,7 @@
11831
-
+ HST receivable - 13%
@@ -53,7 +53,7 @@
11832
-
+ HST receivable - 14%
@@ -61,7 +61,7 @@
11833
-
+ HST receivable - 15%
@@ -79,7 +79,7 @@
2131
-
+ GST to pay
@@ -87,7 +87,7 @@
2132
-
+ PST/QST to pay
@@ -95,7 +95,7 @@
21331
-
+ HST to pay - 13%
@@ -103,7 +103,7 @@
21332
-
+ HST to pay - 14%
@@ -111,7 +111,7 @@
21333
-
+ HST to pay - 15%
diff --git a/addons/l10n_fr_pos_cert/models/account_bank_statement.py b/addons/l10n_fr_pos_cert/models/account_bank_statement.py
index 28afbf0d549..f0753885bc1 100644
--- a/addons/l10n_fr_pos_cert/models/account_bank_statement.py
+++ b/addons/l10n_fr_pos_cert/models/account_bank_statement.py
@@ -6,6 +6,7 @@ from openerp.exceptions import UserError
class AccountBankStatement(models.Model):
_inherit = 'account.bank.statement'
+ @api.multi
def unlink(self):
for statement in self.filtered(lambda s: s.company_id._is_accounting_unalterable() and s.journal_id.journal_user):
raise UserError(_('You cannot modify anything on a bank statement (name: %s) that was created by point of sale operations.') % (statement.name,))
@@ -15,6 +16,7 @@ class AccountBankStatement(models.Model):
class AccountBankStatementLine(models.Model):
_inherit = 'account.bank.statement.line'
+ @api.multi
def unlink(self):
for line in self.filtered(lambda s: s.company_id._is_accounting_unalterable() and s.journal_id.journal_user):
raise UserError(_('You cannot modify anything on a bank statement line (name: %s) that was created by point of sale operations.') % (line.name,))
diff --git a/addons/payment_stripe/models/payment.py b/addons/payment_stripe/models/payment.py
index 0fe3dc746d9..6cd4899bfc1 100644
--- a/addons/payment_stripe/models/payment.py
+++ b/addons/payment_stripe/models/payment.py
@@ -40,16 +40,16 @@ class PaymentAcquirerStripe(models.Model):
stripe_tx_values = dict(tx_values)
temp_stripe_tx_values = {
'company': self.company_id.name,
- 'amount': tx_values.get('amount'),
- 'currency': tx_values.get('currency') and tx_values.get('currency').name or '',
- 'currency_id': tx_values.get('currency') and tx_values.get('currency').id or '',
- 'address_line1': tx_values['partner_address'],
- 'address_city': tx_values['partner_city'],
- 'address_country': tx_values['partner_country'] and tx_values['partner_country'].name or '',
- 'email': tx_values['partner_email'],
- 'address_zip': tx_values['partner_zip'],
- 'name': tx_values['partner_name'],
- 'phone': tx_values['partner_phone'],
+ 'amount': tx_values['amount'], # Mandatory
+ 'currency': tx_values['currency'].name, # Mandatory anyway
+ 'currency_id': tx_values['currency'].id, # same here
+ 'address_line1': tx_values.get('partner_address'), # Any info of the partner is not mandatory
+ 'address_city': tx_values.get('partner_city'),
+ 'address_country': tx_values.get('partner_country') and tx_values.get('partner_country').name or '',
+ 'email': tx_values.get('partner_email'),
+ 'address_zip': tx_values.get('partner_zip'),
+ 'name': tx_values.get('partner_name'),
+ 'phone': tx_values.get('partner_phone'),
}
temp_stripe_tx_values['returndata'] = stripe_tx_values.pop('return_url', '')
diff --git a/addons/point_of_sale/tests/test_frontend.py b/addons/point_of_sale/tests/test_frontend.py
index 1c166f365e4..ef17411513a 100644
--- a/addons/point_of_sale/tests/test_frontend.py
+++ b/addons/point_of_sale/tests/test_frontend.py
@@ -33,7 +33,7 @@ class TestUi(odoo.tests.HttpCase):
# euro's. this will cause issues as the sales journal is in
# USD, because of this all products would have a different
# price
- main_company.currency_id = env.ref('base.USD')
+ cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", [env.ref('base.USD').id, main_company.id])
test_sale_journal = journal_obj.create({'name': 'Sales Journal - Test',
'code': 'TSJ',
diff --git a/addons/project_issue/models/account_analytic_account.py b/addons/project_issue/models/account_analytic_account.py
index 76d9439abce..511cfda9bfd 100644
--- a/addons/project_issue/models/account_analytic_account.py
+++ b/addons/project_issue/models/account_analytic_account.py
@@ -12,7 +12,7 @@ class AccountAnalyticAccount(models.Model):
@api.multi
def unlink(self):
- if self.env['project.issue'].search_count([('project_id.analytic_account_id', 'in', self.ids)]):
+ if self.env['project.issue'].sudo().search_count([('project_id.analytic_account_id', 'in', self.ids)]):
raise UserError(_('Please remove existing issues in the project linked to the accounts you want to delete.'))
return super(AccountAnalyticAccount, self).unlink()
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py
index 2a98db67832..b0d0865af47 100644
--- a/addons/purchase/models/purchase.py
+++ b/addons/purchase/models/purchase.py
@@ -321,8 +321,8 @@ class PurchaseOrder(models.Model):
def button_approve(self, force=False):
self.write({'state': 'purchase', 'date_approve': fields.Date.context_today(self)})
self._create_picking()
- if self.company_id.po_lock == 'lock':
- self.write({'state': 'done'})
+ self.filtered(
+ lambda p: p.company_id.po_lock == 'lock').write({'state': 'done'})
return {}
@api.multi
diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py
index 4bfaef87c6a..a6fc4ae4d07 100644
--- a/addons/sale/models/sale.py
+++ b/addons/sale/models/sale.py
@@ -53,7 +53,7 @@ class SaleOrder(models.Model):
# Search for invoices which have been 'cancelled' (filter_refund = 'modify' in
# 'account.invoice.refund')
# use like as origin may contains multiple references (e.g. 'SO01, SO02')
- refunds = invoice_ids.search([('origin', 'like', order.name)]).filtered(lambda r: r.type in ['out_invoice', 'out_refund'])
+ refunds = invoice_ids.search([('origin', 'like', order.name), ('company_id', '=', order.company_id.id)]).filtered(lambda r: r.type in ['out_invoice', 'out_refund'])
invoice_ids |= refunds.filtered(lambda r: order.name in [origin.strip() for origin in r.origin.split(',')])
# Search for refunds as well
refund_ids = self.env['account.invoice'].browse()
diff --git a/addons/stock/report/report_stock_forecast.xml b/addons/stock/report/report_stock_forecast.xml
index 800aab9240e..928be3c431c 100644
--- a/addons/stock/report/report_stock_forecast.xml
+++ b/addons/stock/report/report_stock_forecast.xml
@@ -45,7 +45,7 @@
formpivot,graph
- {'search_default_pivot_by':1, 'search_default_graph_by':1, 'search_default_product_tmpl_id': active_id}
+ {'search_default_product_tmpl_id': active_id}
@@ -55,7 +55,7 @@
formpivot,graph
- {'search_default_pivot_by':1, 'search_default_graph_by':1, 'search_default_product_id': active_id}
+ {'search_default_product_id': active_id}
diff --git a/addons/web/static/src/less/bootstrap_overridden.less b/addons/web/static/src/less/bootstrap_overridden.less
index 7949971247a..e05d7fbbc67 100644
--- a/addons/web/static/src/less/bootstrap_overridden.less
+++ b/addons/web/static/src/less/bootstrap_overridden.less
@@ -103,3 +103,5 @@
overflow-x: initial;
}
}
+
+@icon-font-path: "/web/static/lib/bootstrap/fonts/";
diff --git a/addons/website/static/src/less/website.ui.less b/addons/website/static/src/less/website.ui.less
index b515ad40096..c3fea349ea9 100644
--- a/addons/website/static/src/less/website.ui.less
+++ b/addons/website/static/src/less/website.ui.less
@@ -54,3 +54,5 @@ body.o_connected_user {
}
}
}
+
+@icon-font-path: "/web/static/lib/bootstrap/fonts/";
diff --git a/addons/website_blog/models/website_blog.py b/addons/website_blog/models/website_blog.py
index c0138220c78..9e13d00875e 100644
--- a/addons/website_blog/models/website_blog.py
+++ b/addons/website_blog/models/website_blog.py
@@ -165,7 +165,7 @@ class BlogPost(models.Model):
blog_post.teaser = blog_post.teaser_manual
else:
content = html2plaintext(blog_post.content).replace('\n', ' ')
- blog_post.teaser = ' '.join(filter(None, content.split(' '))[:50]) + '...'
+ blog_post.teaser = content[:150] + '...'
@api.multi
def _set_teaser(self):
diff --git a/addons/website_blog/views/website_blog_templates.xml b/addons/website_blog/views/website_blog_templates.xml
index 49a5210624f..4a6d8517fab 100644
--- a/addons/website_blog/views/website_blog_templates.xml
+++ b/addons/website_blog/views/website_blog_templates.xml
@@ -101,6 +101,7 @@
+
diff --git a/addons/website_event_sale/tests/test_ui.py b/addons/website_event_sale/tests/test_ui.py
index c2e6f04f4a6..968ab6edcd9 100644
--- a/addons/website_event_sale/tests/test_ui.py
+++ b/addons/website_event_sale/tests/test_ui.py
@@ -12,7 +12,7 @@ class TestUi(odoo.tests.HttpCase):
# - that main demo company is gelocated in US
# - that this test awaits for hardcoded USDs amount
# we have to force company currency as USDs only for this test
- self.env.ref('base.main_company').write({'currency_id': self.env.ref('base.USD').id})
+ self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", [self.env.ref('base.USD').id, self.env.ref('base.main_company').id])
self.phantom_js("/", "odoo.__DEBUG__.services['web_tour.tour'].run('event_buy_tickets')", "odoo.__DEBUG__.services['web_tour.tour'].tours.event_buy_tickets.ready", login="admin")
def test_demo(self):
diff --git a/doc/cla/corporate/acsone.md b/doc/cla/corporate/acsone.md
index 1060d7ccc02..d4ee1947927 100644
--- a/doc/cla/corporate/acsone.md
+++ b/doc/cla/corporate/acsone.md
@@ -26,3 +26,4 @@ Stéphane Bidoul stephane.bidoul@acsone.eu https://github.com/sbidoul
Thomas Binsfeld thomas.binsfeld@acsone.eu https://github.com/ThomasBinsfeld
Benjamin Willig benjamin.willig@acsone.eu https://github.com/benwillig
François Honoré francois.honore@acsone.eu https://github.com/acsonefho
+Denis Robinet denis.robinet@acsone.eu https://github.com/RobinetDenisAcsone
diff --git a/doc/cla/corporate/wink.md b/doc/cla/corporate/wink.md
new file mode 100644
index 00000000000..59b22c1b64b
--- /dev/null
+++ b/doc/cla/corporate/wink.md
@@ -0,0 +1,15 @@
+Belgium, 2018-04-06
+
+WINK SA/NV agrees to the terms of the Odoo Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Thomas Fossoul tfossoul@wink.be https://github.com/tfossoulw
+
+List of contributors:
+
+Thomas Fossoul tfossoul@wink.be https://github.com/tfossoulw
diff --git a/doc/cla/individual/thomas-tankengine.md b/doc/cla/individual/thomas-tankengine.md
new file mode 100644
index 00000000000..ae3ece9b174
--- /dev/null
+++ b/doc/cla/individual/thomas-tankengine.md
@@ -0,0 +1,11 @@
+France, 2018-04-04,
+
+I hereby agree to the terms of the Odoo Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Thomas Lemaire thomas.lemaire@ndp-systemes.fr https://github.com/thomas-tankengine
\ No newline at end of file
diff --git a/odoo/addons/base/res/res_config.py b/odoo/addons/base/res/res_config.py
index f1bb5ffff74..8b2a450e322 100644
--- a/odoo/addons/base/res/res_config.py
+++ b/odoo/addons/base/res/res_config.py
@@ -531,12 +531,14 @@ class ResConfigSettings(models.TransientModel, ResConfigModuleInstallationMixin)
IrValues.set_default(model, field, value)
# group fields: modify group / implied groups
- for name, groups, implied_group in classified['group']:
- if self[name]:
- groups.write({'implied_ids': [(4, implied_group.id)]})
- else:
- groups.write({'implied_ids': [(3, implied_group.id)]})
- implied_group.write({'users': [(3, user.id) for user in groups.mapped('users')]})
+ with self.env.norecompute():
+ for name, groups, implied_group in classified['group']:
+ if self[name]:
+ groups.write({'implied_ids': [(4, implied_group.id)]})
+ else:
+ groups.write({'implied_ids': [(3, implied_group.id)]})
+ implied_group.write({'users': [(3, user.id) for user in groups.mapped('users')]})
+ self.recompute()
# other fields: execute all methods that start with 'set_'
for method in dir(self):
diff --git a/odoo/report/report_sxw.py b/odoo/report/report_sxw.py
index e54ecad953e..6d0433db9fc 100644
--- a/odoo/report/report_sxw.py
+++ b/odoo/report/report_sxw.py
@@ -220,7 +220,8 @@ class rml_parse(object):
date = datetime(*value.timetuple()[:6])
if date_time:
# Convert datetime values to the expected client/context timezone
- record = self.env['base'].with_context(self.localcontext)
+ env = odoo.api.Environment(self.cr, self.uid, {})
+ record = env['base'].with_context(self.localcontext)
date = fields.Datetime.context_timestamp(record, date)
return date.strftime(date_format.encode('utf-8'))