diff --git a/addons/account/models/account_journal_dashboard.py b/addons/account/models/account_journal_dashboard.py index bf060df7344..e7ff9e8efa3 100644 --- a/addons/account/models/account_journal_dashboard.py +++ b/addons/account/models/account_journal_dashboard.py @@ -169,8 +169,8 @@ class account_journal(models.Model): account_ids = tuple(filter(None, [self.default_debit_account_id.id, self.default_credit_account_id.id])) if account_ids: amount_field = 'balance' if not self.currency_id else 'amount_currency' - query = """SELECT sum(%s) FROM account_move_line WHERE account_id in %%s;""" % (amount_field,) - self.env.cr.execute(query, (account_ids,)) + query = """SELECT sum(%s) FROM account_move_line WHERE account_id in %%s AND date <= %%s;""" % (amount_field,) + self.env.cr.execute(query, (account_ids, fields.Date.today(),)) query_results = self.env.cr.dictfetchall() if query_results and query_results[0].get('sum') != None: account_sum = query_results[0].get('sum') diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index e1650c9fae4..ee8aad51b29 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -1390,7 +1390,9 @@ class AccountMoveLine(models.Model): @api.model def _query_get(self, domain=None): context = dict(self._context or {}) - domain = domain and safe_eval(str(domain)) or [] + domain = domain or [] + if not isinstance(domain, (list, tuple)): + domain = safe_eval(domain) date_field = 'date' if context.get('aged_balance'): diff --git a/addons/account/models/partner.py b/addons/account/models/partner.py index a4bc99b8e7d..497d8104703 100644 --- a/addons/account/models/partner.py +++ b/addons/account/models/partner.py @@ -356,7 +356,7 @@ class ResPartner(models.Model): @api.multi def mark_as_reconciled(self): self.env['account.partial.reconcile'].check_access_rights('write') - return self.sudo().write({'last_time_entries_checked': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}) + return self.sudo().with_context(company_id=self.env.user.company_id.id).write({'last_time_entries_checked': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}) @api.one def _get_company_currency(self): diff --git a/addons/account_asset/models/account_invoice.py b/addons/account_asset/models/account_invoice.py index cafa2077299..a6b65b3425e 100644 --- a/addons/account_asset/models/account_invoice.py +++ b/addons/account_asset/models/account_invoice.py @@ -107,6 +107,7 @@ class AccountInvoiceLine(models.Model): self.asset_category_id = self.product_id.product_tmpl_id.deferred_revenue_category_id.id elif invoice.type == 'in_invoice': self.asset_category_id = self.product_id.product_tmpl_id.asset_category_id.id + self.onchange_asset_category_id() super(AccountInvoiceLine, self)._set_additional_fields(invoice) def get_invoice_line_account(self, type, product, fpos, company): diff --git a/addons/account_tax_python/models/account_tax.py b/addons/account_tax_python/models/account_tax.py index 7ab0c2bbe1f..8b438b82859 100644 --- a/addons/account_tax_python/models/account_tax.py +++ b/addons/account_tax_python/models/account_tax.py @@ -37,9 +37,9 @@ class AccountTaxPython(models.Model): @api.multi def compute_all(self, price_unit, currency=None, quantity=1.0, product=None, partner=None): - taxes = self.env['account.tax'] + taxes = self.filtered(lambda r: r.amount_type != 'code') company = self.env.user.company_id - for tax in self: + for tax in self.filtered(lambda r: r.amount_type == 'code'): localdict = {'price_unit': price_unit, 'quantity': quantity, 'product': product, 'partner': partner, 'company': company} safe_eval(tax.python_applicable, localdict, mode="exec", nocopy=True) if localdict.get('result', False): diff --git a/addons/account_voucher/models/account_voucher.py b/addons/account_voucher/models/account_voucher.py index 48b38c90487..467ed1c4533 100644 --- a/addons/account_voucher/models/account_voucher.py +++ b/addons/account_voucher/models/account_voucher.py @@ -82,7 +82,7 @@ class AccountVoucher(models.Model): @api.model def _get_currency(self): - journal = self.env['account.journal'].browse(self._context.get('journal_id', False)) + journal = self.env['account.journal'].browse(self.env.context.get('default_journal_id', False)) if journal.currency_id: return journal.currency_id.id return self.env.user.company_id.currency_id.id diff --git a/addons/base_vat/models/res_partner.py b/addons/base_vat/models/res_partner.py index 17dcef988be..1de5c95aeab 100644 --- a/addons/base_vat/models/res_partner.py +++ b/addons/base_vat/models/res_partner.py @@ -98,7 +98,11 @@ class ResPartner(models.Model): @api.constrains('vat', 'commercial_partner_country_id') def check_vat(self): - if self.env.user.company_id.vat_check_vies: + if self.env.context.get('company_id'): + company = self.env['res.company'].browse(self.env.context['company_id']) + else: + company = self.env.user.company_id + if company.vat_check_vies: # force full VIES online check check_func = self.vies_vat_check else: @@ -121,7 +125,11 @@ class ResPartner(models.Model): self.ensure_one() vat_no = "'CC##' (CC=Country Code, ##=VAT Number)" vat_no = _ref_vat.get(country_code) or vat_no - if self.env.user.company_id.vat_check_vies: + if self.env.context.get('company_id'): + company = self.env['res.company'].browse(self.env.context['company_id']) + else: + company = self.env.user.company_id + if company.vat_check_vies: return '\n' + _('The VAT number [%s] for partner [%s] either failed the VIES VAT validation check or did not respect the expected format %s.') % (self.vat, self.name, vat_no) return '\n' + _('The VAT number [%s] for partner [%s] does not seem to be valid. \nNote: the expected format is %s') % (self.vat, self.name, vat_no) diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py index 0782ae3384a..fe15693d68a 100644 --- a/addons/calendar/models/calendar.py +++ b/addons/calendar/models/calendar.py @@ -1406,7 +1406,8 @@ class Meeting(models.Model): partners_to_notify.append(event_attendees_changes['removed_partners'].ids) self.env['calendar.alarm_manager'].notify_next_alarm(partners_to_notify) - if (values.get('start_date') or values.get('start_datetime')) and values.get('active', True): + if (values.get('start_date') or values.get('start_datetime') or + (values.get('start') and self.env.context.get('from_ui'))) and values.get('active', True): for current_meeting in all_meetings: if attendees_create: attendees_create = attendees_create[current_meeting.id] diff --git a/addons/crm/wizard/base_partner_merge.py b/addons/crm/wizard/base_partner_merge.py index 27f3f3e002d..b8b46f2a7dc 100644 --- a/addons/crm/wizard/base_partner_merge.py +++ b/addons/crm/wizard/base_partner_merge.py @@ -199,7 +199,7 @@ class MergePartnerAutomatic(models.TransientModel): except psycopg2.Error: # updating fails, most likely due to a violated unique constraint # keeping record with nonexistent partner_id is useless, better delete it - query = 'DELETE FROM %(table)s WHERE %(column)s IN %%s' % query_dic + query = 'DELETE FROM "%(table)s" WHERE "%(column)s" IN %%s' % query_dic self._cr.execute(query, (tuple(src_partners.ids),)) @api.model diff --git a/addons/google_calendar/models/google_calendar.py b/addons/google_calendar/models/google_calendar.py index 91eb12166a3..f1afb7b3135 100644 --- a/addons/google_calendar/models/google_calendar.py +++ b/addons/google_calendar/models/google_calendar.py @@ -249,7 +249,8 @@ class GoogleCalendar(models.AbstractModel): if not self.get_need_synchro_attendee(): data.pop("attendees") if isCreating: - other_google_ids = [other_att.google_internal_event_id for other_att in event.attendee_ids if other_att.google_internal_event_id] + other_google_ids = [other_att.google_internal_event_id for other_att in event.attendee_ids + if other_att.google_internal_event_id and not other_att.google_internal_event_id.startswith('_')] if other_google_ids: data["id"] = other_google_ids[0] return data @@ -610,7 +611,8 @@ class GoogleCalendar(models.AbstractModel): ('event_id.final_date', '>', fields.Datetime.to_string(self.get_minTime())), ]) for att in my_attendees: - other_google_ids = [other_att.google_internal_event_id for other_att in att.event_id.attendee_ids if other_att.google_internal_event_id and other_att.id != att.id] + other_google_ids = [other_att.google_internal_event_id for other_att in att.event_id.attendee_ids if + other_att.google_internal_event_id and other_att.id != att.id and not other_att.google_internal_event_id.startswith('_')] for other_google_id in other_google_ids: if self.get_one_event_synchro(other_google_id): att.write({'google_internal_event_id': other_google_id}) diff --git a/addons/mrp/models/mrp_unbuild.py b/addons/mrp/models/mrp_unbuild.py index c1b9e48bcab..3df5fe2b97f 100644 --- a/addons/mrp/models/mrp_unbuild.py +++ b/addons/mrp/models/mrp_unbuild.py @@ -120,11 +120,11 @@ class MrpUnbuild(models.Model): for produce_move in produce_moves: if produce_move.has_tracking != 'none': original = original_quants.filtered(lambda quant: quant.product_id == produce_move.product_id) - if not original.lot_id: + if original and not original[0].lot_id: raise UserError(_("You don't have in the stock the required lot/serial number for %s .") % (produce_move.product_id.name,)) self.env['stock.move.lots'].create({ 'move_id': produce_move.id, - 'lot_id': original.lot_id.id, + 'lot_id': original[0].lot_id.id, 'quantity_done': produce_move.product_uom_qty, 'quantity': produce_move.product_uom_qty }) diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index c9e760a32ca..b264254491b 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -52,7 +52,7 @@ class PurchaseOrder(models.Model): if any(float_compare(line.qty_invoiced, line.product_qty if line.product_id.purchase_method == 'purchase' else line.qty_received, precision_digits=precision) == -1 for line in order.order_line): order.invoice_status = 'to invoice' - elif all(float_compare(line.qty_invoiced, line.product_qty if line.product_id.purchase_method == 'purchase' else line.qty_received, precision_digits=precision) >= 0 for line in order.order_line): + elif all(float_compare(line.qty_invoiced, line.product_qty if line.product_id.purchase_method == 'purchase' else line.qty_received, precision_digits=precision) >= 0 for line in order.order_line) and order.invoice_ids: order.invoice_status = 'invoiced' else: order.invoice_status = 'no' @@ -647,7 +647,9 @@ class PurchaseOrderLine(models.Model): order = line.order_id price_unit = line.price_unit if line.taxes_id: - price_unit = line.taxes_id.with_context(round=False).compute_all(price_unit, currency=line.order_id.currency_id, quantity=1.0)['total_excluded'] + price_unit = line.taxes_id.with_context(round=False).compute_all( + price_unit, currency=line.order_id.currency_id, quantity=1.0, product=line.product_id, partner=line.order_id.partner_id + )['total_excluded'] if line.product_uom.id != line.product_id.uom_id.id: price_unit *= line.product_uom.factor / line.product_id.uom_id.factor if order.currency_id != order.company_id.currency_id: diff --git a/addons/report/views/base_config_settings_views.xml b/addons/report/views/base_config_settings_views.xml index fb7c2ab2c98..f08b25fe336 100644 --- a/addons/report/views/base_config_settings_views.xml +++ b/addons/report/views/base_config_settings_views.xml @@ -18,7 +18,7 @@
diff --git a/addons/stock/models/procurement.py b/addons/stock/models/procurement.py index 77939415492..d75014fd331 100644 --- a/addons/stock/models/procurement.py +++ b/addons/stock/models/procurement.py @@ -190,17 +190,21 @@ class ProcurementOrder(models.Model): def run(self, autocommit=False): # TDE CLEANME: unused context key procurement_auto_defer remove new_self = self.filtered(lambda order: order.state not in ['running', 'done', 'cancel']) - res = super(ProcurementOrder, new_self).run(autocommit=autocommit) + res = True + if new_self: + res = super(ProcurementOrder, new_self).run(autocommit=autocommit) - # after all the procurements are run, check if some created a draft stock move that needs to be confirmed - # (we do that in batch because it fasts the picking assignation and the picking state computation) - new_self.filtered(lambda order: order.state == 'running' and order.rule_id.action == 'move').mapped('move_ids').filtered(lambda move: move.state == 'draft').action_confirm() + # after all the procurements are run, check if some created a draft stock move that needs to be confirmed + # (we do that in batch because it fasts the picking assignation and the picking state computation) + move_ids = new_self.filtered(lambda order: order.state == 'running' and order.rule_id.action == 'move').mapped('move_ids').filtered(lambda move: move.state == 'draft') + if move_ids: + move_ids.action_confirm() - # TDE FIXME: action_confirm in stock_move already call run() ... necessary ?? - # If procurements created other procurements, run the created in batch - new_procurements = self.search([('move_dest_id.procurement_id', 'in', new_self.ids)], order='id') - if new_procurements: - res = new_procurements.run(autocommit=autocommit) + # TDE FIXME: action_confirm in stock_move already call run() ... necessary ?? + # If procurements created other procurements, run the created in batch + new_procurements = self.search([('move_dest_id.procurement_id', 'in', new_self.ids)], order='id') + if new_procurements: + res = new_procurements.run(autocommit=autocommit) return res @api.multi diff --git a/addons/stock_account/models/stock.py b/addons/stock_account/models/stock.py index f68ed53d14e..edace2f8fff 100644 --- a/addons/stock_account/models/stock.py +++ b/addons/stock_account/models/stock.py @@ -176,7 +176,7 @@ class StockQuant(models.Model): class StockMove(models.Model): _inherit = "stock.move" - to_refund = fields.Boolean(string="To Refund (update SO/PO)", + to_refund = fields.Boolean(string="To Refund (update SO/PO)", copy=False, help='Trigger a decrease of the delivered/received quantity in the associated Sale Order/Purchase Order') def _set_default_price_moves(self): diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js index eb6d7176884..4374421d7b3 100644 --- a/addons/web/static/src/js/views/calendar/calendar_model.js +++ b/addons/web/static/src/js/views/calendar/calendar_model.js @@ -2,6 +2,7 @@ odoo.define('web.CalendarModel', function (require) { "use strict"; var AbstractModel = require('web.AbstractModel'); +var Context = require('web.Context'); var core = require('web.core'); var fieldUtils = require('web.field_utils'); var session = require('web.session'); @@ -298,11 +299,12 @@ return AbstractModel.extend({ data[k] = dateToServer(data[k]); } } + var context = new Context(this.data.context, {from_ui: true}); return this._rpc({ model: this.modelName, method: 'write', args: [[record.id], data], - context: this.data.context + context: context }); }, diff --git a/doc/cla/individual/d4n.md b/doc/cla/individual/d4n.md new file mode 100644 index 00000000000..080d8ba9789 --- /dev/null +++ b/doc/cla/individual/d4n.md @@ -0,0 +1,12 @@ +Germany, 2017-09-12 + +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, + +Dan Čermák dan.cermak@cgc-instruments.com https://github.com/D4N +Dan Čermák dan.cermak@cgc-instruments.de https://github.com/D4N