Skip to content

Commit defd568

Browse files
committed
[IMP] estate: add SQL and Python constraints
- Added constraints to enforce unique tags and properties - Fixed style issues and improved validation logic - Chapter: 10
1 parent c427696 commit defd568

File tree

5 files changed

+63
-28
lines changed

5 files changed

+63
-28
lines changed

estate/models/estate_property.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from dateutil.relativedelta import relativedelta
22

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

67

78
class EstateProperty(models.Model):
@@ -76,6 +77,20 @@ class EstateProperty(models.Model):
7677
total_area = fields.Integer(compute="_compute_total_area", store=True)
7778
best_price = fields.Float(compute="_compute_best_price", store=True)
7879

80+
_check_expected_price = models.Constraint(
81+
'CHECK(expected_price > 0)',
82+
'Expected price must be positive!',
83+
)
84+
85+
@api.constrains("selling_price", "expected_price")
86+
def _check_selling_price(self):
87+
for record in self:
88+
if float_is_zero(record.selling_price, precision_digits=2):
89+
continue
90+
min_selling_price = record.expected_price * 0.9
91+
if float_compare(record.selling_price, min_selling_price, precision_digits=2) < 0:
92+
raise ValidationError("The selling price must be at least 90% of the expected price.")
93+
7994
@api.depends("living_area", "garden_area")
8095
def _compute_total_area(self):
8196
for record in self:
@@ -96,8 +111,11 @@ def _onchange_garden(self):
96111
self.garden_orientation = False
97112

98113
def action_cancelled(self):
99-
if self.state == "sold":
100-
raise UserError("Sold property can not be Cancelled")
114+
for record in self:
115+
if record.state == "sold":
116+
raise RedirectWarning("A sold property cannot be cancelled",
117+
self.env.ref('estate.estate_menu_settings_property_offer').id,
118+
"go to offer page!")
101119
self.state = "cancelled"
102120

103121
def action_sold(self):

estate/models/estate_property_offer.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from dateutil.relativedelta import relativedelta
22

33
from odoo import api, fields, models
4-
from odoo.exceptions import UserError
4+
from odoo.exceptions import UserError, ValidationError
55

66

77
class EstatePropertyOffer(models.Model):
@@ -30,6 +30,11 @@ class EstatePropertyOffer(models.Model):
3030
store=True
3131
)
3232

33+
_check_price = models.Constraint(
34+
'CHECK(price > 0)',
35+
'Offer price must be positive',
36+
)
37+
3338
@api.depends("validity", "create_date")
3439
def _compute_date_deadline(self):
3540
for record in self:
@@ -43,15 +48,21 @@ def _inverse_date_deadline(self):
4348
if record.create_date and record.date_deadline:
4449
record.validity = (record.date_deadline - record.create_date.date()).days
4550

46-
def action_confirm(self):
47-
if self.property_id.selling_price or self.status == "accepted":
48-
raise UserError("Offer is already accepted")
49-
else:
51+
def action_accepted(self):
52+
for record in self:
53+
if record.property_id.selling_price or record.status == "accepted":
54+
raise UserError("Offer is already accepted")
5055
self.status = "accepted"
56+
rejected_offer = self.search([
57+
('property_id', '=', self.property_id.id),
58+
('id', '!=', self.id),
59+
])
60+
for ro in rejected_offer:
61+
ro.status = "rejected"
5162
self.property_id.buyer_id = self.partner_id
5263
self.property_id.selling_price = self.price
5364

54-
def action_cancel(self):
65+
def action_rejected(self):
5566
if self.status == "accepted":
5667
self.property_id.selling_price = False
5768
self.status = "rejected"

estate/models/estate_property_tag.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ class EstatePropertyTag(models.Model):
66
_description = "Estate Property Tag"
77

88
name = fields.Char(required=True)
9+
10+
_name_unique = models.Constraint(
11+
'unique(name)',
12+
'The Property Tag must be unique.',
13+
)

estate/models/estate_property_type.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ class PropertyType(models.Model):
66
_description = 'Estate Property Type'
77

88
name = fields.Char(required=True)
9+
10+
_name_unique = models.Constraint(
11+
'unique(name)',
12+
'The Property type must be unique.',
13+
)

estate/views/estate_property_views.xml

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
<form string="Properties">
3131
<header>
3232
<button name="action_sold" type="object" string="Sold"/>
33-
<button name="action_cancelled" type="object" string="Cancle"/>
33+
<button name="action_cancelled" type="object" string="Cancel"/>
3434
</header>
3535
<sheet>
3636
<h1>
@@ -69,29 +69,28 @@
6969
</group>
7070
</group>
7171
</page>
72-
<page string="other info">
73-
<group>
74-
<field name="buyer_id"
75-
readonly="1"
76-
/>
77-
<field name="seller_id"/>
78-
</group>
79-
</page>
8072
<page string="Offers">
8173
<field name="offer_ids">
8274
<list>
8375
<field name="price"/>
8476
<field name="partner_id"/>
8577
<field name="validity"/>
8678
<field name="date_deadline"/>
87-
<button name="action_confirm" states="draft" type="object"
88-
icon="fa-check" title="accepted"/>
89-
<button name="action_cancel" states="draft,open" type="object"
90-
icon="fa-times" title="refused"/>
79+
<button name="action_accepted" states="draft" type="object"
80+
icon="fa-check" title="accepted" invisible="status in ('rejected')"/>
81+
<button name="action_rejected" states="draft,open" type="object"
82+
icon="fa-times" title="refused" invisible="status in ('rejected')"/>
9183
<field name="status"/>
9284
</list>
9385
</field>
9486
</page>
87+
<page string="other info">
88+
<group>
89+
<field name="buyer_id"
90+
readonly="1"/>
91+
<field name="seller_id"/>
92+
</group>
93+
</page>
9594
</notebook>
9695
</sheet>
9796
</form>
@@ -123,18 +122,15 @@
123122
string="Expensive"
124123
domain="[('expected_price','&gt;',1000000)]"/>
125124

126-
<filter
127-
name="group_by_postcode"
125+
<filter name="group_by_postcode"
128126
string="Postcode"
129127
context="{'group_by': 'postcode'}"/>
130128

131-
<filter
132-
name="group_by_bedrooms"
129+
<filter name="group_by_bedrooms"
133130
string="Bedrooms"
134131
context="{'group_by': 'bedrooms'}"/>
135132

136-
<filter
137-
name="group_by_state"
133+
<filter name="group_by_state"
138134
string="State"
139135
context="{'group_by': 'state'}"/>
140136
</search>

0 commit comments

Comments
 (0)