From 88181a303d2d15ff4c409d825d451583d16ccef2 Mon Sep 17 00:00:00 2001 From: "Soham Patil (sopat)" Date: Tue, 10 Mar 2026 18:37:55 +0530 Subject: [PATCH 1/6] [ADD] Chapter 2&3 (Estate) Completed the initial setup for the new Real Estate module. Created the base directory structure and manifest. Successfully installed the module. Initialized model and model fields which generates tables using odoo ORM --- estate/__init__.py | 1 + estate/__manifest__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 28 ++++++++++++++++++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 estate/__init__.py create mode 100644 estate/__manifest__.py create mode 100644 estate/models/__init__.py create mode 100644 estate/models/estate_property.py 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..606035919fb --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1 @@ +{'name': 'Real Estate', 'depends': ['base']} diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..5e1963c9d2f --- /dev/null +++ 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..2b1f75517b3 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,28 @@ +from odoo import fields, models + +class EstateProperty(models.Model): + _name = "estate.property" + _description = "Real Estate Property" # Removes the terminal warning + + # Required fields (not null in database) + name = fields.Char(required=True) + expected_price = fields.Float(required=True) + + # Basic fields + description = fields.Text() + postcode = fields.Char() + date_availability = fields.Date() + selling_price = fields.Float() + bedrooms = fields.Integer() + living_area = fields.Integer() + facades = fields.Integer() + garage = fields.Boolean() + garden = fields.Boolean() + garden_area = fields.Integer() + + # Selection field (Dropdown) + garden_orientation = fields.Selection( + string='Orientation', + selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], + help="The direction the garden faces." + ) \ No newline at end of file From 15ba5f87ef0a2c7cdc93cada8d290103aa61eb90 Mon Sep 17 00:00:00 2001 From: "Soham Patil (sopat)" Date: Wed, 11 Mar 2026 18:01:02 +0530 Subject: [PATCH 2/6] [IMP] Estate:Fixed Issues and Completed Chapter-4 Fixed warnings and errors raised by the first push. Created security/ir.model.access.csv file in estate for defining access rights. Added the data in csv file and defined the csv file in manifest. --- estate/__manifest__.py | 12 +++++++++++- estate/models/estate_property.py | 11 ++++------- estate/security/ir.model.access.csv | 2 ++ 3 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 606035919fb..be547d5fdba 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1 +1,11 @@ -{'name': 'Real Estate', 'depends': ['base']} +{ + 'name': 'Real Estate', + 'author': 'soham', + 'license': 'LGPL-3', + 'depends': ['base'], + 'data': [ + 'security/ir.model.access.csv', + ], + 'installable': True, + 'application': True, +} diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 2b1f75517b3..9556516ad4d 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,14 +1,12 @@ from odoo import fields, models + class EstateProperty(models.Model): _name = "estate.property" - _description = "Real Estate Property" # Removes the terminal warning + _description = "Real Estate Property" - # Required fields (not null in database) name = fields.Char(required=True) expected_price = fields.Float(required=True) - - # Basic fields description = fields.Text() postcode = fields.Char() date_availability = fields.Date() @@ -19,10 +17,9 @@ class EstateProperty(models.Model): garage = fields.Boolean() garden = fields.Boolean() garden_area = fields.Integer() - - # Selection field (Dropdown) garden_orientation = fields.Selection( string='Orientation', selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], help="The direction the garden faces." - ) \ No newline at end of file + + ) 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 1039a390b46dfaaf46f8d4d6ce263006ac13793a Mon Sep 17 00:00:00 2001 From: "Soham Patil (sopat)" Date: Thu, 12 Mar 2026 18:38:16 +0530 Subject: [PATCH 3/6] [IMP] Estate:Partially Completed Chapter-5 Created estate_property_views.xml for the window action. Implemented 3-level menu structure: Root, Advertisements, and Properties. Linked the menu to the window action to enable UI navigation. --- estate/__manifest__.py | 2 ++ estate/views/estate_menus.xml | 7 +++++++ estate/views/estate_property_views.xml | 7 +++++++ 3 files changed, 16 insertions(+) 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 be547d5fdba..b6699025785 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -5,6 +5,8 @@ 'depends': ['base'], 'data': [ 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml', ], 'installable': True, 'application': True, diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..1c6d53ac7bd --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml new file mode 100644 index 00000000000..4d544c18597 --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,7 @@ + + + Properties + estate.property + list,form + + From aab2bd161f0f5d40bf88b474de95e244458440ff Mon Sep 17 00:00:00 2001 From: "Soham Patil (sopat)" Date: Fri, 13 Mar 2026 19:09:33 +0530 Subject: [PATCH 4/6] [IMP] Estate:Completed Chapter-5 Added readonly and copy=False attributes to selling_price field. Set default value of 2 for bedrooms field. Set default availability date to 3 months from today using Date.add(). Added active reserved field with default=True for record visibility. Added state reserved field with specific values. --- estate/models/estate_property.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 9556516ad4d..6e87ec1cb91 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -9,10 +9,11 @@ class EstateProperty(models.Model): expected_price = fields.Float(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date() - selling_price = fields.Float() - bedrooms = fields.Integer() + date_availability = fields.Date(copy=False) + selling_price = fields.Float(readonly=True,copy=False) + bedrooms = fields.Integer(default= 2) living_area = fields.Integer() + active = fields.Boolean(default=True) facades = fields.Integer() garage = fields.Boolean() garden = fields.Boolean() @@ -23,3 +24,17 @@ class EstateProperty(models.Model): help="The direction the garden faces." ) + state = fields.Selection( + selection=[ + ('new', 'New'), + ('offer_received', 'Offer Received'), + ('offer_accepted', 'Offer Accepted'), + ('sold', 'Sold'), + ('canceled', 'Cancelled'), + ], + string="Status", + required=True, + copy=False, + default='new', + ) + \ No newline at end of file From ae34671000caecfc0fe00068541bc709c7c05684 Mon Sep 17 00:00:00 2001 From: "Soham Patil (sopat)" Date: Mon, 16 Mar 2026 23:14:14 +0530 Subject: [PATCH 5/6] [IMP] Estate:Errors Fixed & Completed Chapter-6 Added list view with key property fields for display. Added form view with grouped fields and description tab. Added search view with title and postcode search fields. Added Available filter using date_availability domain. Added Group By postcode option in search view. --- estate/models/estate_property.py | 22 ++++--- estate/views/estate_menus.xml | 4 +- estate/views/estate_property_views.xml | 83 ++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 14 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 6e87ec1cb91..0fb1e631e83 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -9,9 +9,9 @@ class EstateProperty(models.Model): expected_price = fields.Float(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date(copy=False) - selling_price = fields.Float(readonly=True,copy=False) - bedrooms = fields.Integer(default= 2) + date_availability = fields.Date(copy=False, default=lambda self: fields.Date.add(fields.Date.today(), months=3)) + selling_price = fields.Float(readonly=True, copy=False) + bedrooms = fields.Integer(default=2) living_area = fields.Integer() active = fields.Boolean(default=True) facades = fields.Integer() @@ -19,22 +19,20 @@ class EstateProperty(models.Model): garden = fields.Boolean() garden_area = fields.Integer() garden_orientation = fields.Selection( - string='Orientation', - selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], + string="Orientation", + selection=[('north', "North"), ('south', "South"), ('east', "East"), ('west', "West")], help="The direction the garden faces." - ) state = fields.Selection( selection=[ - ('new', 'New'), - ('offer_received', 'Offer Received'), - ('offer_accepted', 'Offer Accepted'), - ('sold', 'Sold'), - ('canceled', 'Cancelled'), + ('new', "New"), + ('offer_received', "Offer Received"), + ('offer_accepted', "Offer Accepted"), + ('sold', "Sold"), + ('canceled', "Cancelled"), ], string="Status", required=True, copy=False, default='new', ) - \ No newline at end of file diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 1c6d53ac7bd..5d240e46a1a 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -2,6 +2,6 @@ + action="estate_property_action" + parent="estate_first_level_menu"/> diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 4d544c18597..1e3ef74349f 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -4,4 +4,87 @@ estate.property list,form + + + estate.property.list + estate.property + + + + + + + + + + + + + + + estate.property.form + estate.property + +
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + estate.property.search + estate.property + + + + + + + + + + + + + + + From 2db9029671811520bc77dc232bc1268630e0a972 Mon Sep 17 00:00:00 2001 From: "Soham Patil (sopat)" Date: Wed, 18 Mar 2026 18:44:31 +0530 Subject: [PATCH 6/6] [IMP] Estate: Completed Chapter-7 Added Many2one fields for property type, buyer and salesman to main model. Added Many2many tag_ids field and created estate.property.tag model. Added One2many offer_ids field and created estate.property.offer model. Added corresponding menus,actions,views and access rights for all new models. --- estate/__manifest__.py | 3 + estate/models/__init__.py | 3 + estate/models/estate_property.py | 26 +++- estate/models/estate_property_offer.py | 25 ++++ 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 | 16 ++- estate/views/estate_property_offer_views.xml | 13 ++ estate/views/estate_property_tag_views.xml | 33 +++++ estate/views/estate_property_type_views.xml | 33 +++++ estate/views/estate_property_views.xml | 133 +++++++++++-------- 12 files changed, 242 insertions(+), 64 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 b6699025785..708f7a1e773 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -5,6 +5,9 @@ 'depends': ['base'], 'data': [ 'security/ir.model.access.csv', + 'views/estate_property_type_views.xml', + 'views/estate_property_tag_views.xml', + 'views/estate_property_offer_views.xml', 'views/estate_property_views.xml', 'views/estate_menus.xml', ], diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 5e1963c9d2f..2f1821a39c1 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +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 index 0fb1e631e83..e657a2b1d1b 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -2,7 +2,7 @@ class EstateProperty(models.Model): - _name = "estate.property" + _name = 'estate.property' _description = "Real Estate Property" name = fields.Char(required=True) @@ -36,3 +36,27 @@ class EstateProperty(models.Model): copy=False, default='new', ) + property_type_id = fields.Many2one( + "estate.property.type", + string="Property Type", +) + + buyer_id = fields.Many2one( + "res.partner", + string="Buyer", + copy=False, +) + salesman_id = fields.Many2one( + "res.users", + string="Salesman", + 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", +) diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py new file mode 100644 index 00000000000..9765b373d00 --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,25 @@ +from odoo import fields, models + + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Real Estate Property Offer" + + price = fields.Float() + status = fields.Selection( + 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 + ) diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..198c1037c41 --- /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 Property Tag" + + name = fields.Char(required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..ced40ef01cc --- /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 Property Type" + + name = fields.Char(required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 0e11f47e58d..05bd9eefba4 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 \ No newline at end of file diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 5d240e46a1a..becc72c64fb 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,7 +1,17 @@ - - + + + + + + + + diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..92ab9007f2b --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,13 @@ + + + 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..056fbe8b61e --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,33 @@ + + + Property Tags + estate.property.tag + list,form + + + + estate.property.tag.list + estate.property.tag + + + + + + + + + estate.property.tag.form + 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..b0713eaaa77 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,33 @@ + + + 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 1e3ef74349f..88768d4a3f3 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -5,8 +5,7 @@ list,form - + estate.property.list estate.property @@ -22,69 +21,85 @@ - - estate.property.form - estate.property - -
- -
-

- -

-
- - - - - + + estate.property.form + estate.property + + + +
+

+ +

+
+ - - - -
- - - - - - - - - - + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-
+
-
+
- - estate.property.search - estate.property - - - - - - - - - - + + estate.property.search + estate.property + + + + + + + + - + string="Available" + name="available" + domain="[('date_availability','<=', context_today())]"/> + + + - - + +