Skip to content
Open
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
23 changes: 23 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
'name': 'RealEstate',
'version': '1.0',
'category': 'Real Estate/Brokerage',
'summary': 'A module to manage real estate advertisements and property offers',
'description': """A simple module to manage real estate ads.List your properties, track details like bedrooms and garden,let buyers make offers, and accept or reject them.""",
'author': 'Pranjali Sangavekar(prsan)',
'license': 'LGPL-3',
'depends': ['base'],
'data': [
'security/security.xml',
'security/ir.model.access.csv',
'views/estate_property_views.xml',
'views/estate_property_type_views.xml',
'views/estate_property_tags_views.xml',
'views/estate_property_offers_views.xml',
'views/estate_menus.xml',
],
'demo': [
'demo/estate_property_data.xml',
],
'application': True,
}
153 changes: 153 additions & 0 deletions estate/demo/estate_property_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="estate_property_1" model="estate.property">
<field name="name">Beautiful Villa in Downtown</field>
<field name="description">A stunning 3-bedroom villa with modern amenities</field>
<field name="postcode">382421</field>
<field name="date_availability">2026-06-15</field>
<field name="expected_price">6767676.00</field>
<field name="bedrooms">3</field>
<field name="living_area">9234</field>
<field name="facades">2</field>
<field name="garage">True</field>
<field name="garden">True</field>
<field name="garden_area">5000</field>
<field name="garden_orientation">south</field>
<field name="state">new</field>
</record>
<record id="estate_property_2" model="estate.property">
<field name="name">Cozy House with Garden</field>
<field name="description">Perfect starter home with large garden</field>
<field name="postcode">400605</field>
<field name="date_availability">2026-07-01</field>
<field name="expected_price">100000.00</field>
<field name="bedrooms">2</field>
<field name="living_area">500</field>
<field name="facades">1</field>
<field name="garage">False</field>
<field name="garden">True</field>
<field name="garden_area">2000</field>
<field name="garden_orientation">north</field>
<field name="state">new</field>
</record>
<record id="estate_property_3" model="estate.property">
<field name="name">Modern Apartment</field>
<field name="description">Newly built apartment in city center</field>
<field name="postcode">382421</field>
<field name="date_availability">2026-05-20</field>
<field name="expected_price">250000.00</field>
<field name="bedrooms">2</field>
<field name="living_area">750</field>
<field name="facades">3</field>
<field name="garage">True</field>
<field name="garden">False</field>
<field name="garden_area">0</field>
<field name="garden_orientation">east</field>
<field name="state">new</field>
</record>
<record id="estate_property_4" model="estate.property">
<field name="name">Traditional Cottage</field>
<field name="description">Charming countryside cottage</field>
<field name="postcode">400605</field>
<field name="date_availability">2026-08-10</field>
<field name="expected_price">180000.00</field>
<field name="bedrooms">3</field>
<field name="living_area">650</field>
<field name="facades">2</field>
<field name="garage">True</field>
<field name="garden">True</field>
<field name="garden_area">3000</field>
<field name="garden_orientation">west</field>
<field name="state">new</field>
</record>
<record id="estate_property_5" model="estate.property">
<field name="name">Luxury Penthouse</field>
<field name="description">High-end penthouse with panoramic views</field>
<field name="postcode">382421</field>
<field name="date_availability">2026-04-01</field>
<field name="expected_price">500000.00</field>
<field name="bedrooms">4</field>
<field name="living_area">1200</field>
<field name="facades">2</field>
<field name="garage">True</field>
<field name="garden">True</field>
<field name="garden_area">1000</field>
<field name="garden_orientation">south</field>
<field name="state">new</field>
</record>
<record id="estate_property_6" model="estate.property">
<field name="name">Seaside Bungalow</field>
<field name="description">Relaxing bungalow with sea view</field>
<field name="postcode">600001</field>
<field name="date_availability">2026-10-01</field>
<field name="expected_price">420000.00</field>
<field name="bedrooms">2</field>
<field name="living_area">800</field>
<field name="facades">2</field>
<field name="garage">False</field>
<field name="garden">True</field>
<field name="garden_area">1500</field>
<field name="garden_orientation">east</field>
<field name="state">new</field>
</record>
<record id="estate_property_7" model="estate.property">
<field name="name">Mountain Cabin</field>
<field name="description">Cozy cabin in the mountains</field>
<field name="postcode">700002</field>
<field name="date_availability">2026-11-15</field>
<field name="expected_price">210000.00</field>
<field name="bedrooms">3</field>
<field name="living_area">600</field>
<field name="facades">1</field>
<field name="garage">False</field>
<field name="garden">True</field>
<field name="garden_area">1200</field>
<field name="garden_orientation">west</field>
<field name="state">new</field>
</record>
<record id="estate_property_8" model="estate.property">
<field name="name">City Studio</field>
<field name="description">Compact studio apartment for singles</field>
<field name="postcode">800003</field>
<field name="date_availability">2026-12-01</field>
<field name="expected_price">95000.00</field>
<field name="bedrooms">1</field>
<field name="living_area">350</field>
<field name="facades">1</field>
<field name="garage">False</field>
<field name="garden">False</field>
<field name="garden_area">0</field>
<field name="garden_orientation">north</field>
<field name="state">new</field>
</record>
<record id="estate_property_9" model="estate.property">
<field name="name">Family Home</field>
<field name="description">Spacious home perfect for families</field>
<field name="postcode">900004</field>
<field name="date_availability">2027-01-10</field>
<field name="expected_price">300000.00</field>
<field name="bedrooms">4</field>
<field name="living_area">1100</field>
<field name="facades">2</field>
<field name="garage">True</field>
<field name="garden">True</field>
<field name="garden_area">2000</field>
<field name="garden_orientation">south</field>
<field name="state">new</field>
</record>
<record id="estate_property_10" model="estate.property">
<field name="name">Downtown Office Space</field>
<field name="description">Modern office space in business district</field>
<field name="postcode">100005</field>
<field name="date_availability">2027-02-01</field>
<field name="expected_price">800000.00</field>
<field name="bedrooms">0</field>
<field name="living_area">2000</field>
<field name="facades">4</field>
<field name="garage">True</field>
<field name="garden">False</field>
<field name="garden_area">0</field>
<field name="garden_orientation">east</field>
<field name="state">new</field>
</record>
</odoo>
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
68 changes: 68 additions & 0 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from dateutil.relativedelta import relativedelta

