diff options
| author | Adrian Torres <adt@odoo.com> | 2018-12-12 09:46:02 +0000 |
|---|---|---|
| committer | Adrian Torres <adt@odoo.com> | 2019-07-05 09:04:45 +0000 |
| commit | 9e71d57d11faf3fabd00b8a09188e9d4f9808c63 (patch) | |
| tree | 4dfda85fb19bf1f68954cadbd8a39bbb582ef775 /addons | |
| parent | f5676fabea8a09f5702d00e75f3cf55f01ed5b22 (diff) | |
[REM] *: remove calls to `api.one` and adapt code
Adapt all code that was using `api.one` to recordset-style method and
remove any and all calls to `api.one` in preparation for its removal.
Diffstat (limited to 'addons')
62 files changed, 819 insertions, 803 deletions
diff --git a/addons/account/models/account.py b/addons/account/models/account.py index cb7ce2dd8ac..9f6c7071950 100644 --- a/addons/account/models/account.py +++ b/addons/account/models/account.py @@ -667,25 +667,25 @@ class AccountJournal(models.Model): sequence = journal.refund_sequence_id._get_current_sequence() sequence.number_next = journal.refund_sequence_number_next - @api.one @api.constrains('currency_id', 'default_credit_account_id', 'default_debit_account_id') def _check_currency(self): - if self.currency_id: - if self.default_credit_account_id and not self.default_credit_account_id.currency_id.id == self.currency_id.id: - raise ValidationError(_('The currency of the journal should be the same than the default credit account.')) - if self.default_debit_account_id and not self.default_debit_account_id.currency_id.id == self.currency_id.id: - raise ValidationError(_('The currency of the journal should be the same than the default debit account.')) + for journal in self: + if journal.currency_id: + if journal.default_credit_account_id and not journal.default_credit_account_id.currency_id.id == journal.currency_id.id: + raise ValidationError(_('The currency of the journal should be the same than the default credit account.')) + if journal.default_debit_account_id and not journal.default_debit_account_id.currency_id.id == journal.currency_id.id: + raise ValidationError(_('The currency of the journal should be the same than the default debit account.')) - @api.one @api.constrains('type', 'bank_account_id') def _check_bank_account(self): - if self.type == 'bank' and self.bank_account_id: - if self.bank_account_id.company_id != self.company_id: - raise ValidationError(_('The bank account of a bank journal must belong to the same company (%s).') % self.company_id.name) - # A bank account can belong to a customer/supplier, in which case their partner_id is the customer/supplier. - # Or they are part of a bank journal and their partner_id must be the company's partner_id. - if self.bank_account_id.partner_id != self.company_id.partner_id: - raise ValidationError(_('The holder of a journal\'s bank account must be the company (%s).') % self.company_id.name) + for journal in self: + if journal.type == 'bank' and journal.bank_account_id: + if journal.bank_account_id.company_id != journal.company_id: + raise ValidationError(_('The bank account of a bank journal must belong to the same company (%s).') % journal.company_id.name) + # A bank account can belong to a customer/supplier, in which case their partner_id is the customer/supplier. + # Or they are part of a bank journal and their partner_id must be the company's partner_id. + if journal.bank_account_id.partner_id != journal.company_id.partner_id: + raise ValidationError(_('The holder of a journal\'s bank account must be the company (%s).') % journal.company_id.name) @api.onchange('default_debit_account_id') def onchange_debit_account_id(self): @@ -980,11 +980,11 @@ class ResPartnerBank(models.Model): journal_id = fields.One2many('account.journal', 'bank_account_id', domain=[('type', '=', 'bank')], string='Account Journal', readonly=True, help="The accounting journal corresponding to this bank account.") - @api.one @api.constrains('journal_id') def _check_journal_id(self): - if len(self.journal_id) > 1: - raise ValidationError(_('A bank account can belong to only one journal.')) + for bank in self: + if len(bank.journal_id) > 1: + raise ValidationError(_('A bank account can belong to only one journal.')) #---------------------------------------------------------- @@ -1111,13 +1111,13 @@ class AccountTax(models.Model): raise ValidationError(_("Invoice and credit note repartitions should match (same percentages, in the same order).")) index += 1 - @api.one @api.constrains('children_tax_ids', 'type_tax_use') def _check_children_scope(self): - if not self._check_m2m_recursion('children_tax_ids'): - raise ValidationError(_("Recursion found for tax '%s'.") % (self.name,)) - if not all(child.type_tax_use in ('none', self.type_tax_use) for child in self.children_tax_ids): - raise ValidationError(_('The application scope of taxes in a group must be either the same as the group or left empty.')) + for tax in self: + if not tax._check_m2m_recursion('children_tax_ids'): + raise ValidationError(_("Recursion found for tax '%s'.") % (tax.name,)) + if not all(child.type_tax_use in ('none', tax.type_tax_use) for child in tax.children_tax_ids): + raise ValidationError(_('The application scope of taxes in a group must be either the same as the group or left empty.')) @api.multi @api.returns('self', lambda value: value.id) diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index fcaec96acc3..5f2ee1702dc 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -17,11 +17,11 @@ class AccountCashboxLine(models.Model): _rec_name = 'coin_value' _order = 'coin_value' - @api.one @api.depends('coin_value', 'number') def _sub_total(self): """ Calculates Sub total""" - self.subtotal = self.coin_value * self.number + for line in self: + line.subtotal = line.coin_value * line.number coin_value = fields.Float(string='Coin/Bill Value', required=True, digits=0) number = fields.Integer(string='Number of Coins/Bills', help='Opening Unit Numbers') @@ -71,27 +71,31 @@ class AccountBankStmtCloseCheck(models.TransientModel): class AccountBankStatement(models.Model): - @api.one @api.depends('line_ids', 'balance_start', 'line_ids.amount', 'balance_end_real') def _end_balance(self): - self.total_entry_encoding = sum([line.amount for line in self.line_ids]) - self.balance_end = self.balance_start + self.total_entry_encoding - self.difference = self.balance_end_real - self.balance_end + for statement in self: + statement.total_entry_encoding = sum([line.amount for line in statement.line_ids]) + statement.balance_end = statement.balance_start + statement.total_entry_encoding + statement.difference = statement.balance_end_real - statement.balance_end @api.multi def _is_difference_zero(self): for bank_stmt in self: bank_stmt.is_difference_zero = float_is_zero(bank_stmt.difference, precision_digits=bank_stmt.currency_id.decimal_places) - @api.one @api.depends('journal_id') def _compute_currency(self): - self.currency_id = self.journal_id.currency_id or self.company_id.currency_id + for statement in self: + statement.currency_id = statement.journal_id.currency_id or statement.company_id.currency_id - @api.one @api.depends('line_ids.journal_entry_ids') def _check_lines_reconciled(self): - self.all_lines_reconciled = all([line.journal_entry_ids.ids or line.account_id.id for line in self.line_ids if not self.currency_id.is_zero(line.amount)]) + for statement in self: + statement.all_lines_reconciled = all( + line.journal_entry_ids.ids or line.account_id.id + for line in statement.line_ids + if not statement.currency_id.is_zero(line.amount) + ) @api.depends('move_line_ids') def _get_move_line_count(self): @@ -322,20 +326,20 @@ class AccountBankStatementLine(models.Model): default=False, copy=False, help="Technical field holding the number given to the journal entry, automatically set when the statement line is reconciled then stored to set the same number again if the line is cancelled, set to draft and re-processed again.") - @api.one @api.constrains('amount') def _check_amount(self): - # Allow to enter bank statement line with an amount of 0, - # so that user can enter/import the exact bank statement they have received from their bank in Odoo - currency = self.currency_id or self.journal_currency_id - if self.journal_id.type != 'bank' and currency.is_zero(self.amount): - raise ValidationError(_('The amount of a cash transaction cannot be 0.')) + for line in self: + # Allow to enter bank statement line with an amount of 0, + # so that user can enter/import the exact bank statement they have received from their bank in Odoo + currency = line.currency_id or line.journal_currency_id + if line.journal_id.type != 'bank' and currency.is_zero(line.amount): + raise ValidationError(_('The amount of a cash transaction cannot be 0.')) - @api.one @api.constrains('amount', 'amount_currency') def _check_amount_currency(self): - if self.amount_currency != 0 and self.amount == 0: - raise ValidationError(_('If "Amount Currency" is specified, then "Amount" must be as well.')) + for line in self: + if line.amount_currency != 0 and line.amount == 0: + raise ValidationError(_('If "Amount Currency" is specified, then "Amount" must be as well.')) @api.constrains('currency_id', 'journal_id') def _check_currency_id(self): diff --git a/addons/account/models/account_journal_dashboard.py b/addons/account/models/account_journal_dashboard.py index 857ca086312..dc760b842da 100644 --- a/addons/account/models/account_journal_dashboard.py +++ b/addons/account/models/account_journal_dashboard.py @@ -15,16 +15,16 @@ import ast class account_journal(models.Model): _inherit = "account.journal" - @api.one def _kanban_dashboard(self): - self.kanban_dashboard = json.dumps(self.get_journal_dashboard_datas()) + for journal in self: + journal.kanban_dashboard = json.dumps(journal.get_journal_dashboard_datas()) - @api.one def _kanban_dashboard_graph(self): - if (self.type in ['sale', 'purchase']): - self.kanban_dashboard_graph = json.dumps(self.get_bar_graph_datas()) - elif (self.type in ['cash', 'bank']): - self.kanban_dashboard_graph = json.dumps(self.get_line_graph_datas()) + for journal in self: + if (journal.type in ['sale', 'purchase']): + journal.kanban_dashboard_graph = json.dumps(journal.get_bar_graph_datas()) + elif (journal.type in ['cash', 'bank']): + journal.kanban_dashboard_graph = json.dumps(journal.get_line_graph_datas()) def _get_json_activity_data(self): for journal in self: diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index c5c8cfd7749..7a96e707be9 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -361,27 +361,28 @@ class account_payment(models.Model): 'context': action_context, } - @api.one @api.depends('invoice_ids', 'payment_type', 'partner_type', 'partner_id') def _compute_destination_account_id(self): - if self.invoice_ids: - self.destination_account_id = self.invoice_ids[0].mapped('line_ids.account_id')\ - .filtered(lambda account: account.user_type_id.type in ('receivable', 'payable'))[0] - elif self.payment_type == 'transfer': - if not self.company_id.transfer_account_id.id: - raise UserError(_('There is no Transfer Account defined in the accounting settings. Please define one to be able to confirm this transfer.')) - self.destination_account_id = self.company_id.transfer_account_id.id - elif self.partner_id: - if self.partner_type == 'customer': - self.destination_account_id = self.partner_id.property_account_receivable_id.id - else: - self.destination_account_id = self.partner_id.property_account_payable_id.id - elif self.partner_type == 'customer': - default_account = self.env['ir.property'].get('property_account_receivable_id', 'res.partner') - self.destination_account_id = default_account.id - elif self.partner_type == 'supplier': - default_account = self.env['ir.property'].get('property_account_payable_id', 'res.partner') - self.destination_account_id = default_account.id + for payment in self: + if payment.invoice_ids: + payment.destination_account_id = payment.invoice_ids[0].mapped( + 'line_ids.account_id').filtered( + lambda account: account.user_type_id.type in ('receivable', 'payable'))[0] + elif payment.payment_type == 'transfer': + if not payment.company_id.transfer_account_id.id: + raise UserError(_('There is no Transfer Account defined in the accounting settings. Please define one to be able to confirm this transfer.')) + payment.destination_account_id = payment.company_id.transfer_account_id.id + elif payment.partner_id: + if payment.partner_type == 'customer': + payment.destination_account_id = payment.partner_id.property_account_receivable_id.id + else: + payment.destination_account_id = payment.partner_id.property_account_payable_id.id + elif payment.partner_type == 'customer': + default_account = self.env['ir.property'].get('property_account_receivable_id', 'res.partner') + payment.destination_account_id = default_account.id + elif payment.partner_type == 'supplier': + default_account = self.env['ir.property'].get('property_account_payable_id', 'res.partner') + payment.destination_account_id = default_account.id @api.depends('move_line_ids.matched_debit_ids', 'move_line_ids.matched_credit_ids') def _compute_reconciled_invoice_ids(self): diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py index 837464563b6..09d85002816 100644 --- a/addons/account/models/chart_template.py +++ b/addons/account/models/chart_template.py @@ -161,12 +161,10 @@ class AccountChartTemplate(models.Model): 'chart_template_id': self.id, } - @api.one def try_loading_for_current_company(self): """ Installs this chart of accounts for the current company if not chart of accounts had been created for it yet. """ - self.ensure_one() # do not use `request.env` here, it can cause deadlocks if request and hasattr(request, 'allowed_company_ids'): company = self.env['res.company'].browse(request.allowed_company_ids[0]) @@ -174,7 +172,8 @@ class AccountChartTemplate(models.Model): company = self.env.company # If we don't have any chart of account on this company, install this chart of account if not company.chart_template_id and not self.existing_accounting(company): - self.load_for_current_company(15.0, 15.0) + for template in self: + template.load_for_current_company(15.0, 15.0) def load_for_current_company(self, sale_tax_rate, purchase_tax_rate): """ Installs this chart of accounts on the current company, replacing diff --git a/addons/account/models/partner.py b/addons/account/models/partner.py index 7c627f769e4..42e8da47d36 100644 --- a/addons/account/models/partner.py +++ b/addons/account/models/partner.py @@ -34,16 +34,15 @@ class AccountFiscalPosition(models.Model): # To be used in hiding the 'Federal States' field('attrs' in view side) when selected 'Country' has 0 states. states_count = fields.Integer(compute='_compute_states_count') - @api.one def _compute_states_count(self): - self.states_count = len(self.country_id.state_ids) + for position in self: + position.states_count = len(position.country_id.state_ids) - @api.one @api.constrains('zip_from', 'zip_to') def _check_zip(self): - if self.zip_from and self.zip_to and self.zip_from > self.zip_to: - raise ValidationError(_('Invalid "Zip Range", please configure it properly.')) - return True + for position in self: + if self.zip_from and self.zip_to and position.zip_from > position.zip_to: + raise ValidationError(_('Invalid "Zip Range", please configure it properly.')) @api.model # noqa def map_tax(self, taxes, product=None, partner=None): @@ -346,53 +345,53 @@ class ResPartner(models.Model): domain += overdue_domain return domain - @api.one def _compute_has_unreconciled_entries(self): - # Avoid useless work if has_unreconciled_entries is not relevant for this partner - if not self.active or not self.is_company and self.parent_id: - return - self.env.cr.execute( - """ SELECT 1 FROM( - SELECT - p.last_time_entries_checked AS last_time_entries_checked, - MAX(l.write_date) AS max_date - FROM - account_move_line l - RIGHT JOIN account_account a ON (a.id = l.account_id) - RIGHT JOIN res_partner p ON (l.partner_id = p.id) - WHERE - p.id = %s - AND EXISTS ( - SELECT 1 - FROM account_move_line l - WHERE l.account_id = a.id - AND l.partner_id = p.id - AND l.amount_residual > 0 - ) - AND EXISTS ( - SELECT 1 - FROM account_move_line l - WHERE l.account_id = a.id - AND l.partner_id = p.id - AND l.amount_residual < 0 - ) - GROUP BY p.last_time_entries_checked - ) as s - WHERE (last_time_entries_checked IS NULL OR max_date > last_time_entries_checked) - """, (self.id,)) - self.has_unreconciled_entries = self.env.cr.rowcount == 1 + for partner in self: + # Avoid useless work if has_unreconciled_entries is not relevant for this partner + if not partner.active or not partner.is_company and partner.parent_id: + continue + self.env.cr.execute( + """ SELECT 1 FROM( + SELECT + p.last_time_entries_checked AS last_time_entries_checked, + MAX(l.write_date) AS max_date + FROM + account_move_line l + RIGHT JOIN account_account a ON (a.id = l.account_id) + RIGHT JOIN res_partner p ON (l.partner_id = p.id) + WHERE + p.id = %s + AND EXISTS ( + SELECT 1 + FROM account_move_line l + WHERE l.account_id = a.id + AND l.partner_id = p.id + AND l.amount_residual > 0 + ) + AND EXISTS ( + SELECT 1 + FROM account_move_line l + WHERE l.account_id = a.id + AND l.partner_id = p.id + AND l.amount_residual < 0 + ) + GROUP BY p.last_time_entries_checked + ) as s + WHERE (last_time_entries_checked IS NULL OR max_date > last_time_entries_checked) + """, (partner.id,)) + partner.has_unreconciled_entries = self.env.cr.rowcount == 1 @api.multi def mark_as_reconciled(self): self.env['account.partial.reconcile'].check_access_rights('write') return self.sudo().with_context(company_id=self.env.company.id).write({'last_time_entries_checked': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}) - @api.one def _get_company_currency(self): - if self.company_id: - self.currency_id = self.sudo().company_id.currency_id - else: - self.currency_id = self.env.company.currency_id + for partner in self: + if partner.company_id: + partner.currency_id = partner.sudo().company_id.currency_id + else: + partner.currency_id = self.env.company.currency_id credit = fields.Monetary(compute='_credit_debit_get', search=_credit_search, string='Total Receivable', help="Total amount this customer owes you.") diff --git a/addons/account/wizard/pos_box.py b/addons/account/wizard/pos_box.py index 7a11dd5c822..776d5ad512c 100644 --- a/addons/account/wizard/pos_box.py +++ b/addons/account/wizard/pos_box.py @@ -30,12 +30,12 @@ class CashBox(models.TransientModel): box._create_bank_statement_line(record) return {} - @api.one def _create_bank_statement_line(self, record): - if record.state == 'confirm': - raise UserError(_("You cannot put/take money in/out for a bank statement which is closed.")) - values = self._calculate_values_for_statement_line(record) - return record.write({'line_ids': [(0, False, values)]}) + for box in self: + if record.state == 'confirm': + raise UserError(_("You cannot put/take money in/out for a bank statement which is closed.")) + values = box._calculate_values_for_statement_line(record) + record.write({'line_ids': [(0, False, values)]}) class CashBoxIn(CashBox): diff --git a/addons/account_check_printing/models/account_journal.py b/addons/account_check_printing/models/account_journal.py index 6151e1e5c5b..76bcef6412a 100644 --- a/addons/account_check_printing/models/account_journal.py +++ b/addons/account_check_printing/models/account_journal.py @@ -8,28 +8,28 @@ from odoo.exceptions import ValidationError class AccountJournal(models.Model): _inherit = "account.journal" - @api.one @api.depends('outbound_payment_method_ids') def _compute_check_printing_payment_method_selected(self): - self.check_printing_payment_method_selected = any(pm.code == 'check_printing' for pm in self.outbound_payment_method_ids) + for journal in self: + journal.check_printing_payment_method_selected = any(pm.code == 'check_printing' for pm in journal.outbound_payment_method_ids) - @api.one @api.depends('check_manual_sequencing') def _get_check_next_number(self): - if self.check_sequence_id: - self.check_next_number = self.check_sequence_id.number_next_actual - else: - self.check_next_number = 1 + for journal in self: + if journal.check_sequence_id: + journal.check_next_number = journal.check_sequence_id.number_next_actual + else: + journal.check_next_number = 1 - @api.one def _set_check_next_number(self): - if self.check_next_number and not re.match(r'^[0-9]+$', self.check_next_number): - raise ValidationError(_('Next Check Number should only contains numbers.')) - if int(self.check_next_number) < self.check_sequence_id.number_next_actual: - raise ValidationError(_("The last check number was %s. In order to avoid a check being rejected " - "by the bank, you can only use a greater number.") % self.check_sequence_id.number_next_actual) - if self.check_sequence_id: - self.check_sequence_id.sudo().number_next_actual = int(self.check_next_number) + for journal in self: + if journal.check_next_number and not re.match(r'^[0-9]+$', journal.check_next_number): + raise ValidationError(_('Next Check Number should only contains numbers.')) + if int(journal.check_next_number) < journal.check_sequence_id.number_next_actual: + raise ValidationError(_("The last check number was %s. In order to avoid a check being rejected " + "by the bank, you can only use a greater number.") % journal.check_sequence_id.number_next_actual) + if journal.check_sequence_id: + journal.check_sequence_id.sudo().number_next_actual = int(journal.check_next_number) check_manual_sequencing = fields.Boolean('Manual Numbering', default=False, help="Check this option if your pre-printed checks are not numbered.") @@ -54,16 +54,16 @@ class AccountJournal(models.Model): rec._create_check_sequence() return rec - @api.one def _create_check_sequence(self): """ Create a check sequence for the journal """ - self.check_sequence_id = self.env['ir.sequence'].sudo().create({ - 'name': self.name + _(" : Check Number Sequence"), - 'implementation': 'no_gap', - 'padding': 5, - 'number_increment': 1, - 'company_id': self.company_id.id, - }) + for journal in self: + journal.check_sequence_id = self.env['ir.sequence'].sudo().create({ + 'name': journal.name + _(" : Check Number Sequence"), + 'implementation': 'no_gap', + 'padding': 5, + 'number_increment': 1, + 'company_id': journal.company_id.id, + }) def _default_outbound_payment_methods(self): methods = super(AccountJournal, self)._default_outbound_payment_methods() diff --git a/addons/account_facturx/models/account_move.py b/addons/account_facturx/models/account_move.py index 10be55f919a..109537e96fb 100644 --- a/addons/account_facturx/models/account_move.py +++ b/addons/account_facturx/models/account_move.py @@ -237,12 +237,13 @@ class AccountMove(models.Model): self._create_invoice_from_attachment(attachment) return res - @api.one def _create_invoice_from_attachment(self, attachment): if 'pdf' in attachment.mimetype: - self._create_invoice_from_pdf(attachment) + for move in self: + move._create_invoice_from_pdf(attachment) if 'xml' in attachment.mimetype: - self._create_invoice_from_xml(attachment) + for move in self: + move._create_invoice_from_xml(attachment) def _create_invoice_from_pdf(self, attachment): def _get_attachment_filename(attachment): diff --git a/addons/barcodes/models/barcodes.py b/addons/barcodes/models/barcodes.py index c7fd1292b92..5f82c963d2c 100644 --- a/addons/barcodes/models/barcodes.py +++ b/addons/barcodes/models/barcodes.py @@ -188,17 +188,17 @@ class BarcodeRule(models.Model): pattern = fields.Char(string='Barcode Pattern', size=32, help="The barcode matching pattern", required=True, default='.*') alias = fields.Char(string='Alias', size=32, default='0', help='The matched pattern will alias to this barcode', required=True) - @api.one @api.constrains('pattern') def _check_pattern(self): - p = self.pattern.replace("\\\\", "X").replace("\{", "X").replace("\}", "X") - findall = re.findall("[{]|[}]", p) # p does not contain escaped { or } - if len(findall) == 2: - if not re.search("[{][N]*[D]*[}]", p): - raise ValidationError(_("There is a syntax error in the barcode pattern ") + self.pattern + _(": braces can only contain N's followed by D's.")) - elif re.search("[{][}]", p): - raise ValidationError(_("There is a syntax error in the barcode pattern ") + self.pattern + _(": empty braces.")) - elif len(findall) != 0: - raise ValidationError(_("There is a syntax error in the barcode pattern ") + self.pattern + _(": a rule can only contain one pair of braces.")) - elif p == '*': - raise ValidationError(_(" '*' is not a valid Regex Barcode Pattern. Did you mean '.*' ?")) + for rule in self: + p = rule.pattern.replace("\\\\", "X").replace("\{", "X").replace("\}", "X") + findall = re.findall("[{]|[}]", p) # p does not contain escaped { or } + if len(findall) == 2: + if not re.search("[{][N]*[D]*[}]", p): + raise ValidationError(_("There is a syntax error in the barcode pattern ") + rule.pattern + _(": braces can only contain N's followed by D's.")) + elif re.search("[{][}]", p): + raise ValidationError(_("There is a syntax error in the barcode pattern ") + rule.pattern + _(": empty braces.")) + elif len(findall) != 0: + raise ValidationError(_("There is a syntax error in the barcode pattern ") + rule.pattern + _(": a rule can only contain one pair of braces.")) + elif p == '*': + raise ValidationError(_(" '*' is not a valid Regex Barcode Pattern. Did you mean '.*' ?")) diff --git a/addons/base_iban/models/res_partner_bank.py b/addons/base_iban/models/res_partner_bank.py index f457a912011..b818e5742b5 100644 --- a/addons/base_iban/models/res_partner_bank.py +++ b/addons/base_iban/models/res_partner_bank.py @@ -87,11 +87,11 @@ class ResPartnerBank(models.Model): pass return super(ResPartnerBank, self).write(vals) - @api.one @api.constrains('acc_number') def _check_iban(self): - if self.acc_type == 'iban': - validate_iban(self.acc_number) + for bank in self: + if bank.acc_type == 'iban': + validate_iban(bank.acc_number) # Map ISO 3166-1 -> IBAN template, as described here : diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index 5bdd4d0acbc..483917ccf92 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -667,31 +667,36 @@ class Lead(models.Model): data['type'] = self._merge_get_result_type() return data - @api.one def _mail_body(self, fields): """ generate the message body with the changed values :param fields : list of fields to track - :returns the body of the message for the current crm.lead + :returns a list of message bodies for the corresponding leads """ - title = "%s : %s\n" % (_('Merged opportunity') if self.type == 'opportunity' else _('Merged lead'), self.name) - body = [title] - fields = self.env['ir.model.fields'].search([('name', 'in', fields or []), ('model_id.model', '=', self._name)]) - for field in fields: - value = getattr(self, field.name, False) - if field.ttype == 'selection': - selections = self.fields_get()[field.name]['selection'] - value = next((v[1] for v in selections if v[0] == value), value) - elif field.ttype == 'many2one': - if value: - value = value.sudo().display_name - elif field.ttype == 'many2many': - if value: - value = ','.join( - val.display_name - for val in value.sudo() - ) - body.append("%s: %s" % (field.field_description, value or '')) - return "<br/>".join(body + ['<br/>']) + bodies = [] + for lead in self: + title = "%s : %s\n" % (_('Merged opportunity') if lead.type == 'opportunity' else _('Merged lead'), lead.name) + body = [title] + _fields = self.env['ir.model.fields'].search([ + ('name', 'in', fields or []), + ('model_id.model', '=', lead._name), + ]) + for field in _fields: + value = getattr(lead, field.name, False) + if field.ttype == 'selection': + selections = lead.fields_get()[field.name]['selection'] + value = next((v[1] for v in selections if v[0] == value), value) + elif field.ttype == 'many2one': + if value: + value = value.sudo().display_name + elif field.ttype == 'many2many': + if value: + value = ','.join( + val.display_name + for val in value.sudo() + ) + body.append("%s: %s" % (field.field_description, value or '')) + bodies.append("<br/>".join(body + ['<br/>'])) + return bodies @api.multi def _merge_notify(self, opportunities): diff --git a/addons/delivery/models/stock_picking.py b/addons/delivery/models/stock_picking.py index d111cf0f657..764f61cb98b 100644 --- a/addons/delivery/models/stock_picking.py +++ b/addons/delivery/models/stock_picking.py @@ -11,18 +11,23 @@ from odoo.exceptions import UserError class StockQuantPackage(models.Model): _inherit = "stock.quant.package" - @api.one @api.depends('quant_ids') def _compute_weight(self): - weight = 0.0 - if self.env.context.get('picking_id'): - current_picking_move_line_ids = self.env['stock.move.line'].search([('result_package_id', '=', self.id), ('picking_id', '=', self.env.context['picking_id'])]) - for ml in current_picking_move_line_ids: - weight += ml.product_uom_id._compute_quantity(ml.qty_done,ml.product_id.uom_id) * ml.product_id.weight - else: - for quant in self.quant_ids: - weight += quant.quantity * quant.product_id.weight - self.weight = weight + for package in self: + weight = 0.0 + if self.env.context.get('picking_id'): + # TODO: potential bottleneck: N packages = N queries, use groupby ? + current_picking_move_line_ids = self.env['stock.move.line'].search([ + ('result_package_id', '=', package.id), + ('picking_id', '=', self.env.context['picking_id']) + ]) + for ml in current_picking_move_line_ids: + weight += ml.product_uom_id._compute_quantity( + ml.qty_done, ml.product_id.uom_id) * ml.product_id.weight + else: + for quant in package.quant_ids: + weight += quant.quantity * quant.product_id.weight + package.weight = weight def _get_default_weight_uom(self): return self.env['product.template']._get_weight_uom_name_from_ir_config_parameter() @@ -40,29 +45,28 @@ class StockPicking(models.Model): _inherit = 'stock.picking' - @api.one @api.depends('move_line_ids', 'move_line_ids.result_package_id') def _compute_packages(self): - self.ensure_one() - packs = set() - for move_line in self.move_line_ids: - if move_line.result_package_id: - packs.add(move_line.result_package_id.id) - self.package_ids = list(packs) + for package in self: + packs = set() + for move_line in package.move_line_ids: + if move_line.result_package_id: + packs.add(move_line.result_package_id.id) + package.package_ids = list(packs) - @api.one @api.depends('move_line_ids', 'move_line_ids.result_package_id', 'move_line_ids.product_uom_id', 'move_line_ids.qty_done') def _compute_bulk_weight(self): - weight = 0.0 - for move_line in self.move_line_ids: - if move_line.product_id and not move_line.result_package_id: - weight += move_line.product_uom_id._compute_quantity(move_line.qty_done, move_line.product_id.uom_id) * move_line.product_id.weight - self.weight_bulk = weight + for picking in self: + weight = 0.0 + for move_line in picking.move_line_ids: + if move_line.product_id and not move_line.result_package_id: + weight += move_line.product_uom_id._compute_quantity(move_line.qty_done, move_line.product_id.uom_id) * move_line.product_id.weight + picking.weight_bulk = weight - @api.one @api.depends('package_ids', 'weight_bulk') def _compute_shipping_weight(self): - self.shipping_weight = self.weight_bulk + sum([pack.shipping_weight for pack in self.package_ids]) + for picking in self: + picking.shipping_weight = picking.weight_bulk + sum([pack.shipping_weight for pack in picking.package_ids]) def _get_default_weight_uom(self): return self.env['product.template']._get_weight_uom_name_from_ir_config_parameter() @@ -231,12 +235,12 @@ class StockPicking(models.Model): } return client_action - @api.one def cancel_shipment(self): - self.carrier_id.cancel_shipment(self) - msg = "Shipment %s cancelled" % self.carrier_tracking_ref - self.message_post(body=msg) - self.carrier_tracking_ref = False + for picking in self: + picking.carrier_id.cancel_shipment(self) + msg = "Shipment %s cancelled" % picking.carrier_tracking_ref + picking.message_post(body=msg) + picking.carrier_tracking_ref = False @api.multi def check_packages_are_identical(self): diff --git a/addons/event/models/event.py b/addons/event/models/event.py index 7f2f6b0d325..b13b7cad4f8 100644 --- a/addons/event/models/event.py +++ b/addons/event/models/event.py @@ -215,21 +215,23 @@ class EventEvent(models.Model): def _tz_get(self): return [(x, x) for x in pytz.all_timezones] - @api.one @api.depends('date_tz', 'date_begin') def _compute_date_begin_tz(self): - if self.date_begin: - self.date_begin_located = format_datetime(self.env, self.date_begin, tz=self.date_tz, dt_format='medium') - else: - self.date_begin_located = False + for event in self: + if event.date_begin: + event.date_begin_located = format_datetime( + self.env, event.date_begin, tz=event.date_tz, dt_format='medium') + else: + event.date_begin_located = False - @api.one @api.depends('date_tz', 'date_end') def _compute_date_end_tz(self): - if self.date_end: - self.date_end_located = format_datetime(self.env, self.date_end, tz=self.date_tz, dt_format='medium') - else: - self.date_end_located = False + for event in self: + if event.date_end: + event.date_end_located = format_datetime( + self.env, event.date_end, tz=event.date_tz, dt_format='medium') + else: + event.date_end_located = False @api.onchange('is_online') def _onchange_is_online(self): @@ -273,11 +275,11 @@ class EventEvent(models.Model): if any(event.seats_availability == 'limited' and event.seats_max and event.seats_available < 0 for event in self): raise ValidationError(_('No more available seats.')) - @api.one @api.constrains('date_begin', 'date_end') def _check_closing_date(self): - if self.date_end < self.date_begin: - raise ValidationError(_('The closing date cannot be earlier than the beginning date.')) + for event in self: + if event.date_end < event.date_begin: + raise ValidationError(_('The closing date cannot be earlier than the beginning date.')) @api.multi @api.depends('name', 'date_begin', 'date_end') @@ -314,9 +316,8 @@ class EventEvent(models.Model): default = dict(default or {}, name=_("%s (copy)") % (self.name)) return super(EventEvent, self).copy(default) - @api.one def button_draft(self): - self.state = 'draft' + self.write({'state': 'draft'}) @api.multi def button_cancel(self): @@ -325,18 +326,16 @@ class EventEvent(models.Model): self.registration_ids.write({'state': 'cancel'}) self.state = 'cancel' - @api.one def button_done(self): - self.state = 'done' + self.write({'state': 'done'}) - @api.one def button_confirm(self): - self.state = 'confirm' + self.write({'state': 'confirm'}) - @api.one def mail_attendees(self, template_id, force_send=False, filter_func=lambda self: self.state != 'cancel'): - for attendee in self.registration_ids.filtered(filter_func): - self.env['mail.template'].browse(template_id).send_mail(attendee.id, force_send=force_send) + for event in self: + for attendee in event.registration_ids.filtered(filter_func): + self.env['mail.template'].browse(template_id).send_mail(attendee.id, force_send=force_send) @api.multi def _is_event_registrable(self): @@ -396,11 +395,11 @@ class EventRegistration(models.Model): phone = fields.Char(string='Phone') name = fields.Char(string='Attendee Name', index=True) - @api.one @api.constrains('event_id', 'state') def _check_seats_limit(self): - if self.event_id.seats_availability == 'limited' and self.event_id.seats_max and self.event_id.seats_available < (1 if self.state == 'draft' else 0): - raise ValidationError(_('No more seats available for this event.')) + for registration in self: + if registration.event_id.seats_availability == 'limited' and registration.event_id.seats_max and registration.event_id.seats_available < (1 if registration.state == 'draft' else 0): + raise ValidationError(_('No more seats available for this event.')) @api.multi def _check_auto_confirmation(self): @@ -437,33 +436,30 @@ class EventRegistration(models.Model): data.update({key: value for key, value in registration.items() if key in self._fields}) return data - @api.one def do_draft(self): - self.state = 'draft' + self.write({'state': 'draft'}) - @api.one def confirm_registration(self): - self.state = 'open' + self.write({'state': 'open'}) # auto-trigger after_sub (on subscribe) mail schedulers, if needed onsubscribe_schedulers = self.event_id.event_mail_ids.filtered( lambda s: s.interval_type == 'after_sub') onsubscribe_schedulers.execute() - @api.one def button_reg_close(self): """ Close Registration """ - today = fields.Datetime.now() - if self.event_id.date_begin <= today and self.event_id.state == 'confirm': - self.write({'state': 'done', 'date_closed': today}) - elif self.event_id.state == 'draft': - raise UserError(_("You must wait the event confirmation before doing this action.")) - else: - raise UserError(_("You must wait the event starting day before doing this action.")) + for registration in self: + today = fields.Datetime.now() + if registration.event_id.date_begin <= today and registration.event_id.state == 'confirm': + registration.write({'state': 'done', 'date_closed': today}) + elif registration.event_id.state == 'draft': + raise UserError(_("You must wait the event confirmation before doing this action.")) + else: + raise UserError(_("You must wait the event starting day before doing this action.")) - @api.one def button_reg_cancel(self): - self.state = 'cancel' + self.write({'state': 'cancel'}) @api.onchange('partner_id') def _onchange_partner(self): diff --git a/addons/event/models/event_mail.py b/addons/event/models/event_mail.py index cc09c9a71fb..43d16c8cb4a 100644 --- a/addons/event/models/event_mail.py +++ b/addons/event/models/event_mail.py @@ -76,47 +76,46 @@ class EventMailScheduler(models.Model): mail_sent = fields.Boolean('Mail Sent on Event') done = fields.Boolean('Sent', compute='_compute_done', store=True) - @api.one @api.depends('mail_sent', 'interval_type', 'event_id.registration_ids', 'mail_registration_ids') def _compute_done(self): - if self.interval_type in ['before_event', 'after_event']: - self.done = self.mail_sent - else: - self.done = len(self.mail_registration_ids) == len(self.event_id.registration_ids) and all(mail.mail_sent for mail in self.mail_registration_ids) + for mail in self: + if mail.interval_type in ['before_event', 'after_event']: + mail.done = mail.mail_sent + else: + mail.done = len(mail.mail_registration_ids) == len(mail.event_id.registration_ids) and all(mail.mail_sent for mail in mail.mail_registration_ids) - @api.one @api.depends('event_id.state', 'event_id.date_begin', 'interval_type', 'interval_unit', 'interval_nbr') def _compute_scheduled_date(self): - if self.event_id.state not in ['confirm', 'done']: - self.scheduled_date = False - else: - if self.interval_type == 'after_sub': - date, sign = self.event_id.create_date, 1 - elif self.interval_type == 'before_event': - date, sign = self.event_id.date_begin, -1 + for mail in self: + if mail.event_id.state not in ['confirm', 'done']: + mail.scheduled_date = False else: - date, sign = self.event_id.date_end, 1 - - self.scheduled_date = date + _INTERVALS[self.interval_unit](sign * self.interval_nbr) + if mail.interval_type == 'after_sub': + date, sign = mail.event_id.create_date, 1 + elif mail.interval_type == 'before_event': + date, sign = mail.event_id.date_begin, -1 + else: + date, sign = mail.event_id.date_end, 1 + mail.scheduled_date = date + _INTERVALS[mail.interval_unit](sign * mail.interval_nbr) - @api.one def execute(self): - now = fields.Datetime.now() - if self.interval_type == 'after_sub': - # update registration lines - lines = [ - (0, 0, {'registration_id': registration.id}) - for registration in (self.event_id.registration_ids - self.mapped('mail_registration_ids.registration_id')) - ] - if lines: - self.write({'mail_registration_ids': lines}) - # execute scheduler on registrations - self.mail_registration_ids.filtered(lambda reg: reg.scheduled_date and reg.scheduled_date <= now).execute() - else: - # Do not send emails if the mailing was scheduled before the event but the event is over - if not self.mail_sent and (self.interval_type != 'before_event' or self.event_id.date_end > now): - self.event_id.mail_attendees(self.template_id.id) - self.write({'mail_sent': True}) + for mail in self: + now = fields.Datetime.now() + if mail.interval_type == 'after_sub': + # update registration lines + lines = [ + (0, 0, {'registration_id': registration.id}) + for registration in (mail.event_id.registration_ids - mail.mapped('mail_registration_ids.registration_id')) + ] + if lines: + mail.write({'mail_registration_ids': lines}) + # execute scheduler on registrations + mail.mail_registration_ids.filtered(lambda reg: reg.scheduled_date and reg.scheduled_date <= now).execute() + else: + # Do not send emails if the mailing was scheduled before the event but the event is over + if not mail.mail_sent and (mail.interval_type != 'before_event' or mail.event_id.date_end > now): + mail.event_id.mail_attendees(mail.template_id.id) + mail.write({'mail_sent': True}) return True @api.model @@ -179,18 +178,18 @@ class EventMailRegistration(models.Model): scheduled_date = fields.Datetime('Scheduled Time', compute='_compute_scheduled_date', store=True) mail_sent = fields.Boolean('Mail Sent') - @api.one def execute(self): - if self.registration_id.state in ['open', 'done'] and not self.mail_sent: - self.scheduler_id.template_id.send_mail(self.registration_id.id) - self.write({'mail_sent': True}) + for mail in self: + if mail.registration_id.state in ['open', 'done'] and not mail.mail_sent: + mail.scheduler_id.template_id.send_mail(mail.registration_id.id) + mail.write({'mail_sent': True}) - @api.one @api.depends('registration_id', 'scheduler_id.interval_unit', 'scheduler_id.interval_type') def _compute_scheduled_date(self): - if self.registration_id: - date_open = self.registration_id.date_open - date_open_datetime = date_open or fields.Datetime.now() - self.scheduled_date = date_open_datetime + _INTERVALS[self.scheduler_id.interval_unit](self.scheduler_id.interval_nbr) - else: - self.scheduled_date = False + for mail in self: + if mail.registration_id: + date_open = mail.registration_id.date_open + date_open_datetime = date_open or fields.Datetime.now() + mail.scheduled_date = date_open_datetime + _INTERVALS[mail.scheduler_id.interval_unit](mail.scheduler_id.interval_nbr) + else: + mail.scheduled_date = False diff --git a/addons/hr_expense/wizard/hr_expense_sheet_register_payment.py b/addons/hr_expense/wizard/hr_expense_sheet_register_payment.py index 9a98f40dc59..eaf0b8f7ac5 100644 --- a/addons/hr_expense/wizard/hr_expense_sheet_register_payment.py +++ b/addons/hr_expense/wizard/hr_expense_sheet_register_payment.py @@ -42,11 +42,11 @@ class HrExpenseSheetRegisterPaymentWizard(models.TransientModel): else: self.partner_bank_account_id = False - @api.one @api.constrains('amount') def _check_amount(self): - if not self.amount > 0.0: - raise ValidationError(_('The payment amount must be strictly positive.')) + for wizard in self: + if not wizard.amount > 0.0: + raise ValidationError(_('The payment amount must be strictly positive.')) @api.depends('payment_method_id') def _compute_show_partner_bank(self): @@ -56,14 +56,15 @@ class HrExpenseSheetRegisterPaymentWizard(models.TransientModel): payment.show_partner_bank_account = payment.payment_method_id.code in self.env['account.payment']._get_method_codes_using_bank_account() payment.require_partner_bank_account = payment.payment_method_id.code in self.env['account.payment']._get_method_codes_needing_bank_account() - @api.one @api.depends('journal_id') def _compute_hide_payment_method(self): - if not self.journal_id: - self.hide_payment_method = True - return - journal_payment_methods = self.journal_id.outbound_payment_method_ids - self.hide_payment_method = len(journal_payment_methods) == 1 and journal_payment_methods[0].code == 'manual' + for wizard in self: + if not wizard.journal_id: + wizard.hide_payment_method = True + else: + journal_payment_methods = wizard.journal_id.outbound_payment_method_ids + wizard.hide_payment_method = (len(journal_payment_methods) == 1 + and journal_payment_methods[0].code == 'manual') @api.onchange('journal_id') def _onchange_journal(self): diff --git a/addons/hr_maintenance/models/equipment.py b/addons/hr_maintenance/models/equipment.py index d52ae7b22a0..343a10c92f2 100644 --- a/addons/hr_maintenance/models/equipment.py +++ b/addons/hr_maintenance/models/equipment.py @@ -15,14 +15,14 @@ class MaintenanceEquipment(models.Model): default='employee') owner_user_id = fields.Many2one(compute='_compute_owner', store=True) - @api.one @api.depends('employee_id', 'department_id', 'equipment_assign_to') def _compute_owner(self): - self.owner_user_id = self.env.user.id - if self.equipment_assign_to == 'employee': - self.owner_user_id = self.employee_id.user_id.id - elif self.equipment_assign_to == 'department': - self.owner_user_id = self.department_id.manager_id.user_id.id + for equipment in self: + equipment.owner_user_id = self.env.user.id + if equipment.equipment_assign_to == 'employee': + equipment.owner_user_id = equipment.employee_id.user_id.id + elif equipment.equipment_assign_to == 'department': + equipment.owner_user_id = equipment.department_id.manager_id.user_id.id @api.onchange('equipment_assign_to') def _onchange_equipment_assign_to(self): diff --git a/addons/hr_recruitment/models/hr_recruitment.py b/addons/hr_recruitment/models/hr_recruitment.py index b639bc2e437..24fd9eba483 100644 --- a/addons/hr_recruitment/models/hr_recruitment.py +++ b/addons/hr_recruitment/models/hr_recruitment.py @@ -167,18 +167,17 @@ class Applicant(models.Model): @api.depends('date_open', 'date_closed') - @api.one def _compute_day(self): - if self.date_open: - date_create = self.create_date - date_open = self.date_open - self.day_open = (date_open - date_create).total_seconds() / (24.0 * 3600) - - if self.date_closed: - date_create = self.create_date - date_closed = self.date_closed - self.day_close = (date_closed - date_create).total_seconds() / (24.0 * 3600) - self.delay_close = self.day_close - self.day_open + for applicant in self: + if applicant.date_open: + date_create = applicant.create_date + date_open = applicant.date_open + applicant.day_open = (date_open - date_create).total_seconds() / (24.0 * 3600) + if applicant.date_closed: + date_create = applicant.create_date + date_closed = applicant.date_closed + applicant.day_close = (date_closed - date_create).total_seconds() / (24.0 * 3600) + applicant.delay_close = applicant.day_close - applicant.day_open @api.depends('email_from') def _compute_application_count(self): diff --git a/addons/im_livechat/models/im_livechat_channel.py b/addons/im_livechat/models/im_livechat_channel.py index 93770819191..f0f8ca0e9d7 100644 --- a/addons/im_livechat/models/im_livechat_channel.py +++ b/addons/im_livechat/models/im_livechat_channel.py @@ -59,9 +59,9 @@ class ImLivechatChannel(models.Model): channel_ids = fields.One2many('mail.channel', 'livechat_channel_id', 'Sessions') rule_ids = fields.One2many('im_livechat.channel.rule', 'channel_id', 'Rules') - @api.one def _are_you_inside(self): - self.are_you_inside = bool(self.env.uid in [u.id for u in self.user_ids]) + for channel in self: + channel.are_you_inside = bool(self.env.uid in [u.id for u in channel.user_ids]) @api.multi def _compute_script_external(self): diff --git a/addons/im_livechat/models/rating.py b/addons/im_livechat/models/rating.py index 07e84678eda..f6a638ed53f 100644 --- a/addons/im_livechat/models/rating.py +++ b/addons/im_livechat/models/rating.py @@ -8,16 +8,16 @@ class Rating(models.Model): _inherit = "rating.rating" - @api.one @api.depends('res_model', 'res_id') def _compute_res_name(self): - # cannot change the rec_name of session since it is use to create the bus channel - # so, need to override this method to set the same alternative rec_name as in reporting - if self.res_model == 'mail.channel': - current_object = self.env[self.res_model].sudo().browse(self.res_id) - self.res_name = ('%s / %s') % (current_object.livechat_channel_id.name, current_object.id) - else: - super(Rating, self)._compute_res_name() + for rating in self: + # cannot change the rec_name of session since it is use to create the bus channel + # so, need to override this method to set the same alternative rec_name as in reporting + if rating.res_model == 'mail.channel': + current_object = self.env[rating.res_model].sudo().browse(rating.res_id) + rating.res_name = ('%s / %s') % (current_object.livechat_channel_id.name, current_object.id) + else: + super(Rating, rating)._compute_res_name() def action_open_rated_object(self): action = super(Rating, self).action_open_rated_object() diff --git a/addons/link_tracker/models/link_tracker.py b/addons/link_tracker/models/link_tracker.py index 2e565a06691..3bc0b02473f 100644 --- a/addons/link_tracker/models/link_tracker.py +++ b/addons/link_tracker/models/link_tracker.py @@ -51,44 +51,42 @@ class LinkTracker(models.Model): link_click_ids = fields.One2many('link.tracker.click', 'link_id', string='Clicks') count = fields.Integer(string='Number of Clicks', compute='_compute_count', store=True) - @api.one @api.depends('link_click_ids.link_id') def _compute_count(self): - self.count = len(self.link_click_ids) + for tracker in self: + tracker.count = len(tracker.link_click_ids) - @api.one @api.depends('code') def _compute_short_url(self): - base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') - self.short_url = urls.url_join(base_url, '/r/%(code)s' % {'code': self.code}) + for tracker in self: + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + tracker.short_url = urls.url_join(base_url, '/r/%(code)s' % {'code': tracker.code}) - @api.one def _compute_short_url_host(self): - self.short_url_host = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + '/r/' + for tracker in self: + tracker.short_url_host = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + '/r/' - @api.one def _compute_code(self): - record = self.env['link.tracker.code'].search([('link_id', '=', self.id)], limit=1, order='id DESC') - self.code = record.code + for tracker in self: + record = self.env['link.tracker.code'].search([('link_id', '=', tracker.id)], limit=1, order='id DESC') + tracker.code = record.code - @api.one @api.depends('favicon') def _compute_icon_src(self): - self.icon_src = 'data:image/png;base64,' + self.favicon + for tracker in self: + tracker.icon_src = 'data:image/png;base64,' + tracker.favicon - @api.one @api.depends('url') def _compute_redirected_url(self): - parsed = urls.url_parse(self.url) - - utms = {} - for key, field, cook in self.env['utm.mixin'].tracking_fields(): - attr = getattr(self, field).name - if attr: - utms[key] = attr - utms.update(parsed.decode_query()) - - self.redirected_url = parsed.replace(query=urls.url_encode(utms)).to_url() + for tracker in self: + parsed = urls.url_parse(tracker.url) + utms = {} + for key, field, cook in self.env['utm.mixin'].tracking_fields(): + attr = getattr(tracker, field).name + if attr: + utms[key] = attr + utms.update(parsed.decode_query()) + tracker.redirected_url = parsed.replace(query=urls.url_encode(utms)).to_url() @api.model @api.depends('url') @@ -102,16 +100,15 @@ class LinkTracker(models.Model): return title - @api.one @api.depends('url') def _compute_favicon(self): - try: - icon = requests.get('http://www.google.com/s2/favicons', params={'domain': self.url}, timeout=5).content - icon_base64 = base64.b64encode(icon).replace(b"\n", b"").decode('ascii') - except: - icon_base64 = 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAACiElEQVQ4EaVTzU8TURCf2tJuS7tQtlRb6UKBIkQwkRRSEzkQgyEc6lkOKgcOph78Y+CgjXjDs2i44FXY9AMTlQRUELZapVlouy3d7kKtb0Zr0MSLTvL2zb75eL838xtTvV6H/xELBptMJojeXLCXyobnyog4YhzXYvmCFi6qVSfaeRdXdrfaU1areV5KykmX06rcvzumjY/1ggkR3Jh+bNf1mr8v1D5bLuvR3qDgFbvbBJYIrE1mCIoCrKxsHuzK+Rzvsi29+6DEbTZz9unijEYI8ObBgXOzlcrx9OAlXyDYKUCzwwrDQx1wVDGg089Dt+gR3mxmhcUnaWeoxwMbm/vzDFzmDEKMMNhquRqduT1KwXiGt0vre6iSeAUHNDE0d26NBtAXY9BACQyjFusKuL2Ry+IPb/Y9ZglwuVscdHaknUChqLF/O4jn3V5dP4mhgRJgwSYm+gV0Oi3XrvYB30yvhGa7BS70eGFHPoTJyQHhMK+F0ZesRVVznvXw5Ixv7/C10moEo6OZXbWvlFAF9FVZDOqEABUMRIkMd8GnLwVWg9/RkJF9sA4oDfYQAuzzjqzwvnaRUFxn/X2ZlmGLXAE7AL52B4xHgqAUqrC1nSNuoJkQtLkdqReszz/9aRvq90NOKdOS1nch8TpL555WDp49f3uAMXhACRjD5j4ykuCtf5PP7Fm1b0DIsl/VHGezzP1KwOiZQobFF9YyjSRYQETRENSlVzI8iK9mWlzckpSSCQHVALmN9Az1euDho9Xo8vKGd2rqooA8yBcrwHgCqYR0kMkWci08t/R+W4ljDCanWTg9TJGwGNaNk3vYZ7VUdeKsYJGFNkfSzjXNrSX20s4/h6kB81/271ghG17l+rPTAAAAAElFTkSuQmCC' - - self.favicon = icon_base64 + for tracker in self: + try: + icon = requests.get('http://www.google.com/s2/favicons', params={'domain': tracker.url}, timeout=5).content + icon_base64 = base64.b64encode(icon).replace(b"\n", b"").decode('ascii') + except: + icon_base64 = 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAACiElEQVQ4EaVTzU8TURCf2tJuS7tQtlRb6UKBIkQwkRRSEzkQgyEc6lkOKgcOph78Y+CgjXjDs2i44FXY9AMTlQRUELZapVlouy3d7kKtb0Zr0MSLTvL2zb75eL838xtTvV6H/xELBptMJojeXLCXyobnyog4YhzXYvmCFi6qVSfaeRdXdrfaU1areV5KykmX06rcvzumjY/1ggkR3Jh+bNf1mr8v1D5bLuvR3qDgFbvbBJYIrE1mCIoCrKxsHuzK+Rzvsi29+6DEbTZz9unijEYI8ObBgXOzlcrx9OAlXyDYKUCzwwrDQx1wVDGg089Dt+gR3mxmhcUnaWeoxwMbm/vzDFzmDEKMMNhquRqduT1KwXiGt0vre6iSeAUHNDE0d26NBtAXY9BACQyjFusKuL2Ry+IPb/Y9ZglwuVscdHaknUChqLF/O4jn3V5dP4mhgRJgwSYm+gV0Oi3XrvYB30yvhGa7BS70eGFHPoTJyQHhMK+F0ZesRVVznvXw5Ixv7/C10moEo6OZXbWvlFAF9FVZDOqEABUMRIkMd8GnLwVWg9/RkJF9sA4oDfYQAuzzjqzwvnaRUFxn/X2ZlmGLXAE7AL52B4xHgqAUqrC1nSNuoJkQtLkdqReszz/9aRvq90NOKdOS1nch8TpL555WDp49f3uAMXhACRjD5j4ykuCtf5PP7Fm1b0DIsl/VHGezzP1KwOiZQobFF9YyjSRYQETRENSlVzI8iK9mWlzckpSSCQHVALmN9Az1euDho9Xo8vKGd2rqooA8yBcrwHgCqYR0kMkWci08t/R+W4ljDCanWTg9TJGwGNaNk3vYZ7VUdeKsYJGFNkfSzjXNrSX20s4/h6kB81/271ghG17l+rPTAAAAAElFTkSuQmCC' + tracker.favicon = icon_base64 @api.model def create(self, vals): diff --git a/addons/mail/models/mail_alias.py b/addons/mail/models/mail_alias.py index 8ae39131099..77bdc216728 100644 --- a/addons/mail/models/mail_alias.py +++ b/addons/mail/models/mail_alias.py @@ -79,13 +79,13 @@ class Alias(models.Model): for record in self: record.alias_domain = alias_domain - @api.one @api.constrains('alias_defaults') def _check_alias_defaults(self): - try: - dict(safe_eval(self.alias_defaults)) - except Exception: - raise ValidationError(_('Invalid expression, it must be a literal python dictionary definition e.g. "{\'field\': \'value\'}"')) + for alias in self: + try: + dict(safe_eval(alias.alias_defaults)) + except Exception: + raise ValidationError(_('Invalid expression, it must be a literal python dictionary definition e.g. "{\'field\': \'value\'}"')) @api.model def create(self, vals): diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py index 1b728482b2e..524f3763d93 100644 --- a/addons/mail/models/mail_channel.py +++ b/addons/mail/models/mail_channel.py @@ -129,10 +129,10 @@ class Channel(models.Model): moderation_guidelines = fields.Boolean(string="Send guidelines to new subscribers", help="Newcomers on this moderated channel will automatically receive the guidelines.") moderation_guidelines_msg = fields.Text(string="Guidelines") - @api.one @api.depends('channel_partner_ids') def _compute_is_subscribed(self): - self.is_subscribed = self.env.user.partner_id in self.channel_partner_ids + for channel in self: + channel.is_subscribed = self.env.user.partner_id in channel.channel_partner_ids @api.multi @api.depends('moderator_ids') diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index a7245bb476f..e1cfa920742 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -114,11 +114,11 @@ class MailThread(models.AbstractModel): message_attachment_count = fields.Integer('Attachment Count', compute='_compute_message_attachment_count', groups="base.group_user") message_main_attachment_id = fields.Many2one(string="Main Attachment", comodel_name='ir.attachment', index=True, copy=False) - @api.one @api.depends('message_follower_ids') def _get_followers(self): - self.message_partner_ids = self.message_follower_ids.mapped('partner_id') - self.message_channel_ids = self.message_follower_ids.mapped('channel_id') + for thread in self: + thread.message_partner_ids = thread.message_follower_ids.mapped('partner_id') + thread.message_channel_ids = thread.message_follower_ids.mapped('channel_id') @api.model def _search_follower_partners(self, operator, operand): diff --git a/addons/maintenance/models/maintenance.py b/addons/maintenance/models/maintenance.py index 3677527e17a..ce4fc8c3e65 100644 --- a/addons/maintenance/models/maintenance.py +++ b/addons/maintenance/models/maintenance.py @@ -25,10 +25,10 @@ class MaintenanceEquipmentCategory(models.Model): _inherit = ['mail.alias.mixin', 'mail.thread'] _description = 'Maintenance Equipment Category' - @api.one @api.depends('equipment_ids') def _compute_fold(self): - self.fold = False if self.equipment_count else True + for category in self: + category.fold = False if category.equipment_count else True name = fields.Char('Category Name', required=True, translate=True) company_id = fields.Many2one('res.company', string='Company', @@ -190,11 +190,11 @@ class MaintenanceEquipment(models.Model): next_date = self.effective_date + timedelta(days=equipment.period) equipment.next_action_date = next_date - @api.one @api.depends('maintenance_ids.stage_id.done') def _compute_maintenance_count(self): - self.maintenance_count = len(self.maintenance_ids) - self.maintenance_open_count = len(self.maintenance_ids.filtered(lambda x: not x.stage_id.done)) + for equipment in self: + equipment.maintenance_count = len(equipment.maintenance_ids) + equipment.maintenance_open_count = len(equipment.maintenance_ids.filtered(lambda x: not x.stage_id.done)) @api.onchange('category_id') def _onchange_category_id(self): @@ -418,17 +418,17 @@ class MaintenanceTeam(models.Model): todo_request_count_block = fields.Integer(string="Number of Requests Blocked", compute='_compute_todo_requests') todo_request_count_unscheduled = fields.Integer(string="Number of Requests Unscheduled", compute='_compute_todo_requests') - @api.one @api.depends('request_ids.stage_id.done') def _compute_todo_requests(self): - self.todo_request_ids = self.request_ids.filtered(lambda e: e.stage_id.done==False) - self.todo_request_count = len(self.todo_request_ids) - self.todo_request_count_date = len(self.todo_request_ids.filtered(lambda e: e.schedule_date != False)) - self.todo_request_count_high_priority = len(self.todo_request_ids.filtered(lambda e: e.priority == '3')) - self.todo_request_count_block = len(self.todo_request_ids.filtered(lambda e: e.kanban_state == 'blocked')) - self.todo_request_count_unscheduled = len(self.todo_request_ids.filtered(lambda e: not e.schedule_date)) - - @api.one + for team in self: + team.todo_request_ids = team.request_ids.filtered(lambda e: e.stage_id.done==False) + team.todo_request_count = len(team.todo_request_ids) + team.todo_request_count_date = len(team.todo_request_ids.filtered(lambda e: e.schedule_date != False)) + team.todo_request_count_high_priority = len(team.todo_request_ids.filtered(lambda e: e.priority == '3')) + team.todo_request_count_block = len(team.todo_request_ids.filtered(lambda e: e.kanban_state == 'blocked')) + team.todo_request_count_unscheduled = len(team.todo_request_ids.filtered(lambda e: not e.schedule_date)) + @api.depends('equipment_ids') def _compute_equipment(self): - self.equipment_count = len(self.equipment_ids) + for team in self: + team.equipment_count = len(team.equipment_ids) diff --git a/addons/membership/models/partner.py b/addons/membership/models/partner.py index 75947a34738..03b69268a12 100644 --- a/addons/membership/models/partner.py +++ b/addons/membership/models/partner.py @@ -97,15 +97,15 @@ class Partner(models.Model): state = 'free' partner.membership_state = state - @api.one @api.constrains('associate_member') def _check_recursion_associate_member(self): - level = 100 - while self: - self = self.associate_member - if not level: - raise ValidationError(_('You cannot create recursive associated members.')) - level -= 1 + for partner in self: + level = 100 + while partner: + partner = partner.associate_member + if not level: + raise ValidationError(_('You cannot create recursive associated members.')) + level -= 1 @api.model def _cron_update_membership(self): diff --git a/addons/mrp/models/mrp_bom.py b/addons/mrp/models/mrp_bom.py index c7e78eb3502..ca46c616e52 100644 --- a/addons/mrp/models/mrp_bom.py +++ b/addons/mrp/models/mrp_bom.py @@ -268,31 +268,31 @@ class MrpBomLine(models.Model): 'You should install the mrp_byproduct module if you want to manage extra products on BoMs !'), ] - @api.one @api.depends('product_id', 'bom_id') def _compute_child_bom_id(self): - if not self.product_id: - self.child_bom_id = False - else: - self.child_bom_id = self.env['mrp.bom']._bom_find( - product_tmpl=self.product_id.product_tmpl_id, - product=self.product_id, - picking_type=self.bom_id.picking_type_id) + for line in self: + if not line.product_id: + line.child_bom_id = False + else: + line.child_bom_id = self.env['mrp.bom']._bom_find( + product_tmpl=line.product_id.product_tmpl_id, + product=line.product_id, + picking_type=line.bom_id.picking_type_id) - @api.one @api.depends('product_id') def _compute_attachments_count(self): - nbr_attach = self.env['mrp.document'].search_count([ - '|', - '&', ('res_model', '=', 'product.product'), ('res_id', '=', self.product_id.id), - '&', ('res_model', '=', 'product.template'), ('res_id', '=', self.product_id.product_tmpl_id.id)]) - self.attachments_count = nbr_attach + for line in self: + nbr_attach = self.env['mrp.document'].search_count([ + '|', + '&', ('res_model', '=', 'product.product'), ('res_id', '=', line.product_id.id), + '&', ('res_model', '=', 'product.template'), ('res_id', '=', line.product_id.product_tmpl_id.id)]) + line.attachments_count = nbr_attach - @api.one @api.depends('child_bom_id') def _compute_child_line_ids(self): """ If the BOM line refers to a BOM, return the ids of the child BOM lines """ - self.child_line_ids = self.child_bom_id.bom_line_ids.ids + for line in self: + line.child_line_ids = line.child_bom_id.bom_line_ids.ids @api.onchange('product_uom_id') def onchange_product_uom_id(self): diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py index 9699b6fd539..76cce1b978f 100644 --- a/addons/mrp/models/mrp_workorder.py +++ b/addons/mrp/models/mrp_workorder.py @@ -203,21 +203,21 @@ class MrpWorkorder(models.Model): def name_get(self): return [(wo.id, "%s - %s - %s" % (wo.production_id.name, wo.product_id.name, wo.name)) for wo in self] - @api.one @api.depends('production_id.product_qty', 'qty_produced') def _compute_is_produced(self): - rounding = self.production_id.product_uom_id.rounding - self.is_produced = float_compare(self.qty_produced, self.production_id.product_qty, precision_rounding=rounding) >= 0 + for order in self: + rounding = order.production_id.product_uom_id.rounding + order.is_produced = float_compare(order.qty_produced, order.production_id.product_qty, precision_rounding=rounding) >= 0 - @api.one @api.depends('time_ids.duration', 'qty_produced') def _compute_duration(self): - self.duration = sum(self.time_ids.mapped('duration')) - self.duration_unit = round(self.duration / max(self.qty_produced, 1), 2) # rounding 2 because it is a time - if self.duration_expected: - self.duration_percent = 100 * (self.duration_expected - self.duration) / self.duration_expected - else: - self.duration_percent = 0 + for order in self: + order.duration = sum(order.time_ids.mapped('duration')) + order.duration_unit = round(order.duration / max(order.qty_produced, 1), 2) # rounding 2 because it is a time + if order.duration_expected: + order.duration_percent = 100 * (order.duration_expected - order.duration) / order.duration_expected + else: + order.duration_percent = 0 def _compute_working_users(self): """ Checks whether the current user is working, all the users currently working and the last user that worked. """ diff --git a/addons/mrp/models/product.py b/addons/mrp/models/product.py index 7ea6e332123..13dfecb427d 100644 --- a/addons/mrp/models/product.py +++ b/addons/mrp/models/product.py @@ -35,9 +35,9 @@ class ProductTemplate(models.Model): action['domain'] = [('bom_line_ids.product_id', 'in', self.product_variant_ids.ids)] return action - @api.one def _compute_mrp_product_qty(self): - self.mrp_product_qty = float_round(sum(self.mapped('product_variant_ids').mapped('mrp_product_qty')), precision_rounding=self.uom_id.rounding) + for template in self: + template.mrp_product_qty = float_round(sum(template.mapped('product_variant_ids').mapped('mrp_product_qty')), precision_rounding=template.uom_id.rounding) @api.multi def action_view_mos(self): diff --git a/addons/pos_cache/models/pos_cache.py b/addons/pos_cache/models/pos_cache.py index 980555ebf30..30ca2d261c0 100644 --- a/addons/pos_cache/models/pos_cache.py +++ b/addons/pos_cache/models/pos_cache.py @@ -22,18 +22,16 @@ class pos_cache(models.Model): def refresh_all_caches(self): self.env['pos.cache'].search([]).refresh_cache() - @api.one def refresh_cache(self): - Product = self.env['product.product'].with_user(self.compute_user_id) - products = Product.search(self.get_product_domain()) - prod_ctx = products.with_context(pricelist=self.config_id.pricelist_id.id, display_default_code=False, - lang=self.compute_user_id.lang) - res = prod_ctx.read(self.get_product_fields()) - datas = { - 'cache': base64.encodestring(json.dumps(res).encode('utf-8')), - } - - self.write(datas) + for cache in self: + Product = self.env['product.product'].with_user(cache.compute_user_id.id) + products = Product.search(cache.get_product_domain()) + prod_ctx = products.with_context(pricelist=cache.config_id.pricelist_id.id, + display_default_code=False, lang=cache.compute_user_id.lang) + res = prod_ctx.read(cache.get_product_fields()) + cache.write({ + 'cache': base64.encodestring(json.dumps(res).encode('utf-8')), + }) @api.model def get_product_domain(self): @@ -56,13 +54,12 @@ class pos_cache(models.Model): class pos_config(models.Model): _inherit = 'pos.config' - @api.one @api.depends('cache_ids') def _get_oldest_cache_time(self): - pos_cache = self.env['pos.cache'] - oldest_cache = pos_cache.search([('config_id', '=', self.id)], order='write_date', limit=1) - if oldest_cache: - self.oldest_cache_time = oldest_cache.write_date + for cache in self: + pos_cache = self.env['pos.cache'] + oldest_cache = pos_cache.search([('config_id', '=', cache.id)], order='write_date', limit=1) + cache.oldest_cache_time = oldest_cache.write_date # Use a related model to avoid the load of the cache when the pos load his config cache_ids = fields.One2many('pos.cache', 'config_id') @@ -94,7 +91,6 @@ class pos_config(models.Model): new_cache = self._get_cache_for_user() return new_cache.get_cache(domain, fields) - @api.one def delete_cache(self): # throw away the old caches self.cache_ids.unlink() diff --git a/addons/pos_mercury/models/pos_mercury.py b/addons/pos_mercury/models/pos_mercury.py index a55e701b3db..4915f948afc 100644 --- a/addons/pos_mercury/models/pos_mercury.py +++ b/addons/pos_mercury/models/pos_mercury.py @@ -37,12 +37,12 @@ class AccountBankStatementLine(models.Model): mercury_record_no = fields.Char(string='Mercury record number', help='Payment record number from Mercury Pay') mercury_invoice_no = fields.Char(string='Mercury invoice number', help='Invoice number from Mercury Pay') - @api.one def _compute_prefixed_card_number(self): - if self.mercury_card_number: - self.mercury_prefixed_card_number = "********" + self.mercury_card_number - else: - self.mercury_prefixed_card_number = "" + for line in self: + if line.mercury_card_number: + line.mercury_prefixed_card_number = "********" + line.mercury_card_number + else: + line.mercury_prefixed_card_number = "" class AccountJournal(models.Model): diff --git a/addons/product/models/product.py b/addons/product/models/product.py index 5c8e4c654ea..2bf174fe3c7 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -301,24 +301,24 @@ class ProductProduct(models.Model): list_price = product.list_price product.lst_price = list_price + product.price_extra - @api.one def _compute_product_code(self): - for supplier_info in self.seller_ids: - if supplier_info.name.id == self._context.get('partner_id'): - self.code = supplier_info.product_code or self.default_code - break - else: - self.code = self.default_code + for product in self: + for supplier_info in product.seller_ids: + if supplier_info.name.id == product._context.get('partner_id'): + product.code = supplier_info.product_code or product.default_code + break + else: + product.code = product.default_code - @api.one def _compute_partner_ref(self): - for supplier_info in self.seller_ids: - if supplier_info.name.id == self._context.get('partner_id'): - product_name = supplier_info.product_name or supplier_info.product_code or self.default_code or self.name - self.partner_ref = '%s%s' % (self.code and '[%s] ' % self.code or '', product_name) - break - else: - self.partner_ref = self.display_name + for product in self: + for supplier_info in product.seller_ids: + if supplier_info.name.id == product._context.get('partner_id'): + product_name = supplier_info.product_name or product.default_code or product.name + product.partner_ref = '%s%s' % (product.code and '[%s] ' % product.code or '', product_name) + break + else: + product.partner_ref = product.display_name @api.depends('product_tmpl_id', 'attribute_value_ids') def _compute_product_template_attribute_value_ids(self): @@ -344,12 +344,12 @@ class ProductProduct(models.Model): else: product.product_template_attribute_value_ids += values_per_template[product.product_tmpl_id.id][pav.id] - @api.one def _get_pricelist_items(self): - self.pricelist_item_ids = self.env['product.pricelist.item'].search([ - '|', - ('product_id', '=', self.id), - ('product_tmpl_id', '=', self.product_tmpl_id.id)]).ids + for product in self: + product.pricelist_item_ids = self.env['product.pricelist.item'].search([ + '|', + ('product_id', '=', product.id), + ('product_tmpl_id', '=', product.product_tmpl_id.id)]).ids @api.constrains('attribute_value_ids') def _check_attribute_value_ids(self): diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py index 7663bf66569..3f6b1d05260 100644 --- a/addons/product/models/product_pricelist.py +++ b/addons/product/models/product_pricelist.py @@ -471,25 +471,25 @@ class PricelistItem(models.Model): raise ValidationError(_('The minimum margin should be lower than the maximum margin.')) return True - @api.one @api.depends('categ_id', 'product_tmpl_id', 'product_id', 'compute_price', 'fixed_price', \ 'pricelist_id', 'percent_price', 'price_discount', 'price_surcharge') def _get_pricelist_item_name_price(self): - if self.categ_id: - self.name = _("Category: %s") % (self.categ_id.name) - elif self.product_tmpl_id: - self.name = self.product_tmpl_id.name - elif self.product_id: - self.name = self.product_id.display_name.replace('[%s]' % self.product_id.code, '') - else: - self.name = _("All Products") - - if self.compute_price == 'fixed': - self.price = ("%s %s") % (self.fixed_price, self.pricelist_id.currency_id.name) - elif self.compute_price == 'percentage': - self.price = _("%s %% discount") % (self.percent_price) - else: - self.price = _("%s %% discount and %s surcharge") % (self.price_discount, self.price_surcharge) + for item in self: + if item.categ_id: + item.name = _("Category: %s") % (item.categ_id.name) + elif item.product_tmpl_id: + item.name = item.product_tmpl_id.name + elif item.product_id: + item.name = item.product_id.display_name.replace('[%s]' % item.product_id.code, '') + else: + item.name = _("All Products") + + if item.compute_price == 'fixed': + item.price = ("%s %s") % (item.fixed_price, item.pricelist_id.currency_id.name) + elif item.compute_price == 'percentage': + item.price = _("%s %% discount") % (item.percent_price) + else: + item.price = _("%s %% discount and %s surcharge") % (item.price_discount, item.price_surcharge) @api.onchange('applied_on') def _onchange_applied_on(self): diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index d1b0a1f95b7..283893bcd2e 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -215,10 +215,10 @@ class ProductTemplate(models.Model): for template in (self - unique_variants): template.standard_price = 0.0 - @api.one def _set_standard_price(self): - if len(self.product_variant_ids) == 1: - self.product_variant_ids.standard_price = self.standard_price + for template in self: + if len(template.product_variant_ids) == 1: + template.product_variant_ids.standard_price = template.standard_price def _search_standard_price(self, operator, value): products = self.env['product.product'].search([('standard_price', operator, value)], limit=None) @@ -232,10 +232,10 @@ class ProductTemplate(models.Model): for template in (self - unique_variants): template.volume = 0.0 - @api.one def _set_volume(self): - if len(self.product_variant_ids) == 1: - self.product_variant_ids.volume = self.volume + for template in self: + if len(template.product_variant_ids) == 1: + template.product_variant_ids.volume = template.volume @api.depends('product_variant_ids', 'product_variant_ids.weight') def _compute_weight(self): @@ -285,16 +285,16 @@ class ProductTemplate(models.Model): for template in self: template.volume_uom_name = self._get_volume_uom_name_from_ir_config_parameter() - @api.one def _set_weight(self): - if len(self.product_variant_ids) == 1: - self.product_variant_ids.weight = self.weight + for template in self: + if len(template.product_variant_ids) == 1: + template.product_variant_ids.weight = template.weight - @api.one @api.depends('product_variant_ids.product_tmpl_id') def _compute_product_variant_count(self): - # do not pollute variants to be prefetched when counting variants - self.product_variant_count = len(self.with_prefetch().product_variant_ids) + for template in self: + # do not pollute variants to be prefetched when counting variants + template.product_variant_count = len(template.with_prefetch().product_variant_ids) @api.depends('product_variant_ids', 'product_variant_ids.default_code') def _compute_default_code(self): @@ -304,10 +304,10 @@ class ProductTemplate(models.Model): for template in (self - unique_variants): template.default_code = '' - @api.one def _set_default_code(self): - if len(self.product_variant_ids) == 1: - self.product_variant_ids.default_code = self.default_code + for template in self: + if len(template.product_variant_ids) == 1: + template.product_variant_ids.default_code = template.default_code @api.depends('product_variant_ids', 'product_variant_ids.packaging_ids') def _compute_packaging_ids(self): diff --git a/addons/product/models/res_partner.py b/addons/product/models/res_partner.py index be1f7f25d41..2b298a1715d 100644 --- a/addons/product/models/res_partner.py +++ b/addons/product/models/res_partner.py @@ -22,24 +22,23 @@ class Partner(models.Model): for p in self: p.property_product_pricelist = res.get(p.id) - @api.one def _inverse_product_pricelist(self): - pls = self.env['product.pricelist'].search( - [('country_group_ids.country_ids.code', '=', self.country_id and self.country_id.code or False)], - limit=1 - ) - default_for_country = pls and pls[0] - actual = self.env['ir.property'].get('property_product_pricelist', 'res.partner', 'res.partner,%s' % self.id) - - # update at each change country, and so erase old pricelist - if self.property_product_pricelist or (actual and default_for_country and default_for_country.id != actual.id): - # keep the company of the current user before sudo - self.env['ir.property'].with_context(force_company=self.env.company.id).sudo().set_multi( - 'property_product_pricelist', - self._name, - {self.id: self.property_product_pricelist or default_for_country.id}, - default_value=default_for_country.id + for partner in self: + pls = self.env['product.pricelist'].search( + [('country_group_ids.country_ids.code', '=', partner.country_id and partner.country_id.code or False)], + limit=1 ) + default_for_country = pls and pls[0] + actual = self.env['ir.property'].get('property_product_pricelist', 'res.partner', 'res.partner,%s' % partner.id) + # update at each change country, and so erase old pricelist + if partner.property_product_pricelist or (actual and default_for_country and default_for_country.id != actual.id): + # keep the company of the current user before sudo + partner.env['ir.property'].with_context(force_company=self.env.company.id).sudo().set_multi( + 'property_product_pricelist', + partner._name, + {partner.id: partner.property_product_pricelist or default_for_country.id}, + default_value=default_for_country.id + ) def _commercial_fields(self): return super(Partner, self)._commercial_fields() + ['property_product_pricelist'] diff --git a/addons/rating/models/rating.py b/addons/rating/models/rating.py index 52630375c38..df25c8244fd 100644 --- a/addons/rating/models/rating.py +++ b/addons/rating/models/rating.py @@ -22,11 +22,11 @@ class Rating(models.Model): ('rating_range', 'check(rating >= 0 and rating <= 10)', 'Rating should be between 0 to 10'), ] - @api.one @api.depends('res_model', 'res_id') def _compute_res_name(self): - name = self.env[self.res_model].sudo().browse(self.res_id).name_get() - self.res_name = name and name[0][1] or ('%s/%s') % (self.res_model, self.res_id) + for rating in self: + name = self.env[rating.res_model].sudo().browse(rating.res_id).name_get() + rating.res_name = name and name[0][1] or ('%s/%s') % (rating.res_model, rating.res_id) @api.model def _default_access_token(self): diff --git a/addons/repair/models/repair.py b/addons/repair/models/repair.py index e0543acec28..37b901f7b42 100644 --- a/addons/repair/models/repair.py +++ b/addons/repair/models/repair.py @@ -115,41 +115,41 @@ class Repair(models.Model): amount_total = fields.Float('Total', compute='_amount_total', store=True) tracking = fields.Selection('Product Tracking', related="product_id.tracking", readonly=False) - @api.one @api.depends('partner_id') def _compute_default_address_id(self): - if self.partner_id: - self.default_address_id = self.partner_id.address_get(['contact'])['contact'] + for order in self: + if order.partner_id: + order.default_address_id = order.partner_id.address_get(['contact'])['contact'] - @api.one @api.depends('operations.price_subtotal', 'invoice_method', 'fees_lines.price_subtotal', 'pricelist_id.currency_id') def _amount_untaxed(self): - total = sum(operation.price_subtotal for operation in self.operations) - total += sum(fee.price_subtotal for fee in self.fees_lines) - self.amount_untaxed = self.pricelist_id.currency_id.round(total) + for order in self: + total = sum(operation.price_subtotal for operation in order.operations) + total += sum(fee.price_subtotal for fee in order.fees_lines) + order.amount_untaxed = order.pricelist_id.currency_id.round(total) - @api.one @api.depends('operations.price_unit', 'operations.product_uom_qty', 'operations.product_id', 'fees_lines.price_unit', 'fees_lines.product_uom_qty', 'fees_lines.product_id', 'pricelist_id.currency_id', 'partner_id') def _amount_tax(self): - val = 0.0 - for operation in self.operations: - if operation.tax_id: - tax_calculate = operation.tax_id.compute_all(operation.price_unit, self.pricelist_id.currency_id, operation.product_uom_qty, operation.product_id, self.partner_id) - for c in tax_calculate['taxes']: - val += c['amount'] - for fee in self.fees_lines: - if fee.tax_id: - tax_calculate = fee.tax_id.compute_all(fee.price_unit, self.pricelist_id.currency_id, fee.product_uom_qty, fee.product_id, self.partner_id) - for c in tax_calculate['taxes']: - val += c['amount'] - self.amount_tax = val - - @api.one + for order in self: + val = 0.0 + for operation in order.operations: + if operation.tax_id: + tax_calculate = operation.tax_id.compute_all(operation.price_unit, order.pricelist_id.currency_id, operation.product_uom_qty, operation.product_id, order.partner_id) + for c in tax_calculate['taxes']: + val += c['amount'] + for fee in order.fees_lines: + if fee.tax_id: + tax_calculate = fee.tax_id.compute_all(fee.price_unit, order.pricelist_id.currency_id, fee.product_uom_qty, fee.product_id, order.partner_id) + for c in tax_calculate['taxes']: + val += c['amount'] + order.amount_tax = val + @api.depends('amount_untaxed', 'amount_tax') def _amount_total(self): - self.amount_total = self.pricelist_id.currency_id.round(self.amount_untaxed + self.amount_tax) + for order in self: + order.amount_total = order.pricelist_id.currency_id.round(order.amount_untaxed + order.amount_tax) _sql_constraints = [ ('name', 'unique (name)', 'The name of the Repair Order must be unique!'), @@ -596,11 +596,11 @@ class RepairLine(models.Model): for line in self.filtered(lambda x: x.product_id.tracking != 'none' and not x.lot_id): raise ValidationError(_("Serial number is required for operation line with product '%s'") % (line.product_id.name)) - @api.one @api.depends('price_unit', 'repair_id', 'product_uom_qty', 'product_id', 'repair_id.invoice_method') def _compute_price_subtotal(self): - taxes = self.tax_id.compute_all(self.price_unit, self.repair_id.pricelist_id.currency_id, self.product_uom_qty, self.product_id, self.repair_id.partner_id) - self.price_subtotal = taxes['total_excluded'] + for line in self: + taxes = line.tax_id.compute_all(line.price_unit, line.repair_id.pricelist_id.currency_id, line.product_uom_qty, line.product_id, line.repair_id.partner_id) + line.price_subtotal = taxes['total_excluded'] @api.onchange('type', 'repair_id') def onchange_operation_type(self): @@ -688,11 +688,11 @@ class RepairFee(models.Model): invoice_line_id = fields.Many2one('account.move.line', 'Invoice Line', copy=False, readonly=True) invoiced = fields.Boolean('Invoiced', copy=False, readonly=True) - @api.one @api.depends('price_unit', 'repair_id', 'product_uom_qty', 'product_id') def _compute_price_subtotal(self): - taxes = self.tax_id.compute_all(self.price_unit, self.repair_id.pricelist_id.currency_id, self.product_uom_qty, self.product_id, self.repair_id.partner_id) - self.price_subtotal = taxes['total_excluded'] + for fee in self: + taxes = fee.tax_id.compute_all(fee.price_unit, fee.repair_id.pricelist_id.currency_id, fee.product_uom_qty, fee.product_id, fee.repair_id.partner_id) + fee.price_subtotal = taxes['total_excluded'] @api.onchange('repair_id', 'product_id', 'product_uom_qty') def onchange_product_id(self): diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index aa770884e07..f2627a1520b 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -247,12 +247,12 @@ class SaleOrder(models.Model): for trans in self: trans.authorized_transaction_ids = trans.transaction_ids.filtered(lambda t: t.state == 'authorized') - @api.one def _compute_amount_undiscounted(self): - total = 0.0 - for line in self.order_line: - total += line.price_subtotal + line.price_unit * ((line.discount or 0.0) / 100.0) * line.product_uom_qty # why is there a discount in a field named amount_undiscounted ?? - self.amount_undiscounted = total + for order in self: + total = 0.0 + for line in order.order_line: + total += line.price_subtotal + line.price_unit * ((line.discount or 0.0) / 100.0) * line.product_uom_qty # why is there a discount in a field named amount_undiscounted ?? + order.amount_undiscounted = total @api.multi @api.depends('state') diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index dce8ea91c58..b68ec1fad5d 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -715,14 +715,14 @@ class ProductCategory(models.Model): readonly=True) putaway_rule_ids = fields.One2many('stock.putaway.rule', 'category_id', 'Putaway Rules') - @api.one def _compute_total_route_ids(self): - category = self - routes = self.route_ids - while category.parent_id: - category = category.parent_id - routes |= category.route_ids - self.total_route_ids = routes + for category in self: + base_cat = category + routes = category.route_ids + while base_cat.parent_id: + base_cat = base_cat.parent_id + routes |= base_cat.route_ids + category.total_route_ids = routes class UoM(models.Model): diff --git a/addons/stock/models/stock_location.py b/addons/stock/models/stock_location.py index 80f6f94b54d..2a5aeae005f 100644 --- a/addons/stock/models/stock_location.py +++ b/addons/stock/models/stock_location.py @@ -66,14 +66,14 @@ class Location(models.Model): _sql_constraints = [('barcode_company_uniq', 'unique (barcode,company_id)', 'The barcode for a location must be unique per company !')] - @api.one @api.depends('name', 'location_id.complete_name') def _compute_complete_name(self): """ Forms complete name of location from parent location to child location. """ - if self.location_id.complete_name: - self.complete_name = '%s/%s' % (self.location_id.complete_name, self.name) - else: - self.complete_name = self.name + for location in self: + if location.location_id.complete_name: + location.complete_name = '%s/%s' % (location.location_id.complete_name, location.name) + else: + location.complete_name = location.name @api.onchange('usage') def _onchange_usage(self): diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 1489525b7fc..2dbdbc44ed4 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -250,11 +250,12 @@ class StockMove(models.Model): for move in self: move.has_move_lines = bool(move.move_line_ids) - @api.one @api.depends('product_id', 'product_uom', 'product_uom_qty') def _compute_product_qty(self): rounding_method = self._context.get('rounding_method', 'UP') - self.product_qty = self.product_uom._compute_quantity(self.product_uom_qty, self.product_id.uom_id, rounding_method=rounding_method) + for move in self: + move.product_qty = move.product_uom._compute_quantity( + move.product_uom_qty, move.product_id.uom_id, rounding_method=rounding_method) @api.depends('move_line_ids.qty_done', 'move_line_ids.product_uom_id') def _quantity_done_compute(self): @@ -305,18 +306,18 @@ class StockMove(models.Model): for rec in self: rec.reserved_availability = rec.product_id.uom_id._compute_quantity(result.get(rec.id, 0.0), rec.product_uom, rounding_method='HALF-UP') - @api.one @api.depends('state', 'product_id', 'product_qty', 'location_id') def _compute_product_availability(self): """ Fill the `availability` field on a stock move, which is the quantity to potentially reserve. When the move is done, `availability` is set to the quantity the move did actually move. """ - if self.state == 'done': - self.availability = self.product_qty - else: - total_availability = self.env['stock.quant']._get_available_quantity(self.product_id, self.location_id) - self.availability = min(self.product_qty, total_availability) + for move in self: + if move.state == 'done': + move.availability = move.product_qty + else: + total_availability = self.env['stock.quant']._get_available_quantity(move.product_id, move.location_id) + move.availability = min(move.product_qty, total_availability) def _compute_string_qty_information(self): precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index b4e055b364a..53eddd5fe81 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -55,19 +55,19 @@ class StockMoveLine(models.Model): picking_type_entire_packs = fields.Boolean(related='picking_id.picking_type_id.show_entire_packs', readonly=True) description_picking = fields.Text(string="Description picking") - @api.one @api.depends('picking_id.picking_type_id', 'product_id.tracking') def _compute_lots_visible(self): - picking = self.picking_id - if picking.picking_type_id and self.product_id.tracking != 'none': # TDE FIXME: not sure correctly migrated - self.lots_visible = picking.picking_type_id.use_existing_lots or picking.picking_type_id.use_create_lots - else: - self.lots_visible = self.product_id.tracking != 'none' + for line in self: + picking = line.picking_id + if picking.picking_type_id and line.product_id.tracking != 'none': # TDE FIXME: not sure correctly migrated + line.lots_visible = picking.picking_type_id.use_existing_lots or picking.picking_type_id.use_create_lots + else: + line.lots_visible = line.product_id.tracking != 'none' - @api.one @api.depends('product_id', 'product_uom_id', 'product_uom_qty') def _compute_product_qty(self): - self.product_qty = self.product_uom_id._compute_quantity(self.product_uom_qty, self.product_id.uom_id, rounding_method='HALF-UP') + for line in self: + line.product_qty = line.product_uom_id._compute_quantity(line.product_uom_qty, line.product_id.uom_id, rounding_method='HALF-UP') @api.constrains('lot_id', 'product_id') def _check_lot_product(self): @@ -75,7 +75,6 @@ class StockMoveLine(models.Model): if line.lot_id and line.product_id != line.lot_id.product_id: raise ValidationError(_('This lot %s is incompatible with this product %s' % (line.lot_id.name, line.product_id.display_name))) - @api.one def _set_product_qty(self): """ The meaning of product_qty field changed lately and is now a functional field computing the quantity in the default product UoM. This code has been added to raise an error if a write is made given a value diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index d2699c95382..b6a76e5ebf3 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -66,18 +66,17 @@ class PickingType(models.Model): barcode = fields.Char('Barcode', copy=False) company_id = fields.Many2one('res.company', 'Company', related='warehouse_id.company_id', store=True) - @api.one def _compute_last_done_picking(self): - # TDE TODO: true multi - tristates = [] - for picking in self.env['stock.picking'].search([('picking_type_id', '=', self.id), ('state', '=', 'done')], order='date_done desc', limit=10): - if picking.date_done > picking.date: - tristates.insert(0, {'tooltip': picking.name or '' + ": " + _('Late'), 'value': -1}) - elif picking.backorder_id: - tristates.insert(0, {'tooltip': picking.name or '' + ": " + _('Backorder exists'), 'value': 0}) - else: - tristates.insert(0, {'tooltip': picking.name or '' + ": " + _('OK'), 'value': 1}) - self.last_done_picking = json.dumps(tristates) + for type in self: + tristates = [] + for picking in self.env['stock.picking'].search([('picking_type_id', '=', type.id), ('state', '=', 'done')], order='date_done desc', limit=10): + if picking.date_done > picking.date: + tristates.insert(0, {'tooltip': picking.name or '' + ": " + _('Late'), 'value': -1}) + elif picking.backorder_id: + tristates.insert(0, {'tooltip': picking.name or '' + ": " + _('Backorder exists'), 'value': 0}) + else: + tristates.insert(0, {'tooltip': picking.name or '' + ": " + _('OK'), 'value': 1}) + type.last_done_picking = json.dumps(tristates) def _compute_picking_count(self): # TDE TODO count picking can be done using previous two @@ -343,7 +342,6 @@ class Picking(models.Model): picking.show_lots_text = False @api.depends('move_type', 'move_lines.state', 'move_lines.picking_id') - @api.one def _compute_state(self): ''' State of a picking depends on the state of its related stock.move - Draft: only used for "planned pickings" @@ -357,58 +355,59 @@ class Picking(models.Model): - Done: if the picking is done. - Cancelled: if the picking is cancelled ''' - if not self.move_lines: - self.state = 'draft' - elif any(move.state == 'draft' for move in self.move_lines): # TDE FIXME: should be all ? - self.state = 'draft' - elif all(move.state == 'cancel' for move in self.move_lines): - self.state = 'cancel' - elif all(move.state in ['cancel', 'done'] for move in self.move_lines): - self.state = 'done' - else: - relevant_move_state = self.move_lines._get_relevant_state_among_moves() - if relevant_move_state == 'partially_available': - self.state = 'assigned' + for picking in self: + if not picking.move_lines: + picking.state = 'draft' + elif any(move.state == 'draft' for move in picking.move_lines): # TDE FIXME: should be all ? + picking.state = 'draft' + elif all(move.state == 'cancel' for move in picking.move_lines): + picking.state = 'cancel' + elif all(move.state in ['cancel', 'done'] for move in picking.move_lines): + picking.state = 'done' else: - self.state = relevant_move_state + relevant_move_state = picking.move_lines._get_relevant_state_among_moves() + if relevant_move_state == 'partially_available': + picking.state = 'assigned' + else: + picking.state = relevant_move_state - @api.one @api.depends('move_lines.priority') def _compute_priority(self): - if self.mapped('move_lines'): - priorities = [priority for priority in self.mapped('move_lines.priority') if priority] or ['1'] - self.priority = max(priorities) - else: - self.priority = '1' + for picking in self: + if picking.mapped('move_lines'): + priorities = [priority for priority in picking.mapped('move_lines.priority') if priority] or ['1'] + picking.priority = max(priorities) + else: + picking.priority = '1' - @api.one def _set_priority(self): - self.move_lines.write({'priority': self.priority}) + for picking in self: + picking.move_lines.write({'priority': picking.priority}) - @api.one @api.depends('move_lines.date_expected') def _compute_scheduled_date(self): - if self.move_type == 'direct': - self.scheduled_date = min(self.move_lines.mapped('date_expected') or [fields.Datetime.now()]) - else: - self.scheduled_date = max(self.move_lines.mapped('date_expected') or [fields.Datetime.now()]) + for picking in self: + if picking.move_type == 'direct': + picking.scheduled_date = min(picking.move_lines.mapped('date_expected') or [fields.Datetime.now()]) + else: + picking.scheduled_date = max(picking.move_lines.mapped('date_expected') or [fields.Datetime.now()]) - @api.one def _set_scheduled_date(self): - self.move_lines.write({'date_expected': self.scheduled_date}) + for picking in self: + picking.move_lines.write({'date_expected': picking.scheduled_date}) - @api.one def _has_scrap_move(self): - # TDE FIXME: better implementation - self.has_scrap_move = bool(self.env['stock.move'].search_count([('picking_id', '=', self.id), ('scrapped', '=', True)])) + for picking in self: + # TDE FIXME: better implementation + picking.has_scrap_move = bool(self.env['stock.move'].search_count([('picking_id', '=', picking.id), ('scrapped', '=', True)])) - @api.one def _compute_move_line_exist(self): - self.move_line_exist = bool(self.move_line_ids) + for picking in self: + picking.move_line_exist = bool(picking.move_line_ids) - @api.one def _compute_has_packages(self): - self.has_packages = self.move_line_ids.filtered(lambda ml: ml.result_package_id) + for picking in self: + picking.has_packages = picking.move_line_ids.filtered(lambda ml: ml.result_package_id) def _compute_show_check_availability(self): """ According to `picking.show_check_availability`, the "check availability" button will be @@ -539,9 +538,9 @@ class Picking(models.Model): # Actions # ---------------------------------------- - @api.one def action_assign_owner(self): - self.move_line_ids.write({'owner_id': self.owner_id.id}) + for picking in self: + picking.move_line_ids.write({'owner_id': picking.owner_id.id}) def action_assign_partner(self): for picking in self: diff --git a/addons/stock/models/stock_production_lot.py b/addons/stock/models/stock_production_lot.py index 433b5c67e47..3e4b9c2667f 100644 --- a/addons/stock/models/stock_production_lot.py +++ b/addons/stock/models/stock_production_lot.py @@ -63,11 +63,11 @@ class ProductionLot(models.Model): )) return super(ProductionLot, self).write(vals) - @api.one def _product_qty(self): - # We only care for the quants in internal or transit locations. - quants = self.quant_ids.filtered(lambda q: q.location_id.usage in ['internal', 'transit']) - self.product_qty = sum(quants.mapped('quantity')) + for lot in self: + # We only care for the quants in internal or transit locations. + quants = lot.quant_ids.filtered(lambda q: q.location_id.usage in ['internal', 'transit']) + lot.product_qty = sum(quants.mapped('quantity')) def action_lot_open_quants(self): self = self.with_context(search_default_lot_id=self.id) diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py index 0de38e5b8c6..a896d63374d 100644 --- a/addons/stock/models/stock_quant.py +++ b/addons/stock/models/stock_quant.py @@ -180,9 +180,9 @@ class StockQuant(models.Model): if quant.location_id.usage == 'view': raise ValidationError(_('You cannot take products from or deliver products to a location of type "view".')) - @api.one def _compute_name(self): - self.name = '%s: %s%s' % (self.lot_id.name or self.product_id.code or '', self.quantity, self.product_id.uom_id.name) + for quant in self: + quant.name = '%s: %s%s' % (quant.lot_id.name or quant.product_id.code or '', quant.quantity, quant.product_id.uom_id.name) @api.model def _get_removal_strategy(self, product_id, location_id): diff --git a/addons/stock/wizard/stock_backorder_confirmation.py b/addons/stock/wizard/stock_backorder_confirmation.py index 31e7a6ca963..5c8fc2a43c4 100644 --- a/addons/stock/wizard/stock_backorder_confirmation.py +++ b/addons/stock/wizard/stock_backorder_confirmation.py @@ -11,16 +11,18 @@ class StockBackorderConfirmation(models.TransientModel): pick_ids = fields.Many2many('stock.picking', 'stock_picking_backorder_rel') - @api.one def _process(self, cancel_backorder=False): - if cancel_backorder: - for pick_id in self.pick_ids: - moves_to_log = {} - for move in pick_id.move_lines: - if float_compare(move.product_uom_qty, move.quantity_done, precision_rounding=move.product_uom.rounding) > 0: - moves_to_log[move] = (move.quantity_done, move.product_uom_qty) - pick_id._log_less_quantities_than_expected(moves_to_log) - self.pick_ids.with_context({'cancel_backorder': cancel_backorder}).action_done() + for confirmation in self: + if cancel_backorder: + for pick_id in confirmation.pick_ids: + moves_to_log = {} + for move in pick_id.move_lines: + if float_compare(move.product_uom_qty, + move.quantity_done, + precision_rounding=move.product_uom.rounding) > 0: + moves_to_log[move] = (move.quantity_done, move.product_uom_qty) + pick_id._log_less_quantities_than_expected(moves_to_log) + confirmation.pick_ids.with_context({'cancel_backorder': cancel_backorder}).action_done() def process(self): self._process() diff --git a/addons/stock/wizard/stock_package_destination.py b/addons/stock/wizard/stock_package_destination.py index d5fc31d7aef..910dfe6d21b 100644 --- a/addons/stock/wizard/stock_package_destination.py +++ b/addons/stock/wizard/stock_package_destination.py @@ -13,15 +13,15 @@ class ChooseDestinationLocation(models.TransientModel): location_dest_id = fields.Many2one('stock.location', 'Destination location', required=True) filtered_location = fields.One2many(comodel_name='stock.location', compute='_filter_location') - @api.one @api.depends('picking_id') def _compute_move_line_ids(self): - self.move_line_ids = self.picking_id.move_line_ids.filtered(lambda l: l.qty_done > 0 and not l.result_package_id) + for destination in self: + destination.move_line_ids = destination.picking_id.move_line_ids.filtered(lambda l: l.qty_done > 0 and not l.result_package_id) - @api.one @api.depends('move_line_ids') def _filter_location(self): - self.filtered_location = self.move_line_ids.mapped('location_dest_id') + for destination in self: + destination.filtered_location = destination.move_line_ids.mapped('location_dest_id') def action_done(self): # set the same location on each move line and pass again in _put_in_pack diff --git a/addons/stock/wizard/stock_track_confirmation.py b/addons/stock/wizard/stock_track_confirmation.py index fa8cc62e3a1..946fbe68e20 100644 --- a/addons/stock/wizard/stock_track_confirmation.py +++ b/addons/stock/wizard/stock_track_confirmation.py @@ -11,9 +11,9 @@ class StockTrackConfirmation(models.TransientModel): tracking_line_ids = fields.One2many('stock.track.line', 'wizard_id') inventory_id = fields.Many2one('stock.inventory', 'Inventory') - @api.one def action_confirm(self): - return self.inventory_id._action_done() + for confirmation in self: + confirmation.inventory_id._action_done() class StockTrackingLines(models.TransientModel): _name = 'stock.track.line' diff --git a/addons/stock/wizard/stock_warn_insufficient_qty.py b/addons/stock/wizard/stock_warn_insufficient_qty.py index 3e480c73e83..113ee1d1356 100644 --- a/addons/stock/wizard/stock_warn_insufficient_qty.py +++ b/addons/stock/wizard/stock_warn_insufficient_qty.py @@ -13,13 +13,13 @@ class StockWarnInsufficientQty(models.AbstractModel): location_id = fields.Many2one( 'stock.location', 'Location', domain="[('usage', '=', 'internal')]", required=True) quant_ids = fields.Many2many('stock.quant', compute='_compute_quant_ids') - @api.one @api.depends('product_id') def _compute_quant_ids(self): - self.quant_ids = self.env['stock.quant'].search([ - ('product_id', '=', self.product_id.id), - ('location_id.usage', '=', 'internal') - ]) + for quantity in self: + quantity.quant_ids = self.env['stock.quant'].search([ + ('product_id', '=', quantity.product_id.id), + ('location_id.usage', '=', 'internal') + ]) def action_done(self): raise NotImplementedError() diff --git a/addons/stock_landed_costs/models/stock_landed_cost.py b/addons/stock_landed_costs/models/stock_landed_cost.py index d6b36aadd92..0eb9f2b65b4 100644 --- a/addons/stock_landed_costs/models/stock_landed_cost.py +++ b/addons/stock_landed_costs/models/stock_landed_cost.py @@ -48,10 +48,10 @@ class LandedCost(models.Model): related='account_journal_id.company_id', readonly=False) stock_valuation_layer_ids = fields.One2many('stock.valuation.layer', 'stock_landed_cost_id') - @api.one @api.depends('cost_lines.price_unit') def _compute_total_amount(self): - self.amount_total = sum(line.price_unit for line in self.cost_lines) + for cost in self: + cost.amount_total = sum(line.price_unit for line in cost.cost_lines) @api.model def create(self, vals): @@ -292,21 +292,21 @@ class AdjustmentLines(models.Model): 'Final Cost', compute='_compute_final_cost', digits=0, store=True) - @api.one @api.depends('cost_line_id.name', 'product_id.code', 'product_id.name') def _compute_name(self): - name = '%s - ' % (self.cost_line_id.name if self.cost_line_id else '') - self.name = name + (self.product_id.code or self.product_id.name or '') + for line in self: + name = '%s - ' % (line.cost_line_id.name if line.cost_line_id else '') + line.name = name + (line.product_id.code or line.product_id.name or '') - @api.one @api.depends('former_cost', 'quantity') def _compute_former_cost_per_unit(self): - self.former_cost_per_unit = self.former_cost / (self.quantity or 1.0) + for line in self: + line.former_cost_per_unit = line.former_cost / (line.quantity or 1.0) - @api.one @api.depends('former_cost', 'additional_landed_cost') def _compute_final_cost(self): - self.final_cost = self.former_cost + self.additional_landed_cost + for line in self: + line.final_cost = line.former_cost + line.additional_landed_cost def _create_accounting_entries(self, move, qty_out): # TDE CLEANME: product chosen for computation ? diff --git a/addons/survey/models/survey_question.py b/addons/survey/models/survey_question.py index 3019d1f0bdd..f84a5c41aba 100644 --- a/addons/survey/models/survey_question.py +++ b/addons/survey/models/survey_question.py @@ -381,9 +381,9 @@ class SurveyLabel(models.Model): answer_score = fields.Float('Score for this choice', help="A positive score indicates a correct choice; a negative or null score indicates a wrong answer") - @api.one @api.constrains('question_id', 'question_id_2') def _check_question_not_empty(self): """Ensure that field question_id XOR field question_id_2 is not null""" - if not bool(self.question_id) != bool(self.question_id_2): - raise ValidationError(_("A label must be attached to only one question.")) + for label in self: + if not bool(label.question_id) != bool(label.question_id_2): + raise ValidationError(_("A label must be attached to only one question.")) diff --git a/addons/uom/models/uom_uom.py b/addons/uom/models/uom_uom.py index 6907a9fb890..ae8e22b1c10 100644 --- a/addons/uom/models/uom_uom.py +++ b/addons/uom/models/uom_uom.py @@ -64,10 +64,10 @@ class UoM(models.Model): ('factor_reference_is_one', "CHECK((uom_type = 'reference' AND factor = 1.0) OR (uom_type != 'reference'))", "The reference unit must have a conversion factor equal to 1.") ] - @api.one @api.depends('factor') def _compute_factor_inv(self): - self.factor_inv = self.factor and (1.0 / self.factor) or 0.0 + for uom in self: + uom.factor_inv = uom.factor and (1.0 / uom.factor) or 0.0 @api.onchange('uom_type') def _onchange_uom_type(self): diff --git a/addons/web_editor/models/ir_attachment.py b/addons/web_editor/models/ir_attachment.py index ac441d821e8..b0c48defee8 100644 --- a/addons/web_editor/models/ir_attachment.py +++ b/addons/web_editor/models/ir_attachment.py @@ -15,12 +15,12 @@ class IrAttachment(models.Model): image_width = fields.Integer(compute='_compute_image_size') image_height = fields.Integer(compute='_compute_image_size') - @api.one def _compute_local_url(self): - if self.url: - self.local_url = self.url - else: - self.local_url = '/web/image/%s?unique=%s' % (self.id, self.checksum) + for attachment in self: + if attachment.url: + attachment.local_url = attachment.url + else: + attachment.local_url = '/web/image/%s?unique=%s' % (attachment.id, attachment.checksum) @api.multi @api.depends('mimetype', 'url', 'name') diff --git a/addons/website/models/website_menu.py b/addons/website/models/website_menu.py index 6529174decd..7a18b3a982d 100644 --- a/addons/website/models/website_menu.py +++ b/addons/website/models/website_menu.py @@ -84,12 +84,12 @@ class Menu(models.Model): ('id', '!=', menu.id)]) return super(Menu, menus_to_remove).unlink() - @api.one def _compute_visible(self): - visible = True - if self.page_id and not self.page_id.sudo().is_visible and not self.user_has_groups('base.group_user'): - visible = False - self.is_visible = visible + for menu in self: + visible = True + if menu.page_id and not menu.page_id.sudo().is_visible and not menu.user_has_groups('base.group_user'): + visible = False + menu.is_visible = visible @api.model def clean_url(self): diff --git a/addons/website/models/website_page.py b/addons/website/models/website_page.py index e1f3a86787d..f7423efe415 100644 --- a/addons/website/models/website_page.py +++ b/addons/website/models/website_page.py @@ -28,23 +28,25 @@ class Page(models.Model): # don't use mixin website_id but use website_id on ir.ui.view instead website_id = fields.Many2one(related='view_id.website_id', store=True, readonly=False) - @api.one def _compute_homepage(self): - self.is_homepage = self == self.env['website'].get_current_website().homepage_id + for page in self: + page.is_homepage = page == self.env['website'].get_current_website().homepage_id - @api.one def _set_homepage(self): - website = self.env['website'].get_current_website() - if self.is_homepage: - if website.homepage_id != self: - website.write({'homepage_id': self.id}) - else: - if website.homepage_id == self: - website.write({'homepage_id': None}) + for page in self: + website = self.env['website'].get_current_website() + if page.is_homepage: + if website.homepage_id != page: + website.write({'homepage_id': page.id}) + else: + if website.homepage_id == page: + website.write({'homepage_id': None}) - @api.one def _compute_visible(self): - self.is_visible = self.website_published and (not self.date_publish or self.date_publish < fields.Datetime.now()) + for page in self: + page.is_visible = page.website_published and ( + not page.date_publish or page.date_publish < fields.Datetime.now() + ) @api.multi def _is_most_specific_page(self, page_to_test): diff --git a/addons/website_crm_partner_assign/models/res_partner.py b/addons/website_crm_partner_assign/models/res_partner.py index 80b4d7996ba..e3973d596af 100644 --- a/addons/website_crm_partner_assign/models/res_partner.py +++ b/addons/website_crm_partner_assign/models/res_partner.py @@ -54,10 +54,10 @@ class ResPartner(models.Model): ) implemented_count = fields.Integer(compute='_compute_implemented_partner_count', store=True) - @api.one @api.depends('implemented_partner_ids', 'implemented_partner_ids.website_published', 'implemented_partner_ids.active') def _compute_implemented_partner_count(self): - self.implemented_count = len(self.implemented_partner_ids.filtered('website_published')) + for partner in self: + partner.implemented_count = len(partner.implemented_partner_ids.filtered('website_published')) @api.onchange('grade_id') def _onchange_grade_id(self): diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index 329b60f7d03..e668fc173ee 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -115,15 +115,15 @@ class Forum(models.Model): karma_post = fields.Integer(string='Ask questions without validation', default=100) karma_moderate = fields.Integer(string='Moderate posts', default=1000) - @api.one def _compute_count_posts_waiting_validation(self): - domain = [('forum_id', '=', self.id), ('state', '=', 'pending')] - self.count_posts_waiting_validation = self.env['forum.post'].search_count(domain) + for forum in self: + domain = [('forum_id', '=', forum.id), ('state', '=', 'pending')] + forum.count_posts_waiting_validation = self.env['forum.post'].search_count(domain) - @api.one def _compute_count_flagged_posts(self): - domain = [('forum_id', '=', self.id), ('state', '=', 'flagged')] - self.count_flagged_posts = self.env['forum.post'].search_count(domain) + for forum in self: + domain = [('forum_id', '=', forum.id), ('state', '=', 'flagged')] + forum.count_flagged_posts = self.env['forum.post'].search_count(domain) @api.model def create(self, values): @@ -277,19 +277,19 @@ class Post(models.Model): # don't use param named because orm will add other param (test_active, ...) return [('id', op, (req, (user.id, user.karma, user.id, user.karma, user.id)))] - @api.one @api.depends('content') def _get_plain_content(self): - self.plain_content = tools.html2plaintext(self.content)[0:500] if self.content else False + for post in self: + post.plain_content = tools.html2plaintext(post.content)[0:500] if post.content else False - @api.one @api.depends('vote_count', 'forum_id.relevancy_post_vote', 'forum_id.relevancy_time_decay') def _compute_relevancy(self): - if self.create_date: - days = (datetime.today() - self.create_date).days - self.relevancy = math.copysign(1, self.vote_count) * (abs(self.vote_count - 1) ** self.forum_id.relevancy_post_vote / (days + 2) ** self.forum_id.relevancy_time_decay) - else: - self.relevancy = 0 + for post in self: + if post.create_date: + days = (datetime.today() - post.create_date).days + post.relevancy = math.copysign(1, post.vote_count) * (abs(post.vote_count - 1) ** post.forum_id.relevancy_post_vote / (days + 2) ** post.forum_id.relevancy_time_decay) + else: + post.relevancy = 0 @api.multi def _get_user_vote(self): @@ -308,21 +308,20 @@ class Post(models.Model): for post in self: post.vote_count = result[post.id] - @api.one def _get_user_favourite(self): - self.user_favourite = self._uid in self.favourite_ids.ids + for post in self: + post.user_favourite = post._uid in post.favourite_ids.ids - @api.one @api.depends('favourite_ids') def _get_favorite_count(self): - self.favourite_count = len(self.favourite_ids) + for post in self: + post.favourite_count = len(post.favourite_ids) - @api.one @api.depends('create_uid', 'parent_id') def _is_self_reply(self): - self.self_reply = self.parent_id.create_uid.id == self._uid + for post in self: + post.self_reply = post.parent_id.create_uid.id == post._uid - @api.one @api.depends('child_ids.create_uid', 'website_message_ids') def _get_child_count(self): def process(node): @@ -330,16 +329,18 @@ class Post(models.Model): for child in node.child_ids: total += process(child) return total - self.child_count = process(self) - @api.one + for post in self: + post.child_count = process(post) + def _get_uid_has_answered(self): - self.uid_has_answered = any(answer.create_uid.id == self._uid for answer in self.child_ids) + for post in self: + post.uid_has_answered = any(answer.create_uid.id == post._uid for answer in post.child_ids) - @api.one @api.depends('child_ids.is_correct') def _get_has_validated_answer(self): - self.has_validated_answer = any(answer.is_correct for answer in self.child_ids) + for post in self: + post.has_validated_answer = any(answer.is_correct for answer in post.child_ids) @api.multi def _get_post_karma_rights(self): @@ -568,63 +569,65 @@ class Post(models.Model): }) return True - @api.one def validate(self): - if not self.can_moderate: - raise KarmaError(_('%d karma required to validate a post.') % self.forum_id.karma_moderate) - - # if state == pending, no karma previously added for the new question - if self.state == 'pending': - self.create_uid.sudo().add_karma(self.forum_id.karma_gen_question_new) - - self.write({ - 'state': 'active', - 'active': True, - 'moderator_id': self.env.user.id, - }) - self.post_notification() + for post in self: + if not post.can_moderate: + raise KarmaError(_('%d karma required to validate a post.') % post.forum_id.karma_moderate) + # if state == pending, no karma previously added for the new question + if post.state == 'pending': + post.create_uid.sudo().add_karma(post.forum_id.karma_gen_question_new) + post.write({ + 'state': 'active', + 'active': True, + 'moderator_id': self.env.user.id, + }) + post.post_notification() return True - @api.one def refuse(self): - if not self.can_moderate: - raise KarmaError(_('%d karma required to refuse a post.') % self.forum_id.karma_moderate) - - self.moderator_id = self.env.user + for post in self: + if not post.can_moderate: + raise KarmaError(_('%d karma required to refuse a post.') % post.forum_id.karma_moderate) + post.moderator_id = self.env.user return True - @api.one def flag(self): - if not self.can_flag: - raise KarmaError(_('%d karma required to flag a post.') % self.forum_id.karma_flag) - - if(self.state == 'flagged'): - return {'error': 'post_already_flagged'} - elif(self.state == 'active'): - self.write({ - 'state': 'flagged', - 'flag_user_id': self.env.user.id, - }) - return self.can_moderate and {'success': 'post_flagged_moderator'} or {'success': 'post_flagged_non_moderator'} - else: - return {'error': 'post_non_flaggable'} + res = [] + for post in self: + if not post.can_flag: + raise KarmaError(_('%d karma required to flag a post.') % post.forum_id.karma_flag) + if post.state == 'flagged': + res.append({'error': 'post_already_flagged'}) + elif post.state == 'active': + # TODO: potential performance bottleneck, can be batched + post.write({ + 'state': 'flagged', + 'flag_user_id': self.env.user.id, + }) + res.append( + post.can_moderate and + {'success': 'post_flagged_moderator'} or + {'success': 'post_flagged_non_moderator'} + ) + else: + res.append({'error': 'post_non_flaggable'}) + return res - @api.one def mark_as_offensive(self, reason_id): - if not self.can_moderate: - raise KarmaError(_('%d karma required to mark a post as offensive.') % self.forum_id.karma_moderate) - - # remove some karma - _logger.info('Downvoting user <%s> for posting spam/offensive contents', self.create_uid) - self.create_uid.sudo().add_karma(self.forum_id.karma_gen_answer_flagged) - - self.write({ - 'state': 'offensive', - 'moderator_id': self.env.user.id, - 'closed_date': datetime.today().strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT), - 'closed_reason_id': reason_id, - 'active': False, - }) + for post in self: + if not post.can_moderate: + raise KarmaError(_('%d karma required to mark a post as offensive.') % post.forum_id.karma_moderate) + # remove some karma + _logger.info('Downvoting user <%s> for posting spam/offensive contents', post.create_uid) + post.create_uid.sudo().add_karma(post.forum_id.karma_gen_answer_flagged) + # TODO: potential bottleneck, could be done in batch + post.write({ + 'state': 'offensive', + 'moderator_id': self.env.user.id, + 'closed_date': fields.Datetime.now(), + 'closed_reason_id': reason_id, + 'active': False, + }) return True @api.multi @@ -756,18 +759,24 @@ class Post(models.Model): return new_post - @api.one def unlink_comment(self, message_id): - user = self.env.user - comment = self.env['mail.message'].sudo().browse(message_id) - if not comment.model == 'forum.post' or not comment.res_id == self.id: - return False - # karma-based action check: must check the message's author to know if own or all - karma_unlink = comment.author_id.id == user.partner_id.id and self.forum_id.karma_comment_unlink_own or self.forum_id.karma_comment_unlink_all - can_unlink = user.karma >= karma_unlink - if not can_unlink: - raise KarmaError(_('%d karma required to unlink a comment.') % karma_unlink) - return comment.unlink() + result = [] + for post in self: + user = self.env.user + comment = self.env['mail.message'].sudo().browse(message_id) + if not comment.model == 'forum.post' or not comment.res_id == post.id: + result.append(False) + continue + # karma-based action check: must check the message's author to know if own or all + karma_unlink = ( + comment.author_id.id == user.partner_id.id and + post.forum_id.karma_comment_unlink_own or post.forum_id.karma_comment_unlink_all + ) + can_unlink = user.karma >= karma_unlink + if not can_unlink: + raise KarmaError(_('%d karma required to unlink a comment.') % karma_unlink) + result.append(comment.unlink()) + return result @api.multi def set_viewed(self): diff --git a/addons/website_hr_recruitment/models/hr_recruitment.py b/addons/website_hr_recruitment/models/hr_recruitment.py index 69aa3aaf062..bb441a6fc98 100644 --- a/addons/website_hr_recruitment/models/hr_recruitment.py +++ b/addons/website_hr_recruitment/models/hr_recruitment.py @@ -12,7 +12,6 @@ class RecruitmentSource(models.Model): url = fields.Char(compute='_compute_url', string='Url Parameters') - @api.one @api.depends('source_id', 'source_id.name', 'job_id') def _compute_url(self): base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py index 65634ea10c3..ef21416714d 100644 --- a/addons/website_sale/models/sale_order.py +++ b/addons/website_sale/models/sale_order.py @@ -29,9 +29,9 @@ class SaleOrder(models.Model): website_id = fields.Many2one('website', string='Website', readonly=True, help='Website through which this order was placed.') - @api.one def _compute_website_order_line(self): - self.website_order_line = self.order_line + for order in self: + order.website_order_line = order.order_line @api.multi @api.depends('website_order_line.product_uom_qty', 'website_order_line.product_id') diff --git a/addons/website_sale/models/website.py b/addons/website_sale/models/website.py index c99933dedfd..891976d0e2b 100644 --- a/addons/website_sale/models/website.py +++ b/addons/website_sale/models/website.py @@ -43,14 +43,12 @@ class Website(models.Model): shop_ppg = fields.Integer(default=20, string="Number of products in the grid on the shop") shop_ppr = fields.Integer(default=4, string="Number of grid columns on the shop") - @api.one def _compute_pricelist_ids(self): - """ Return the pricelists that can be used directly or indirectly on - the website. - """ - Pricelist = self.env["product.pricelist"] - domain = Pricelist._get_website_pricelists_domain(self.id) - self.pricelist_ids = Pricelist.search(domain) + Pricelist = self.env['product.pricelist'] + for website in self: + website.pricelist_ids = Pricelist.search( + Pricelist._get_website_pricelists_domain(website.id) + ) @api.multi def _compute_pricelist_id(self): diff --git a/addons/website_sale_coupon/models/sale_order.py b/addons/website_sale_coupon/models/sale_order.py index f4a0a5e6620..49f18e80570 100644 --- a/addons/website_sale_coupon/models/sale_order.py +++ b/addons/website_sale_coupon/models/sale_order.py @@ -6,7 +6,6 @@ from odoo.http import request class SaleOrder(models.Model): _inherit = "sale.order" - @api.one def _compute_website_order_line(self): """ This method will merge multiple discount lines generated by a same program into a single one (temporary line with `new()`). @@ -27,21 +26,29 @@ class SaleOrder(models.Model): Note: The line will be created without tax(es) and the amount will be computed depending if B2B or B2C is enabled. """ - super(SaleOrder, self)._compute_website_order_line() - for program in self._get_applied_programs_with_rewards_on_current_order(): - program_lines = self.order_line.filtered(lambda line: line.product_id == program.discount_line_product_id) - if len(program_lines) > 1: - price_unit = sum(l.price_subtotal if self.env.user.has_group('sale.group_show_price_subtotal') else l.price_total for l in program_lines) - self.website_order_line += self.env['sale.order.line'].new({ - 'product_id': program_lines[0].product_id.id, - 'price_unit': price_unit, - 'name': program_lines[0].name, - 'product_uom_qty': 1, - 'product_uom': program_lines[0].product_uom.id, - 'order_id': self.id, - 'is_reward_line': True, - }) - self.website_order_line -= program_lines + super()._compute_website_order_line() + for order in self: + # TODO: potential performance bottleneck downstream + programs = order._get_applied_programs_with_rewards_on_current_order() + for program in programs: + program_lines = order.order_line.filtered(lambda line: + line.product_id == program.discount_line_product_id) + if len(program_lines) > 1: + if self.env.user.has_group('sale.group_show_price_subtotal'): + price_unit = sum(program_lines.mapped('price_subtotal')) + else: + price_unit = sum(program_lines.mapped('price_total')) + # TODO: batch then flush + order.website_order_line += self.env['sale.order.line'].new({ + 'product_id': program_lines[0].product_id.id, + 'price_unit': price_unit, + 'name': program_lines[0].name, + 'product_uom_qty': 1, + 'product_uom': program_lines[0].product_uom.id, + 'order_id': order.id, + 'is_reward_line': True, + }) + order.website_order_line -= program_lines def _compute_cart_info(self): diff --git a/addons/website_sale_delivery/models/sale_order.py b/addons/website_sale_delivery/models/sale_order.py index b81dc6dbf6d..620a3190791 100644 --- a/addons/website_sale_delivery/models/sale_order.py +++ b/addons/website_sale_delivery/models/sale_order.py @@ -15,10 +15,10 @@ class SaleOrder(models.Model): string='Delivery Amount', help="The amount without tax.", store=True, tracking=True) - @api.one def _compute_website_order_line(self): super(SaleOrder, self)._compute_website_order_line() - self.website_order_line = self.website_order_line.filtered(lambda l: not l.is_delivery) + for order in self: + order.website_order_line = order.website_order_line.filtered(lambda l: not l.is_delivery) @api.depends('order_line.price_unit', 'order_line.tax_id', 'order_line.discount', 'order_line.product_uom_qty') def _compute_amount_delivery(self): |
