Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
19 changes: 19 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
'name': 'Real Estate',
'version': '1.0',
'depends': ['crm'],
'author': 'jaldip vekariya (javek)',
'description': """
An Real Estate App to buy, sell, and rent properties.
""",
'application': True,
'license': 'LGPL-3',
'data': [
'security/ir.model.access.csv',
'views/estate_property_offer_views.xml',
'views/estate_property_tag_views.xml',
'views/estate_property_views.xml',
'views/estate_property_type_views.xml',
'views/estate_menus.xml'
]
}
4 changes: 4 additions & 0 deletions estate/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import real_estate_property_offer
from . import real_estate_property_tag
from . import real_estate_property_type
from . import real_estate
104 changes: 104 additions & 0 deletions estate/models/real_estate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
from dateutil.relativedelta import relativedelta

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


class RealEstate(models.Model):
_name = "real_estate"
_description = "Real Estate"
_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.context_today(self) + relativedelta(months=3),
)
expected_price = fields.Float(required=True)
selling_price = fields.Float()
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(
selection=[
("new", "New"),
("offer_received", "Offer Received"),
("offer_accepted", "Offer Accepted"),
("sold", "Sold"),
("cancelled", "Cancelled"),
],
string="Status",
default="new",
)
active = fields.Boolean(default=True)
property_type_id = fields.Many2one("estate.property.type", string="Property Type", required=True)
buyer_id = fields.Many2one("res.partner", string="Buyer")
sales_id = fields.Many2one("res.users", string="Salesperson")
tag_ids = fields.Many2many("estate.property.tag", string="Tags")
offer_ids = fields.One2many("estate.property.offer", "property_id")
total_area = fields.Integer(compute="_compute_total_area")
best_price = fields.Integer(compute="_compute_best_price")

