Skip to content

Commit e1c39cf

Browse files
committed
random comments
1 parent 4bf49aa commit e1c39cf

17 files changed

+289
-76
lines changed

.idea/.gitignore

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/inspectionProfiles/profiles_settings.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/tutorials.iml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

estate/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from . import models
1+
from . import models

estate/__manifest__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
'name': 'Estate',
2+
'name': "Estate",
33
'depends': ['base'],
44
'application': True,
55
'installable': True,

estate/models/estate_property.py

Lines changed: 83 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1-
from odoo import fields, models
21
from datetime import date, timedelta
32

3+
from odoo import api, fields, models
4+
from odoo.exceptions import UserError, ValidationError
5+
from odoo.tools.float_utils import float_compare, float_is_zero
6+
47
class EstateProperty(models.Model):
5-
_name = "estate.property"
8+
_name = 'estate.property'
69
_description = "Real Estate Property"
710

11+
_sql_constraints = [
12+
('check_expected_price', 'CHECK(expected_price > 0)', "Expected price must be strictly positive."),
13+
('check_selling_price', 'CHECK(selling_price >= 0)', "Selling price must be strictly positive.")
14+
]
15+
816
name = fields.Char(string="Title", required=True)
917
description = fields.Text()
1018
postcode = fields.Char()
@@ -13,30 +21,89 @@ class EstateProperty(models.Model):
1321
selling_price = fields.Float(readonly=True, copy=False)
1422
bedrooms = fields.Integer(default=2)
1523
living_area = fields.Integer(string="Living Area (sqm)")
16-
facades = fields.Integer()
24+
facades = fields.Integer(string="Facade")
1725
garage = fields.Boolean()
1826
garden = fields.Boolean()
19-
garden_area = fields.Integer()
27+
garden_area = fields.Integer(string="Garden Area (sqm)")
2028
garden_orientation = fields.Selection(
2129
selection=[
22-
('north', 'North'),
23-
('south', 'South'),
24-
('east', 'East'),
25-
('west', 'West'),
30+
('north', "North"),
31+
('south', "South"),
32+
('east', "East"),
33+
('west', "West"),
2634
],
2735
string="Garden Orientation"
2836
)
2937
available = fields.Boolean(default=True)
30-
property_type = fields.Many2one("estate.property.type", string="Property Type")
31-
property_salesman = fields.Many2one("res.users", string="Salesman", default=lambda self: self.env.user)
32-
property_buyer = fields.Many2one("res.partner", string="Buyer");
33-
property_tags = fields.Many2many("estate.property.tag", string="Tags")
34-
property_offers = fields.One2many("estate.property.offer", "property_id", string="Offers")
38+
property_type_id = fields.Many2one("estate.property.type", string="Property Type")
39+
salesman_id = fields.Many2one("res.users", string="Salesman", default=lambda self: self.env.user)
40+
buyer_id = fields.Many2one("res.partner", string="Buyer")
41+
tag_ids = fields.Many2many("estate.property.tag", string="Tags")
42+
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers")
3543
state = fields.Selection(
36-
selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'),
37-
('sold', 'Sold'), ('cancelled', 'Cancelled')],
44+
selection=[
45+
('new', "New"),
46+
('offer_received', "Received"),
47+
('offer_accepted', "Accepted"),
48+
('sold', "Sold"),
49+
('cancelled', "Cancelled"),
50+
('refused', "Refused")
51+
],
3852
required=True,
3953
copy=False,
4054
default='new'
4155
)
42-
note = fields.Text("Special mention about the property.")
56+
note = fields.Text(string="Special mention about the property.")
57+
total_area = fields.Integer(string="Total Area (sqm)", compute="_compute_total_area")
58+
best_offer = fields.Float(string="Best Offer", compute="_compute_best_price")
59+
60+
@api.depends("living_area", "garden_area")
61+
def _compute_total_area(self):
62+
for record in self:
63+
record.total_area = record.living_area + record.garden_area
64+
65+
@api.depends("offer_ids.price")
66+
def _compute_best_price(self):
67+
for record in self:
68+
if record.offer_ids:
69+
record.best_offer = max(record.offer_ids.mapped("price"))
70+
else:
71+
record.best_offer = 0.0
72+
73+
@api.onchange("garden")
74+
def _onchange_garden(self):
75+
if self.garden:
76+
self.garden_area = 10
77+
self.garden_orientation = 'north'
78+
else:
79+
self.garden_area = 0
80+
self.garden_orientation = None
81+
82+
def cancel_property_button(self):
83+
for record in self:
84+
if record.state != 'sold':
85+
record.state = 'cancelled'
86+
else:
87+
raise UserError("You cannot cancel a sold property.")
88+
89+
def sold_property_button(self):
90+
for record in self:
91+
if record.state != 'cancelled':
92+
record.state = 'sold'
93+
else:
94+
raise UserError("You cannot sell a cancelled property.")
95+
96+
@api.constrains('expected_price')
97+
def _check_expected_price_positive(self):
98+
for record in self:
99+
if record.expected_price <= 0:
100+
raise ValidationError("Expected price must be strictly positive.")
101+
102+
@api.constrains('selling_price', 'expected_price')
103+
def _check_selling_price_margin(self):
104+
for record in self:
105+
if float_is_zero(record.selling_price, precision_digits=2):
106+
continue
107+
min_acceptable_price = record.expected_price * 0.9
108+
if float_compare(record.selling_price, min_acceptable_price, precision_digits=2) < 0:
109+
raise ValidationError("The selling price cannot be lower than 90% of the expected price.")
Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,45 @@
1-
from odoo import fields,models,api
2-
from dateutil.relativedelta import relativedelta
1+
from datetime import date, timedelta
32

4-
class estate_property_offer(models.Model):
3+
from odoo import api, fields, models
4+
from odoo.exceptions import UserError
5+
6+
7+
class EstatePropertyOffer(models.Model):
58
_name = "estate.property.offer"
69
_description = "Estate property offer"
710

811
price = fields.Float()
9-
status = fields.Selection([('accepted', 'Accepted'), ('refused', 'Refused')], copy=False)
12+
status = fields.Selection(
13+
selection=[
14+
('accepted', "Accepted"),
15+
('refused', "Refused")
16+
],
17+
copy=False
18+
)
1019
partner_id = fields.Many2one("res.partner", required=True)
11-
property_id = fields.Many2one("estate.property", required=True)
20+
property_id = fields.Many2one("estate.property", required=True)
21+
validity = fields.Integer(default=7)
22+
deadline = fields.Date(string="Deadline", compute="_compute_deadline", inverse="_inverse_deadline")
23+
24+
@api.depends("validity")
25+
def _compute_deadline(self):
26+
for record in self:
27+
record.deadline = date.today() + timedelta(days=record.validity)
28+
29+
def _inverse_deadline(self):
30+
for record in self:
31+
if record.deadline:
32+
record.validity = (record.deadline - date.today()).days
33+
34+
def offer_accept(self):
35+
if 'accepted' in self.mapped("property_id.offer_ids.status"):
36+
raise UserError("An offer is already accepted.")
37+
for record in self:
38+
record.status = 'accepted'
39+
record.property_id.state = 'offer_accepted'
40+
record.property_id.buyer_id = record.partner_id
41+
record.property_id.selling_price = record.price
42+
43+
def offer_refuse(self):
44+
for record in self:
45+
record.status = 'refused'

0 commit comments

Comments
 (0)