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
20 changes: 20 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
'name': 'Real Estate',
'version': '1.0',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please follow the same quote in the same file?

'depends': ['base'],
'author': 'Shivam Saksham(shsak)',
'category': 'Sales',
'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_views.xml',
'views/estate_property_tag_views.xml',
'views/estate_property_offer_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 estate_property
from . import estate_property_type
from . import estate_property_tag
from . import estate_property_offer
76 changes: 76 additions & 0 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from odoo import models, fields, api, exceptions


class EstateProperty(models.Model):
_name = 'estate_property'
_description = 'Estate Property details'

name = fields.Char(required=True)
description = fields.Text()
postcode = fields.Char()
date_availability = fields.Date(
default=lambda self: fields.Date.add(fields.Date.today(), months=3),
copy=False
)
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')]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to follow the same quote in the same file.

)
state = fields.Selection(
string='Status',
selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')],
default='new',
required=True,
copy=False
)
active = fields.Boolean(default=True)
property_type_id = fields.Many2one('estate.property.type', string='Type')
buyer = fields.Many2one('res.partner', copy=False)
salesperson = fields.Many2one('res.users', string='Salesman', default=lambda self: self.env.user)
tag_ids = fields.Many2many('estate.property.tag', string='Tag')
offer_ids = fields.One2many('estate.property.offer', 'property_id')
total_area = fields.Integer(compute='_compute_total_area')
best_price = fields.Float(compute='_compute_best_price')

@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 _onchange_garden(self):
if self.garden:
self.garden_orientation = 'north'
self.garden_area = 10
else:
self.garden_orientation = None
self.garden_area = 0

def cancel_property_sale(self):
for record in self:
if record.state == 'sold':
raise exceptions.UserError('A sold property cannot be cancelled')
else:
record.state = 'cancelled'
return True

def set_property_sold(self):
for record in self:
if record.state == 'cancelled':
raise exceptions.UserError('A cancelled property cannot be Sold')
else:
record.state = 'sold'
return True
45 changes: 45 additions & 0 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from odoo import models, fields, api, exceptions


class EstatePropertyOffer(models.Model):
_name = 'estate.property.offer'
_description = 'Offer to buy the property'

price = fields.Float()
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_offer_date_deadline', inverse='_inverse_offer_date_deadline')

@api.depends('create_date', 'validity')
def _compute_offer_date_deadline(self):
for record in self:
if record.create_date:
record.date_deadline = fields.Date.add(record.create_date.date(), days=record.validity)
else:
record.date_deadline = fields.Date.add(fields.Date.today(), days=record.validity)

def _inverse_offer_date_deadline(self):
for record in self:
record.validity = (record.date_deadline - record.create_date.date()).days

def action_offer_accepted(self):
for record in self:
if record.status == 'accepted':
return False
if record.property_id.buyer:
raise exceptions.UserError('An another offer is already accepted')
record.property_id.selling_price = record.price
record.property_id.buyer = record.partner_id
record.status = 'accepted'
return True

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


class EstatePropertyTag(models.Model):
_name = "estate.property.tag"
_description = "Tag for the property"

name = fields.Char(required=True)
8 changes: 8 additions & 0 deletions estate/models/estate_property_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from odoo import models, fields


class EstatePropertyType(models.Model):
_name = "estate.property.type"
_description = "Defines the type of Real Estate Property"

name = fields.Char(required=True)
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_estate_property,access_estate_property,estate.model_estate_property,base.group_user,1,1,1,1
estate.access_estate_property_type,access_estate_property_type,estate.model_estate_property_type,base.group_user,1,1,1,1
estate.access_estate_property_tag,access_estate_property_tag,estate.model_estate_property_tag,base.group_user,1,1,1,1
estate.access_estate_property_offer,access_estate_property_offer,estate.model_estate_property_offer,base.group_user,1,1,1,1
14 changes: 14 additions & 0 deletions estate/views/estate_menus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<odoo>
<menuitem id="estate_menu_root" name="Real Estate">
<menuitem id="estate_first_level_menu" name="Advertisement">
<menuitem id="estate_property_model_menu_action" action="estate_property_action" />
</menuitem>

<menuitem id="estate_first_level_setting_menu" name="Settings">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<menuitem id="estate_first_level_setting_menu" name="Settings">
<menuitem id="estate_first_level_setting_menu" name="Settings">

For better visibility.