_expected_price_positive = models.Constraint(
'CHECK(expected_price > 0.0)',
'The expected price must be strictly positive.'
)
_selling_price_positive = models.Constraint(
'CHECK(selling_price >= 0.0 or selling_price IS NULL)',
'The selling 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:
record.best_price = max(record.offer_ids.mapped("price") or [0])

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

def action_sold(self):
for record in self:
if record.state != "cancelled":
record.state = "sold"
else:
raise UserError("Cancelled Property can not be sold")
return True

def action_cancel(self):
for record in self:
if record.state != "sold":
record.state = "cancelled"
else:
raise UserError("Sold Property can not be cancelled")
return True

@api.constrains("expected_price", "selling_price")
def _check_selling_price(self):
for record in self:
if record.selling_price == 0:
return False
if float_compare(record.selling_price, record.expected_price * 0.9, precision_digits=2) < 0:
raise ValidationError("The selling price cannot be lower than 90 of the expected price.")
63 changes: 63 additions & 0 deletions estate/models/real_estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from dateutil.relativedelta import relativedelta

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


class PropertyOffer(models.Model):
_name = "estate.property.offer"
_description = "Property Offers"
_order = "price desc"

price = fields.Float()
status = fields.Selection(
selection=[
("accepted", "Accepted"),
("refused", "Refused")
]
)
partner_id = fields.Many2one("res.partner", string="Partner", required=True)
property_id = fields.Many2one("real_estate", string="Property", required=True)
validity = fields.Integer(string="Validity(days)", default=7)
deadline = fields.Date(
compute="_compute_deadline",
inverse="_inverse_validity"
)
property_type_id = fields.Many2one(related="property_id.property_type_id", store=True)

_price_positive = models.Constraint(
'CHECK(price > 0)',
'The offer price must be positive.'
)

@api.depends("validity", "create_date")
def _compute_deadline(self):
for record in self:
date = record.create_date.date() if record.create_date else fields.Date.today()
record.deadline = date + relativedelta(days=record.validity)

def _inverse_validity(self):
for record in self:
record.validity = ((record.deadline) - record.create_date.date()).days

def accept_offer(self):
for record in self:
if record.property_id.buyer_id:
raise UserError("Only One Offer can be accepted")
else:
for ids in record.property_id.offer_ids:
if (record.id != ids.id):
ids.status = "refused"
record.property_id.buyer_id = record.partner_id
record.property_id.selling_price = record.price
record.status = "accepted"
record.property_id.state = "offer_accepted"
return True

def reject_offer(self):
for record in self:
if record.property_id.buyer_id and record.status == "accepted":
raise UserError("Accepted Offer can not be rejected")
else:
record.status = "refused"
return True
22 changes: 22 additions & 0 deletions estate/models/real_estate_property_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from random import randint

from odoo import fields, models


class PropertyTag(models.Model):
_name = "estate.property.tag"
_description = "Property Tags"
_order = "name"

name = fields.Char(string="Name")
color = fields.Integer(
string='Color Index', default=lambda self: self._default_color()
)

_name_unique = models.Constraint(
'UNIQUE(name)',
'The name must be unique'
)

def _default_color(self):
return randint(1, 11)
23 changes: 23 additions & 0 deletions estate/models/real_estate_property_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from odoo import api, fields, models


class PropertyType(models.Model):
_name = "estate.property.type"
_description = "Property Types"
_order = "sequence, name"

name = fields.Char(string="Name")
property_ids = fields.One2many("real_estate", "property_type_id", required=True)
sequence = fields.Integer("Sequence")
offer_id = fields.One2many("estate.property.offer", "property_type_id")
offer_count = fields.Integer(compute="_compute_offer_count")

_name_unique = models.Constraint(
'UNIQUE(name)',
'The name must be unique'
)

@api.depends("offer_id")
def _compute_offer_count(self):
for record in self:
record.offer_count = len(record.offer_id)
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
estate.access_real_estate,access_real_estate,model_real_estate,base.group_user,1,1,1,1
estate.access_estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1
estate.access_estate_property_tag,access_estate_property_tag,model_estate_property_tag,base.group_user,1,1,1,1
estate.access_estate_property_offer,access_estate_property_offer,model_estate_property_offer,base.group_user,1,1,1,1
9 changes: 9 additions & 0 deletions estate/views/estate_menus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<menuitem id="estate" name="Estate"/>
<menuitem id="estate_advertisement" name="Advertisement" parent="estate"/>
<menuitem id="estate_advertisement_properties" name="Properties" parent="estate_advertisement" action="real_estate"/>
<menuitem id="estate_settings" name="Settings" parent="estate"/>
<menuitem id="estate_settings_property_type" name="Property Type" parent="estate_settings" action="estate_property_type"/>
<menuitem id="estate_settings_property_tag" name="Property Tags" parent="estate_settings" action="estate_property_tag"/>
</odoo>
43 changes: 43 additions & 0 deletions estate/views/estate_property_offer_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>

<record id="estate_property_offer" model="ir.actions.act_window">
<field name="name">PropertyOffers</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_list" model="ir.ui.view">
<field name="name">estate.property.offer.list</field>
<field name="model">estate.property.offer</field>
<field name="arch" type="xml">
<list string="Offers" editable="bottom" decoration-danger="status == 'refused'" decoration-success="status == 'accepted'">
<field name="price" />
<field name="partner_id" string="Partner" />
<field name="validity" string="Validity(days)"/>
<field name="deadline"/>
<button name="accept_offer" string="Accept" type="object" icon="fa-check" invisible="status == 'accepted' or status == 'refused'"/>
<button name="reject_offer" string="Reject" type="object" icon="fa-close" invisible="status == 'accepted' or status == 'refused'"/>
<field name="status"/>
</list>
</field>
</record>

<record id="estate_property_offer_form" model="ir.ui.view">
<field name="name">estate.property.offer.form</field>
<field name="model">estate.property.offer</field>
<field name="arch" type="xml">
<form string="Offer">
<group>
<field name="price" />
<field name="partner_id" string="Partner" />
<field name="validity"/>
<field name="deadline" readonly="0"/>
<field name="status"/>
</group>
</form>
</field>
</record>
</odoo>
37 changes: 37 additions & 0 deletions estate/views/estate_property_tag_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>

<record id="estate_property_tag" model="ir.actions.act_window">
<field name="name">Tag Name</field>
<field name="res_model">estate.property.tag</field>
<field name="view_mode">list,form</field>
</record>


<record id="estate_property_tag_list" model="ir.ui.view">
<field name="name">estate.property.tag.list</field>
<field name="model">estate.property.tag</field>
<field name="arch" type="xml">
<list string="Types">
<field name="name" string="Type"/>
<field name="color" widget="color_picker" options="{'color_field': 'color'}"/>
</list>
</field>
</record>

<record id="estate_property_tag_form" model="ir.ui.view">
<field name="name">estate.property.tag.form</field>
<field name="model">estate.property.tag</field>
<field name="arch" type="xml">
<form string="Tags">
<sheet>
<group>
<field name="name" />
<field name="color" widget="color_picker"/>
</group>
</sheet>
</form>
</field>
</record>

</odoo>
57 changes: 57 additions & 0 deletions estate/views/estate_property_type_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>

<record id="estate_property_type" model="ir.actions.act_window">
<field name="name">Property Type</field>
<field name="res_model">estate.property.type</field>
<field name="view_mode">list,form</field>
</record>


<record id="estate_property_type_list" model="ir.ui.view">
<field name="name">estate.property.type.list</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<list string="Types">
<field name="sequence" widget="handle"/>
<field name="name" string="Type"/>
</list>
</field>
</record>


<record id="estate_property_type_form" model="ir.ui.view">
<field name="name">estate.property.type.form</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<form string="Properties">
<sheet>
<div class="oe_button_box" name="button_box">
<button type="action" name="%(estate_property_offer)d" icon="fa-dollar">
<div class="o_form_field o_stat_info">
<span class="o_stat_value">
<field name="offer_count" string="Offers" widget="statinfo"/>
</span>
</div>
</button>
</div>
<h1>
<field name="name" placeholder="Name"/>
</h1>
<notebook>
<page string="Properties">
<field name="property_ids">
<list>
<field name="name" string="Title" />
<field name="expected_price" />
<field name="state" string="Status" readonly="1"/>
</list>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>

</odoo>
Loading