Skip to content

Commit 58239c2

Browse files
committed
[IMP] estate, estate_account: implement data access restrictions and module data
- Added security groups, access rights, and record rules to both estate and estate_account modules. - Defined and updated security XML files: created agent and manager groups, set appropriate access permissions for each model. - Added record rules to restrict agents to their own properties and ensure managers have global access. - Populated initial group and access data using XML data files. - Updated module manifests to reference new security and data files. - estate_account inherits and respects estate security, and applied access rules to accounting-related features. - Create demo records for estate properties and link them to the appropriate property types. These records will be used for testing and demonstration purposes. - Add demo offers related to the demo properties, ensuring each offer is associated with a valid property and partner. - Add initial master data for property types, including Residential, Commercial, Industrial, and Land. This provides the base categories for estate properties.
1 parent 756fc9e commit 58239c2

18 files changed

+289
-189
lines changed

estate/__init__.py

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

estate/__manifest__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
{
22
'name': "Real Estate",
33
'summary': "This is real estate module",
4-
'category': "Tutorials",
4+
'category': "Real Estate/Brokerage",
55
'description': "This is real estate module",
66
'author': "Dhruvrajsinh Zala (zadh)",
77
'installable': True,
88
'application': True,
9-
'data': ['security/ir.model.access.csv', 'views/estate_property_views.xml', 'views/estate_property_offers.xml', 'views/estate_property_type_views.xml', 'views/estate_property_tags.xml', 'views/res_users_views.xml', 'views/estate_menus.xml'],
9+
'data': ['security/security.xml', 'security/ir.model.access.csv', 'views/estate_property_views.xml', 'views/estate_property_offers.xml', 'views/estate_property_type_views.xml', 'views/estate_property_tags.xml', 'views/res_users_views.xml', 'views/estate_menus.xml', 'data/estate.property.types.csv'],
10+
'demo': ['demo/demo_data.xml'],
1011
'license': 'AGPL-3'
1112
}

estate/data/estate.property.types.csv

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
id,name
2+
property_type_residential,Residential
3+
property_type_commercial,Commercial
4+
property_type_industrial,Industrial
5+
property_type_land,Land

