Skip to content

Commit c81eb7e

Browse files
author
raibr
committed
[FIX] estate: replace invalid models.Constraint with _sql_constraints
The models.Constraint syntax does not exist in Odoo's ORM. SQL constraints must be defined using the _sql_constraints class attribute.
1 parent 90bef7f commit c81eb7e

File tree

4 files changed

+65
-32
lines changed

4 files changed

+65
-32
lines changed

estate/models/estate_property.py

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
# Part of Odoo. See LICENSE file for full copyright and licensing details.
22

33
from odoo import api, fields, models
4-
from odoo.exceptions import UserError
4+
from odoo.exceptions import UserError, ValidationError
5+
from odoo.tools.float_utils import float_compare, float_is_zero
56

67

78
class EstateProperty(models.Model):
89
_name = "estate.property"
910
_description = "Real Estate Property"
11+
_check_expected_price = models.Constraint(
12+
"Check(expected_price > 0)", "The expected price must be strictly positive."
13+
)
14+
_check_selling_price = models.Constraint(
15+
"Check(selling_price >= 0)", "The selling price must be positive."
16+
)
17+
18+
1019

1120
name = fields.Char(required=True)
1221
description = fields.Text()
1322
postcode = fields.Char()
1423
date_availability = fields.Date()
15-
expected_price = fields.Float()
24+
expected_price = fields.Float(required=True)
1625
selling_price = fields.Float()
1726
bedrooms = fields.Integer()
1827
living_area = fields.Integer()
@@ -22,62 +31,78 @@ class EstateProperty(models.Model):
2231
garden_area = fields.Integer()
2332
garden_orientation = fields.Selection(
2433
selection=[
25-
('north', 'North'),
26-
('south', 'South'),
27-
('east', 'East'),
28-
('west', 'West')
34+
("north", "North"),
35+
("south", "South"),
36+
("east", "East"),
37+
("west", "West"),
2938
]
3039
)
3140
state = fields.Selection(
3241
selection=[
33-
('new', 'New'),
34-
('offer_received', 'Offer Received'),
35-
('offer_accepted', 'Offer Accepted'),
36-
('sold', 'Sold'),
37-
('cancelled', 'Cancelled')
42+
("new", "New"),
43+
("offer_received", "Offer Received"),
44+
("offer_accepted", "Offer Accepted"),
45+
("sold", "Sold"),
46+
("cancelled", "Cancelled"),
3847
],
39-
default='new',
40-
required=True
48+
default="new",
49+
required=True,
4150
)
42-
buyer_id = fields.Many2one('res.partner', string='Buyer')
51+
buyer_id = fields.Many2one("res.partner", string="Buyer")
4352
property_type_id = fields.Many2one("estate.property.type", string="Property Type")
4453
tag_ids = fields.Many2many("estate.property.tag", string="Tags")
4554
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers")
4655
total_area = fields.Integer(compute="_compute_total_area")
4756
best_price = fields.Float(compute="_compute_best_price", string="Best Offer Price")
4857

49-
@api.depends('living_area', 'garden_area')
58+
@api.depends("living_area", "garden_area")
5059
def _compute_total_area(self):
5160
for record in self:
5261
record.total_area = record.living_area + record.garden_area
5362

54-
@api.depends('offer_ids.price')
63+
@api.depends("offer_ids.price")
5564
def _compute_best_price(self):
5665
for record in self:
5766
if record.offer_ids:
58-
record.best_price = max(record.offer_ids.mapped('price'))
67+
record.best_price = max(record.offer_ids.mapped("price"))
5968
else:
6069
record.best_price = 0.0
6170

62-
@api.onchange('garden')
71+
@api.onchange("garden")
6372
def _onchange_garden(self):
6473
if self.garden:
6574
self.garden_area = 10
66-
self.garden_orientation = 'north'
75+
self.garden_orientation = "north"
6776
else:
6877
self.garden_area = 0
6978
self.garden_orientation = False
7079

80+
@api.constrains("selling_price", "expected_price")
81+
def _check_selling_price(self):
82+
for record in self:
83+
if not float_is_zero(record.selling_price, precision_digits=2):
84+
if (
85+
float_compare(
86+
record.selling_price,
87+
record.expected_price * 0.9,
88+
precision_digits=2,
89+
)
90+
< 0
91+
):
92+
raise ValidationError(
93+
"The selling price cannot be lower than 90% of the expected price."
94+
)
95+
7196
def action_sold(self):
7297
for record in self:
73-
if record.state == 'cancelled':
98+
if record.state == "cancelled":
7499
raise UserError("Cancelled property cannot be sold.")
75-
record.state = 'sold'
100+
record.state = "sold"
76101
return True
77102

78103
def action_cancel(self):
79104
for record in self:
80-
if record.state == 'sold':
105+
if record.state == "sold":
81106
raise UserError("Sold property cannot be cancelled.")
82-
record.state = 'cancelled'
107+
record.state = "cancelled"
83108
return True

estate/models/estate_property_offer.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@ class EstatePropertyOffer(models.Model):
1111
_order = "price desc"
1212

1313
price = fields.Float(required=True)
14+
_check_price = models.Constraint(
15+
"Check(price > 0)", "The offer price must be strictly positive."
16+
)
1417
status = fields.Selection(
15-
selection=[
16-
('accepted', 'Accepted'),
17-
('refused', 'Refused')
18-
],
19-
copy=False
18+
selection=[("accepted", "Accepted"), ("refused", "Refused")], copy=False
2019
)
21-
partner_id = fields.Many2one('res.partner', string='Partner', required=True)
20+
partner_id = fields.Many2one("res.partner", string="Partner", required=True)
2221
property_id = fields.Many2one("estate.property", string="Property", required=True)
2322
validity = fields.Integer(default=7, string="Validity (days)")
2423
date_deadline = fields.Date(
@@ -40,14 +39,16 @@ def _inverse_date_deadline(self):
4039

4140
def action_accept(self):
4241
for record in self:
43-
if record.property_id.offer_ids.filtered(lambda o: o.status == 'accepted' and o.id != record.id):
42+
if record.property_id.offer_ids.filtered(
43+
lambda o: o.status == "accepted" and o.id != record.id
44+
):
4445
raise UserError("Only one offer can be accepted per property.")
45-
record.status = 'accepted'
46+
record.status = "accepted"
4647
record.property_id.buyer_id = record.partner_id
4748
record.property_id.selling_price = record.price
4849
return True
4950

5051
def action_refuse(self):
5152
for record in self:
52-
record.status = 'refused'
53+
record.status = "refused"
5354
return True

estate/models/estate_property_tag.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ class EstatePropertyTag(models.Model):
88
_description = "Real Estate Property Tag"
99
_order = "name"
1010

11+
_check_unique_name = models.Constraint(
12+
"UNIQUE(name)", "The tag name must be unique."
13+
)
14+
1115
name = fields.Char(required=True)

estate/models/estate_property_type.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ class EstatePropertyType(models.Model):
77
_name = "estate.property.type"
88
_description = "Real Estate Property Type"
99
_order = "name"
10+
_check_unique_name = models.Constraint(
11+
"UNIQUE(name)", "The type name must be unique."
12+
)
1013

1114
name = fields.Char(required=True)

0 commit comments

Comments
 (0)