Skip to content

Commit d7f849d

Browse files
committed
[IMP] estate: Adds inline views, widget, decorations, Stat button
will be able to edit the property tags and offer from inline without opening the form view Adds the decoration to properties, offers Adds a status bar for the property state Adds a stat button to the property types to view all the offer related to that property type
1 parent 3caeedd commit d7f849d

8 files changed

+161
-56
lines changed

estate/models/estate_property.py

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from odoo import models, fields, api, exceptions
1+
from odoo import models, fields, api, exceptions, _
22
from odoo.tools.float_utils import float_compare
33

44

55
class EstateProperty(models.Model):
66
_name = 'estate_property'
77
_description = 'Estate Property details'
8+
_order = 'id desc'
89

910
name = fields.Char(required=True)
1011
description = fields.Text()
@@ -23,11 +24,22 @@ class EstateProperty(models.Model):
2324
garden_area = fields.Integer()
2425
garden_orientation = fields.Selection(
2526
string='Garden Orientation',
26-
selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')]
27+
selection=[
28+
('north', 'North'),
29+
('south', 'South'),
30+
('east', 'East'),
31+
('west', 'West')
32+
]
2733
)
2834
state = fields.Selection(
2935
string='Status',
30-
selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')],
36+
selection=[
37+
('new', 'New'),
38+
('offer_received', 'Offer Received'),
39+
('offer_accepted', 'Offer Accepted'),
40+
('sold', 'Sold'),
41+
('cancelled', 'Cancelled')
42+
],
3143
default='new',
3244
required=True,
3345
copy=False
@@ -41,6 +53,24 @@ class EstateProperty(models.Model):
4153
total_area = fields.Integer(compute='_compute_total_area')
4254
best_price = fields.Float(compute='_compute_best_price')
4355

56+
_check_expected_price = models.Constraint(
57+
'CHECK(expected_price > 0)',
58+
'The Expected price cannot be 0 or less then 0'
59+
)
60+
61+
_check_selling_price = models.Constraint(
62+
'CHECK(selling_price >= 0)',
63+
'The Selling price cannot be less then 0'
64+
)
65+
66+
@api.constrains('selling_price', 'buyer', 'expected_price')
67+
def _check_selling_price_90p(self):
68+
for record in self:
69+
if record.selling_price == 0:
70+
return False
71+
if float_compare((record.selling_price / record.expected_price) * 100, 90, precision_digits=2) < 0:
72+
raise exceptions.ValidationError(_('Selling Price should be 90% or more of expected price.'))
73+
4474
@api.depends('living_area', 'garden_area')
4575
def _compute_total_area(self):
4676
for record in self:
@@ -60,36 +90,16 @@ def _onchange_garden(self):
6090
self.garden_orientation = None
6191
self.garden_area = 0
6292

63-
def cancel_property_sale(self):
64-
for record in self:
65-
if record.state == 'sold':
66-
raise exceptions.UserError('A sold property cannot be cancelled')
67-
else:
68-
record.state = 'cancelled'
69-
return True
93+
def action_cancel_property(self):
94+
if self.filtered(lambda x: x.state == 'sold'):
95+
raise exceptions.UserError(_('A sold property cannot be cancelled'))
7096

71-
def set_property_sold(self):
72-
for record in self:
73-
if record.state == 'cancelled':
74-
raise exceptions.UserError('A cancelled property cannot be Sold')
75-
else:
76-
record.state = 'sold'
97+
self.state = 'cancelled'
7798
return True
7899

79-
_check_expected_price = models.Constraint(
80-
'CHECK(expected_price > 0)',
81-
'The Expected price cannot be 0 or less then 0'
82-
)
83-
84-
_check_selling_price = models.Constraint(
85-
'CHECK(selling_price >= 0)',
86-
'The Selling price cannot be less then 0'
87-
)
100+
def action_property_sold(self):
101+
if self.filtered(lambda x: x.state == 'cancelled'):
102+
raise exceptions.UserError(_('A cancelled property cannot be sold'))
88103

89-
@api.constrains('selling_price', 'buyer', 'expected_price')
90-
def _check_selling_price_90p(self):
91-
for record in self:
92-
if record.selling_price == 0:
93-
return False
94-
if float_compare((record.selling_price / record.expected_price) * 100, 90, precision_digits=2) < 0:
95-
raise exceptions.ValidationError('Selling Price should be 90% or more of expected price.')
104+
self.state = 'sold'
105+
return True

estate/models/estate_property_offer.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from odoo import models, fields, api, exceptions
1+
from odoo import models, fields, api, exceptions, _
22

33

44
class EstatePropertyOffer(models.Model):
55
_name = 'estate.property.offer'
66
_description = 'Offer to buy the property'
7+
_order = 'price desc'
78

89
price = fields.Float()
910
status = fields.Selection(
@@ -15,6 +16,12 @@ class EstatePropertyOffer(models.Model):
1516
property_id = fields.Many2one('estate_property', required=True)
1617
validity = fields.Integer(default=7)
1718
date_deadline = fields.Date(compute='_compute_offer_date_deadline', inverse='_inverse_offer_date_deadline')
19+
property_type_id = fields.Many2one(related='property_id.property_type_id')
20+
21+
_check_offer_price = models.Constraint(
22+
'CHECK(price > 0)',
23+
'Offer Price cannot be 0 or below 0'
24+
)
1825

1926
@api.depends('validity')
2027
def _compute_offer_date_deadline(self):
@@ -31,18 +38,14 @@ def _inverse_offer_date_deadline(self):
3138
def action_offer_accepted(self):
3239
for record in self:
3340
if record.property_id.buyer:
34-
raise exceptions.UserError('An another offer is already accepted')
41+
raise exceptions.UserError(_('An another offer is already accepted'))
3542
record.property_id.selling_price = record.price
3643
record.property_id.buyer = record.partner_id
44+
record.property_id.state = 'offer_accepted'
3745
record.status = 'accepted'
3846
return True
3947

4048
def action_offer_refused(self):
4149
for record in self:
4250
record.status = 'refused'
4351
return True
44-
45-
_check_offer_price = models.Constraint(
46-
'CHECK(price > 0)',
47-
'Offer Price cannot be 0 or below 0'
48-
)

estate/models/estate_property_tag.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
class EstatePropertyTag(models.Model):
55
_name = 'estate.property.tag'
66
_description = 'Tag for the property'
7+
_order = 'name'
78

89
name = fields.Char(required=True)
10+
color = fields.Integer()
911

1012
_check_unique_name = models.Constraint(
1113
'unique(name)',
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1-
from odoo import models, fields
1+
from odoo import models, fields, api
22

33

44
class EstatePropertyType(models.Model):
55
_name = 'estate.property.type'
66
_description = 'Defines the type of Real Estate Property'
7+
_order = 'name'
78

89
name = fields.Char(required=True)
10+
property_ids = fields.One2many('estate_property', 'property_type_id', string='Properties')
11+
sequence = fields.Integer(
12+
default=1,
13+
help='used to order the type based on the number of time it is used'
14+
)
15+
offer_ids = fields.One2many('estate.property.offer', 'property_type_id', string='Offers')
16+
offer_count = fields.Integer(compute='_compute_offers_count')
917

1018
_check_unique_name = models.Constraint(
1119
'unique(name)',
1220
'A tag with the same name already exists.'
1321
)
22+
23+
@api.depends('offer_ids')
24+
def _compute_offers_count(self):
25+
for record in self:
26+
record.offer_count = len(record.offer_ids)

estate/views/estate_property_offer_views.xml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
<odoo>
22
<record id="estate_property_offer_list_view" model="ir.ui.view">
3-
<field name="name">estate_property_offer_form</field>
3+
<field name="name">estate_property_offer_list</field>
44
<field name="model">estate.property.offer</field>
55
<field name="arch" type="xml">
6-
<list string="Offers">
6+
<list string="Offers" editable="bottom" decoration-success="status == 'accepted'" decoration-danger="status == 'refused'">
77
<field name="price" />
88
<field name="partner_id" string="Partner" />
99
<field name="validity" string="Validity (days)" />
1010
<field name="date_deadline" />
11-
<button name="action_offer_accepted" string="Accept" type="object" icon="fa-check"/>
12-
<button name="action_offer_refused" string="Refuse" type="object" icon="fa-close" />
13-
<field name="status" />
11+
<button name="action_offer_accepted" string="Accept" type="object" icon="fa-check"
12+
invisible="status" />
13+
<button name="action_offer_refused" string="Refuse" type="object" icon="fa-close"
14+
invisible="status" />
1415
</list>
1516
</field>
1617
</record>
@@ -32,4 +33,11 @@
3233
</form>
3334
</field>
3435
</record>
36+
37+
<record id="estaet_property_offer_view_action" model="ir.actions.act_window">
38+
<field name="name">Estate Property Offers</field>
39+
<field name="res_model">estate.property.offer</field>
40+
<field name="domain">[('property_type_id', '=', active_id)]</field>
41+
<field name="view_mode">list,form</field>
42+
</record>
3543
</odoo>

estate/views/estate_property_tag_views.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
<odoo>
2+
<record id="estate_property_tag_list_view" model="ir.ui.view">
3+
<field name="name">Tags</field>
4+
<field name="model">estate.property.tag</field>
5+
<field name="arch" type="xml">
6+
<list editable="bottom">
7+
<field name="name" />
8+
</list>
9+
</field>
10+
</record>
11+
212
<record id="estate_property_tag_action" model="ir.actions.act_window">
313
<field name="name">Property Tags</field>
414
<field name="res_model">estate.property.tag</field>

estate/views/estate_property_type_views.xml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,53 @@
11
<odoo>
2+
<record id="estate_property_type_properties_view" model="ir.ui.view">
3+
<field name="name">estate_property_type_form</field>
4+
<field name="model">estate.property.type</field>
5+
<field name="arch" type="xml">
6+
<form string="Properties">
7+
<sheet>
8+
<div class="oe_button_box" name="button_box">
9+
<button class="oe_stat_button" name="estate.estaet_property_offer_view_action"
10+
type="action" >
11+
<div class="o_stat_info">
12+
<span class="o_stat_value">
13+
<field name="offer_count" />
14+
</span>
15+
<span class="o_stat_text">
16+
Offers
17+
</span>
18+
</div>
19+
</button>
20+
</div>
21+
<h1>
22+
<field name="name" />
23+
</h1>
24+
<notebook>
25+
<page string="Properties">
26+
<field name="property_ids">
27+
<list>
28+
<field name="name" string="Title" />
29+
<field name="expected_price" />
30+
<field name="state" string="Status" />
31+
</list>
32+
</field>
33+
</page>
34+
</notebook>
35+
</sheet>
36+
</form>
37+
</field>
38+
</record>
39+
40+
<record id="estate_property_type_list_view" model="ir.ui.view">
41+
<field name="name">estate_property_type_list</field>
42+
<field name="model">estate.property.type</field>
43+
<field name="arch" type="xml">
44+
<list string="Property Types">
45+
<field name="sequence" widget="handle" />
46+
<field name="name" />
47+
</list>
48+
</field>
49+
</record>
50+
251
<record id="estate_property_type_action" model="ir.actions.act_window">
352
<field name="name">Property Types</field>
453
<field name="res_model">estate.property.type</field>

estate/views/estate_property_views.xml

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,22 @@
55
<field name="arch" type="xml">
66
<form string="Description">
77
<header>
8-
<button type="object" name="cancel_property_sale" string="Cancel" />
9-
<button type="object" name="set_property_sold" string="Sold" />
8+
<button type="object" name="action_cancel_property" string="Cancel"
9+
invisible="state in ('cancelled', 'sold')" />
10+
<button type="object" name="action_property_sold" string="Sold"
11+
invisible="state in ('cancelled', 'sold')" />
12+
<field name="state" widget="statusbar" />
1013
</header>
1114
<sheet>
1215
<h1>
1316
<field name="name" nolabel="True" />
1417
</h1>
15-
<field name="tag_ids" widget="many2many_tags" class="mb-5" />
18+
<field name="tag_ids" widget="many2many_tags" class="mb-5"
19+
options="{'color_field': 'color'}" />
1620
<group>
1721
<group>
18-
<field name="property_type_id" string="Property Type" />
22+
<field name="property_type_id" string="Property Type"
23+
options="{'no_create': true}" />
1924
<field name="postcode" />
2025
<field name="date_availability" string="Available From" />
2126
</group>
@@ -34,15 +39,16 @@
3439
<field name="facades" />
3540
<field name="garage" />
3641
<field name="garden" />
37-
<field name="garden_area" string="Garden Area (sqm)" />
38-
<field name="garden_orientation" />
39-
<field name="state" />
42+
<field name="garden_area" string="Garden Area (sqm)"
43+
invisible="not garden" />
44+
<field name="garden_orientation" invisible="not garden" />
4045
<field name="total_area" />
4146
</group>
4247
</page>
4348
<page string="Offers">
4449
<list>
45-
<field name="offer_ids" widget="one2many_list" />
50+
<field name="offer_ids" widget="one2many_list"
51+
readonly="state in ('sold', 'cancelled', 'offer_accepted')" />
4652
</list>
4753
</page>
4854
<page string="Other Info">
@@ -61,15 +67,17 @@
6167
<field name="name">Properties List</field>
6268
<field name="model">estate_property</field>
6369
<field name="arch" type="xml">
64-
<list string="Properties">
70+
<list string="Properties" decoration-success="offer_ids and state != 'sold'"
71+
decoration-bf="state == 'offer_accepted'" decoration-muted="state == 'sold'">
6572
<field name="name" string="Title" />
6673
<field name="postcode" />
74+
<field name="tag_ids" widget="many2many_tags" />
6775
<field name="property_type_id" />
6876
<field name="bedrooms" />
6977
<field name="living_area" string="Living Area (sqm)" />
7078
<field name="expected_price" />
7179
<field name="selling_price" />
72-
<field name="date_availability" string="Available From" />
80+
<field name="date_availability" string="Available From" optional="hide" />
7381
</list>
7482
</field>
7583
</record>
@@ -83,7 +91,8 @@
8391
<field name="postcode" />
8492
<field name="expected_price" />
8593
<field name="bedrooms" />
86-
<field name="living_area" string="Living Area (sqm)" />
94+
<field name="living_area" string="Living Area (sqm)"
95+
filter_domain="[('living_area', '&gt;=', self)]" />
8796
<field name="facades" />
8897
<field name="property_type_id" string="Type" />
8998
<filter name="available" string="Available"
@@ -96,6 +105,7 @@
96105
<record id="estate_property_action" model="ir.actions.act_window">
97106
<field name="name">Properties</field>
98107
<field name="res_model">estate_property</field>
108+
<field name="context">{'search_default_available': True}</field>
99109
<field name="view_mode">list,form</field>
100110
</record>
101111
</odoo>

0 commit comments

Comments
 (0)