Search code examples
pythonodooodoo-14

Python constraint doesn't check edited value


I'm doing this official tutorial https://www.odoo.com/documentation/14.0/developer/howtos/rdtraining/11_constraints.html#howto-rdtraining-11-constraints in Odoo 14 docs and have trouble with Python constraint, which doesn't trigger if I change selling_price.

I have this method on selling_price, which change selling_price whenever any offer is accepted (This works fine).

@api.depends('offer_ids')
def _compute_selling_price(self):
    """When any offer is accepted set selling_price"""
    for offer in self.offer_ids:
        if offer.status == "accepted":
            self.selling_price = offer.price
            break
    else:
        self.selling_price = 0

Then I have this python constraint, which should raise ValidationError, whenever selling_price is set and is lower than 90% of the expected price.

@api.constrains('selling_price', 'expected_price', 'offer_ids')
def _check_selling_price(self):
    """Raise Validation Error, if selling_price is lower than 90% of expected price"""
    if float_utils.float_compare(self.selling_price, 0.9 * self.expected_price, precision_digits=2) == -1:
        raise ValidationError("Selling price cannot be lower than 90% of the expected price.")

Attribute selling_price looks like this:

selling_price = fields.Float(readonly=True, copy=False, compute="_compute_selling_price")

The problem is, if I accept any offer, it doesn't do anything. I searched through the internet for some solution but didn't find any answer for this. In their docs, there's also no solution, so maybe I'm doing something different than they do.

PS: float_utils.float_compare just compares 2 floats with precision and return -1, if value1 is lower than value2.


Solution

  • I'm not sure if your solution for setting the selling_price is correct. But in Chapter 4 selling_price is created and called "basic field". That's a contradiction to a computed field, which you've implemented. Even in Chapter 9 (Computed Fields And Onchanges) there is no hint to change selling_price to a computed field.

    So first you could try is to set your computed field sellling_price to store in the database, by adding the parameter store=True to the field definition:

    selling_price = fields.Float(
        readonly=True, copy=False, store=True,
        compute="_compute_selling_price")
    

    A second approach would be changing selling_price back to a basic field (removing compute parameter) and changing the implementation of setting the selling price, when an offer was accepted. I won't reveal a solution for the second part, because that's what a tutorial is for.