Skip to content

Commit d851b07

Browse files
author
joyep
committed
[ADD] estate: Chapter 10 - add SQL and python constraints
Add SQL constraints for price and uniqueness in property models and add Python constraints for the accepted price.
1 parent 59f4c76 commit d851b07

File tree

4 files changed

+36
-14
lines changed

4 files changed

+36
-14
lines changed

estate/models/estate_property.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1+
from dateutil.relativedelta import relativedelta
2+
13
from odoo import api, fields, models
24
from odoo.exceptions import UserError
3-
from dateutil.relativedelta import relativedelta
45

56

67
class EstateProperty(models.Model):
8+
# ----------------------------------------
9+
# Private attributes
10+
# ----------------------------------------
711
_name = "estate.property"
812
_description = "Estate Property"
913
_order = "sequence"
1014

11-
# Default fields
15+
# ----------------------------------------
16+
# Field declarations
17+
# ----------------------------------------
1218
name = fields.Char("Title", required=True)
1319
sequence = fields.Integer("Sequence", default=10)
14-
15-
# Basic fields
1620
description = fields.Text("Description")
1721
postcode = fields.Char("Postcode")
1822
date_availability = fields.Date(
@@ -53,28 +57,37 @@ class EstateProperty(models.Model):
5357
)
5458
salesperson_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user)
5559
partner_id = fields.Many2one("res.partner", string="Partner", copy=False)
56-
57-
# Relational fields
5860
property_type_id = fields.Many2one("estate.property.type", string="Property Type")
5961
tag_ids = fields.Many2many("estate.property.tag", string="Tags")
6062
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers")
63+
total_area = fields.Integer("Total Area (sqm)", compute="_compute_total_area", store=True)
64+
best_offer = fields.Float("Best Offer", compute="_compute_best_offer", store=True)
65+
66+
# ----------------------------------------
67+
# SQL constraints
68+
# ----------------------------------------
69+
_price_positive = [
70+
("check_expected_price", "CHECK(expected_price > 0)", "The expected price must be positive."),
71+
("check_selling_price", "CHECK(selling_price >= 0)", "The selling price cannot be negative."),
72+
]
6173

62-
# Computed fields
74+
# ----------------------------------------
75+
# Compute methods
76+
# ----------------------------------------
6377
@api.depends("living_area", "garden_area")
6478
def _compute_total_area(self):
6579
for record in self:
6680
record.total_area = record.living_area + record.garden_area
6781

68-
total_area = fields.Integer("Total Area (sqm)", compute="_compute_total_area", store=True)
69-
7082
@api.depends("offer_ids.price")
7183
def _compute_best_offer(self):
7284
for record in self:
7385
prices = record.offer_ids.mapped("price")
7486
record.best_offer = max(prices) if prices else 0.0
7587

76-
best_offer = fields.Float("Best Offer", compute="_compute_best_offer", store=True)
77-
88+
# ----------------------------------------
89+
# Onchange methods
90+
# ----------------------------------------
7891
@api.onchange("garden")
7992
def _onchange_garden(self):
8093
if not self.garden:
@@ -86,7 +99,9 @@ def _onchange_garden(self):
8699
if not self.garden_orientation:
87100
self.garden_orientation = "north"
88101

89-
# Action methods and other business logic
102+
# ----------------------------------------
103+
# Action methods
104+
# ----------------------------------------
90105
def action_set_sold(self):
91106
for record in self:
92107
if record.status == "canceled":

estate/models/estate_property_offer.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from datetime import timedelta
22

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

66

77
class EstatePropertyOffer(models.Model):
@@ -22,6 +22,9 @@ class EstatePropertyOffer(models.Model):
2222
validity = fields.Integer("Validity (days)", default=7)
2323
date_deadline = fields.Date("Deadline", compute="_compute_date_deadline", inverse="_inverse_date_deadline")
2424

25+
# SQL constraints
26+
_offer_price_positive = models.Constraint("CHECK(price > 0)")
27+
2528
@api.depends("create_date", "validity")
2629
def _compute_date_deadline(self):
2730
for offer in self:
@@ -42,7 +45,7 @@ def action_accept_offer(self):
4245
# Check if there's already an accepted offer
4346
other_offers = offer.property_id.offer_ids - offer
4447
if any(other_offers.filtered(lambda o: o.status == "accepted")):
45-
raise UserWarning("An offer has already been accepted for this property.")
48+
raise UserError("An offer has already been accepted for this property.")
4649
offer.status = "accepted"
4750
# Refuse other offers for the same property
4851
other_offers.write({"status": "refused"})

estate/models/estate_property_tag.py

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

88
name = fields.Char("Name", required=True)
9+
10+
_tag_name_unique = models.Constraint("UNIQUE(name)")

estate/models/estate_property_type.py

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

88
name = fields.Char("Name", required=True)
9+
10+
_property_type_name_unique = models.Constraint("UNIQUE(name)")

0 commit comments

Comments
 (0)