From f28b1ca106fbe2fe437bca7a38a273abb35de568 Mon Sep 17 00:00:00 2001 From: kapat-odoo Date: Mon, 9 Feb 2026 14:37:15 +0530 Subject: [PATCH 1/6] [ADD] estate: added the Real Estate Modeule. Initialized the 'estate' module and made it installable in Odoo. This commit bootstraps the custom estate module and sets up the minimal structure required by Odoo to load and install a new application. Created the module structure 'estate' inside the tutorials directory, configured basic module metadata. Restarted the server to load the module, then verified it is visible in the Apps menu. Chapter 1 and 2 of the documentation. --- estate/README.rst | 1 + estate/__init__.py | 0 estate/__manifest__.py | 12 ++++++++++++ estate/models/__init__.py | 0 4 files changed, 13 insertions(+) create mode 100644 estate/README.rst create mode 100644 estate/__init__.py create mode 100644 estate/__manifest__.py create mode 100644 estate/models/__init__.py diff --git a/estate/README.rst b/estate/README.rst new file mode 100644 index 00000000000..b2543652afd --- /dev/null +++ b/estate/README.rst @@ -0,0 +1 @@ +Real Estate Module README file \ No newline at end of file diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..741e7f7e13d --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,12 @@ +{ + 'name': 'Real Estate Kapat', + 'version': '1.1', + 'summary': 'Module to Mangage Real Estate Property Listings', + 'website': 'https://www.odoo.com/app/estate', + 'depends': [ + 'base', + ], + 'application': True, + 'author': 'Odoo S.A.', + 'license': 'LGPL-3', +} diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..e69de29bb2d From 5969188f6b212b61a4c6fd96e414b0c6ccf6ced7 Mon Sep 17 00:00:00 2001 From: kapat-odoo Date: Tue, 10 Feb 2026 14:16:15 +0530 Subject: [PATCH 2/6] [ADD] estate: add basic fields to property model Added the 'estate.property' model with all required fields and enforce field constraints. This commit implements the core data structure for the Real Estate module, ensuring properties have the appropriate attributes stored in the database and enforcing essential constraints to maintain data quality. These fields serve as the foundation for later views, business logic, and workflows built on top of the model. Defined fields such as name, description, postcode, date_availability, expected_price, selling_price, bedrooms, living_area, facades, garage, garden, garden_area, garden_orientation as per Chapter 3 of documentation. --- estate/README.rst | 1 - estate/__init__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 25 +++++++++++++++++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) delete mode 100644 estate/README.rst create mode 100644 estate/models/estate_property.py diff --git a/estate/README.rst b/estate/README.rst deleted file mode 100644 index b2543652afd..00000000000 --- a/estate/README.rst +++ /dev/null @@ -1 +0,0 @@ -Real Estate Module README file \ No newline at end of file diff --git a/estate/__init__.py b/estate/__init__.py index e69de29bb2d..0650744f6bc 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/estate/models/__init__.py b/estate/models/__init__.py index e69de29bb2d..5e1963c9d2f 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -0,0 +1 @@ +from . import estate_property diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py new file mode 100644 index 00000000000..159ee09e80c --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,25 @@ +from odoo import fields, models + + +class EstateProperty(models.Model): + _name = "estate.property" + _description = "Estate Property module for Odoo 19 tutorials Hello World" + + name = fields.Char(required=True) + description = fields.Text() + postcode = fields.Char() + date_availability = fields.Date() + expected_price = fields.Float(required=True) + selling_price = fields.Float() + bedrooms = fields.Integer() + 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"), + ]) From 6e5ea80ed0b88eaaaa3aeeabe8bd3cac5ca2304d Mon Sep 17 00:00:00 2001 From: kapat-odoo Date: Wed, 11 Feb 2026 15:44:33 +0530 Subject: [PATCH 3/6] [IMP] estate: implemented access rights for the estate module. Implemented security access control to the estate module to remove the missing access rules warning and allow proper user access. Without explicit access rules, Odoo blocks access to the new models and logs a warning about missing security rules. Adding these ACL entries ensures that regular users in the 'base.group_user' group can interact with the estate models as intended, providing a baseline security setup for the module. As per discussed in Chapter 4 provided permission to base.group_user to read, write, create and unlink. --- estate/__manifest__.py | 3 +++ estate/security/ir.model.access.csv | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 741e7f7e13d..0204cd95bf9 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -6,6 +6,9 @@ 'depends': [ 'base', ], + 'data': [ + 'security/ir.model.access.csv', + ], 'application': True, 'author': 'Odoo S.A.', 'license': 'LGPL-3', diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..0e11f47e58d --- /dev/null +++ b/estate/security/ir.model.access.csv @@ -0,0 +1,2 @@ +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 \ No newline at end of file From 270530588534673f495cdffda0b1d0cedba2b75e Mon Sep 17 00:00:00 2001 From: kapat-odoo Date: Fri, 13 Feb 2026 10:42:16 +0530 Subject: [PATCH 4/6] [IMP] estate: implemented default list and form view for the estate module. Made the estate module interactive and visible in root menu of Odoo, also implemented action menus with different menu items and hierarchy. Now the listings of property appears in list view and while creating a new property it opens in form view while also making changes to fields to make them have default values and made sure they cannot be copied. As per Chapter 5 of Documentation. --- estate/__manifest__.py | 2 ++ estate/models/estate_property.py | 16 ++++++++++++---- estate/views/estate_menus.xml | 8 ++++++++ estate/views/estate_property_views.xml | 8 ++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 estate/views/estate_menus.xml create mode 100644 estate/views/estate_property_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 0204cd95bf9..cdee1044471 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -8,6 +8,8 @@ ], 'data': [ 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml', ], 'application': True, 'author': 'Odoo S.A.', diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 159ee09e80c..9eb12ff9a7b 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -5,13 +5,13 @@ class EstateProperty(models.Model): _name = "estate.property" _description = "Estate Property module for Odoo 19 tutorials Hello World" - name = fields.Char(required=True) + name = fields.Char(default="Unknown", required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date() + date_availability = fields.Date(copy=False, default=fields.Date.add(fields.Date.today(), months=3)) expected_price = fields.Float(required=True) - selling_price = fields.Float() - bedrooms = fields.Integer() + selling_price = fields.Float(readonly=True, copy=False) + bedrooms = fields.Integer(default=2) living_area = fields.Integer() facades = fields.Integer() garage = fields.Boolean() @@ -23,3 +23,11 @@ class EstateProperty(models.Model): ("east", "East"), ("west", "West"), ]) + active = fields.Boolean(default=True) + state = fields.Selection([ + ("new", "New"), + ("offer_received", "Offer Received"), + ("offer_accepted", "Offer Accepted"), + ("sold", "Sold"), + ("canceled", "Canceled"), + ], copy=False, default="new") diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..045d7de5393 --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml new file mode 100644 index 00000000000..9a7257a24df --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,8 @@ + + + + Estate Properties + estate.property + list,form + + From 4d9298d447e44e7eb92389c6d0898d6d3cdfe24e Mon Sep 17 00:00:00 2001 From: kapat-odoo Date: Mon, 16 Feb 2026 17:18:56 +0530 Subject: [PATCH 5/6] [ADD] estate: added list and form views for estate.property along with search. Added list and form views for estate.property along with search and custom filters like (to check availability and Group by Postcode). This commit replaces the default auto-generated views with list view for providing a quick glance at all important attributes related to the property and implemented better custom form view (which now also features 'state' selection which will be further useful in checking functionality of the custom filter). Along with that also added fields in search so that it can provide user to choose which particular attribute the search should query, also implemented custom filter for checking if the property is available by looking up the state and a 'Group By Postcode'. As per discussed in Chapter 6. --- estate/views/estate_property_views.xml | 75 ++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 9a7257a24df..df3823af9d1 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -5,4 +5,79 @@ estate.property list,form + + + estate.property.list + estate.property + + + + + + + + + + + + + + + estate.property.form + estate.property + +
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + estate.property.search + estate.property + + + + + + + + + + + + + + + From b8876ae7d24043270bcf6554516cc7595990fdeb Mon Sep 17 00:00:00 2001 From: kapat-odoo Date: Tue, 17 Feb 2026 17:16:19 +0530 Subject: [PATCH 6/6] [ADD] estate: added relational models and fields for estate module. Added relational fields like Property Type, Buyer and Salesperson, Property Tags and Offers. Property Type makes it more dynamic and easy to add common types of property types to any new property listing while also maintaining its own table as 'estate_property_type', Buyer and Salesperson have been defined based on their property such that further validating can be done by using their respective external:id, Property tags allows multiple properties to have multiple tags which is displayed in the form view and is maintained in a separate join table and lastly the offers tab lists all the offers particular to that property. As per discussed in Chapter 7. --- estate/__manifest__.py | 3 ++ estate/models/__init__.py | 3 ++ estate/models/estate_property.py | 5 +++ estate/models/estate_property_offer.py | 14 ++++++++ estate/models/estate_property_tag.py | 8 +++++ estate/models/estate_property_type.py | 8 +++++ estate/security/ir.model.access.csv | 5 ++- estate/views/estate_menus.xml | 11 ++++-- estate/views/estate_property_offer_views.xml | 21 ++++++++++++ estate/views/estate_property_tag_views.xml | 19 +++++++++++ estate/views/estate_property_type_views.xml | 35 ++++++++++++++++++++ estate/views/estate_property_views.xml | 19 ++++++++++- 12 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 estate/models/estate_property_offer.py create mode 100644 estate/models/estate_property_tag.py create mode 100644 estate/models/estate_property_type.py create mode 100644 estate/views/estate_property_offer_views.xml create mode 100644 estate/views/estate_property_tag_views.xml create mode 100644 estate/views/estate_property_type_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index cdee1044471..95facd959f4 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -9,7 +9,10 @@ 'data': [ 'security/ir.model.access.csv', 'views/estate_property_views.xml', + 'views/estate_property_type_views.xml', + 'views/estate_property_tag_views.xml', 'views/estate_menus.xml', + 'views/estate_property_offer_views.xml', ], 'application': True, 'author': 'Odoo S.A.', diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 5e1963c9d2f..8f2187ee09e 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,4 @@ from . import estate_property +from . import estate_property_offer +from . import estate_property_tag +from . import estate_property_type diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 9eb12ff9a7b..d01e79d31f5 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -31,3 +31,8 @@ class EstateProperty(models.Model): ("sold", "Sold"), ("canceled", "Canceled"), ], copy=False, default="new") + property_type_id = fields.Many2one("estate.property.type", string="Property Type") + salesperson_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user) + buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) + tag_ids = fields.Many2many("estate.property.tag", string="Property Tags") + offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py new file mode 100644 index 00000000000..e14de5391f4 --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,14 @@ +from odoo import fields, models + + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Estate Property Offer module for Odoo 19 tutorials Hello World" + + price = fields.Float(required=True, string="Offer Price") + status = fields.Selection([ + ("accepted", "Accepted"), + ("refused", "Refused"), + ], copy=False, string="Offer Status") + partner_id = fields.Many2one("res.partner", string="Partner", required=True) + property_id = fields.Many2one("estate.property", string="Property", required=True) diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..9140422c93b --- /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 = "Estate Property Tags module for Odoo 19 tutorials Hello World" + + name = fields.Char(required=True, string="Tag Name") diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..aa0875562f1 --- /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 = "Estate Property Type module for Odoo 19 tutorials Hello World" + + name = fields.Char(required=True, string="Property Type Name") diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 0e11f47e58d..89f97c50842 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +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 \ No newline at end of file +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 diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 045d7de5393..c29811c19ca 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,8 +1,13 @@ - - + + + + + + + - + diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..e26075d98ce --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,21 @@ + + + + Estate Property Offers + estate.property.offer + list,form + + + + estate.property.offer.list + estate.property.offer + + + + + + + + + + diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 00000000000..6ca5016f35b --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,19 @@ + + + + Estate Property Tags + estate.property.tag + list,form + + + + estate.property.tag.list + estate.property.tag + + + + + + + + diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..b66d6cd6b03 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,35 @@ + + + + Estate Property Types + estate.property.type + list,form + + + + estate.property.type.list + estate.property.type + + + + + + + + + estate.property.type.form + estate.property.type + +
+ +
+

+ +

+
+
+
+
+
+ +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index df3823af9d1..ffd6255950a 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -12,6 +12,8 @@ + + @@ -22,6 +24,7 @@ + estate.property.form estate.property @@ -30,11 +33,13 @@

- +

+
+ @@ -57,11 +62,21 @@ + + + + + + + + +
+ estate.property.search estate.property @@ -74,10 +89,12 @@ + +