estate/demo/demo_data.xml

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<odoo>
2+
<record id="property_big_villa" model="estate.property">
3+
<field name="name">Big Villa</field>
4+
<field name="state">new</field>
5+
<field name="description">A nice and big villa</field>
6+
<field name="postcode">12345</field>
7+
<field name="date_availability">2020-02-02</field>
8+
<field name="expected_price">1600000</field>
9+
<field name="selling_price">1600000</field>
10+
<field name="bedrooms">6</field>
11+
<field name="living_area">100</field>
12+
<field name="facades">4</field>
13+
<field name="garage">True</field>
14+
<field name="garden">True</field>
15+
<field name="garden_area">100000</field>
16+
<field name="garden_orientation">south</field>
17+
<field name="property_type_id" ref="property_type_residential"/>
18+
</record>
19+
<record id="property_trailer_home" model="estate.property">
20+
<field name="name">Trailer home</field>
21+
<field name="state">cancelled</field>
22+
<field name="description">Home in a trailer park</field>
23+
<field name="postcode">54321</field>
24+
<field name="date_availability">1970-01-01</field>
25+
<field name="expected_price">100000</field>
26+
<field name="bedrooms">1</field>
27+
<field name="living_area">10</field>
28+
<field name="facades">4</field>
29+
<field name="garage">False</field>
30+
<field name="garden">True</field>
31+
<field name="property_type_id" ref="property_type_residential"/>
32+
</record>
33+
<record id="property_with_offers" model="estate.property">
34+
<field name="name">Property with Offers</field>
35+
<field name="state">new</field>
36+
<field name="description">Villa with Offers</field>
37+
<field name="postcode">12345</field>
38+
<field name="date_availability">2021-07-07</field>
39+
<field name="expected_price">3600000</field>
40+
<field name="selling_price">3600000</field>
41+
<field name="bedrooms">7</field>
42+
<field name="living_area">150</field>
43+
<field name="facades">6</field>
44+
<field name="garage">True</field>
45+
<field name="garden">True</field>
46+
<field name="garden_area">200000</field>
47+
<field name="garden_orientation">south</field>
48+
<field name="property_type_id" ref="property_type_residential"/>
49+
<field name="offer_ids" eval="[Command.create({'partner_id': ref('base.res_partner_2'), 'price': 50000, 'validity': 10}), Command.create({'partner_id': ref('base.res_partner_3'), 'price': 60000, 'validity': 15})]"/>
50+
</record>
51+
<record id="offer1" model="estate.property.offer">
52+
<field name="partner_id" ref="base.res_partner_2"/>
53+
<field name="property_id" ref="property_big_villa"/>
54+
<field name="price">1000</field>
55+
<field name="validity">14</field>
56+
<field name="date_deadline" eval="(DateTime.today() + timedelta(days=14)).strftime('%Y-%m-%d')" />
57+
</record>
58+
<record id="offer2" model="estate.property.offer">
59+
<field name="partner_id" ref="base.res_partner_2"/>
60+
<field name="property_id" ref="property_big_villa"/>
61+
<field name="price">1500000</field>
62+
<field name="validity">14</field>
63+
<field name="date_deadline" />
64+
<field name="date_deadline" eval="(DateTime.today() + timedelta(days=14)).strftime('%Y-%m-%d')" />
65+
</record>
66+
<record id="offer3" model="estate.property.offer">
67+
<field name="partner_id" ref="base.res_partner_3"/>
68+
<field name="property_id" ref="property_big_villa"/>
69+
<field name="price">1500001</field>
70+
<field name="validity">14</field>
71+
<field name="date_deadline" />
72+
<field name="date_deadline" eval="(DateTime.today() + timedelta(days=14)).strftime('%Y-%m-%d')" />
73+
</record>
74+
<record id="offer11" model="estate.property.offer">
75+
<field name="partner_id" ref="base.res_partner_2"/>
76+
<field name="property_id" ref="property_trailer_home"/>
77+
<field name="price">1000</field>
78+
<field name="validity">14</field>
79+
<field name="date_deadline" eval="(DateTime.today() + timedelta(days=14)).strftime('%Y-%m-%d')" />
80+
</record>
81+
<record id="offer12" model="estate.property.offer">
82+
<field name="partner_id" ref="base.res_partner_2"/>
83+
<field name="property_id" ref="property_trailer_home"/>
84+
<field name="price">1500000</field>
85+
<field name="validity">14</field>
86+
<field name="date_deadline" />
87+
<field name="date_deadline" eval="(DateTime.today() + timedelta(days=14)).strftime('%Y-%m-%d')" />
88+
</record>
89+
<record id="offer13" model="estate.property.offer">
90+
<field name="partner_id" ref="base.res_partner_3"/>
91+
<field name="property_id" ref="property_trailer_home"/>
92+
<field name="price">1500001</field>
93+
<field name="validity">14</field>
94+
<field name="date_deadline" />
95+
<field name="date_deadline" eval="(DateTime.today() + timedelta(days=14)).strftime('%Y-%m-%d')" />
96+
</record>
97+
<function model="estate.property.offer" name="action_accept_offer">
98+
<value eval="[ref('offer12')]"/>
99+
</function>
100+
<function model="estate.property.offer" name="action_refuse_offer">
101+
<value eval="[ref('offer11'), ref('offer13')]"/>
102+
</function>
103+
</odoo>

estate/models/esatate_property_type.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ class EstatePropertyTyeps(models.Model):
1010
("_unique_type_name", "UNIQUE(name)", "Property type name must be unique.")
1111
]
1212

13-
name = fields.Char(required=True)
13+
name = fields.Char(required=True, string="Title")
1414
property_ids = fields.One2many(
1515
"estate.property", "property_type_id", string="Properties"
1616
)
17-
sequence = fields.Integer(default=1)
17+
sequence = fields.Integer(default=1 ,string="sequence")
1818

1919
offer_ids = fields.One2many(
2020
"estate.property.offer", "property_type_id", string="Offers"

estate/models/estate_property.py

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -23,39 +23,28 @@ class EstateProperty(models.Model):
2323
]
2424

