Skip to content

Commit d63b5b2

Browse files
committed
[IMP] real_estate: Added model relations, computed fields and action buttons
- Linked models using One2many, Many2one, and Many2many fields - Added computed fields like best_offer and offer_deadline - Implemented onchange methods for dynamic field updates - Created type='object' buttons: • Sold / Cancelled on properties • Accept / Refuse on offers
1 parent ced49e0 commit d63b5b2

14 files changed

+369
-147
lines changed

real_estate/__manifest__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
'depends': ['base'],
55
'author': "Megha Tulsyani",
66
'category': 'Ecommerce For Properties',
7-
'data' :[
7+
'data': [
88

99
'security/ir.model.access.csv',
10-
'views/real_estate_views.xml',
11-
'views/real_estate_menus.xml',
10+
'views/estate_property_views.xml',
11+
'views/estate_property_type_views.xml',
12+
"views/estate_property_tag_views.xml",
13+
"views/estate_property_offer_views.xml",
14+
'views/estate_property_menus.xml'
1215
],
1316
'license': 'LGPL-3',
1417
'installable': True,

real_estate/models/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
from . import real_estate
1+
from . import estate_property
2+
from . import estate_property_offers
3+
from . import estate_property_tags
4+
from . import estate_property_types

real_estate/models/estate_property.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
from odoo import api, fields, models
2+
from dateutil.relativedelta import relativedelta
3+
from odoo.exceptions import UserError
4+
5+
6+
class EstateProperty(models.Model):
7+
_name = "estate.property"
8+
_description = "This is a real estate module"
9+
10+
name = fields.Char(required=True)
11+
description = fields.Text()
12+
postcode = fields.Char()
13+
expected_price = fields.Float(required=True)
14+
selling_price = fields.Float(readonly=True, copy=False)
15+
bedrooms = fields.Integer(default=2)
16+
living_area = fields.Integer(string="Living Area (sqm)")
17+
facades = fields.Integer()
18+
garage = fields.Boolean()
19+
garden = fields.Boolean()
20+
garden_area = fields.Integer()
21+
active = fields.Boolean(default=True)
22+
buyer_id = fields.Many2one(comodel_name="res.partner", string="Buyer", copy=False)
23+
total_area = fields.Float(compute='_compute_total_area', string="Total Area" )
24+
best_offer = fields.Float(compute='_compute_best_price',string="Best Offer")
25+
date_availability = fields.Date(
26+
string="Availability From",
27+
default=lambda self: fields.Date.today() + relativedelta(months=3),
28+
copy=False,
29+
)
30+
estate_property_offer_ids = fields.One2many(
31+
comodel_name="estate.property.offers",
32+
inverse_name="property_id",
33+
string="Offers",
34+
)
35+
seller_id = fields.Many2one(
36+
comodel_name="res.users",
37+
string="SalesPerson",
38+
default=lambda self: self.env.user,
39+
)
40+
estate_property_type_id = fields.Many2one(
41+
comodel_name="estate.property.types", string="Property Type"
42+
)
43+
estate_property_tag_ids = fields.Many2many(
44+
comodel_name="estate.property.tags",
45+
string="Tags"
46+
)
47+
garden_orientation = fields.Selection(
48+
selection=[
49+
("north", "North"),
50+
("south", "South"),
51+
("east", "East"),
52+
("west", "West"),
53+
]
54+
)
55+
state = fields.Selection(
56+
selection=[
57+
("new", "New"),
58+
("offer_received", "Offer Received"),
59+
("offer_accepted", "Offer Accepted"),
60+
("sold", "Sold"),
61+
("cancelled", "Cancelled"),
62+
],
63+
copy=False,
64+
required=True,
65+
default="new",
66+
)
67+
68+
@api.depends('living_area','garden_area')
69+
def _compute_total_area(self):
70+
for record in self:
71+
record.total_area = record.living_area + record.garden_area
72+
73+
74+
@api.depends('estate_property_offer_ids')
75+
def _compute_best_price(self):
76+
for record in self:
77+
prices = record.estate_property_offer_ids.mapped("price")
78+
record.best_offer = max(prices) if prices else 0.0
79+
80+
@api.onchange("garden")
81+
def _onchange_garden(self):
82+
if self.garden:
83+
self.garden_area = 10
84+
self.garden_orientation = "north"
85+
else:
86+
self.garden_area = 0
87+
self.garden_orientation = False
88+
89+
90+
def action_sold(self):
91+
for record in self:
92+
if record.state == 'cancelled':
93+
raise UserError("You cannot mark a cancelled property as sold.")
94+
record.state = 'sold'
95+
96+
def action_cancel(self):
97+
for record in self:
98+
if record.state == 'sold':
99+
raise UserError("You cannot mark a sold property as cancelled.")
100+
record.state = 'cancelled'
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from odoo import api, fields, models
2+
from odoo.exceptions import UserError
3+
4+
5+
class EstatePropertyOffers(models.Model):
6+
_name = "estate.property.offers"
7+
_description = "Estate Property Offers"
8+
9+
price = fields.Float()
10+
partner_id = fields.Many2one(comodel_name="res.partner", required=True)
11+
property_id = fields.Many2one(comodel_name="estate.property", required=True)
12+
validity = fields.Integer(default='7')
13+
offer_deadline = fields.Date(
14+
compute='_compute_date_deadline',
15+
inverse='_inverse_date_deadline'
16+
)
17+
status = fields.Selection(
18+
selection=[
19+
("accepted", "Accepted"),
20+
("refused", "Refused")
21+
]
22+
)
23+
24+
@api.depends('create_date', 'validity')
25+
def _compute_date_deadline(self):
26+
for record in self:
27+
if record.create_date and record.validity:
28+
record.offer_deadline = fields.Date.add(record.create_date, days=record.validity)
29+
else:
30+
record.offer_deadline = fields.Date.add(fields.Date.today(), days=record.validity)
31+
32+
def _inverse_date_deadline(self):
33+
for record in self:
34+
if record.create_date and record.offer_deadline:
35+
record.validity = (record.offer_deadline - fields.Date.to_date(record.create_date)).days
36+
37+
def action_accept_offer(self):
38+
for offer in self:
39+
accepted_offer = self.env['estate.property.offers'].search([
40+
('property_id', '=', offer.property_id.id),
41+
('status', '=', 'accepted')
42+
])
43+
if accepted_offer:
44+
raise UserError("Only one offer can be accepted per property.")
45+
offer.status = 'accepted'
46+
offer.property_id.selling_price = offer.price
47+
offer.property_id.buyer_id = offer.partner_id
48+
offer.property_id.state = 'offer_accepted'
49+
50+
def action_refuse_offer(self):
51+
for offer in self:
52+
offer.status = 'refused'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from odoo import models, fields
2+
3+
4+
class EstatePropertyTags(models.Model):
5+
_name = "estate.property.tags"
6+
_description = "Estate Property Tags"
7+
8+
name = fields.Char(required=True)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from odoo import fields, models
2+
3+
4+
class EstatePropertyTypes(models.Model):
5+
_name = "estate.property.types"
6+
_description = "Estate Property Types"
7+
8+
name = fields.Char(required=True)
9+

real_estate/models/real_estate.py

Lines changed: 0 additions & 45 deletions
This file was deleted.
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2-
real_estate.access_real_estate,access_real_estate,real_estate.model_real_estate,base.group_user,1,1,1,1
2+
real_estate.access_estate_property,access_estate_property,real_estate.model_estate_property,base.group_user,1,1,1,1
3+
real_estate.access_estate_property_types,access_estate_property_types,real_estate.model_estate_property_types,base.group_user,1,1,1,1
4+
real_estate.access_estate_property_tags,access_estate_property_tags,real_estate.model_estate_property_tags,base.group_user,1,1,1,1
5+
real_estate.access_estate_property_offers,access_estate_property_offers,real_estate.model_estate_property_offers,base.group_user,1,1,1,1
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
32
<odoo>
43
<!-- Root menu -->
5-
<menuitem id="estate_menu_root" name="Real Estate" />
4+
<menuitem id="estate_menu_root" name="Real Estate"/>
65

76
<!-- First level submenu under root -->
87
<menuitem id="estate_menu_advertisements" name="Advertisements" parent="estate_menu_root"/>
8+
<menuitem id="estate_menu_settings" name="Settings" parent="estate_menu_root"/>
99

1010
<!-- Action menu under first level -->
1111
<menuitem id="estate_property_menu_action" parent="estate_menu_advertisements" action="real_estate_main_action"/>
12+
<menuitem id="estate_property_type_menu_action" parent="estate_menu_settings" action="estate_property_type_action"/>
13+
<menuitem id="estate_property_tag_menu_action" parent="estate_menu_settings" action="estate_property_tag_action"/>
14+
1215
</odoo>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<odoo>
3+
<record id="estate_property_offer_view" model="ir.ui.view">
4+
<field name="name">estate.property.offer.list</field>
5+
<field name="model">estate.property.offers</field>
6+
<field name="arch" type="xml">
7+
<list editable="bottom">
8+
<field name="price" />
9+
<field name="partner_id" />
10+
<field name="status" />
11+
<field name="validity" string="Validity(Days)" />
12+
<field name="offer_deadline" />
13+
<button name="action_accept_offer" string="Accept" type="object" icon="fa-check" invisible="status in ('accepted','refused')"/>
14+
<button name="action_refuse_offer" string="Refuse" type="object" icon="fa-close" invisible="status in ('accepted','refused')"/>
15+
</list>
16+
</field>
17+
</record>
18+
19+
<record id="estate_property_offer_view_form" model="ir.ui.view">
20+
<field name="name">estate.property.offer.form</field>
21+
<field name="model">estate.property.offers</field>
22+
<field name="arch" type="xml">
23+
<form string="Offers">
24+
<group>
25+
<group>
26+
<field name="price" />
27+
<field name="partner_id" />
28+
<field name="status" />
29+
</group>
30+
</group>
31+
</form>
32+
</field>
33+
</record>
34+
</odoo>

0 commit comments

Comments
 (0)