Skip to content

Commit 728a8e2

Browse files
committed
[ADD] real_estate: add business login in estate property and offers for property
implement Sold and Cancel button in estate property with validation add offer option in property with accept and refused button automatic update selling price when buyer accept offer only one buyer can accept one offer through validation
1 parent 6904337 commit 728a8e2

13 files changed

+224
-7
lines changed

real_estate/__manifest__.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
'installable': True,
1212
'license':'LGPL-3',
1313
'data': [
14-
'data/ir.model.access.csv',
15-
'data/estate_property_views.xml',
16-
'data/estate_menus.xml',
14+
'security/ir.model.access.csv',
15+
'view/estate_property_views.xml',
16+
17+
'view/estate_property_type_views.xml',
18+
'view/estate_property_tag_views.xml',
19+
'view/estate_property_offer_views.xml',
20+
'view/estate_menus.xml',
1721
],
1822
}

real_estate/data/ir.model.access.csv

Lines changed: 0 additions & 2 deletions
This file was deleted.

real_estate/models/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
from . import estate_property
2+
from . import estate_property_type
3+
from . import estate_property_tag
4+
from . import estate_property_offer

real_estate/models/estate_property.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from datetime import date, timedelta
22
from odoo import fields, models
3+
from odoo.exceptions import UserError
34

45

