Skip to content

Commit c4659cf

Browse files
committed
[FIX] estate: Reviewed and aligned code with Odoo coding guidelines
1 parent eb71a5c commit c4659cf

23 files changed

+272
-155
lines changed

estate/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
# -*- coding: utf-8 -*-
2+
# Part of Odoo. See LICENSE file for full copyright and licensing details.
13
from . import models

estate/__manifest__.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
{
22
'name': 'Estate',
3-
'installable': True,
4-
'application': True,
5-
'auto_install': False,
6-
3+
'version': '1.0',
4+
"category": "Real Estate/Brokerage",
75
'data': [
86
'security/ir.model.access.csv',
7+
'security/security.xml',
98
'views/estate_property_views.xml',
109
'views/estate_property_type_views.xml',
1110
'views/estate_property_tag_views.xml',
1211
'views/inherited_model_view.xml',
1312
'views/estate_menu.xml',
13+
'data/estate_property_type.xml',
14+
],
15+
'demo': [
16+
'demo/estate_property_demo.xml',
17+
'demo/estate_property_offer.xml',
1418
],
15-
19+
'installable': True,
20+
'application': True,
1621
'license': 'LGPL-3',
1722
}

estate/data/estate_property_type.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<odoo>
3+
<record id="estate_property_type_residential" model="estate.property.type">
4+
<field name="name">Residential</field>
5+
</record>
6+
7+
<record id="estate_property_type_commercial" model="estate.property.type">
8+
<field name="name">Commercial</field>
9+
</record>
10+
11+
<record id="estate_property_type_industrial" model="estate.property.type">
12+
<field name="name">Industrial</field>
13+
</record>
14+
15+
<record id="estate_property_type_land" model="estate.property.type">
16+
<field name="name">Land</field>
17+
</record>
18+
</odoo>

estate/demo/estate_property_demo.xml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
<record id="estate_property_demo_1" model="estate.property">
4+
<field name="name">Big Villa</field>
5+
<field name="state">new</field>
6+
<field name="description">A nice and big villa</field>
7+
<field name="postcode">12345</field>
8+
<field name="date_avaiblity">2020-02-02</field>
9+
<field name="expected_price">1600000</field>
10+
<!-- <field name="selling_price"></field> -->
11+
<field name="bedrooms">6</field>
12+
<field name="living_area">100</field>
13+
<field name="facades">4</field>
14+
<field name="garage">1</field>
15+
<field name="garden">1</field>
16+
<field name="garden_area">100000</field>
17+
<field name="garden_orientation">south</field>
18+
<field name="property_type_id">1</field>
19+
</record>
20+
<record id="estate_property_demo_2" model="estate.property">
21+
<field name="name">Trailer Home</field>
22+
<field name="state">cancelled</field>
23+
<field name="description">Home in trailer park.</field>
24+
<field name="postcode">54321</field>
25+
<field name="date_avaiblity">1970-01-01</field>
26+
<field name="expected_price">100000</field>
27+
<field name="bedrooms">1</field>
28+
<field name="living_area">10</field>
29+
<field name="facades">4</field>
30+
<field name="garage">0</field>
31+
<field name="property_type_id" ref="estate_property_type_residential" />
32+
<field name="offer_ids"
33+
eval="[
34+
Command.create({
35+
'partner_id': ref('base.res_partner_2'),
36+
'price': 15000025,
37+
'validity': 14,
38+
'date_deadline': (DateContext().today() + relativedelta(days=14)).isoformat()
39+
}),
40+
Command.create({
41+
'partner_id': ref('base.res_partner_2'),
42+
'price': 15000036,
43+
'validity': 14,
44+
'date_deadline': (DateContext().today() + relativedelta(days=14)).isoformat()
45+
}),
46+
Command.create({
47+
'partner_id': ref('base.res_partner_3'),
48+
'price': 15000047,
49+
'validity': 11,
50+
'date_deadline': (DateContext().today() + relativedelta(days=11)).isoformat()
51+
}),
52+
]" />
53+
</record>
54+
</odoo>

estate/demo/estate_property_offer.xml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<odoo>
3+
<record id="estate_property_offer_1" model="estate.property.offer">
4+
<field name="price">10000</field>
5+
<field name="validity">14</field>
6+
<field name="property_id" ref="estate_property_demo_1" />
7+
<field name="partner_id" ref="base.res_partner_12" />
8+
</record>
9+
<record id="estate_property_offer_2" model="estate.property.offer">
10+
<field name="price">1500000</field>
11+
<field name="validity">14</field>
12+
<field name="property_id" ref="estate_property_demo_1" />
13+
<field name="partner_id" ref="base.res_partner_12" />
14+
</record>
15+
<record id="estate_property_offer_3" model="estate.property.offer">
16+
<field name="price">1500001</field>
17+
<field name="validity">11</field>
18+
<field name="property_id" ref="estate_property_demo_1" />
19+
<field name="partner_id" ref="base.res_partner_2" />
20+
</record>
21+
22+
<function model="estate.property.offer" name="accept_icon_action">
23+
<value eval="[ref('estate_property_offer_1')]" />
24+
</function>
25+
<function model="estate.property.offer" name="accept_icon_action">
26+
<value eval="[ref('estate_property_offer_2')]" />
27+
</function>
28+
<function model="estate.property.offer" name="refuse_icon_action">
29+
<value eval="[ref('estate_property_offer_3')]" />
30+
</function>
31+
32+
</odoo>