2525
name = fields.Char(required=True, string="Title")
26-
description = fields.Text()
27-
postcode = fields.Char()
26+
description = fields.Text(string="Description")
27+
postcode = fields.Char(string="Postcode")
2828
date_availability = fields.Date(
2929
default=lambda self: fields.Date.today() + relativedelta(months=3),
3030
copy=False,
3131
string="Available From",
3232
)
33-
expected_price = fields.Float(required=True)
34-
selling_price = fields.Float(readonly=True, copy=False)
35-
bedrooms = fields.Integer(default=2)
33+
expected_price = fields.Float(required=True, string="Expected Price")
34+
selling_price = fields.Float(readonly=True, copy=False, string="Selling Price")
35+
bedrooms = fields.Integer(default=2, string="Bedrooms")
3636
living_area = fields.Integer(string="Living Area (sqm)")
37-
total_area = fields.Float(compute="_compute_total_area", store=True)
38-
facades = fields.Integer()
39-
garage = fields.Boolean()
40-
garden = fields.Boolean()
37+
total_area = fields.Float(compute="_compute_total_area", store=True, string="Total Area")
38+
facades = fields.Integer(string="Facades")
39+
garage = fields.Boolean(string="Garage")
40+
garden = fields.Boolean(string="Garden")
4141
garden_area = fields.Integer(string="Garden Area (sqm)")
42-
active = fields.Boolean(default=True)
42+
active = fields.Boolean(default=True, string="Active")
4343
garden_orientation = fields.Selection(
4444
[("north", "North"), ("south", "South"), ("east", "East"), ("west", "West")],
4545
string="Garden Orientation",
4646
)
47-
state = fields.Selection(
48-
[
49-
("new", "New"),
50-
("offer_received", "Offer Received"),
51-
("offer_accepted", "Offer Accepted"),
52-
("sold", "Sold"),
53-
("cancelled", "Cancelled"),
54-
],
55-
required=True,
56-
copy=False,
57-
default="new",
58-
)
47+
state = fields.Selection([("new", "New"), ("offer_received", "Offer Received"), ("offer_accepted", "Offer Accepted"), ("sold", "Sold"), ("cancelled", "Cancelled")], required=True, copy=False, default="new", string="State")
5948
property_type_id = fields.Many2one("estate.property.types", string="Property Type")
6049
buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False)
6150
salesperson_id = fields.Many2one(
@@ -65,15 +54,15 @@ class EstateProperty(models.Model):
6554

6655
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers")
6756

68-
best_price = fields.Float(compute="_get_best_offer_price", store=True)
57+
best_price = fields.Float(compute="_get_best_offer_price", store=True, string="Best Price")
58+
59+
company_id = fields.Many2one('res.company', required=True, default=lambda self: self.env.company)
6960

7061
@api.ondelete(at_uninstall=False)
7162
def _unlink_except_state_new_or_cancelled(self):
7263
for record in self:
7364
if record.state not in ["new", "cancelled"]:
74-
raise UserError(
75-
_("You can only delete properties in 'New' or 'Cancelled' state.")
76-
)
65+
raise UserError(_("You can only delete properties in 'New' or 'Cancelled' state."))
7766

7867
@api.depends("living_area", "garden_area")
7968
def _compute_total_area(self):
@@ -116,16 +105,5 @@ def action_set_state_cancel(self):
116105
def _check_selling_price(self):
117106
for record in self:
118107
if not float_is_zero(record.selling_price, precision_digits=2):
119-
if (
120-
float_compare(
121-
record.selling_price,
122-
record.expected_price * 0.9,
123-
precision_digits=2,
124-
)
125-
< 0
126-
):
127-
raise ValidationError(
128-
_(
129-
"The selling price cannot be lower than 90% of the expected price"
130-
)
131-
)
108+
if float_compare(record.selling_price, record.expected_price * 0.9, precision_digits=2 ) < 0 :
109+
raise ValidationError(_("The selling price cannot be lower than 90% of the expected price"))

estate/models/estate_property_offer.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ class EstatePropertyOffer(models.Model):
1111
("_check_offer_price", "CHECK(price > 0)", "The Offer price must be positive.")
1212
]
1313

14-
price = fields.Float()
14+
price = fields.Float(string="Price")
1515
status = fields.Selection(
16-
[("accepted", "Accepted"), ("refused", "Refused")], copy=False
16+
[("accepted", "Accepted"), ("refused", "Refused")], copy=False, string="Status"
1717
)
1818
partner_id = fields.Many2one("res.partner", string="Partner", required=True)
1919
property_id = fields.Many2one("estate.property", string="Property", required=True)
@@ -23,10 +23,8 @@ class EstatePropertyOffer(models.Model):
2323
string="Property Type",
2424
required=True,
2525
)
26-
validity = fields.Integer(default=7)
27-
date_deadline = fields.Date(
28-
compute="_compute_deadline", inverse="_inverse_deadline", store=True
29-
)
26+
validity = fields.Integer(default=7, string="Validity")
27+
date_deadline = fields.Date(compute="_compute_deadline", inverse="_inverse_deadline", store=True, string="Deadline Date")
3028

3129
@api.model_create_multi
3230
def create(self, vals):
@@ -46,11 +44,7 @@ def create(self, vals):
4644
max_price = result[0]["price"] if result else 0
4745