from odoo import api, fields, models


class EstateProperty(models.Model):
_name = "estate.property"
_description = "Real estate system"

def _get_default_date_calculation(self):
return fields.Date.today() + relativedelta(months=3)

name = fields.Char(string="Property Name", required=True)
description = fields.Text()
postcode = fields.Char(string="Postal Code")
date_availability = fields.Date(copy=False, default=_get_default_date_calculation)
expected_price = fields.Float(string="Expected Price", required=True)
selling_price = fields.Float(readonly=True, copy=False)
bedrooms = fields.Integer(default=2)
living_area = fields.Integer(string="Living Area", help="Living area in square meters")
facades = fields.Integer()
garage = fields.Boolean()
garden = fields.Boolean(string="Garden", help="Has garden")
garden_area = fields.Integer()
garden_orientation = fields.Selection([
('north', 'North'),
('south', 'South'),
('east', 'East'),
('west', 'West')
])
active = fields.Boolean(default=True, help="Uncheck to archive this property")

state = fields.Selection([
('new', 'New'),
('offer_received', 'Offer Received'),
('offer_accepted', 'Offer Accepted'),
('sold', 'Sold'),
('cancelled', 'Cancelled'),
], required=True, copy=False, default='new')

property_type_id = fields.Many2one('estate.property.type', string="Property Type", ondelete='cascade')
buyer_id = fields.Many2one('res.partner', string="Buyer", copy=False)
seller_id = fields.Many2one('res.users', string="Seller", default=lambda self: self.env.user)

tag_ids = fields.Many2many('estate.property.tag', 'pranjali', 'property_id', 'tag_id', string="Tags")
offer_ids = fields.One2many('estate.property.offer', 'property_id', string="Offers")

total_area = fields.Float(compute='_compute_total_area', store=True)
best_price = fields.Float(compute='_compute_best_price', readonly=True, store=True)

@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'), default=0.0)

@api.onchange('garden')
def _onchange_garden(self):
if not self.garden:
self.garden_area = 0
self.garden_orientation = False
else:
self.garden_area = 10
self.garden_orientation = 'north'
35 changes: 35 additions & 0 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from datetime import timedelta

