Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
956e40e
[ADD] estate: Initialize the real estate busniess
Piyush11204 Jul 2, 2026
8718baf
[ADD] estate: add estate property model
Piyush11204 Jul 2, 2026
bb27eb2
[LINT] estate: ensure consistent coding style
Piyush11204 Jul 3, 2026
157ce4b
[LINT] estate: resolve remaining lint errors
Piyush11204 Jul 3, 2026
c218672
[ADD] estate: add access control for property model
Piyush11204 Jul 3, 2026
dce4853
[LINT] estate: resolve security file issues
Piyush11204 Jul 3, 2026
648424f
[LINT] estate: fix spacing inconsistencies
Piyush11204 Jul 3, 2026
bf65082
[ADD] estate: add property views and menus
Piyush11204 Jul 6, 2026
ac5be22
[FIX] estate: correct property default values
Piyush11204 Jul 6, 2026
69fc96a
[IMP] estate: improve property form and search
Piyush11204 Jul 7, 2026
ec93d3a
[IMP] estate: filter expensive properties
Piyush11204 Jul 7, 2026
afdd419
[ADD] estate: add property types and tags
Piyush11204 Jul 9, 2026
d5bc7b6
[LINT] estate: resolve Runbot lint errors
Piyush11204 Jul 9, 2026
31cbc6a
[ADD] estate: add property offer model
Piyush11204 Jul 10, 2026
1bd0e1c
[FIX] estate: prevent changing offer property
Piyush11204 Jul 13, 2026
53b1939
[REF] estate: clean up whitespace and formatting
Piyush11204 Jul 20, 2026
781a2c8
[IMP] estate: complete property offer setup
Piyush11204 Jul 24, 2026
b0df03f
[LINT] estate: document invisible property field
Piyush11204 Jul 24, 2026
c42e855
[LINT] estate: removed the invisible property field
Piyush11204 Jul 24, 2026
1c376a8
[ADD] estate: automate total area calculation
Piyush11204 Jul 28, 2026
5705b98
[LINT] estate: fix computed field style
Piyush11204 Jul 28, 2026
7a544ec
[IMP] estate: display highest offer on properties
Piyush11204 Jul 30, 2026
d7cc3ed
[IMP] estate: compute offer deadline from validity
Piyush11204 Jul 31, 2026
a2e8f28
[IMP] estate: add deadline computation for property offers
Piyush11204 Aug 3, 2026
d247bd0
[IMP] estate: automate property and offer fields
Piyush11204 Aug 5, 2026
de62760
[REF] estate: reuse base date calculation for offer deadlines
Piyush11204 Aug 5, 2026
5ac9b7d
[CLN] estate: remove temporary list ordering
Piyush11204 Aug 6, 2026
cd58443
[IMP] estate: add sold and cancel property actions
Piyush11204 Aug 10, 2026
6b339bb
[IMP] estate: add offer accept and refuse actions
Piyush11204 Aug 11, 2026
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
22 changes: 22 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "Real Estate",
"version": "1.0",
"summary": "Real Estate Management",
"description": """
Real Estate Tutorial Module
""",
"author": "Piyush",
"category": "Tutorials",
"depends": ["base"],
"license": "LGPL-3",
"data": [
"security/ir.model.access.csv",
"views/estate_property_views.xml",
"views/estate_property_type_views.xml",
"views/estate_property_tag_view.xml",
"views/estate_property_offer_view.xml",
"views/estate_menus.xml",
],
"application": True,
"installable": True,
}
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
94 changes: 94 additions & 0 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from odoo import api, fields, models
from odoo.exceptions import UserError


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

name = fields.Char(required=True)
description = fields.Text()
postcode = fields.Char()
date_availability = fields.Date(
copy=False, default=lambda self: fields.Date.add(fields.Date.today(), 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(
selection=[
("north", "North"),
("south", "South"),
("east", "East"),
("west", "West"),
],
string="Garden Orientation",
)
active = fields.Boolean(default=True)
state = fields.Selection(
selection=[
("new", "New"),
("offer_received", "Offer Received"),
("offer_accepted", "Offer Accepted"),
("sold", "Sold"),
("canceled", "Canceled"),
],
copy=False,
default="new",
required=True,
)
property_type_id = fields.Many2one("estate.property.type", string="Type")
seller_id = fields.Many2one(
"res.users",
string="Sales Person",
default=lambda self: self.env.user,
)
buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False)
tag_ids = fields.Many2many("estate.property.tag", string="Tags")
offer_ids = fields.One2many(
"estate.property.offer",
"property_id",
string="Offers",
)
total_area = fields.Integer(compute="_compute_total_area", string="Total Area")

def action_sold(self):
for record in self:
if record.state == "canceled":
raise UserError("A canceled property cannot be sold.")
record.state = "sold"
return True

def action_cancel(self):
for record in self:
if record.state == "sold":
raise UserError("A sold property cannot be canceled.")
record.state = "canceled"
return 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

best_price = fields.Float(compute="_compute_best_price", string="Best Offer")

@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):
for record in self:
if record.garden:
record.garden_area = 10
record.garden_orientation = "north"
else:
record.garden_area = False
record.garden_orientation = False
60 changes: 60 additions & 0 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from odoo import api, fields, models
from odoo.exceptions import UserError


class EstatePropertyOffer(models.Model):
_name = "estate.property.offer"
_description = "its for the offers that we recive in the estate"