56
class EstateProperty(models.Model):
@@ -13,11 +14,12 @@ class EstateProperty(models.Model):
1314
expected_price = fields.Float(string="Expected Price",required=True)
1415
selling_price = fields.Float(readonly=True, copy=False)
1516
bedrooms = fields.Integer(default=2)
16-
living_area = fields.Integer(string="Living Area")
17+
living_area = fields.Float(string="Living Area")
1718
facades = fields.Integer(string="Facades")
1819
garage = fields.Boolean(string="Garage")
1920
garden = fields.Boolean(string="Garden")
20-
garden_area = fields.Integer(string="Garden Area")
21+
garden_area = fields.Float(string="Garden Area")
22+
total_area = fields.Float(string="Total Area", compute="_compute_total_area")
2123
garden_orientation = fields.Selection(
2224
[
2325
('north', 'North'),
@@ -40,3 +42,43 @@ class EstateProperty(models.Model):
4042
copy=False,
4143
default='new'
4244
)
45+
property_type_id = fields.Many2one('estate.property.type', string="Property Type")
46+
buyer_id = fields.Many2one('res.partner', string="Buyer", copy=False)
47+
salesperson_id = fields.Many2one('res.users', string="Salesperson", default=lambda self: self.env.user)
48+
tag_ids = fields.Many2many('estate.property.tag', string="Tags")
49+
offer_ids = fields.One2many('estate.property.offer', 'property_id', string="Offers")
50+
best_price = fields.Float(string="Best Offer", compute="_compute_best_price")
51+
52+
@api.depends('living_area', 'garden_area')
53+
def _compute_total_area(self):
54+
for record in self:
55+
record.total_area = (record.living_area or 0.0) + (record.garden_area or 0.0)
56+
57+
@api.depends('offer_ids.price')
58+
def _compute_best_price(self):
59+
for record in self:
60+
prices = record.offer_ids.mapped('price')
61+
record.best_price = max(prices) if prices else 0.0
62+
63+
@api.onchange('garden')
64+
def _onchange_garden(self):
65+
if self.garden:
66+
self.garden_area = 10
67+
self.garden_orientation = 'north'
68+
else:
69+
self.garden_area = 0
70+
self.garden_orientation = False
71+
72+
def action_cancel(self):
73+
for record in self:
74+
if record.state == 'sold':
75+
raise UserError("Sold properties cannot be cancelled.")
76+
record.state = 'cancelled'
77+
return True
78+
79+
def action_sold(self):
80+
for record in self:
81+
if record.state == 'cancelled':
82+
raise UserError("Cancelled properties cannot be sold.")
83+
record.state = 'sold'
84+
return True
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from datetime import timedelta
2+
from odoo import api, fields, models
3+
from odoo.exceptions import UserError
4+
5+
6+
class EstatePropertyOffer(models.Model):
7+
_name = "estate.property.offer"
8+
_description = "Property Offer"
9+
10+
price = fields.Float(string="Offer Price")
11+
status = fields.Selection(
12+
[('accepted', 'Accepted'), ('refused', 'Refused')],
13+
string="Status",
14+
copy=False
15+
)
16+
partner_id = fields.Many2one('res.partner', string="Partner", required=True)
17+
property_id = fields.Many2one('estate.property', string="Property", required=True)
18+
19+
validity = fields.Integer(default=7)
20+
date_deadline = fields.Date(compute="_compute_date_deadline", inverse="_inverse_date_deadline", store=True)
21+
22+
@api.depends('create_date', 'validity')
23+
def _compute_date_deadline(self):
24+
for record in self:
25+
create_date = record.create_date or fields.Datetime.now()
26+
record.date_deadline = create_date.date() + timedelta(days=record.validity)
27+
28+
def _inverse_date_deadline(self):
29+
for record in self:
30+
create_date = record.create_date or fields.Datetime.now()
31+
delta = record.date_deadline - create_date.date()
32+
record.validity = delta.days
33+
34+
def action_accept(self):
35+
for offer in self:
36+
if offer.property_id.buyer_id:
37+
raise UserError("An offer has already been accepted.")
38+
offer.status = 'accepted'
39+
offer.property_id.write({
40+
'selling_price': offer.price,
41+
'buyer_id': offer.partner_id.id,
42+
'state': 'offer_accepted'
43+
})
44+
return True
45+
46+
def action_refuse(self):
47+
for offer in self:
48+
offer.status = 'refused'
49+
return True
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from odoo import models, fields
2+
3+
class EstatePropertyTag(models.Model):
4+
_name = "estate.property.tag"
5+
_description = "Property Tag"
6+
7+
name = fields.Char(string="Name", required=True)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from odoo import models, fields
2+
3+
class EstatePropertyType(models.Model):
4+
_name = 'estate.property.type'
5+
_description = 'Property Type'
6+
7+
name = fields.Char(required=True)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
2+
access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1
3+
access_estate_property_type_user,access.estate.property.type.user,model_estate_property_type,base.group_user,1,1,1,1
4+
access_estate_property_tag_user,access.estate.property.tag.user,model_estate_property_tag,base.group_user,1,1,1,1
5+
access_estate_property_offer_user,access.estate.property.offer.user,model_estate_property_offer,base.group_user,1,1,1,1

real_estate/data/estate_menus.xml renamed to real_estate/view/estate_menus.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
<menuitem id="menu_real_estate_root" name="Real Estate"/>
44
<menuitem id="menu_real_estate_properties" name="Properties" parent="menu_real_estate_root"/>
55
<menuitem id="menu_estate_property_action" action="action_estate_property" parent="menu_real_estate_properties"/>
6+
<menuitem id="setting" name="Settings" parent="menu_real_estate_root"/>
7+
<menuitem id="menu_property_type_root" name="Property Types" parent="setting" action="estate_property_type_action"/>
8+
<menuitem id="menu_estate_property_tag" name="Property Tags" parent="setting" action="action_estate_property_tag"/>
69
</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="action_estate_property_offer" model="ir.actions.act_window">
4+
<field name="name">Real estate offer</field>
5+
<field name="res_model">estate.property.offer</field>
6+
<field name="view_mode">list,form</field>
7+
</record>
8+
<!-- Form View for Offer -->
9+
<record id="view_estate_property_offer_form" model="ir.ui.view">
10+
<field name="name">estate.property.offer.form</field>
11+
<field name="model">estate.property.offer</field>
12+
<field name="arch" type="xml">
13+
<form string="Property Offer">
14+
<header>
15+
<button name="action_accept" type="object" string="Accept" class="btn-primary"/>
16+
<button name="action_refuse" type="object" string="Refuse" class="btn-secondary"/>
17+
</header>
18+
<sheet>
19+
<group>
20+
<field name="price"/>
21+
<field name="partner_id"/>
22+
<field name="status"/>
23+
</group>
24+
</sheet>
25+
</form>
26+
</field>
27+
</record>
28+
29+
<!-- List View for Offer -->
30+
<record id="view_estate_property_offer_list" model="ir.ui.view">
31+
<field name="name">estate.property.offer.list</field>
32+
<field name="model">estate.property.offer</field>
33+
<field name="arch" type="xml">
34+
<list string="Offers">
35+
<field name="price"/>
36+
<field name="partner_id"/>
37+
<field name="status"/>
38+
<button name="action_accept" type="object" string="" icon="fa-check"/>
39+
<button name="action_refuse" type="object" string="" icon="fa-times"/>
40+
</list>
41+
</field>
42+
</record>
43+
</odoo>

0 commit comments

Comments
 (0)