Skip to content
1 change: 1 addition & 0 deletions estate/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
17 changes: 17 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
'name': 'Estate',
'version': '0.1',
'summary': 'This is the Real Estate Advertisement module',
'description': 'This is the Real Estate Advertisement module.',
'data': [
'security/ir.model.access.csv',
'views/estate_property_offer_views.xml',
'views/estate_property_views.xml',
'views/estate_property_type_views.xml',
'views/estate_property_tag_views.xml',
'views/res_users_views.xml',
'views/estate_menus.xml'
],
'author': 'Milan Bavishi',
'license': 'LGPL-3'
}
5 changes: 5 additions & 0 deletions estate/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from . import estate_property
from . import estate_property_type
from . import estate_property_tag
from . import estate_property_offer
from . import res_users
133 changes: 133 additions & 0 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
from dateutil.relativedelta import relativedelta

from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_compare, float_is_zero


class EstateProperty(models.Model):
_name = "estate.property"
_description = "This is the table of real estate property data"
_order = "id desc"

name = fields.Char(required=True)
description = fields.Text()
postcode = fields.Char()
date_availability = fields.Date(
copy=False, default=lambda self: fields.Date.today() + relativedelta(month=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(
string="Garden Orientation",
selection=[
("north", "North"),
("south", "South"),
("east", "East"),
("west", "West"),
],
)
state = fields.Selection(
string="State",
default="new",
required=True,
copy=False,
selection=[
("new", "New"),
("offer received", "Offer Received"),
("offer accepted", "Offer accepted"),
("sold", "Sold"),
("cancelled", "Cancelled"),
],
)
active = fields.Boolean()
property_type_id = fields.Many2one("estate.property.type", string="Property Type")
customer_id = fields.Many2one(
"res.partner", string="Customer", copy=False, readonly=True
)
salesperson_id = fields.Many2one(
"res.users",
string="Salesperson",
readonly=True,
default=lambda self: self.env.user,
)
tag_ids = fields.Many2many("estate.property.tag", string="Tag type")
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers")
total_area = fields.Integer(compute="_compute_total_area")
best_price = fields.Float(compute="_compute_best_price")

_check_expected_price = models.Constraint(
"check(expected_price > 0)",
"The Expected Price must be positive",
)

@api.depends("living_area", "garden_area")
def _compute_total_area(self):
for record in self:
record.total_area = record.living_area + record.garden_area

@api.depends("offer_ids.price")
def _compute_best_price(self):
for record in self:
prices = record.offer_ids.mapped("price")
record.best_price = max(prices) if prices else 0.0

@api.onchange("garden")
def _onchange_garden(self):
if self.garden:
self.garden_area = 10
self.garden_orientation = "north"
else:
self.garden_area = 0
self.garden_orientation = None

def action_cancel(self):
for record in self:
if record.state == 'sold':
raise UserError(_("You cannot cannoy cancel the property that already cancelled"))
self.write({"state": "cancelled"})

def action_sold(self):
if self.filtered(lambda record: record.state == "cancelled"):
raise UserError(
_("You cannot Sold the property offer that already Cancelled")
)
if not self.customer_id:
raise UserError(
_("You can not sold the property that has no customer")
)
self.write({"state": "sold"})

@api.constrains("selling_price", "expected_price")
def _check_selling_price(self):
for record in self:
if float_is_zero(record.selling_price, precision_digits=2):
continue

min_price = record.expected_price * 0.9
if float_compare(record.selling_price, min_price, precision_digits=2) < 0:
raise ValidationError(_("The Selling price cannot be lower than 90% of the expected price."))

@api.constrains("offer_ids")
def _check_offer_vaild(self):
for record in self:
if record.state == "sold":
raise UserError(
_("already offer is accept")
)
return True

@api.ondelete(at_uninstall=False)
def _check_property_deletion(self):
for record in self:
if record.state not in ("new", "cancelled"):
raise UserError(
_("You can only delete properties in new or cancelled state")
)
return True
59 changes: 59 additions & 0 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from dateutil.relativedelta import relativedelta

from odoo import _, api, fields, models
from odoo.exceptions import UserError


class EstatePropertyOffer(models.Model):
_name = "estate.property.offer"
_description = "This is the table of offer that is received for property"
_order = "price desc"

price = fields.Float('price')
status = fields.Selection(
string="Status",
selection=[
('accepted', 'Accepted'),
('refused', 'Refused')
],
copy=False
)
partner_id = fields.Many2one('res.partner', required=True)
property_id = fields.Many2one('estate.property', required=True)
validity = fields.Integer(default=7)
date_deadline = fields.Date(compute="_compute_date_deadline", inverse="_inverse_date_deadline", store=True)
property_type_id = fields.Many2one("estate.property.type", related="property_id.property_type_id", store=True)

_check_offer_price = models.Constraint(
"check(price > 0)",
"Offer price must be positive",
)

@api.depends("validity")
def _compute_date_deadline(self):
for record in self:
create = record.create_date or fields.Date.today()
record.date_deadline = (create + relativedelta(days=record.validity))

def _inverse_date_deadline(self):
for record in self:
create = record.create_date or fields.Date.today()
record.validity = (record.date_deadline - fields.Date.today(create)).days

def action_accept_offer(self):
for offer in self:
if offer.property_id.customer_id:
raise UserError(_("Only one offer can be accepted."))
offer.property_id.customer_id = offer.partner_id
offer.property_id.selling_price = offer.price
offer.property_id.state = "sold"
offer.status = "accepted"
other_offer = offer.property_id.offer_ids.filtered(
lambda s: s.status != offer.status
)
other_offer.status = "refused"

def action_refuse_offer(self):
for offer in self:
offer.status = "refused"
return True
15 changes: 15 additions & 0 deletions estate/models/estate_property_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from odoo import fields, models


class EstatePropertyTags(models.Model):
_name = "estate.property.tag"
_description = "This table contain the types of tags"
_order = "name asc"

name = fields.Char(required=True)
color = fields.Integer(string="color")

_name_uniq = models.Constraint(
"unique(name)",
"Tag name is must be Unique",
)
22 changes: 22 additions & 0 deletions estate/models/estate_property_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from odoo import api, fields, models


class EstatePropertyTypes(models.Model):
_name = "estate.property.type"
_description = "This is table contain the types of property"
_order = "name asc"

name = fields.Char(required=True)
property_ids = fields.One2many("estate.property", "property_type_id")
offer_ids = fields.One2many("estate.property.offer", "property_type_id")
offer_count = fields.Integer(compute="_compute_offer_count")

_name_uniq = models.Constraint(
"unique(name)",
"Property Types must be Unique",
)

@api.depends("offer_ids")
def _compute_offer_count(self):
for record in self:
record.offer_count = len(record.offer_ids)
11 changes: 11 additions & 0 deletions estate/models/res_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from odoo import fields, models


class ResUsers(models.Model):
_inherit = "res.users"

property_ids = fields.One2many(
"estate.property",
"salesperson_id",
domain=[("state", "=", "new")]
)
5 changes: 5 additions & 0 deletions estate/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1
access_estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1
access_estate_property_tag,access_estate_property_tag,model_estate_property_tag,base.group_user,1,1,1,1
access_estate_property_offer,access_estate_property_offer,model_estate_property_offer,base.group_user,1,1,1,1
35 changes: 35 additions & 0 deletions estate/views/estate_menus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<odoo>
<data>
<menuitem
id="estate_property_menu"
name="Estate Property"/>
<menuitem
id="estate_property_menu_advertisements"
name="Advertisements"
parent="estate_property_menu"
sequence="5"/>
<menuitem
id="estate_property_menu_properties"
name="Properties"
parent="estate_property_menu_advertisements"
action="estate_property_action"
sequence="5"/>
<menuitem
id="estate_property_menu_settings"
name="Settings"
parent="estate_property_menu"
sequence="10"/>
<menuitem
id="estate_property_menu_types"
name="Property Types"
parent="estate_property_menu_settings"
action="estate_property_type_action"
sequence="5"/>
<menuitem
id="estate_property_menu_tags"
name="Property Tags"
parent="estate_property_menu_settings"
action="estate_property_tag_action"
sequence="10"/>
</data>
</odoo>
54 changes: 54 additions & 0 deletions estate/views/estate_property_offer_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="estate_property_offer_action" model="ir.actions.act_window">
<field name="name">Property Offer</field>
<field name="res_model">estate.property.offer</field>
<field name="view_mode">list,form</field>
<field name="domain">[("property_type_id", "=", active_id)]</field>
</record>

<record id="estate_property_offer_view_form" model="ir.ui.view">
<field name="name">estate.property.offer.view.form</field>
<field name="model">estate.property.offer</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="price"/>
<field name="partner_id"/>
<field name="validity"/>
<field name="date_deadline"/>
</group>
</sheet>
</form>
</field>
</record>

<record id="estate_property_offer_view_list" model="ir.ui.view">
<field name="name">estate_property_offer.view.list</field>
<field name="model">estate.property.offer</field>
<field name="arch" type="xml">
<list editable="bottom" decoration-danger="status == 'refused'"
decoration-success="status == 'accepted'">
<field name="price"/>
<field name="partner_id"/>
<field name="validity"/>
<button
name="action_accept_offer"
type="object"
string="Accpet"
icon="fa-check"
invisible="status in ('accepted', 'refused')"/>
<button
name="action_refuse_offer"
type="object"
string="refuse"
icon="fa-close"
invisible="status in ('accepted', 'refused')"/>
<field name="date_deadline"/>
<field name="status"/>
</list>
</field>
</record>

</odoo>
Loading