Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
1e08d46
[ADD] added estate property model with basic fields using Odoo ORM
sasri-odoo Feb 5, 2026
60035e9
[CLN] estate: align code with coding guidelines
sasri-odoo Feb 5, 2026
45334f0
[CLN] estate: code cleanup
sasri-odoo Feb 6, 2026
a3de2f7
[FIX] estate: add missing author and license to manifest
sasri-odoo Feb 6, 2026
fdc5376
[IMP] estate: add menus, actions, and custom list/form/search views
sasri-odoo Feb 6, 2026
331964c
[IMP] estate: add many2one relations for property type, buyer, and sa…
sasri-odoo Feb 9, 2026
894cde3
[IMP] estate: CH-7 added model relations using many2one, many2many, a…
sasri-odoo Feb 10, 2026
2b960e9
[LINT] Fix linting errors and formatting in estate property models
sasri-odoo Feb 10, 2026
2fde279
[LINT] spacing mistake cleared
sasri-odoo Feb 10, 2026
f244f8d
[LINT] estate: fixed spacing, quotes(referred docs), view naming
sasri-odoo Feb 11, 2026
87514d8
[LINT] estate: fix End Of File newline in 2files and bracket spacing…
sasri-odoo Feb 11, 2026
4e9557d
[IMP] estate: implemented computed fields, inverse logic for offer de…
sasri-odoo Feb 12, 2026
675a77a
[LINT] estate: Fixed spacing and naming issues
sasri-odoo Feb 12, 2026
a8a0104
[LINT] estate: Fixed minor spacing issues and formatting issues
sasri-odoo Feb 13, 2026
003b7a3
[IMP] estate: [CH-9] implemented cancel/sold actions and offer accept…
sasri-odoo Feb 13, 2026
039c606
[LINT] estate: fixed spacing error
sasri-odoo Feb 13, 2026
5f08659
[IMP] estate: created a custom group, edited page view in the tab 'of…
sasri-odoo Feb 16, 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
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",
"category": "Tutorial",
"summary": "Manage real estate properties",
"author": "sasri-odoo",
"license": "LGPL-3",
"depends": ["base"],
"data": [
"security/estate_security.xml",
"security/ir.model.access.csv",
"views/estate_property_views.xml",
"views/estate_property_type_views.xml",
"views/estate_property_tag_views.xml",
"views/estate_property_offer_views.xml",
"views/estate_menus.xml",
],
"application": 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
118 changes: 118 additions & 0 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from datetime import timedelta

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()
description = fields.Text(required=True)
postcode = fields.Char()
date_availability = fields.Date(
default=lambda self: fields.Date.today() + timedelta(days=90),
copy=False,
)
expected_price = fields.Float(readonly=True, copy=False)
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"),
]
)
active = fields.Boolean(default=True)
state = fields.Selection(
[
('new', "New"),
('offer_received', "Offer Received"),
('offer_accepted', "Offer Accepted"),
('sold', "Sold"),
('cancelled', "Cancelled"),
],
readonly=True,
default="new",
required=True,
copy=False,
)
property_type_id = fields.Many2one(
"estate.property.type",
string="Property Type",
)
buyer_id = fields.Many2one(
"res.partner",
string="Buyer",
copy=False,
)
user_id = fields.Many2one(
"res.users",
string="Salesperson",
default=lambda self: self.env.user,
)
tag_ids = fields.Many2many(
"estate.property.tag",
string="Tags",
)
offer_ids = fields.One2many(
"estate.property.offer",
"property_id",
string="Offers",
)
total_area = fields.Float(
string="Total Area",
compute="_compute_total_area"
)
best_price = fields.Float(
string="Best Price",
compute="_computer_best_price"
)

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

@api.depends("offer_ids.price")
def _computer_best_price(self):
for record in self:
if record.offer_ids:
record.best_price = max(record.offer_ids.mapped("price"))
else:
record.best_price = 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 = False

def action_cancel(self):
for record in self:
if record.state == "sold":
raise UserError("A sold property cannot be cancelled")
record.state = "cancelled"

def action_sold(self):
for record in self:
if record.state == "cancelled":
raise UserError("A cancelled property cannot be sold")
accepted = record.offer_ids.filtered(
lambda o: o.status == "accepted"
)
if not accepted:
raise UserError("You must accept an offer before selling.")
record.state = "sold"
74 changes: 74 additions & 0 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from datetime import timedelta

