Skip to content

Commit 63068b7

Browse files
committed
[ADD] real_estate: Property maintenance requests and validations
- Created maintenance request model linked to property - Added status workflow - Validated approved maintenance cost - Computed total maintenance cost on property - Blocked property sale if any maintenance request is not done - Blocked deletion of properties and maintenance when maintenance is not done
1 parent fedc96f commit 63068b7

8 files changed

+172
-41
lines changed

real_estate/__manifest__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
'security/ir.model.access.csv',
1111
'views/real_estate_properties_offer_views.xml',
1212
'views/real_estate_properties_views.xml',
13-
'views/real_estate_tag_views.xml',
1413
'views/real_estate_property_type.xml',
14+
'views/real_estate_tag_views.xml',
15+
'views/real_estate_properties_maintenance_request_view.xml',
1516
'views/real_estate_menus.xml',
1617
],
1718
'application': True,

real_estate/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
from . import real_estate_tag
33
from . import real_estate_property_offer
44
from . import real_estate_property_type
5+
from . import real_estate_properties_maintenance_request

real_estate/models/real_estate_properties.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
class real_estate(models.Model):
99
_name = 'real.estate'
1010
_description = 'Real Estate Property'
11+
_order = "id desc"
1112

12-
name = fields.Char(default="Unknown", required=True)
13+
name = fields.Char(required=True)
1314
property_type_id = fields.Many2one(
1415
"real.estate.property.type", string="Property Type")
1516
street_address = fields.Char()
@@ -36,6 +37,7 @@ class real_estate(models.Model):
3637
offer_ids = fields.One2many(
3738
"real.estate.property.offer", "property_id", string="Offers")
3839
total_area = fields.Float(compute="_compute_total", store=True)
40+
total_area_square = fields.Float(compute="_compute_total_area_square", store=True)
3941
best_price = fields.Float(
4042
string="Best Offer",
4143
compute="_compute_best_price",
@@ -56,6 +58,9 @@ class real_estate(models.Model):
5658
string='Buyer',
5759
copy=False)
5860
selling_price = fields.Float()
61+
maintenance_request_ids = fields.One2many(
62+
"real.estate.property.maintenance.request", "property_id", string="Maintenance Requests")
63+
total_maintenance_cost = fields.Float(compute="_compute_total_maintenance_cost", store=True)
5964
_check_expected_price_positive = models.Constraint(
6065
'CHECK(expected_price > 0)',
6166
'The expected price must be strictly positive.',
@@ -80,11 +85,22 @@ def _compute_best_price(self):
8085
prices = record.offer_ids.mapped('price')
8186
record.best_price = max(prices) if prices else 0.0
8287

88+
@api.depends('maintenance_request_ids.cost')
89+
def _compute_total_maintenance_cost(self):
90+
for record in self:
91+
costs = record.maintenance_request_ids.mapped('cost')
92+
record.total_maintenance_cost = sum(costs) if costs else 0.0
93+
8394
@api.depends('living_area', 'garden_area')
8495
def _compute_total(self):
8596
for record in self:
8697
record.total_area = (record.living_area or 0) + (record.garden_area or 0)
8798

99+
@api.depends("total_area")
100+
def _compute_total_area_square(self):
101+
for record in self:
102+
record.total_area_square = (record.total_area or 0) ** 2
103+
88104
@api.onchange('garden')
89105
def _onchange_garden(self):
90106
if self.garden:
@@ -96,10 +112,9 @@ def _onchange_garden(self):
96112

97113
@api.ondelete(at_uninstall=False)
98114
def _unlink_if_accepted_offer(self):
99-
for record in self:
100-
for offer in record.offer_ids:
101-
if offer.status == 'accepted':
102-
raise UserError("Can't delete an active record!")
115+
accepted_offer = self.offer_ids.filtered_domain([('status', '=', 'accepted')])
116+
if accepted_offer:
117+
raise UserError("Can't delete an active record!")
103118

104119
# @api.depends('create_date')
105120
# def _compute_create_date_ist(self):
@@ -120,4 +135,7 @@ def action_cancel(self):
120135
def action_sold(self):
121136
if self.stage == 'cancelled':
122137
raise UserError("A cancelled property cannot be sold.")
138+
maintenace_request = self.maintenance_request_ids.filtered_domain([('status', '!=', 'done')])
139+
if maintenace_request:
140+
raise UserError("CProperty cannot be sold , there is any maintenance request not done")
123141
self.stage = 'sold'
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from odoo.exceptions import UserError
2+
3+
from odoo import fields, models, api
4+
5+
6+
class real_estate_properties_maintenance_request(models.Model):
7+
_name = 'real.estate.property.maintenance.request'
8+
_description = 'Real Estate Property Maintenance Request'
9+
10+
name = fields.Char()
11+
cost = fields.Integer()
12+
status = fields.Selection([
13+
('new', 'New'),
14+
('approved', 'Approved'),
15+
('done', 'Done'),
16+
], string="Status", copy=False, default='new')
17+
property_id = fields.Many2one('real.estate', string='Property', ondelete='restrict')
18+
19+
@api.onchange('status')
20+
def _check_cost_on_accepted_status(self):
21+
if self.status == 'approved' and self.cost <= 0:
22+
raise UserError(" Maintenance Request Approved cost must be greater than 0")
23+
24+
@api.ondelete(at_uninstall=False)
25+
def _unlink_if_maintenance_request_not_done(self):
26+
maintenace_request = self.filtered_domain([('status', '!=', 'done')])
27+
if maintenace_request:
28+
raise UserError("Can't delete an active Maintenance Request Record.")

real_estate/security/ir.model.access.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ real_estate,real_estate,model_real_estate,base.group_user,1,1,1,1
33
real_estate_tag,real_estate_tag,model_real_estate_tag,base.group_user,1,1,1,1
44
real_estate_property_offer,real_estate_property_offer,model_real_estate_property_offer,base.group_user,1,1,1,1
55
real_estate_property_type,real_estate_property_type,model_real_estate_property_type,base.group_user,1,1,1,1
6+
real_estate_property_maintenance_request,real_estate_property_maintenance_request,model_real_estate_property_maintenance_request,base.group_user,1,1,1,1
67
,,,,,,,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
<odoo>
22

33
<menuitem id="real_estate_menu" name="Real Estate"/>
4+
45
<menuitem id="real_estate_menu_Advertisements" name="Advertisements" parent="real_estate_menu" sequence="265"/>
6+
57
<menuitem id="real_estate_menu_properties" name="Properties" parent="real_estate_menu_Advertisements"
68
action="real_estate_action_view"/>
9+
710
<menuitem id="real_estate_menu_configuration" name="configuration" parent="real_estate_menu" sequence="267"/>
11+
812
<menuitem id="real_estate_menu_property_offer"
913
name="Property Offers"
1014
parent="real_estate_menu_Advertisements"
1115
action="real_estate_property_offer_action_view"/>
16+
1217
<menuitem id="rewal_estate_menu_tag"
1318
name="Property Tags"
1419
parent="real_estate_menu_configuration"
1520
action="real_estate_tag_action_view"/>
21+
1622
<menuitem id="real_estate_menu_property_type"
1723
name="Property Type"
1824
parent="real_estate_menu_configuration"
1925
action="real_estate_property_type_action_view"/>
2026

27+
<menuitem id="real_estate_menu_property_maintenance_request"
28+
name="Maintenance Request"
29+
parent="real_estate_menu_configuration"
30+
action="real_estate_property_maintenance_request_action_view"/>
31+
2132
</odoo>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<odoo>
2+
3+
<record id="real_estate_property_maintenance_request_view_tree" model="ir.ui.view">
4+
<field name="name">real.estate.property.maintenance.request.view.tree</field>
5+
<field name="model">real.estate.property.maintenance.request</field>
6+
<field name="arch" type="xml">
7+
<list>
8+
<field name="name"/>
9+
<field name="cost"/>
10+
<field name="status"/>
11+
<field name="property_id"/>
12+
</list>
13+
</field>
14+
</record>
15+
16+
<record id="real_estate_property_maintenance_request_view_form" model="ir.ui.view">
17+
<field name="name">real.estate.property.maintenance.request.view.form</field>
18+
<field name="model">real.estate.property.maintenance.request</field>
19+
<field name="arch" type="xml">
20+
<form>
21+
<header>
22+
<field name="status" widget="statusbar"
23+
options="{'clickable': 1}"
24+
statusbar_visible="new,approved, done"/>
25+
</header>
26+
<sheet>
27+
<group>
28+
<field name="name"/>
29+
<field name="cost"/>
30+
<field name="property_id" required="1"/>
31+
</group>
32+
</sheet>
33+
</form>
34+
</field>
35+
</record>
36+
37+
<record id="real_estate_property_maintenance_request_action_view" model="ir.actions.act_window">
38+
<field name="name">Maintenance request</field>
39+
<field name="res_model">real.estate.property.maintenance.request</field>
40+
<field name="view_mode">list,form</field>
41+
</record>
42+
43+
</odoo>

real_estate/views/real_estate_properties_views.xml

Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
<field name="name">real.estate.view.list</field>
55
<field name="model">real.estate</field>
66
<field name="arch" type="xml">
7-
<list>
7+
<list
8+
decoration-success="stage in ('offer_received', 'offer_accepted')"
9+
decoration-bf="stage == 'offer_accepted'"
10+
decoration-muted="stage == 'sold'">
811
<field name="name"/>
912
<field name="postcode"/>
10-
<field name="date_availability"/>
13+
<field name="date_availability" optional="hide"/>
1114
<field name="expected_price"/>
1215
<field name="selling_price"/>
13-
<field name="tag_ids" widget="many2many_tags"/>
16+
<field name="tag_ids" widget="many2many_tags" optional="show"/>
1417
<field name="best_price"/>
1518
<field name="total_area"/>
1619
</list>
@@ -24,16 +27,18 @@
2427
<form>
2528
<header>
2629
<button
27-
name="action_sold"
28-
type="object"
29-
string="Sold"
30-
class="btn-primary"
30+
name="action_sold"
31+
type="object"
32+
string="Sold"
33+
class="btn-primary"
34+
invisible="stage in ('sold', 'cancelled')"
3135
/>
3236
<button
33-
name="action_cancel"
34-
type="object"
35-
string="Cancel"
36-
class="btn-secondary"
37+
name="action_cancel"
38+
type="object"
39+
string="Cancel"
40+
class="btn-secondary"
41+
invisible="stage in ('sold', 'cancelled')"
3742
/>
3843
<field name="stage" widget="statusbar"
3944
options="{'clickable': False}"
@@ -43,15 +48,12 @@
4348
<group>
4449
<group>
4550
<field name="name"/>
46-
<field name="property_type_id"/>
51+
<field name="property_type_id" options="{'no_create': True, 'no_create_edit': True}"/>
4752
<field name="postcode"/>
4853
<field name="date_availability"/>
49-
<field name="living_area"/>
50-
<field name="garden_area"/>
51-
<field name="total_area" readonly="1"/>
5254
</group>
5355
<group>
54-
<field name="tag_ids" widget="many2many_tags"/>
56+
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}"/>
5557
<field name="expected_price"/>
5658
<field name="best_price" readonly="1"/>
5759
</group>
@@ -64,12 +66,18 @@
6466
</page>
6567
<page string="Extra Info">
6668
<group>
67-
<group string="Email">
69+
<group string="Property Features">
6870
<field name="garage"/>
6971
<field name="garden"/>
70-
<field name="garden_orientation"/>
72+
<field name="garden_orientation" invisible="not garden"/>
73+
<field name="garden_area" invisible="not garden"/>
7174
</group>
72-
<group string="Marketing">
75+
<group string="Area Details">
76+
<field name="living_area"/>
77+
<field name="total_area"/>
78+
<field name="total_area_square"/>
79+
</group>
80+
<group string="Interior Details">
7381
<field name="bedrooms"/>
7482
<field name="bathrooms"/>
7583
<field name="facades"/>
@@ -78,9 +86,22 @@
7886
</page>
7987
<page string="Offers">
8088
<group>
81-
<field name="offer_ids" nolabel="0"/>
89+
<field name="offer_ids" readonly="stage in ('offer_accepted', 'sold', 'cancelled')"/>
8290
</group>
8391
</page>
92+
<page string="Maintenance Requests">
93+
<group>
94+
<field name="maintenance_request_ids">
95+
<list editable="bottom">
96+
<field name="name"/>
97+
<field name="cost"/>
98+
<field name="status"/>
99+
</list>
100+
</field>
101+
<field name="total_maintenance_cost"/>
102+
</group>
103+
</page>
104+
84105
<page string="Other Info">
85106
<group>
86107
<field name="selling_price" readonly="1"/>
@@ -101,23 +122,31 @@
101122
<field name="name"/>
102123
<field name="best_price"/>
103124
<field name="total_area"/>
125+
<field name="living_area"
126+
filter_domain="[('living_area', '>=', self)]"/>
127+
<field name="description"
128+
filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"/>
104129
<filter
105-
string="Active"
106-
name="active_record"
107-
domain="[('active', '=', True)]"
130+
string="Active"
131+
name="active_record"
132+
domain="[('active', '=', True)]"
108133
/>
109134
<filter
110-
string="Garden orientation"
111-
name="name"
112-
domain="['|','&amp;',('garden_orientation', '=' , 'north'),
113-
('garden_orientation', '=' , 'south'),
114-
('name', '=' , 'test')]"
135+
name="In_active_record"
136+
string="IN Active"
137+
domain="[('active', '=', False)]"
138+
/>
139+
<filter
140+
string="Garden orientation"
141+
name="name"
142+
domain="['|',('garden_orientation', '=' , 'north'),
143+
('garden_orientation', '=' , 'south')]"
115144
/>
116145
<group>
117146
<filter
118-
string="Orientation"
119-
name="garden_orientation"
120-
context="{'group_by': 'garden_orientation'}"
147+
string="Orientation"
148+
name="garden_orientation"
149+
context="{'group_by': 'garden_orientation'}"
121150
/>
122151
</group>
123152
</search>
@@ -128,12 +157,11 @@
128157
<field name="name">Real Estate</field>
129158
<field name="res_model">real.estate</field>
130159
<field name="view_mode">list,form</field>
131-
<field name="context">
160+
<field name="context">
132161
{
133-
134-
'search_default_active_record': 1,
162+
'search_default_active_record': 1,
135163
}
136-
</field>
164+
</field>
137165
</record>
138166

139167
</odoo>

0 commit comments

Comments
 (0)