estate/models/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
# -*- coding: utf-8 -*-
2+
# Part of Odoo. See LICENSE file for full copyright and licensing details.
13
from . import estate_property
24
from . import estate_property_type
35
from . import estate_property_tag
46
from . import estate_property_offer
5-
from . import inherited_model
7+
from . import res_users

estate/models/estate_property.py

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
class EstateProperty(models.Model):
88
_name = "estate.property"
99
_description = "Estate Property is defined"
10-
1110
_order = "id desc"
11+
_sql_constraints = [
12+
('selling_price_positive', 'CHECK(selling_price>=0)', 'The selling price should be positive.'),
13+
('expected_price_positive', 'CHECK(expected_price>=0)', 'The expected price should be positive.')
14+
]
1215

1316
name = fields.Char(required=True)
1417
description = fields.Text()
@@ -22,41 +25,21 @@ class EstateProperty(models.Model):
2225
garage = fields.Boolean()
2326
garden = fields.Boolean()
2427
garden_area = fields.Integer()
25-
garden_orientation = fields.Selection(
26-
string='Direction',
27-
selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')],
28-
help="Orientation is used to locate garden's direction"
29-
)
3028
active = fields.Boolean(default=True)
31-
state = fields.Selection(
32-
selection=[('new', 'new'), ('Offer Received', 'Offer Received'), ('Offer Accepted', 'Offer Accepted'), ('sold', 'sold'), ('cancelled', 'Cancelled')],
33-
required=True,
34-
default='new',
35-
copy=False,
36-
)
3729
salesman_id = fields.Many2one("res.users", index=True, string="salesman", default=lambda self: self.env.user)
3830
buyer_id = fields.Many2one("res.partner", string="buyer", index=True, default=lambda self: self.env.user.partner_id.id)
39-
4031
property_type_id = fields.Many2one("estate.property.type", string="property type")
41-
4232
property_tag_ids = fields.Many2many("estate.property.tag", string="tags")
43-
4433
offer_ids = fields.One2many("estate.property.offer", "property_id", string="offers")
45-
46-
_sql_constraints = [
47-
('selling_price_positive', 'CHECK(selling_price>=0)', 'The selling price should be positive.'),
48-
('expected_price_positive', 'CHECK(expected_price>=0)', 'The expected price should be positive.')
49-
]
50-
5134
total_area = fields.Float(compute="_compute_total")
35+
best_offer = fields.Float(compute="_find_best")
36+
company_id = fields.Many2one("res.company", required=True, default=lambda self: self.env.company)
5237

5338
@api.depends("garden_area", "living_area")
5439
def _compute_total(self):
5540
for record in self:
5641
record.total_area = record.garden_area + record.living_area
5742

58-
best_offer = fields.Float(compute="_find_best")
59-
6043
@api.depends("offer_ids.price")
6144
def _find_best(self):
6245
for record in self:
@@ -65,15 +48,19 @@ def _find_best(self):
6548
else:
6649
record.best_offer = 0.0
6750

