diff --git a/estate/__init__.py b/estate/__init__.py
new file mode 100644
index 00000000000..0650744f6bc
--- /dev/null
+++ b/estate/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/estate/__manifest__.py b/estate/__manifest__.py
new file mode 100644
index 00000000000..508f7064eff
--- /dev/null
+++ b/estate/__manifest__.py
@@ -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,
+}
diff --git a/estate/demo/estate_property_data.xml b/estate/demo/estate_property_data.xml
new file mode 100644
index 00000000000..8ea006ac286
--- /dev/null
+++ b/estate/demo/estate_property_data.xml
@@ -0,0 +1,153 @@
+
+
+
+ Beautiful Villa in Downtown
+ A stunning 3-bedroom villa with modern amenities
+ 382421
+ 2026-06-15
+ 6767676.00
+ 3
+ 9234
+ 2
+ True
+ True
+ 5000
+ south
+ new
+
+
+ Cozy House with Garden
+ Perfect starter home with large garden
+ 400605
+ 2026-07-01
+ 100000.00
+ 2
+ 500
+ 1
+ False
+ True
+ 2000
+ north
+ new
+
+
+ Modern Apartment
+ Newly built apartment in city center
+ 382421
+ 2026-05-20
+ 250000.00
+ 2
+ 750
+ 3
+ True
+ False
+ 0
+ east
+ new
+
+
+ Traditional Cottage
+ Charming countryside cottage
+ 400605
+ 2026-08-10
+ 180000.00
+ 3
+ 650
+ 2
+ True
+ True
+ 3000
+ west
+ new
+
+
+ Luxury Penthouse
+ High-end penthouse with panoramic views
+ 382421
+ 2026-04-01
+ 500000.00
+ 4
+ 1200
+ 2
+ True
+ True
+ 1000
+ south
+ new
+
+
+ Seaside Bungalow
+ Relaxing bungalow with sea view
+ 600001
+ 2026-10-01
+ 420000.00
+ 2
+ 800
+ 2
+ False
+ True
+ 1500
+ east
+ new
+
+
+ Mountain Cabin
+ Cozy cabin in the mountains
+ 700002
+ 2026-11-15
+ 210000.00
+ 3
+ 600
+ 1
+ False
+ True
+ 1200
+ west
+ new
+
+
+ City Studio
+ Compact studio apartment for singles
+ 800003
+ 2026-12-01
+ 95000.00
+ 1
+ 350
+ 1
+ False
+ False
+ 0
+ north
+ new
+
+
+ Family Home
+ Spacious home perfect for families
+ 900004
+ 2027-01-10
+ 300000.00
+ 4
+ 1100
+ 2
+ True
+ True
+ 2000
+ south
+ new
+
+
+ Downtown Office Space
+ Modern office space in business district
+ 100005
+ 2027-02-01
+ 800000.00
+ 0
+ 2000
+ 4
+ True
+ False
+ 0
+ east
+ new
+
+
diff --git a/estate/models/__init__.py b/estate/models/__init__.py
new file mode 100644
index 00000000000..2f1821a39c1
--- /dev/null
+++ b/estate/models/__init__.py
@@ -0,0 +1,4 @@
+from . import estate_property
+from . import estate_property_type
+from . import estate_property_tag
+from . import estate_property_offer
diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py
new file mode 100644
index 00000000000..73fe80f2f7c
--- /dev/null
+++ b/estate/models/estate_property.py
@@ -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'
diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py
new file mode 100644
index 00000000000..3e2fd5bad5c
--- /dev/null
+++ b/estate/models/estate_property_offer.py
@@ -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
diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py
new file mode 100644
index 00000000000..6e4099899cf
--- /dev/null
+++ b/estate/models/estate_property_tag.py
@@ -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)
diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py
new file mode 100644
index 00000000000..1dd588218ff
--- /dev/null
+++ b/estate/models/estate_property_type.py
@@ -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)
diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv
new file mode 100644
index 00000000000..6905974b938
--- /dev/null
+++ b/estate/security/ir.model.access.csv
@@ -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
diff --git a/estate/security/security.xml b/estate/security/security.xml
new file mode 100644
index 00000000000..aceaae91826
--- /dev/null
+++ b/estate/security/security.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ Real Estate
+ Real Estate Management
+
+
+
+ Real Estate
+
+
+
+
+ Agent
+
+
+
+
+ Manager
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/estate/static/description/icon.png b/estate/static/description/icon.png
new file mode 100644
index 00000000000..6fc6561a21c
Binary files /dev/null and b/estate/static/description/icon.png differ
diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml
new file mode 100644
index 00000000000..53f245deb28
--- /dev/null
+++ b/estate/views/estate_menus.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/estate/views/estate_property_offers_views.xml b/estate/views/estate_property_offers_views.xml
new file mode 100644
index 00000000000..c8bb1198f92
--- /dev/null
+++ b/estate/views/estate_property_offers_views.xml
@@ -0,0 +1,34 @@
+
+
+
+ estate.property.offer.form
+ estate.property.offer
+
+
+
+
+
+
+ estate.property.offer.list
+ estate.property.offer
+
+
+
+
+
+
+
+
+
+
+
diff --git a/estate/views/estate_property_tags_views.xml b/estate/views/estate_property_tags_views.xml
new file mode 100644
index 00000000000..6a3adee6972
--- /dev/null
+++ b/estate/views/estate_property_tags_views.xml
@@ -0,0 +1,42 @@
+
+
+
+ estate.property.tag.form
+ estate.property.tag
+
+
+
+
+
+
+ estate.property.tag.list
+ estate.property.tag
+
+
+
+
+
+
+
+
+ estate.property.tag.search
+ estate.property.tag
+
+
+
+
+
+
+
+
+ Property Tags
+ estate.property.tag
+ list,form
+
+
diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml
new file mode 100644
index 00000000000..6fab9d23e29
--- /dev/null
+++ b/estate/views/estate_property_type_views.xml
@@ -0,0 +1,42 @@
+
+
+
+ estate.property.type.form
+ estate.property.type
+
+
+
+
+
+
+ estate.property.type.list
+ estate.property.type
+
+
+
+
+
+
+
+
+ estate.property.type.search
+ estate.property.type
+
+
+
+
+
+
+
+
+ Property Types
+ estate.property.type
+ list,form
+
+
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml
new file mode 100644
index 00000000000..446a1b6dfce
--- /dev/null
+++ b/estate/views/estate_property_views.xml
@@ -0,0 +1,121 @@
+
+
+
+ estate.property.form
+ estate.property
+
+
+
+
+
+
+ estate.property.list
+ estate.property
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ estate.property.search
+ estate.property
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Properties
+ estate.property
+ list,form
+ {'search_default_properties_with_offers': 1}
+
+