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: Refuse Application 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: Interest Application 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 @@ form pivot,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 @@ form pivot,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'))