68-
@api.onchange("garden")
69-
def _onchange_garden(self):
70-
if self.garden:
71-
self.garden_area = 10
72-
self.garden_orientation = "north"
73-
else:
74-
self.garden_area = 0
75-
self.garden_orientation = False
76-
51+
garden_orientation = fields.Selection(
52+
string='Direction',
53+
selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')],
54+
help="Orientation is used to locate garden's direction"
55+
)
56+
57+
state = fields.Selection(
58+
selection=[('new', 'new'), ('Offer Received', 'Offer Received'), ('Offer Accepted', 'Offer Accepted'), ('sold', 'sold'), ('cancelled', 'Cancelled')],
59+
required=True,
60+
default='new',
61+
copy=False,
62+
)
63+
7764
status = fields.Selection(
7865
selection=[
7966
('new', 'New'),
@@ -84,6 +71,15 @@ def _onchange_garden(self):
8471
copy=False
8572
)
8673

74+
@api.onchange("garden")
75+
def _onchange_garden(self):
76+
if self.garden:
77+
self.garden_area = 10
78+
self.garden_orientation = "north"
79+
else:
80+
self.garden_area = 0
81+
self.garden_orientation = False
82+
8783
def sold_button_action(self):
8884
for record in self:
8985
if record.status == 'cancelled':
Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
1-
from odoo import api, fields, models
21
from datetime import timedelta
2+
from odoo import api, fields, models
33
from odoo.exceptions import UserError, ValidationError
44
from odoo.tools.float_utils import float_compare
55

66

77
class EstatePropertyOffer(models.Model):
88
_name = "estate.property.offer"
99
_description = "estate property OFFER created"
10-
1110
_order = "price desc"
11+
_sql_constraints = [
12+
('offer_price_positive', 'CHECK(price>=0)', 'The offer price should be positive.')
13+
]
1214

1315
price = fields.Float()
1416
status = fields.Selection(
1517
selection=[('accepted', 'Accepted'), ('refused', 'Refused')],
1618
copy=False,
1719
)
18-
1920
partner_id = fields.Many2one("res.partner", string="Partner", index=True, required=True, default=lambda self: self.env.user.partner_id.id)
2021
property_id = fields.Many2one("estate.property", index=True, required=True)
21-
2222
property_type_id = fields.Many2one('estate.property.type', string="property type", related="property_id.property_type_id", store=True)
23-
2423
validity = fields.Integer(default=7)
2524
date_deadline = fields.Date(
2625
string="Deadline",
@@ -29,10 +28,6 @@ class EstatePropertyOffer(models.Model):
2928
store=True
3029
)
3130

32-
_sql_constraints = [
33-
('offer_price_positive', 'CHECK(price>=0)', 'The offer price should be positive.')
34-
]
35-
3631
@api.depends('create_date', 'validity')
3732
def _compute_date_deadline(self):
3833
for record in self:
@@ -51,49 +46,41 @@ def _inverse_date_deadline(self):
5146
if record.date_deadline:
5247
record.validity = (record.date_deadline - create_date).days
5348

49+
@api.model_create_multi
50+
def create(self, vals_list):
51+
for vals in vals_list:
52+
property_id = vals.get("property_id")
53+
price = vals.get("price", 0.0)
54+
if property_id:
55+
property_obj = self.env["estate.property"].browse(property_id)
56+
best_price = property_obj.best_offer or 0.0
57+
if price < best_price:
58+
raise UserError(
59+
"Offer price must be greater than or equal to the best offer price.")
60+
records = super().create(vals_list)
61+
for record in records:
62+
if record.partner_id:
63+
record.property_id.state = "Offer Received"
64+
return records
65+
66+
def refuse_icon_action(self):
67+
for record in self:
68+
record.status = 'refused'
69+
5470
def accept_icon_action(self):
5571
for record in self:
56-
# Ensure only one accepted offer per property
5772
if any(
5873
offer.status == 'accepted'
5974
for offer in record.property_id.offer_ids
6075
):
6176
raise UserError("Only one offer can be accepted per property.")
62-
63-
# ✅ Enforce 90% price check
6477
min_price = record.property_id.expected_price * 0.9
6578
if float_compare(record.price, min_price, precision_digits=2) < 0:
6679
raise ValidationError("Offer must be at least 90% of the expected price to be accepted.")
6780

6881
record.status = 'accepted'
6982
record.property_id.state = 'Offer Accepted'
70-
71-
# Refuse all other offers
7283
other_offers = record.property_id.offer_ids - record
7384
other_offers.write({'status': 'refused'})
74-
75-
# Set buyer and selling price on property
7685
record.property_id.selling_price = record.price
7786
record.property_id.buyer_id = record.partner_id
78-
79-
def refuse_icon_action(self):
80-
for record in self:
81-
record.status = 'refused'
82-
83-
@api.model_create_multi
84-
def create(self, vals_list):
85-
for vals in vals_list:
86-
property_id = vals.get("property_id")
87-
price = vals.get("price", 0.0)
88-
if property_id:
89-
property_obj = self.env["estate.property"].browse(property_id)
90-
best_price = property_obj.best_offer or 0.0
91-
if price < best_price:
92-
raise UserError(
93-
"Offer price must be greater than or equal to the best offer price."
94-
)
95-
records = super().create(vals_list)
96-
for record in records:
97-
if record.partner_id:
98-
record.property_id.state = "offer_received"
99-
return records

estate/models/estate_property_tag.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44
class EstatePropertyTag(models.Model):
55
_name = "estate.property.tag"
66
_description = "estate property TAG created"
7-
87
_order = "name asc"
9-
10-
name = fields.Char(required=True)
11-
color = fields.Integer()
12-
138
_sql_constraints = [
149
('tag_name_unique', 'unique(name)', 'Tag name should be unique')
1510
]
11+
12+
name = fields.Char(required=True)
13+
color = fields.Integer()

0 commit comments

Comments
 (0)