from odoo import api, fields, models


class EstatePropertyOffer(models.Model):
_name = "estate.property.offer"
_description = "Real estate system - Property Offer"

price = fields.Float(string="Offer Price")
status = fields.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'
)

@api.depends('create_date', 'validity')
def _compute_date_deadline(self):
for offer in self:
date = offer.create_date or fields.Date.today()
offer.date_deadline = date + timedelta(days=offer.validity)

def _inverse_date_deadline(self):
for record in self:
start = record.create_date.date() if record.create_date else fields.Date.today()
record.validity = (record.date_deadline - start).days
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 fields, models


class EstatePropertyTag(models.Model):
_name = "estate.property.tag"
_description = "Real estate system - Property Tag"

name = fields.Char(string="Tag Name", 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 fields, models


class EstatePropertyType(models.Model):
_name = "estate.property.type"
_description = "Real estate system - Property Type"

name = fields.Char(string="Property Type Name", required=True)
9 changes: 9 additions & 0 deletions estate/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_estate_property_manager,estate.property manager,model_estate_property,estate.estate_group_manager,1,1,1,1
access_estate_property_user,estate.property user,model_estate_property,estate.estate_group_user,1,1,0,0
access_estate_property_type_manager,estate.property.type manager,model_estate_property_type,estate.estate_group_manager,1,1,1,1
access_estate_property_type_user,estate.property.type user,model_estate_property_type,estate.estate_group_user,1,0,0,0
access_estate_property_tag_manager,estate.property.tag manager,model_estate_property_tag,estate.estate_group_manager,1,1,1,1
access_estate_property_tag_user,estate.property.tag user,model_estate_property_tag,estate.estate_group_user,1,0,0,0
access_estate_property_offer_manager,estate.property.offer manager,model_estate_property_offer,estate.estate_group_manager,1,1,1,1
access_estate_property_offer_user,estate.property.offer user,model_estate_property_offer,estate.estate_group_user,1,1,1,0
29 changes: 29 additions & 0 deletions estate/security/security.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="module_category_real_estate_brokerage" model="ir.module.category">
<field name="name">Real Estate</field>
<field name="description">Real Estate Management</field>
</record>

<record model="res.groups.privilege" id="groups_privilege_real_estate">
<field name="name">Real Estate</field>
<field name="category_id" ref="module_category_real_estate_brokerage"/>
</record>

<record id="estate_group_user" model="res.groups">
<field name="name">Agent</field>
<field name="privilege_id" ref="groups_privilege_real_estate"/>
</record>

<record id="estate_group_manager" model="res.groups">
<field name="name">Manager</field>
<field name="privilege_id" ref="groups_privilege_real_estate"/>
<field name="implied_ids" eval="[Command.link(ref('estate_group_user'))]"/>
</record>

<record id="base.user_admin" model="res.users">
<field name="group_ids" eval="[Command.link(ref('estate_group_manager'))]"/>
</record>
</data>
</odoo>
Binary file added estate/static/description/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions estate/views/estate_menus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem id="estate_menu_root" name="Real Estate" web_icon="estate,static/description/icon.png">
<menuitem id="estate_first_level_menu" name="Advertisements">
<menuitem id="estate_property_menu_action" name="Properties" action="estate_property_action"/>
</menuitem>
<menuitem id="estate_settings_menu" name="Settings">
<menuitem id="estate_property_type_menu" name="Property Types" action="estate_property_type_action"/>
<menuitem id="estate_property_tags_menu" name="Property Tags" action="estate_property_tags_action"/>
</menuitem>
</menuitem>
</odoo>
34 changes: 34 additions & 0 deletions estate/views/estate_property_offers_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="estate_property_offers_view_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>
<sheet>
<group>
<field name="price"/>
<field name="partner_id"/>
<field name="validity"/>
<field name="date_deadline"/>
<field name="status"/>
</group>
</sheet>
</form>
</field>
</record>

<record id="estate_property_offers_view_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 editable="bottom" default_order="price desc">
<field name="price"/>
<field name="partner_id"/>
<field name="validity"/>
<field name="date_deadline"/>
<field name="status"/>
</list>
</field>
</record>
</odoo>
Loading