<menuitem id="estate_property_type_model_menu_action"
action="estate_property_type_action" />
<menuitem id="estate_property_tag_model_menu_action"
action="estate_property_tag_action" />
</menuitem>
</menuitem>
</odoo>
35 changes: 35 additions & 0 deletions estate/views/estate_property_offer_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<odoo>
<record id="estate_property_offer_list_view" model="ir.ui.view">
<field name="name">estate_property_offer_form</field>
<field name="model">estate.property.offer</field>
<field name="arch" type="xml">
<list string="Offers">
<field name="price" />
<field name="partner_id" string="Partner" />
<field name="validity" string="Validity (days)" />
<field name="date_deadline" />
<button name="action_offer_accepted" string="Accept" type="object" icon="fa-check"/>
<button name="action_offer_refused" string="Refuse" type="object" icon="fa-close" />
<field name="status" />
</list>
</field>
</record>

<record id="estate_property_offer_form_view" model="ir.ui.view">
<field name="name">Property Offer List</field>
<field name="model">estate.property.offer</field>
<field name="arch" type="xml">
<form string="Offer">
<sheet>
<group>
<field name="price" />
<field name="partner_id" string="Partener" />
<field name="validity" string="Validity (days)" />
<field name="date_deadline" />
<field name="status" />
</group>
</sheet>
</form>
</field>
</record>
</odoo>
7 changes: 7 additions & 0 deletions estate/views/estate_property_tag_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<odoo>
<record id="estate_property_tag_action" model="ir.actions.act_window">
<field name="name">Property Tags</field>
<field name="res_model">estate.property.tag</field>
<field name="view_mode">list,form</field>
</record>
</odoo>
7 changes: 7 additions & 0 deletions estate/views/estate_property_type_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<odoo>
<record id="estate_property_type_action" model="ir.actions.act_window">
<field name="name">Property Types</field>
<field name="res_model">estate.property.type</field>
<field name="view_mode">list,form</field>
</record>
</odoo>
103 changes: 103 additions & 0 deletions estate/views/estate_property_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<odoo>
<record id="estate_property_form_view" model="ir.ui.view">
<field name="name">estate_property_form</field>
<field name="model">estate_property</field>
<field name="arch" type="xml">
<form string="Description">
<haeder>
<group col="2">
<button type="object" name="cancel_property_sale" string="Cancel" />
<button type="object" name="set_property_sold" string="Sold" />
</group>
</haeder>
<sheet>
<h1>
<field name="name" nolabel="True" />
</h1>
<field name="tag_ids" widget="many2many_tags" class="mb-5" />
<group>
<group>
<field name="property_type_id" string="Property Type" />
<field name="postcode" />
<field name="date_availability" string="Available From" />
</group>
<group>
<field name="expected_price" />
<field name="selling_price" />
<field name="best_price" />
</group>
</group>
<notebook>
<page string="Description">
<group col="2">
<field name="description" />
<field name="bedrooms" />
<field name="living_area" string="Living Area (sqm)" />
<field name="facades" />
<field name="garage" />
<field name="garden" />
<field name="garden_area" string="Garden Area (sqm)" />
<field name="garden_orientation" />
<field name="state" />
<field name="total_area" />
</group>
</page>
<page string="Offers">
<list>
<field name="offer_ids" widget="one2many_list" />
</list>
</page>
<page string="Other Info">
<group>
<field name="salesperson" />
<field name="buyer" />
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>

<record id="estate_property_list_view" model="ir.ui.view">
<field name="name">Properties List</field>
<field name="model">estate_property</field>
<field name="arch" type="xml">
<list string="Properties">
<field name="name" string="Title" />
<field name="postcode" />
<field name="property_type_id" />
<field name="bedrooms" />
<field name="living_area" string="Living Area (sqm)" />
<field name="expected_price" />
<field name="selling_price" />
<field name="date_availability" string="Available From" />
</list>
</field>
</record>

<record id="estate_property_search_options_view" model="ir.ui.view">
<field name="name">Properties Search</field>
<field name="model">estate_property</field>
<field name="arch" type="xml">
<search string="Property Search">
<field name="name" string="Title" />
<field name="postcode" />
<field name="expected_price" />
<field name="bedrooms" />
<field name="living_area" string="Living Area (sqm)" />
<field name="facades" />
<field name="property_type_id" string="Type" />
<filter name="available" string="Available"
domain="['|', ('state', '=', 'new'), ('state', '=', 'offer_received')]" />
<filter name="group_by_postcode" string="Postcode" context="{'group_by':'postcode'}" />
</search>
</field>
</record>

<record id="estate_property_action" model="ir.actions.act_window">
<field name="name">Properties</field>
<field name="res_model">estate_property</field>
<field name="view_mode">list,form</field>
</record>
</odoo>