4846
if max_price >= offer_price:
49-
raise UserError(
50-
_(
51-
"You cannot create an offer with a lower or equal amount than an existing offer for this property."
52-
)
53-
)
47+
raise UserError(_("You cannot create an offer with a lower or equal amount than an existing offer for this property."))
5448

5549
if is_state_new:
5650
self.env["estate.property"].browse(property_id).state = "offer_received"

estate/models/estate_property_tags.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ class EstatePropertyTags(models.Model):
1010
("_unique_tag_name", "UNIQUE(name)", "Tag name must be unique.")
1111
]
1212

13-
name = fields.Char(required=True)
14-
color = fields.Integer(default=3)
13+
name = fields.Char(required=True, string="Title")
14+
color = fields.Integer(default=3, string="Color")

estate/security/ir.model.access.csv

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2-
estate.access_estate_property,access_estate_property,estate.model_estate_property,base.group_user,1,1,1,1
3-
estate.access_estate_property_types,access_estate_property_types,estate.model_estate_property_types,base.group_user,1,1,1,1
4-
estate.access_estate_property_tags,access_estate_property_tags,estate.model_estate_property_tags,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
2+
estate.access_estate_property_manager,access_estate_property_manager,estate.model_estate_property,estate.estate_group_manager,1,1,1,0
3+
estate.access_estate_property_agent,access_estate_property_agent,estate.model_estate_property,estate.estate_group_agent,1,1,1,0
4+
estate.access_estate_property_types_manager,access_estate_property_types_manager,estate.model_estate_property_types,estate.estate_group_manager,1,1,1,0
5+
estate.access_estate_property_types_agent,access_estate_property_types_agent,estate.model_estate_property_types,estate.estate_group_agent,1,0,0,0
6+
estate.access_estate_property_tags_manager,access_estate_property_tags_manager,estate.model_estate_property_tags,estate.estate_group_manager,1,1,1,0
7+
estate.access_estate_property_tags_agent,access_estate_property_tags_agent,estate.model_estate_property_tags,estate.estate_group_agent,1,0,0,0
8+
estate.access_estate_property_offer_manager,access_estate_property_offer_manager,estate.model_estate_property_offer,estate.estate_group_manager,1,1,1,0
9+
estate.access_estate_property_offer_agent,access_estate_property_offer_agent,estate.model_estate_property_offer,estate.estate_group_agent,1,1,1,0

estate/security/security.xml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<odoo>
2+
<record id="estate_group_agent" model="res.groups">
3+
<field name="name">Agent</field>
4+
<field name="category_id" ref="base.module_category_real_estate_brokerage" />
5+
</record>
6+
<record id="estate_group_manager" model="res.groups">
7+
<field name="name">Manager</field>
8+
<field name="category_id" ref="base.module_category_real_estate_brokerage"/>
9+
<field name="implied_ids" eval="[(4,ref('estate_group_agent'))]"/>
10+
</record>
11+
<record id="estate_property_agent_rule" model="ir.rule">
12+
<field name="name">Agent: Own or Unassigned Properties</field>
13+
<field name="model_id" ref="model_estate_property"/>
14+
<field name="groups" eval="[(4,ref('estate.estate_group_agent'))]"/>
15+
<field name="domain_force">
16+
['|',('salesperson_id','=',user.id),('salesperson_id','=',0)]
17+
</field>
18+
<field name="perm_read" eval="1"/>
19+
<field name="perm_write" eval="1"/>
20+
<field name="perm_create" eval="1"/>
21+
<field name="perm_unlink" eval="0"/>
22+
</record>
23+
<record id="estate_property_manager_rule" model="ir.rule">
24+
<field name="name">Manager: All Properties</field>
25+
<field name="model_id" ref="estate.model_estate_property"/>
26+
<field name="groups" eval="[(4, ref('estate.estate_group_manager'))]"/>
27+
<field name="domain_force">[(1,'=',1)]</field>
28+
<field name="perm_read" eval="1"/>
29+
<field name="perm_write" eval="1"/>
30+
<field name="perm_create" eval="1"/>
31+
<field name="perm_unlink" eval="0"/>
32+
</record>
33+
<record id="estate_property_company_rule" model="ir.rule">
34+
<field name="name">Estate Property: Multi-company</field>
35+
<field name="model_id" ref="model_estate_property"/>
36+
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
37+
<field name="perm_read" eval="True"/>
38+
<field name="perm_write" eval="True"/>
39+
<field name="perm_create" eval="True"/>
40+
<field name="perm_unlink" eval="True"/>
41+
</record>
42+
</odoo>

0 commit comments

Comments
 (0)