from odoo import api, fields, models

from odoo.exceptions import UserError


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

price = fields.Float(required=True)
status = fields.Selection(
[
('accepted', "Accepted"),
('refused', "Refused"),
],
copy=False,
)
partner_id = fields.Many2one(
"res.partner",
string="Buyer",
required=True,
)
property_id = fields.Many2one(
"estate.property",
string="Property",
required=True,
)
validity = fields.Integer(
string="Validity (days)",
default=7
)
date_deadline = fields.Date(
string="Deadline",
compute="_compute_date_deadline",
inverse="_inverse_date_deadline"
)

@api.depends("create_date", "validity")
def _compute_date_deadline(self):
for record in self:
base_date = record.create_date.date() if record.create_date else fields.Date.today()
record.date_deadline = base_date + timedelta(days=record.validity)

def _inverse_date_deadline(self):
for record in self:
if record.create_date and record.date_deadline:
delta = record.date_deadline - record.create_date.date()
record.validity = delta.days

def action_accept(self):
for record in self:
if record.property_id.state in ["cancelled", "sold"]:
raise UserError("Cannot accept an offer for a cancelled or sold property")
accepted_offers = record.property_id.offer_ids.filtered(
lambda o: o.status == "accepted"
)
if accepted_offers:
raise UserError("an offer has already been accepted for this property")
record.status = "accepted"
record.property_id.selling_price = record.price
record.property_id.buyer_id = record.partner_id
record.property_id.state = "offer_accepted"

def action_refuse(self):
for record in self:
if record.property_id.state in ["cancelled", "sold"]:
raise UserError("Cannot modify offers for a sold or cancelled property")
if record.status == "accepted":
record.property_id.selling_price = 0.0
record.property_id.buyer_id = False
record.property_id.state = "new"
record.status = "refused"
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 = "Property Tag"

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 = "Property Type"

name = fields.Char(required=True)
5 changes: 5 additions & 0 deletions estate/security/estate_security.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<odoo>
<record id="group_estate_manager" model="res.groups">
<field name="name">Estate Manager</field>
</record>
</odoo>
6 changes: 6 additions & 0 deletions estate/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
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
access_estate_property_manager,access_estate_property_manager,model_estate_property,estate.group_estate_manager,1,1,1,1
31 changes: 31 additions & 0 deletions estate/views/estate_menus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>

<odoo>
<menuitem id="estate_menu_root" name="Real Estate">
<menuitem id="estate_menu_properties" name="Properties">
<menuitem
id="estate_menu_properties_action"
action="estate_property_action"
/>
</menuitem>
<menuitem id="estate_menu_property_type" name="Property Type">
<menuitem
id="estate_menu_property_type_action"
action="estate_property_type_action"
/>
</menuitem>
<menuitem id="estate_menu_property_tag" name="Property Tag">
<menuitem
id="estate_menu_property_tag_action"
action="estate_property_tag_action"
/>
</menuitem>
<menuitem id="estate_menu_property_offer" name="Property Offer">
<menuitem
id="estate_menu_property_offer_action"
action="estate_property_offer_action"
/>
</menuitem>

</menuitem>
</odoo>
42 changes: 42 additions & 0 deletions estate/views/estate_property_offer_views.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">Offer</field>
<field name="res_model">estate.property.offer</field>
<field name="view_mode">list,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>
<field name="price"/>
<field name="partner_id"/>
<field name="status"/>
<field name="property_id"/>
</list>
</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="status"/>
<field name="validity"/>
<field name="date_deadline"/>
<field name="property_id"/>
</group>
</sheet>
</form>
</field>
</record>

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

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

<record id="estate_property_tag_view_list" model="ir.ui.view">
<field name="name">estate.property.tag.view.list</field>
<field name="model">estate.property.tag</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
</list>
</field>
</record>

</odoo>
34 changes: 34 additions & 0 deletions estate/views/estate_property_type_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_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>

<record id="estate_property_type_view_list" model="ir.ui.view">
<field name="name">estate.property.type.view.list</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
</list>
</field>
</record>

<record id="estate_property_type_view_form" model="ir.ui.view">
<field name="name">estate.property.type.view.form</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="name"/>
</group>
</sheet>
</form>
</field>
</record>

</odoo>
Loading