price = fields.Float()
status = fields.Selection(
selection=[
("accepted", "Accepted"),
("refused", "Refused"),
],
copy=False,
)
partner_id = fields.Many2one("res.partner", required=True)
property_id = fields.Many2one("estate.property", required=True, readonly=True)
validity = fields.Integer(default=7)

date_deadline = fields.Date(
compute="_compute_date_deadline",
inverse="_inverse_date_deadline",
)

def _get_base_date(self):
self.ensure_one()
return self.create_date.date() if self.create_date else fields.Date.today()

@api.depends("create_date", "validity")
def _compute_date_deadline(self):
for offer in self:
offer.date_deadline = fields.Date.add(
offer._get_base_date(),
days=offer.validity,
)

def _inverse_date_deadline(self):
for offer in self:
if offer.date_deadline:
offer.validity = (offer.date_deadline - offer._get_base_date()).days

def action_accept(self):
for offer in self:
property_record = offer.property_id
for other_offer in property_record.offer_ids:
if other_offer.status == "accepted":
raise UserError("Only one offer can be accepted for a property.")
offer.status = "accepted"
property_record.buyer_id = offer.partner_id
property_record.selling_price = offer.price
property_record.state = "offer_accepted"
return True

def action_refuse(self):
for offer in self:
if offer.status == "accepted":
raise UserError("An accepted offer cannot be refused.")
offer.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 fields, models


class EstatePropertyTags(models.Model):
_name = "estate.property.tag"
_description = "This model will have tags"

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 fields, models


class EstatePropertyType(models.Model):
_name = "estate.property.type"
_description = "It stores the property types"

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
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
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">
<menuitem id="estate_advertisements_menu" name="Advertisements">
<menuitem id="estate_property_menu_action" action="estate_property_action"/>
</menuitem>
<menuitem id="estate_settings_menu" name="Settings">
<menuitem id="estate_property_type_menu_action" name="Property Types" action="estate_property_type_action"/>
<menuitem id="estate_property_tag_menu_action" name="Property Tags" action="estate_property_tag_action"/>
</menuitem>
</menuitem>
</odoo>
42 changes: 42 additions & 0 deletions estate/views/estate_property_offer_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="estate_property_offer_action" model="ir.actions.act_window">
<field name="name">Estate Property Offers</field>
<field name="res_model">estate.property.offer</field>
<field name="view_mode">tree,form</field>
</record>
<record id="estate_property_offer_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>
<field name="price"/>
<field name="partner_id"/>
<field name="status"/>
<field name="validity"/>
<field name="date_deadline"/>
</list>
</field>
</record>
<record id="estate_property_offer_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>
<header>
<button name="action_accept" type="object" string="Accept" class="btn-primary" />
<button name="action_refuse" type="object" string="Refuse" />
</header>
<sheet>
<group>
<field name="price"/>
<field name="partner_id"/>
<field name="status"/>
<field name="validity"/>
<field name="date_deadline"/>
</group>
</sheet>
</form>
</field>
</record>
</odoo>
8 changes: 8 additions & 0 deletions estate/views/estate_property_tag_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<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>
8 changes: 8 additions & 0 deletions estate/views/estate_property_type_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<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>
102 changes: 102 additions & 0 deletions estate/views/estate_property_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<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>
<record id="estate_property_view_list" model="ir.ui.view">
<field name="name">estate.property.list</field>
<field name="model">estate.property</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
<field name="expected_price"/>
<field name="selling_price"/>
<field name="bedrooms"/>
<field name="living_area"/>
<field name="postcode"/>
<field name="state"/>
</list>
</field>
</record>
<record id="estate_property_view_form" model="ir.ui.view">
<field name="name">estate.property.view.form</field>
<field name="model">estate.property</field>
<field name="arch" type="xml">
<form>
<header>
<button string="Sold" name="action_sold" type="object" class="btn-primary"/>
<button string="Cancel" name="action_cancel" type="object"/>
</header>
<sheet>
<group>
<group>
<field name="name"/>
<field name="expected_price"/>
<field name="bedrooms"/>
<field name="property_type_id" />
<field name="living_area"/>
<field name="facades"/>
<field name="best_price" readonly="1"/>
<!-- <field name="total_area" readonly="1"/> -->
<field name="total_area"/>
</group>
<group>
<field name="selling_price" readonly="1"/>
<field name="postcode"/>
<field name="tag_ids" widget="many2many_tags"/>
<field name="date_availability"/>
<field name="garden"/>
<field name="garden_area"/>
<field name="garden_orientation"/>
</group>
</group>
<notebook>
<page string="Description">
<group>
<field name="description"/>
</group>
</page>
<page string="Other Info">
<group >
<group>
<field name="seller_id"/>
<field name="buyer_id"/>
</group>
</group>
</page>
<page name="Offers" string="Offers">
<group >
<group>
<field name="offer_ids"/>
</group>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>

<record id="estate_property_view_search" model="ir.ui.view">
<field name="name">estate.property.view.search</field>
<field name="model">estate.property</field>
<field name="arch" type="xml">
<search string="Properties">
<field name="name"/>
<field name="postcode"/>
<field name="expected_price"/>
<field name="bedrooms"/>
<field name="living_area"/>
<field name="facades"/>
<filter name="available" string="Available" domain="[('state', 'in', ['new', 'offer_received'])]" />
<filter name="expensive" string="Expensive" domain="[('expected_price', '>', 50000)]" />
<group >
<filter name="group_by_postcode" string="Postcode" context="{'group_by': 'postcode'}" />
<filter name="group_by_bedroom" string="Bedrooms" context="{'group_by': 'bedrooms'}" />
</group>
</search>
</field>
</record>
</odoo>