-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ADD] estate: create real estate module with basic property managemen… #136
Changes from all commits
2bbbbe9
8d72692
00416dd
a3a7461
99a0673
bdf1931
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import models |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "Real_estate", | ||
"version": "0.1", | ||
"license": "LGPL-3", | ||
"category": "Real Estate/Brokerage", | ||
"author": "sahilpanghal(span)", | ||
"summary": "Real estate module", | ||
"description": "Real estate module", | ||
"installable": True, | ||
"application": True, | ||
"icons": ["static/description/realestate.png"], | ||
"depends": ["base"], | ||
"data": [ | ||
"security/security.xml", | ||
"security/ir.model.access.csv", | ||
"data/estate.property.type.csv", | ||
"report/estate_property_offer_report.xml", | ||
"report/estate_property_offer_subTemplate.xml", | ||
"report/estate_property_offer_report_template.xml", | ||
"views/estate_property_view.xml", | ||
"views/estate_property_offer_view.xml", | ||
"views/estate_property_type_view.xml", | ||
"views/estate_property_tag_view.xml", | ||
"views/estate_menu.xml", | ||
"views/res_users.xml", | ||
], | ||
"demo": [ | ||
"demo/estate_property_demo.xml", | ||
], | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
id,name | ||
id1,Residential | ||
id2,Commercial | ||
id3,Industrial | ||
id4,Land |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<odoo> | ||
|
||
<record id="demo_data_1" model="estate.property"> | ||
<field name="name">Big Villa</field> | ||
<field name="state">new</field> | ||
<field name="description">A nice and big villa</field> | ||
<field name="postcode">12345</field> | ||
<field name="date_availablity">2020-02-02</field> | ||
<field name="expected_price">1600000</field> | ||
<field name="bedrooms">6</field> | ||
<field name="living_area">100</field> | ||
<field name="facades">4</field> | ||
<field name="garage">True</field> | ||
<field name="garden">True</field> | ||
<field name="garden_area">100000</field> | ||
<field name="garden_orientation">south</field> | ||
<field name="property_type_id" ref="estate.id1" /> | ||
</record> | ||
|
||
<record id="demo_data_2" model="estate.property"> | ||
<field name="name">Trailer home</field> | ||
<field name="state">canceled</field> | ||
<field name="description">Home in a trailer park</field> | ||
<field name="postcode">54321</field> | ||
<field name="date_availablity">1970-01-01</field> | ||
<field name="expected_price">100000</field> | ||
<field name="selling_price">120000</field> | ||
<field name="bedrooms">1</field> | ||
<field name="living_area">10</field> | ||
<field name="facades">4</field> | ||
<field name="garage">False</field> | ||
<field name="property_type_id" ref="estate.id1" /> | ||
</record> | ||
|
||
<record id="demo_data_3" model="estate.property"> | ||
<field name="name">Luxury villa</field> | ||
<field name="state">new</field> | ||
<field name="description">A very nice villa</field> | ||
<field name="postcode">12345</field> | ||
<field name="date_availablity">2020-02-02</field> | ||
<field name="expected_price">100</field> | ||
<field name="bedrooms">6</field> | ||
<field name="living_area">100</field> | ||
<field name="garage">True</field> | ||
<field name="garden">True</field> | ||
<field name="garden_area">100000</field> | ||
<field name="garden_orientation">south</field> | ||
<field name="facades">4</field> | ||
<field name="offer_ids" | ||
eval="[ | ||
Command.create({ | ||
'partner_id': ref('base.res_partner_2'), | ||
'price': 190000000, | ||
'Validity': 14 | ||
}), | ||
|
||
]" /> | ||
<field name="property_type_id" ref="estate.id1"></field> | ||
</record> | ||
|
||
<record id="offer_demo_data_1" model="estate.property.offer"> | ||
<field name="partner_id" ref="base.res_partner_12" /> | ||
<field name="property_id" ref="demo_data_1" /> | ||
<field name="price">10000</field> | ||
<field name="deadline" eval="(datetime.now() + relativedelta(days=20))" /> | ||
</record> | ||
|
||
<record id="offer_demo_data_2" model="estate.property.offer"> | ||
<field name="partner_id" ref="base.res_partner_12" /> | ||
<field name="property_id" ref="demo_data_1" /> | ||
<field name="price">1500000</field> | ||
<field name="Validity">14</field> | ||
</record> | ||
|
||
<record id="offer_demo_data_3" model="estate.property.offer"> | ||
<field name="partner_id" ref="base.res_partner_2" /> | ||
<field name="property_id" ref="demo_data_1" /> | ||
<field name="price">1500001</field> | ||
<field name="Validity">14</field> | ||
</record> | ||
|
||
<function model="estate.property.offer" name="action_accept"> | ||
<value eval="[ref('offer_demo_data_3')]" /> | ||
</function> | ||
</odoo> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# imported all the models taht are made inside the model folder | ||
from . import estate_property | ||
from . import estate_property_type | ||
from . import estate_property_tag | ||
from . import estate_property_offer | ||
from . import res_users |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
from dateutil.relativedelta import relativedelta | ||
from odoo import api, fields, models | ||
from odoo.exceptions import UserError, ValidationError | ||
|
||
|
||
class EstateProperty(models.Model): | ||
_name = "estate.property" | ||
_description = "EstateProperty" | ||
_order = "id desc" | ||
# created the field for the estate.property model | ||
name = fields.Char(required=True, default="Unkown") | ||
description = fields.Text() | ||
property_type_id = fields.Many2one("estate.property.type", string="Property Types") | ||
postcode = fields.Char() | ||
date_availablity = fields.Date( | ||
copy=False, default=lambda self: fields.Date.today() + relativedelta(months=3) | ||
) | ||
expected_price = fields.Float(required=True) | ||
selling_price = fields.Float(readonly=True, copy=False) | ||
bedrooms = fields.Integer(default="2") | ||
living_area = fields.Integer() | ||
facades = fields.Integer() | ||
garage = fields.Boolean() | ||
garden = fields.Boolean() | ||
garden_area = fields.Integer() | ||
garden_orientation = fields.Selection( | ||
[("north", "North"), ("south", "South"), ("east", "East"), ("west", "West")] | ||
) | ||
state = fields.Selection( | ||
[ | ||
("new", "New"), | ||
("offer_recieved", "Offer Recieved"), | ||
("offer_accepted", "Offer Accepted"), | ||
("sold", "Sold"), | ||
("canceled", "Canceled"), | ||
], | ||
default="new", | ||
readonly=True, | ||
) | ||
active = fields.Boolean(default=True) | ||
saler_id = fields.Many2one( | ||
"res.users", | ||
string="Salesperson", | ||
index=True, | ||
default=lambda self: self.env.user, | ||
) | ||
buyer_id = fields.Many2one("res.partner", string="Buyer", index=True) | ||
tag_ids = fields.Many2many("estate.property.tag", string="Tags") | ||
offer_ids = fields.One2many("estate.property.offer", "property_id") | ||
total = fields.Integer(compute="_compute_area") | ||
best_price = fields.Integer(compute="_compute_bestprice") | ||
|
||
# created the sql constraints for only accepting positive values for expected price and selling price | ||
_sql_constraints = [ | ||
( | ||
"check_expected_price", | ||
"CHECK(expected_price > 0.0)", | ||
"A property expected price must be strictly positive and Grater then Zero.", | ||
), | ||
( | ||
"check_selling_price", | ||
"CHECK(selling_price > 0.0)", | ||
"A property selling price must be positive and Grater then Zero.", | ||
), | ||
] | ||
|
||
# created the area computation function that will compute area from living area and garden area i.e living area + garden area | ||
@api.depends("living_area", "garden_area") | ||
def _compute_area(self): | ||
for record in self: | ||
record.total = record.living_area + record.garden_area | ||
|
||
# created the best price computation function that will compute best price from offers i.e maximum from the offers | ||
@api.depends("offer_ids") | ||
def _compute_bestprice(self): | ||
for record in self: | ||
if record.offer_ids: | ||
max1 = 0 | ||
for i in record.offer_ids: | ||
if i.price > max1: | ||
max1 = i.price | ||
record.best_price = max1 | ||
else: | ||
record.best_price = 0 | ||
|
||
# created the garden onchange function that will change the values of the dependent fiels when the particular field triger is activated i.e turning on the garden field will affect the dependent fields | ||
@api.onchange("garden") | ||
def _onchange_garden(self): | ||
if self.garden: | ||
self.garden_area = 10 | ||
self.garden_orientation = "north" | ||
|
||
# created a python constraint that will check weather the selling price is grater then the 90% of the expected price | ||
@api.constrains("selling_price") | ||
def _check_selling_price(self): | ||
for record in self: | ||
if record.selling_price <= (90 / 100) * record.expected_price: | ||
raise ValidationError( | ||
"the selling price cannot be lower than 90'%' of the expected price." | ||
) | ||
|
||
# creating a delection check function that will check if the property is sold or not | ||
@api.ondelete(at_uninstall=False) | ||
def _check_property(self): | ||
if any(user.state not in ("new", "canceled") for user in self): | ||
raise UserError("You can't delete a property that is in process.") | ||
|
||
# created the action for the sold button that will chage the state field of the property to sold | ||
def action_sold(self): | ||
for record in self: | ||
if record.state in ["sold", "canceled"]: | ||
raise UserError( | ||
"This property is alredy sold or canceled. You can't sell it." | ||
) | ||
else: | ||
record.state = "sold" | ||
return True | ||
|
||
# created the action for the cancel button that will change the state of the property to canceled | ||
def action_cancel(self): | ||
for record in self: | ||
if record.state == "sold": | ||
raise UserError("This property is alredy sold. You can't cancel it.") | ||
elif record.state == "canceled": | ||
raise UserError("This property is alredy canceled.") | ||
else: | ||
record.state = "canceled" | ||
return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try same as above