[FIX] *: adapt python constraints to support multi recordsets
Otherwise, they may crash or be incorrectly verified when creating/updating recordsets containing multiple records. Also improve the constraint error messages to be more detailed. When possible, use a sql constraint instead to speed up the records validation. Task Id: 2328664 COM PR: https://github.com/odoo/odoo/pull/55525 ENT PR: https://github.com/odoo/enterprise/pull/12250
This commit is contained in:
@@ -126,8 +126,12 @@ class Contract(models.Model):
|
||||
|
||||
@api.constrains('date_start', 'date_end')
|
||||
def _check_dates(self):
|
||||
if self.filtered(lambda c: c.date_end and c.date_start > c.date_end):
|
||||
raise ValidationError(_('Contract start date must be earlier than contract end date.'))
|
||||
for contract in self:
|
||||
if contract.date_end and contract.date_start > contract.date_end:
|
||||
raise ValidationError(_(
|
||||
'Contract %(contract)s: start date (%(start)s) must be earlier than contract end date (%(end)s).',
|
||||
contract=contract.name, start=contract.date_start, end=contract.date_end,
|
||||
))
|
||||
|
||||
@api.model
|
||||
def update_state(self):
|
||||
|
||||
@@ -194,8 +194,12 @@ class HrExpense(models.Model):
|
||||
|
||||
@api.constrains('product_id', 'product_uom_id')
|
||||
def _check_product_uom_category(self):
|
||||
if self.product_id and self.product_uom_id.category_id != self.product_id.uom_id.category_id:
|
||||
raise UserError(_('Selected Unit of Measure does not belong to the same category as the product Unit of Measure.'))
|
||||
for expense in self:
|
||||
if expense.product_id and expense.product_uom_id.category_id != expense.product_id.uom_id.category_id:
|
||||
raise UserError(_(
|
||||
'Selected Unit of Measure for expense %(expense)s does not belong to the same category as the Unit of Measure of product %(product)s.',
|
||||
expense=expense.name, product=expense.product_id.name,
|
||||
))
|
||||
|
||||
def create_expense_from_attachments(self, attachment_ids=None, view_type='tree'):
|
||||
''' Create the expenses from files.
|
||||
|
||||
@@ -13,5 +13,6 @@ class AccountJournal(models.Model):
|
||||
|
||||
@api.constrains('l10n_se_invoice_ocr_length')
|
||||
def _check_l10n_se_invoice_ocr_length(self):
|
||||
if self.l10n_se_invoice_ocr_length < 6:
|
||||
return ValidationError(_('OCR Reference Number length need to be greater than 5. Please correct settings under invoice journal settings.'))
|
||||
for journal in self:
|
||||
if journal.l10n_se_invoice_ocr_length < 6:
|
||||
return ValidationError(_('OCR Reference Number length need to be greater than 5. Please correct settings under invoice journal settings.'))
|
||||
|
||||
@@ -87,8 +87,12 @@ class Alias(models.Model):
|
||||
local-part. Quoted-string and internationnal characters are
|
||||
to be rejected. See rfc5322 sections 3.4.1 and 3.2.3
|
||||
"""
|
||||
if self.alias_name and not dot_atom_text.match(self.alias_name):
|
||||
raise ValidationError(_("You cannot use anything else than unaccented latin characters in the alias address."))
|
||||
for alias in self:
|
||||
if alias.alias_name and not dot_atom_text.match(alias.alias_name):
|
||||
raise ValidationError(_(
|
||||
"You cannot use anything else than unaccented latin characters in the alias address (%s).",
|
||||
alias.alias_name,
|
||||
))
|
||||
|
||||
def _compute_alias_domain(self):
|
||||
alias_domain = self._default_alias_domain()
|
||||
|
||||
@@ -124,8 +124,9 @@ class MrpUnbuild(models.Model):
|
||||
|
||||
@api.constrains('product_qty')
|
||||
def _check_qty(self):
|
||||
if self.product_qty <= 0:
|
||||
raise ValueError(_('Unbuild Order product quantity has to be strictly positive.'))
|
||||
for unbuild in self:
|
||||
if unbuild.product_qty <= 0:
|
||||
raise ValueError(_('Unbuild Order product quantity has to be strictly positive.'))
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
|
||||
@@ -73,8 +73,9 @@ class MrpWorkcenter(models.Model):
|
||||
|
||||
@api.constrains('alternative_workcenter_ids')
|
||||
def _check_alternative_workcenter(self):
|
||||
if self in self.alternative_workcenter_ids:
|
||||
raise ValidationError(_("A workcenter cannot be an alternative of itself"))
|
||||
for workcenter in self:
|
||||
if workcenter in workcenter.alternative_workcenter_ids:
|
||||
raise ValidationError(_("Workcenter %s cannot be an alternative of itself.", workcenter.name))
|
||||
|
||||
@api.depends('order_ids.duration_expected', 'order_ids.workcenter_id', 'order_ids.state', 'order_ids.date_planned_start')
|
||||
def _compute_workorder_count(self):
|
||||
|
||||
@@ -328,13 +328,24 @@ class PosConfig(models.Model):
|
||||
|
||||
@api.constrains('rounding_method')
|
||||
def _check_rounding_method_strategy(self):
|
||||
if self.cash_rounding and self.rounding_method.strategy != 'add_invoice_line':
|
||||
raise ValidationError(_("Cash rounding strategy must be: 'Add a rounding line'"))
|
||||
for config in self:
|
||||
if config.cash_rounding and config.rounding_method.strategy != 'add_invoice_line':
|
||||
selection_value = "Add a rounding line"
|
||||
for key, val in self.env["account.cash.rounding"]._fields["stategy"]._description_selection(config.env):
|
||||
if key == "add_invoice_line":
|
||||
selection_value = val
|
||||
break
|
||||
raise ValidationError(_(
|
||||
"The cash rounding strategy of the point of sale %(pos)s must be: '%(value)s'",
|
||||
pos=config.name,
|
||||
value=selection_value,
|
||||
))
|
||||
|
||||
@api.constrains('company_id', 'journal_id')
|
||||
def _check_company_journal(self):
|
||||
if self.journal_id and self.journal_id.company_id.id != self.company_id.id:
|
||||
raise ValidationError(_("The sales journal and the point of sale must belong to the same company."))
|
||||
for config in self:
|
||||
if config.journal_id and config.journal_id.company_id.id != config.company_id.id:
|
||||
raise ValidationError(_("The sales journal of the point of sale %s must belong to its company.", config.name))
|
||||
|
||||
def _check_profit_loss_cash_journal(self):
|
||||
if self.cash_control and self.payment_method_ids:
|
||||
@@ -344,13 +355,15 @@ class PosConfig(models.Model):
|
||||
|
||||
@api.constrains('company_id', 'invoice_journal_id')
|
||||
def _check_company_invoice_journal(self):
|
||||
if self.invoice_journal_id and self.invoice_journal_id.company_id.id != self.company_id.id:
|
||||
raise ValidationError(_("The invoice journal and the point of sale must belong to the same company."))
|
||||
for config in self:
|
||||
if config.invoice_journal_id and config.invoice_journal_id.company_id.id != config.company_id.id:
|
||||
raise ValidationError(_("The invoice journal of the point of sale %s must belong to the same company.", config.name))
|
||||
|
||||
@api.constrains('company_id', 'payment_method_ids')
|
||||
def _check_company_payment(self):
|
||||
if self.env['pos.payment.method'].search_count([('id', 'in', self.payment_method_ids.ids), ('company_id', '!=', self.company_id.id)]):
|
||||
raise ValidationError(_("The payment methods and the point of sale must belong to the same company."))
|
||||
for config in self:
|
||||
if self.env['pos.payment.method'].search_count([('id', 'in', config.payment_method_ids.ids), ('company_id', '!=', config.company_id.id)]):
|
||||
raise ValidationError(_("The payment methods for the point of sale %s must belong to its company.", self.name))
|
||||
|
||||
@api.constrains('pricelist_id', 'use_pricelist', 'available_pricelist_ids', 'journal_id', 'invoice_journal_id', 'payment_method_ids')
|
||||
def _check_currencies(self):
|
||||
@@ -393,8 +406,9 @@ class PosConfig(models.Model):
|
||||
|
||||
@api.constrains('company_id', 'available_pricelist_ids')
|
||||
def _check_companies(self):
|
||||
if any(self.available_pricelist_ids.mapped(lambda pl: pl.company_id.id not in (False, self.company_id.id))):
|
||||
raise ValidationError(_("The selected pricelists must belong to no company or the company of the point of sale."))
|
||||
for config in self:
|
||||
if any(pricelist.company_id.id not in [False, config.company_id.id] for pricelist in config.available_pricelist_ids):
|
||||
raise ValidationError(_("The selected pricelists must belong to no company or the company of the point of sale."))
|
||||
|
||||
@api.onchange('iface_tipproduct')
|
||||
def _onchange_tipproduct(self):
|
||||
|
||||
@@ -73,6 +73,6 @@ class AnotherBox(models.Model):
|
||||
val2 = fields.Integer('Value 2', required=True)
|
||||
|
||||
@api.constrains('val1', 'val2')
|
||||
def _check(self):
|
||||
if self.val1 != self.val2:
|
||||
def _check_values(self):
|
||||
if any(box.val1 != box.val2 for box in self):
|
||||
raise ValidationError("The two values must be equals")
|
||||
|
||||
Reference in New Issue
Block a user