Skip to content

Commit 664c01d

Browse files
author
Ana Zurabashvili [anzu]
committed
[IMP] estate: Chapter 11: Add The Sprinkles
- Inline views - Widgets & Attributes: Enhanced field display and behavior. - List features: Configured default ordering and enabled quick edits. - Search: Improved filtering options. - Stat button: Added link to related offers. - [REF] refactoring feedback [email protected]
1 parent 6080f12 commit 664c01d

13 files changed

+147
-64
lines changed

estate/__init__.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
# -*- coding: utf-8 -*-
21
from . import models

estate/__manifest__.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# -*- coding: utf-8 -*-
21
{
32
'name': "Real Estate",
43
'summary': """
@@ -10,7 +9,7 @@
109
'author': "Odoo",
1110
'website': "https://www.odoo.com/",
1211
'category': 'Tutorials/Real Estate',
13-
'version': '18.0.1.7.0',
12+
'version': '1.0',
1413
'application': True,
1514
'installable': True,
1615
'depends': ['base'],
@@ -19,7 +18,8 @@
1918
"views/estate_property_views.xml",
2019
"views/estate_property_type_views.xml",
2120
"views/estate_property_tag_views.xml",
21+
"views/estate_property_offer_views.xml",
2222
"views/estate_menus.xml",
2323
],
24-
'license': 'AGPL-3'
24+
'license': "LGPL-3",
2525
}

estate/models/__init__.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# -*- coding: utf-8 -*-
21
from . import estate_property
32
from . import estate_property_tag
43
from . import estate_property_type

estate/models/estate_property.py

+29-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from dateutil.relativedelta import relativedelta
2-
32
from odoo import api, fields, models
43
from odoo.exceptions import UserError
54
from odoo.exceptions import ValidationError
@@ -9,13 +8,14 @@
98
class EstateProperty(models.Model):
109
_name = "estate.property"
1110
_description = "Estate Property"
11+
_order = "id desc"
1212

1313
name = fields.Char(string="Title", required=True)
1414
description = fields.Text(string="Description")
1515
postcode = fields.Char(string="Postcode")
1616
date_availability = fields.Date(
1717
default=lambda self: fields.Date.today() + relativedelta(months=3),
18-
string="Available From", copy=False,
18+
string="Available From", copy=False
1919
)
2020
expected_price = fields.Float(string="Property Expected Price", required=True)
2121
selling_price = fields.Float(string="Selling Price", readonly=True, copy=False)
@@ -32,7 +32,7 @@ class EstateProperty(models.Model):
3232
('south', "South"),
3333
('east', "East"),
3434
('west', "West"),
35-
],
35+
]
3636
)
3737
state = fields.Selection(
3838
string="State",
@@ -42,7 +42,7 @@ class EstateProperty(models.Model):
4242
('accepted', "Offer Accepted"),
4343
('sold', "Sold"),
4444
('cancelled', "Cancelled"),
45-
], required=True, copy=False, default='new',
45+
], required=True, copy=False, default='new'
4646
)
4747
buyer_id = fields.Many2one("res.partner")
4848
salesman_id = fields.Many2one("res.users", default=lambda self: self.env.user)
@@ -51,23 +51,27 @@ class EstateProperty(models.Model):
5151
offer_ids = fields.One2many('estate.property.offer', 'property_id',
5252
string="Offers")
5353

54-
total_area = fields.Float(string="Total Area", compute="_compute_total_area",
54+
total_area = fields.Float(string="Total Area", compute='_compute_total_area',
5555
store=True)
5656

5757
best_price = fields.Float(string="Best price",
5858
compute='_compute_best_price', store=True)
59+
is_offer_excepted = fields.Boolean(string="Offer Excepted",
60+
compute='_compute_is_offer_excepted')
61+
is_available = fields.Boolean(string="Available", compute='_compute_is_available',
62+
store=True)
5963

6064
_sql_constraints = [
6165
(
62-
"check_expected_price_positive",
63-
"CHECK(expected_price >= 0)",
64-
"Expected price must be strictly positive.",
66+
'check_expected_price_positive',
67+
'CHECK(expected_price >= 0)',
68+
'Expected price must be strictly positive.',
6569
),
6670
(
67-
"check_selling_price_positive",
68-
"CHECK(selling_price >= 0)",
69-
"Selling price must be strictly positive.",
70-
),
71+
'check_selling_price_positive',
72+
'CHECK(selling_price >= 0)',
73+
'Selling price must be strictly positive.',
74+
)
7175
]
7276

7377
@api.depends('garden_area', 'living_area')
@@ -80,15 +84,25 @@ def _compute_best_price(self):
8084
for val in self:
8185
val.best_price = max(val.offer_ids.mapped('price'), default=0)
8286

87+
@api.depends('offer_ids.state')
88+
def _compute_is_offer_excepted(self):
89+
for val in self:
90+
val.is_offer_excepted = any(x.state == 'accepted' for x in val.offer_ids)
91+
92+
@api.depends('state')
93+
def _compute_is_available(self):
94+
for val in self:
95+
val.is_available = val.state in ('new', 'received')
96+
8397
def action_sold(self):
8498
if self.state == 'cancelled':
85-
raise UserError('Cancelled property cannot be sold.')
99+
raise UserError("Cancelled property cannot be sold.")
86100
self.state = 'sold'
87101

88102
def action_cancel(self):
89103
for val in self:
90104
if val.state == 'sold':
91-
raise UserError('Sold property cannot be cancelled.')
105+
raise UserError("Sold property cannot be cancelled.")
92106
val.state = 'cancelled'
93107

94108
@api.onchange('garden')
@@ -100,7 +114,7 @@ def _onchange_garden(self):
100114
self.garden_area = False
101115
self.garden_orientation = False
102116

103-
@api.constrains("expected_price", "selling_price")
117+
@api.constrains('expected_price', 'selling_price')
104118
def _check_selling_price_vs_expected(self):
105119
for rec in self:
106120
if float_is_zero(rec.selling_price or 0.0, precision_digits=2):
@@ -111,8 +125,3 @@ def _check_selling_price_vs_expected(self):
111125
raise ValidationError(
112126
"Here Selling price must be at least 90% of the expected price."
113127
)
114-
# if rec.selling_price and rec.selling_price <= rec.expected_price * 0.90:
115-
# raise ValidationError(
116-
# "Selling price should not be possible to accept an offer lower "
117-
# "than 90% of the expected price",
118-
# )

estate/models/estate_property_offer.py

+25-18
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,31 @@
44

55

66
class EstatePropertyOffer(models.Model):
7-
_name = "estate.property.offer"
8-
_description = "Estate Property Offer"
7+
_name = 'estate.property.offer'
8+
_description = 'Estate Property Offer'
9+
_order = 'price desc'
910

10-
price = fields.Float()
11-
status = fields.Selection(
11+
price = fields.Float("Price")
12+
state = fields.Selection(
13+
"State",
1214
selection=[
13-
("accepted", "Accepted"),
14-
("refused", "Refused")
15-
], copy=False,
15+
('accepted', "Accepted"),
16+
('refused', "Refused")
17+
], copy=False
1618
)
17-
partner_id = fields.Many2one("res.partner", required=True)
18-
property_id = fields.Many2one("estate.property", required=True)
19-
20-
date_deadline = fields.Date(string="Deadline Date",
21-
compute="_compute_date_deadline",
22-
inverse="_inverse_date_deadline")
23-
validity = fields.Integer(string="Validity Days", default=7)
19+
partner_id = fields.Many2one('res.partner',
20+
"Partner",
21+
required=True)
22+
property_id = fields.Many2one("estate.property",
23+
"Property",
24+
required=True)
25+
date_deadline = fields.Date("Deadline Date",
26+
compute='_compute_date_deadline',
27+
inverse='_inverse_date_deadline')
28+
validity = fields.Integer("Validity Days", default=7)
2429

30+
property_type_id = fields.Many2one('estate.property.type',
31+
related='property_id.type_id', store=True)
2532
_sql_constraints = [
2633
(
2734
"check_price_positive",
@@ -47,19 +54,19 @@ def _inverse_date_deadline(self):
4754
def action_accept(self):
4855
for val in self:
4956
self.property_id.offer_ids.filtered(
50-
lambda x: x.status == "accepted").write({
51-
'status': "refused",
57+
lambda x: x.state == 'accepted').write({
58+
'state': 'refused',
5259
})
5360

54-
val.status = 'accepted'
61+
val.state = 'accepted'
5562
val.property_id.write({
5663
'buyer_id': val.partner_id.id,
5764
'selling_price': val.price,
5865
})
5966

6067
def action_refuse(self):
6168
for val in self:
62-
val.status = 'refused'
69+
val.state = 'refused'
6370
val.property_id.write({
6471
'buyer_id': False,
6572
'selling_price': False,

estate/models/estate_property_tag.py

+2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
class EstatePropertyTag(models.Model):
55
_name = "estate.property.tag"
66
_description = "Estate Property Tag"
7+
_order = "name"
78

89
name = fields.Char(string="Property Tag", required=True)
10+
color = fields.Integer(string="Color")
911

1012
_sql_constraints = [
1113
('unique_name', 'unique(name)',

estate/models/estate_property_type.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
1-
from odoo import fields, models
1+
from odoo import api, fields, models
22

33

44
class EstatePropertyType(models.Model):
55
_name = "estate.property.type"
66
_description = "Estate Property Type"
7+
_order = "sequence desc"
78

89
name = fields.Char(string="Property Type", required=True)
10+
sequence = fields.Integer(string="Sequence", default=1)
11+
property_ids = fields.Many2many(
12+
"estate.property",
13+
)
14+
15+
offer_ids = fields.One2many('estate.property.offer', 'property_type_id',
16+
string="Offers")
17+
18+
offer_count = fields.Integer(string="Offer Count", compute="_compute_offer_count")
919

1020
_sql_constraints = [
1121
('unique_name', 'unique(name)',
1222
'Types should have unique names.'),
1323
]
24+
25+
@api.depends("offer_ids")
26+
def _compute_offer_count(self):
27+
for val in self:
28+
val.offer_count = len(val.offer_ids)

estate/security/ir.model.access.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
22
estate.access_estate_property,access_estate_property,estate.model_estate_property,base.group_user,1,1,1,1
33
estate.access_estate_property_tag,access_estate_property_tag,estate.model_estate_property_tag,base.group_user,1,1,1,1
44
estate.access_estate_property_type,access_estate_property_type,estate.model_estate_property_type,base.group_user,1,1,1,1
5-
estate.access_estate_property_offer,access_estate_property_offer,estate.model_estate_property_offer,base.group_user,1,1,1,1
5+
estate.access_estate_property_offer,access_estate_property_offer,estate.model_estate_property_offer,base.group_user,1,1,1,1

estate/views/estate_menus.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99
<menuitem id="menu_property_tag" action="estate_property_tag_action" name="Property Tags"/>
1010
</menuitem>
1111
</menuitem>
12-
</odoo>
12+
</odoo>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<odoo>
2+
<data>
3+
4+
<record id="estate_property_offer_list" model="ir.ui.view">
5+
<field name="name">estate.property.offer.list</field>
6+
<field name="model">estate.property.offer</field>
7+
<field name="arch" type="xml">
8+
<list editable="bottom"
9+
decoration-success="state == 'accepted'"
10+
decoration-danger="state == 'refused'">
11+
<field name="price"/>
12+
<field name="partner_id"/>
13+
<field name="date_deadline"/>
14+
<field name="validity"/>
15+
<button name="action_accept" type="object" class="oe_stat_button"
16+
icon="fa-check" string=" " invisible="state=='accepted'"/>
17+
<button name="action_refuse" type="object" class="oe_stat_button"
18+
icon="fa-close" string=" " invisible="state=='refused'"/>
19+
<field name="state" column_invisible="1"/>
20+
<field name="property_type_id"/>
21+
</list>
22+
</field>
23+
</record>
24+
<record id="estate_property_offer_action" model="ir.actions.act_window">
25+
<field name="name">Offers</field>
26+
<field name="res_model">estate.property.offer</field>
27+
<field name="view_mode">list,form</field>
28+
<field name="domain">[("property_type_id", "=", active_id)]</field>
29+
</record>
30+
</data>
31+
</odoo>

estate/views/estate_property_tag_views.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
<field name="view_mode">list,form</field>
1717
</record>
1818
</data>
19-
</odoo>
19+
</odoo>

estate/views/estate_property_type_views.xml

+10-2
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,23 @@
55
<field name="model">estate.property.type</field>
66
<field name="arch" type="xml">
77
<list string="Estate Property Type" editable="bottom">
8+
<field name="sequence" widget="handle"/>
89
<field name="name"/>
10+
<field name="offer_count"/>
11+
<button name="%(estate.estate_property_offer_action)d"
12+
type="action"
13+
class="oe_stat_button"
14+
icon="fa-list">
15+
<field name="offer_count"/>
16+
</button>
917
</list>
1018
</field>
1119
</record>
1220

1321
<record id="estate_property_type_action" model="ir.actions.act_window">
1422
<field name="name">Estate Property Type</field>
1523
<field name="res_model">estate.property.type</field>
16-
<field name="view_mode">list,form</field>
24+
<field name="view_mode">list</field>
1725
</record>
1826
</data>
19-
</odoo>
27+
</odoo>

0 commit comments

Comments
 (0)