From abcede92d76be4893c508693f86c2d3c04b82a28 Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Wed, 31 Dec 2025 17:23:46 +0530 Subject: [PATCH 01/17] [ADD] estate - new module added models and security folder added Chapter 1: Architecture Overview Chapter 2: A New Application Chapter 3: Models And Basic Fields Chapter 4: Security - A Brief Introduction --- estate/__init__.py | 1 + estate/__manifest__.py | 20 ++++++++++++++++++++ estate/models/__init__.py | 1 + estate/models/real_estate.py | 23 +++++++++++++++++++++++ estate/security/ir.model.access.csv | 2 ++ 5 files changed, 47 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/real_estate.py create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..9a7e03eded3 --- /dev/null +++ b/estate/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..2e6b5b2e20e --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,20 @@ +{ + 'name':'Real Estate', + 'version': '1.0', + + 'depends':['crm'], + 'author':'jaldip vekariya (javek)', + 'description': """ + An Real Estate App to buy, sell, and rent properties. + """, + 'application': True, + 'license': 'LGPL-3', + 'data':[ + 'security/ir.model.access.csv', + 'security/res_groups.xml' + ], + 'demo':[ + 'demo/demo.xml' + ] + +} \ No newline at end of file diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..22c8ee9c371 --- /dev/null +++ b/estate/models/__init__.py @@ -0,0 +1 @@ +from . import real_estate \ No newline at end of file diff --git a/estate/models/real_estate.py b/estate/models/real_estate.py new file mode 100644 index 00000000000..580791d58fa --- /dev/null +++ b/estate/models/real_estate.py @@ -0,0 +1,23 @@ +from odoo import models,fields + +class RealEstate(models.Model): + _name="real_estate" + _description = "Test model" + + 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( + string = 'Orientation', + selection = [('north','North'),('south','South'),('east','East'),('weast','Weast')] + ) + diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..f9fb0b16842 --- /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 +estate.access_real_estate,access_real_estate,estate.model_real_estate,base.group_user,1,0,0,0 \ No newline at end of file From a09d9e24c0ba4aac207c662879b0df6aae6cd846 Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Wed, 31 Dec 2025 22:26:00 +0530 Subject: [PATCH 02/17] [ADD] estate - new module added models and security folder added Chapter 1: Architecture Overview Chapter 2: A New Application Chapter 3: Models And Basic Fields Chapter 4: Security - A Brief Introduction --- estate/__manifest__.py | 16 +++++----------- estate/models/real_estate.py | 15 ++++++++------- estate/security/ir.model.access.csv | 2 +- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 2e6b5b2e20e..c441e363093 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,20 +1,14 @@ { - 'name':'Real Estate', + 'name': 'Real Estate', 'version': '1.0', - - 'depends':['crm'], - 'author':'jaldip vekariya (javek)', + 'depends': ['crm'], + 'author': 'jaldip vekariya (javek)', 'description': """ An Real Estate App to buy, sell, and rent properties. """, 'application': True, 'license': 'LGPL-3', - 'data':[ - 'security/ir.model.access.csv', - 'security/res_groups.xml' - ], - 'demo':[ - 'demo/demo.xml' + 'data': [ + 'security/ir.model.access.csv' ] - } \ No newline at end of file diff --git a/estate/models/real_estate.py b/estate/models/real_estate.py index 580791d58fa..06daed3e96c 100644 --- a/estate/models/real_estate.py +++ b/estate/models/real_estate.py @@ -1,6 +1,6 @@ -from odoo import models,fields +from odoo import models, fields -class RealEstate(models.Model): +class RealEstate (models.Model): _name="real_estate" _description = "Test model" @@ -16,8 +16,9 @@ class RealEstate(models.Model): garage = fields.Boolean() garden = fields.Boolean() garden_area = fields.Integer() - garden_orientation = fields.Selection( - string = 'Orientation', - selection = [('north','North'),('south','South'),('east','East'),('weast','Weast')] - ) - + garden_orientation = fields.Selection([ + ('north', 'North'), + ('south', 'South'), + ('east', 'East'), + ('west', 'West'), + ]) \ No newline at end of file diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index f9fb0b16842..bc7c725ac0e 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,2 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink -estate.access_real_estate,access_real_estate,estate.model_real_estate,base.group_user,1,0,0,0 \ No newline at end of file +estate.access_real_estate,access_real_estate,estate.model_real_estate,base.group_user,1,1,1,1 \ No newline at end of file From 2f7c73f04008551ec160941e788b827e9db0e656 Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Wed, 31 Dec 2025 22:53:55 +0530 Subject: [PATCH 03/17] [ADD] estate - new module added models and security folder added Chapter 1: Architecture Overview Chapter 2: A New Application Chapter 3: Models And Basic Fields Chapter 4: Security - A Brief Introduction --- estate/__manifest__.py | 4 ++-- estate/models/__init__.py | 2 +- estate/models/real_estate.py | 8 +++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index c441e363093..e422ebbddd8 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -9,6 +9,6 @@ 'application': True, 'license': 'LGPL-3', 'data': [ - 'security/ir.model.access.csv' + 'security/ir.model.access.csv' ] -} \ No newline at end of file +} diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 22c8ee9c371..05018e037ce 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1 @@ -from . import real_estate \ No newline at end of file +from . import real_estate diff --git a/estate/models/real_estate.py b/estate/models/real_estate.py index 06daed3e96c..26ed1e14c19 100644 --- a/estate/models/real_estate.py +++ b/estate/models/real_estate.py @@ -1,7 +1,8 @@ from odoo import models, fields -class RealEstate (models.Model): - _name="real_estate" + +class RealEstate(models.Model): + _name= "real_estate" _description = "Test model" name = fields.Char(required=True) @@ -21,4 +22,5 @@ class RealEstate (models.Model): ('south', 'South'), ('east', 'East'), ('west', 'West'), - ]) \ No newline at end of file + ]) + \ No newline at end of file From 2811babbbdf2a13803d3cb3b975d98cc037dcc83 Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Wed, 31 Dec 2025 22:58:58 +0530 Subject: [PATCH 04/17] [ADD] estate - new module added models and security folder added Chapter 1: Architecture Overview Chapter 2: A New Application Chapter 3: Models And Basic Fields Chapter 4: Security - A Brief Introduction --- estate/models/__init__.py | 1 + estate/models/real_estate.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 05018e037ce..48a3b57d17e 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,2 @@ from . import real_estate + diff --git a/estate/models/real_estate.py b/estate/models/real_estate.py index 26ed1e14c19..4cac5f818f3 100644 --- a/estate/models/real_estate.py +++ b/estate/models/real_estate.py @@ -2,7 +2,7 @@ class RealEstate(models.Model): - _name= "real_estate" + _name = "real_estate" _description = "Test model" name = fields.Char(required=True) @@ -23,4 +23,3 @@ class RealEstate(models.Model): ('east', 'East'), ('west', 'West'), ]) - \ No newline at end of file From 8c4ca8f3e4870d62fd4145fe5b09c5e277a3dbba Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Thu, 1 Jan 2026 09:59:44 +0530 Subject: [PATCH 05/17] [ADD] estate - new module added models and security folder added Chapter 1: Architecture Overview Chapter 2: A New Application Chapter 3: Models And Basic Fields Chapter 4: Security - A Brief Introduction --- estate/__init__.py | 2 +- estate/models/__init__.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/estate/__init__.py b/estate/__init__.py index 9a7e03eded3..0650744f6bc 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -1 +1 @@ -from . import models \ No newline at end of file +from . import models diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 48a3b57d17e..05018e037ce 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1,2 +1 @@ from . import real_estate - From b90bee4ad3130b6471aba306a2b90ff77c7480b5 Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Thu, 1 Jan 2026 12:55:02 +0530 Subject: [PATCH 06/17] [IMP] estate: created views, menuitem modified manifest file. added action view in estate property. added more fields to model Chapter 5: Finally, Some UI To Play With --- estate/__manifest__.py | 4 +++- estate/models/real_estate.py | 20 ++++++++++++++++++-- estate/security/ir.model.access.csv | 2 +- estate/views/estate_menus.xml | 10 ++++++++++ estate/views/estate_property_views.xml | 13 +++++++++++++ 5 files changed, 45 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 e422ebbddd8..c0171432e11 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -9,6 +9,8 @@ 'application': True, 'license': 'LGPL-3', 'data': [ - 'security/ir.model.access.csv' + 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml' ] } diff --git a/estate/models/real_estate.py b/estate/models/real_estate.py index 4cac5f818f3..6c5d638d9fb 100644 --- a/estate/models/real_estate.py +++ b/estate/models/real_estate.py @@ -1,4 +1,5 @@ from odoo import models, fields +from dateutil.relativedelta import relativedelta class RealEstate(models.Model): @@ -8,10 +9,13 @@ class RealEstate(models.Model): name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date() + date_availability = fields.Date( + copy=False, + default=lambda self: fields.Date.context_today(self) + relativedelta(months=3), + ) expected_price = fields.Float(required=True) selling_price = fields.Float() - bedrooms = fields.Integer() + bedrooms = fields.Integer(default=2) living_area = fields.Integer() facades = fields.Integer() garage = fields.Boolean() @@ -23,3 +27,15 @@ class RealEstate(models.Model): ('east', 'East'), ('west', 'West'), ]) + state = fields.Selection( + selection=[ + ("new", "New"), + ("offer_received", "Offer Received"), + ("offer_accepted", "Offer Accepted"), + ("sold", "Sold"), + ("cancelled", "Cancelled"), + ], + string="Status", + default="new", + ) + active = fields.Boolean(default=False) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index bc7c725ac0e..7b9f8497c45 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,2 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink -estate.access_real_estate,access_real_estate,estate.model_real_estate,base.group_user,1,1,1,1 \ No newline at end of file +estate.access_real_estate,access_real_estate,model_real_estate,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 new file mode 100644 index 00000000000..059d3ffb971 --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml new file mode 100644 index 00000000000..01da5cd4900 --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,13 @@ + + + + Real Estate + real_estate + list,form + +

+ Create your Properties here ! +

+
+
+
From 60d0594645f1fcc9d24b4d7050fa05203ede8eba Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Fri, 2 Jan 2026 11:35:58 +0530 Subject: [PATCH 07/17] [IMP] estate: Added basic views for property estate property list view. estate property form view. estate property search view. --- estate/views/estate_property_views.xml | 89 ++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 01da5cd4900..f910b585812 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,13 +1,90 @@ - - Real Estate - real_estate - list,form - + + real_estate.list + real_estate + + + + + + + + + + + + + + + real_estate.form + real_estate + +
+ +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + Search Property + real_estate + + + + + + + + + + + + + + + Real Estate + real_estate + list,form +

Create your Properties here !

-
+
From f7fbdb67308d4b26d0dafff316d8c09c785922d3 Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Fri, 2 Jan 2026 18:12:12 +0530 Subject: [PATCH 08/17] [IMP] estate: model relations Implemented relations between models (Many2one, One2many, Many2many). Added estate_property_offer model and views. Added estate_property_type model and views. Added estate_property_tags model and views. Chapter 7: Relations Between Models --- estate/__manifest__.py | 5 ++- estate/models/__init__.py | 3 ++ estate/models/real_estate.py | 5 +++ estate/models/real_estate_property_offer.py | 16 +++++++++ estate/models/real_estate_property_tag.py | 8 +++++ estate/models/real_estate_property_type.py | 8 +++++ estate/security/ir.model.access.csv | 5 ++- estate/views/estate_menus.xml | 12 +++---- estate/views/estate_property_offer_views.xml | 36 ++++++++++++++++++++ estate/views/estate_property_tag_views.xml | 20 +++++++++++ estate/views/estate_property_type_views.xml | 20 +++++++++++ estate/views/estate_property_views.xml | 20 +++++++---- 12 files changed, 144 insertions(+), 14 deletions(-) create mode 100644 estate/models/real_estate_property_offer.py create mode 100644 estate/models/real_estate_property_tag.py create mode 100644 estate/models/real_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 c0171432e11..138e6fc815e 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -10,7 +10,10 @@ 'license': 'LGPL-3', 'data': [ 'security/ir.model.access.csv', - 'views/estate_property_views.xml', + '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' ] } diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 05018e037ce..44874f060c0 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,4 @@ +from . import real_estate_property_offer +from . import real_estate_property_tag +from . import real_estate_property_type from . import real_estate diff --git a/estate/models/real_estate.py b/estate/models/real_estate.py index 6c5d638d9fb..ea5560736f9 100644 --- a/estate/models/real_estate.py +++ b/estate/models/real_estate.py @@ -39,3 +39,8 @@ class RealEstate(models.Model): default="new", ) active = fields.Boolean(default=False) + property_type_id = fields.Many2one("estate.property.type", string="Property Type", required=True) + buyer_id = fields.Many2one("res.partner", string="Buyer") + sales_id = fields.Many2one("res.users", string="Salesperson") + tag_ids = fields.Many2many("estate.property.tag", string="Tags") + offer_ids = fields.One2many("estate.property.offer", "property_id") diff --git a/estate/models/real_estate_property_offer.py b/estate/models/real_estate_property_offer.py new file mode 100644 index 00000000000..f96e23ab954 --- /dev/null +++ b/estate/models/real_estate_property_offer.py @@ -0,0 +1,16 @@ +from odoo import fields, models + + +class PropertyType(models.Model): + _name = "estate.property.offer" + _description = "Test-tag" + + price = fields.Float() + status = fields.Selection( + selection = [ + ('accepted', 'Accepted'), + ('refused', 'Refused') + ] + ) + partner_id = fields.Many2one("res.partner", string="Partner", required=True) + property_id = fields.Many2one("real_estate", string="Property", required=True) diff --git a/estate/models/real_estate_property_tag.py b/estate/models/real_estate_property_tag.py new file mode 100644 index 00000000000..a9383565daa --- /dev/null +++ b/estate/models/real_estate_property_tag.py @@ -0,0 +1,8 @@ +from odoo import fields, models + + +class PropertyType(models.Model): + _name = "estate.property.tag" + _description = "Test-tag" + + name= fields.Char(string="Name") diff --git a/estate/models/real_estate_property_type.py b/estate/models/real_estate_property_type.py new file mode 100644 index 00000000000..297f7d7e389 --- /dev/null +++ b/estate/models/real_estate_property_type.py @@ -0,0 +1,8 @@ +from odoo import fields, models + + +class PropertyType(models.Model): + _name = "estate.property.type" + _description = "Test" + + name= fields.Char(string="Name") diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 7b9f8497c45..0ea0cffe8d6 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 -estate.access_real_estate,access_real_estate,model_real_estate,base.group_user,1,1,1,1 \ No newline at end of file +estate.access_real_estate,access_real_estate,model_real_estate,base.group_user,1,1,1,1 +estate.access.estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 +estate.access_estate_property_tag,access_estate_property_tag,estate.model_estate_property_tag,base.group_user,1,1,1,1 +estate.access_estate_property_offer,access_estate_property_offer,estate.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 059d3ffb971..2c12decdfca 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,10 +1,10 @@ - - - - - - + + + + + + diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..07c28d12d86 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,36 @@ + + + + + PropertyOffers + estate.property.offer + list,form + + + + + estate.property.offer.list + estate.property.offer + + + + + + + + + + + estate.property.offer.form + 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..e1fc23800c5 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,20 @@ + + + + + Tag Name + 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..90e935f247f --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,20 @@ + + + + + Property Type + estate.property.type + list,form + + + + + estate.property.type.list + estate.property.type + + + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index f910b585812..456ac7ac368 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -25,8 +25,13 @@

+ + + + + @@ -52,7 +57,15 @@ - + + + + + + + + + @@ -81,10 +94,5 @@ Real Estate real_estate list,form - -

- Create your Properties here ! -

-
From 43dbcf0d36374bb776cddd8ebda7e06bd5ca6827 Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Fri, 2 Jan 2026 19:10:33 +0530 Subject: [PATCH 09/17] [FIX] estate: removed whitespace Implemented new suggestions --- estate/__manifest__.py | 2 +- estate/models/real_estate.py | 12 ++++++------ estate/models/real_estate_property_offer.py | 4 ++-- estate/models/real_estate_property_tag.py | 2 +- estate/models/real_estate_property_type.py | 2 +- estate/security/ir.model.access.csv | 2 +- estate/views/estate_menus.xml | 1 - estate/views/estate_property_views.xml | 1 - 8 files changed, 12 insertions(+), 14 deletions(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 138e6fc815e..a065cac3e2e 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -10,7 +10,7 @@ 'license': 'LGPL-3', 'data': [ 'security/ir.model.access.csv', - 'views/estate_property_views.xml', + 'views/estate_property_views.xml', 'views/estate_property_type_views.xml', 'views/estate_property_tag_views.xml', 'views/estate_property_offer_views.xml', diff --git a/estate/models/real_estate.py b/estate/models/real_estate.py index ea5560736f9..9c82fbfaa3f 100644 --- a/estate/models/real_estate.py +++ b/estate/models/real_estate.py @@ -1,10 +1,10 @@ -from odoo import models, fields +from odoo import fields, models from dateutil.relativedelta import relativedelta class RealEstate(models.Model): _name = "real_estate" - _description = "Test model" + _description = "Real Estate" name = fields.Char(required=True) description = fields.Text() @@ -22,10 +22,10 @@ class RealEstate(models.Model): garden = fields.Boolean() garden_area = fields.Integer() garden_orientation = fields.Selection([ - ('north', 'North'), - ('south', 'South'), - ('east', 'East'), - ('west', 'West'), + ("north", "North"), + ("south", "South"), + ("east", "East"), + ("west", "West"), ]) state = fields.Selection( selection=[ diff --git a/estate/models/real_estate_property_offer.py b/estate/models/real_estate_property_offer.py index f96e23ab954..c9ce040033c 100644 --- a/estate/models/real_estate_property_offer.py +++ b/estate/models/real_estate_property_offer.py @@ -7,10 +7,10 @@ class PropertyType(models.Model): price = fields.Float() status = fields.Selection( - selection = [ + selection=[ ('accepted', 'Accepted'), ('refused', 'Refused') ] - ) + ) partner_id = fields.Many2one("res.partner", string="Partner", required=True) property_id = fields.Many2one("real_estate", string="Property", required=True) diff --git a/estate/models/real_estate_property_tag.py b/estate/models/real_estate_property_tag.py index a9383565daa..138898d867b 100644 --- a/estate/models/real_estate_property_tag.py +++ b/estate/models/real_estate_property_tag.py @@ -5,4 +5,4 @@ class PropertyType(models.Model): _name = "estate.property.tag" _description = "Test-tag" - name= fields.Char(string="Name") + name = fields.Char(string="Name") diff --git a/estate/models/real_estate_property_type.py b/estate/models/real_estate_property_type.py index 297f7d7e389..76ac682b8f9 100644 --- a/estate/models/real_estate_property_type.py +++ b/estate/models/real_estate_property_type.py @@ -5,4 +5,4 @@ class PropertyType(models.Model): _name = "estate.property.type" _description = "Test" - name= fields.Char(string="Name") + name = fields.Char(string="Name") diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 0ea0cffe8d6..d58eef71331 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -2,4 +2,4 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink estate.access_real_estate,access_real_estate,model_real_estate,base.group_user,1,1,1,1 estate.access.estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 estate.access_estate_property_tag,access_estate_property_tag,estate.model_estate_property_tag,base.group_user,1,1,1,1 -estate.access_estate_property_offer,access_estate_property_offer,estate.model_estate_property_offer,base.group_user,1,1,1,1 \ No newline at end of file +estate.access_estate_property_offer,access_estate_property_offer,estate.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 2c12decdfca..c87da8d7326 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,6 +1,5 @@ - diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 456ac7ac368..7cd31c9cf8d 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -73,7 +73,6 @@ - Search Property real_estate From b0c2cf30670c81f9d386455b1efe1d44c4be5e4c Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Mon, 5 Jan 2026 17:54:14 +0530 Subject: [PATCH 10/17] [IMP] estate: Added Computed Fields And Onchanges Added computed fields for best offer and Total area. Added computed fields for validity and deadline. Added onchange method for garden Chapter 8 --- estate/models/real_estate.py | 22 ++++++++++++++++- estate/models/real_estate_property_offer.py | 26 ++++++++++++++++---- estate/models/real_estate_property_tag.py | 4 +-- estate/models/real_estate_property_type.py | 2 +- estate/views/estate_property_offer_views.xml | 4 +++ estate/views/estate_property_views.xml | 2 ++ 6 files changed, 51 insertions(+), 9 deletions(-) diff --git a/estate/models/real_estate.py b/estate/models/real_estate.py index 9c82fbfaa3f..83ce48bfcba 100644 --- a/estate/models/real_estate.py +++ b/estate/models/real_estate.py @@ -1,4 +1,4 @@ -from odoo import fields, models +from odoo import api, fields, models from dateutil.relativedelta import relativedelta @@ -44,3 +44,23 @@ class RealEstate(models.Model): sales_id = fields.Many2one("res.users", string="Salesperson") tag_ids = fields.Many2many("estate.property.tag", string="Tags") offer_ids = fields.One2many("estate.property.offer", "property_id") + total_area = fields.Integer(compute="_compute_totalarea") + best_price = fields.Integer(compute="_compute_bestoffer") + @api.depends("living_area", "garden_area") + def _compute_totalarea(self): + for record in self: + record.total_area = record.living_area + record.garden_area + + @api.depends("offer_ids.price") + def _compute_bestoffer(self): + for record in self: + record.best_price = max(record.offer_ids.mapped("price") or [0] ) + + @api.onchange("garden") + def _garden_changes(self): + if self.garden: + self.garden_area = 10 + self.garden_orientation = "north" + else: + self.garden_area = 0 + self.garden_orientation = None diff --git a/estate/models/real_estate_property_offer.py b/estate/models/real_estate_property_offer.py index c9ce040033c..2055fcd0d0c 100644 --- a/estate/models/real_estate_property_offer.py +++ b/estate/models/real_estate_property_offer.py @@ -1,16 +1,32 @@ -from odoo import fields, models +from odoo import api, fields, models +from dateutil.relativedelta import relativedelta -class PropertyType(models.Model): +class PropertyOffer(models.Model): _name = "estate.property.offer" - _description = "Test-tag" + _description = "Property Offers" price = fields.Float() status = fields.Selection( selection=[ - ('accepted', 'Accepted'), - ('refused', 'Refused') + ("accepted", "Accepted"), + ("refused", "Refused") ] ) partner_id = fields.Many2one("res.partner", string="Partner", required=True) property_id = fields.Many2one("real_estate", string="Property", required=True) + validity = fields.Integer(string="Validity(days)", default=7) + deadline = fields.Date( + compute="_compute_deadline", + inverse="_inverse_validity" + ) + + @api.depends("validity", "create_date") + def _compute_deadline(self): + for record in self: + date = record.create_date.date() if record.create_date else fields.Date.today() + record.deadline = date + relativedelta(days=record.validity) + + def _inverse_validity(self): + for record in self: + record.validity = ((record.deadline) - record.create_date.date()).days diff --git a/estate/models/real_estate_property_tag.py b/estate/models/real_estate_property_tag.py index 138898d867b..7e741da3dfd 100644 --- a/estate/models/real_estate_property_tag.py +++ b/estate/models/real_estate_property_tag.py @@ -1,8 +1,8 @@ from odoo import fields, models -class PropertyType(models.Model): +class PropertyTag(models.Model): _name = "estate.property.tag" - _description = "Test-tag" + _description = "Property Tags" name = fields.Char(string="Name") diff --git a/estate/models/real_estate_property_type.py b/estate/models/real_estate_property_type.py index 76ac682b8f9..2ba20eba638 100644 --- a/estate/models/real_estate_property_type.py +++ b/estate/models/real_estate_property_type.py @@ -3,6 +3,6 @@ class PropertyType(models.Model): _name = "estate.property.type" - _description = "Test" + _description = "Property Types" name = fields.Char(string="Name") diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 07c28d12d86..28e48ef845c 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -15,6 +15,8 @@ + + @@ -28,6 +30,8 @@ + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 7cd31c9cf8d..ff3b6d68b35 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -38,6 +38,7 @@ + @@ -52,6 +53,7 @@ + From 6385d9b7793560be74bde0779a622e59e41d53d6 Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Tue, 6 Jan 2026 19:10:43 +0530 Subject: [PATCH 11/17] [IMP] estate: Added action button and sql constraint Button action to manage offers and property. SQL constraint for data validation. expected price and offer price must be strictly positive. selling price must be positive. property type and tag names must be unique. Python constraint for selling price Chapter 9,10 --- estate/models/real_estate.py | 40 +++++++++++++++++++- estate/models/real_estate_property_offer.py | 30 +++++++++++++-- estate/models/real_estate_property_tag.py | 5 +++ estate/models/real_estate_property_type.py | 5 +++ estate/security/ir.model.access.csv | 6 +-- estate/views/estate_property_offer_views.xml | 2 + estate/views/estate_property_views.xml | 6 +++ 7 files changed, 85 insertions(+), 9 deletions(-) diff --git a/estate/models/real_estate.py b/estate/models/real_estate.py index 83ce48bfcba..1ec3e93a769 100644 --- a/estate/models/real_estate.py +++ b/estate/models/real_estate.py @@ -1,5 +1,6 @@ -from odoo import api, fields, models +from odoo import exceptions, api, fields, models from dateutil.relativedelta import relativedelta +from odoo.tools import float_compare class RealEstate(models.Model): @@ -46,6 +47,7 @@ class RealEstate(models.Model): offer_ids = fields.One2many("estate.property.offer", "property_id") total_area = fields.Integer(compute="_compute_totalarea") best_price = fields.Integer(compute="_compute_bestoffer") + @api.depends("living_area", "garden_area") def _compute_totalarea(self): for record in self: @@ -54,7 +56,7 @@ def _compute_totalarea(self): @api.depends("offer_ids.price") def _compute_bestoffer(self): for record in self: - record.best_price = max(record.offer_ids.mapped("price") or [0] ) + record.best_price = max(record.offer_ids.mapped("price") or [0]) @api.onchange("garden") def _garden_changes(self): @@ -64,3 +66,37 @@ def _garden_changes(self): else: self.garden_area = 0 self.garden_orientation = None + + def estate_sold(self): + for record in self: + if record.state != "cancelled": + record.state = "sold" + else: + raise exceptions.UserError("Cancelled Property can not be sold") + return True + + def estate_cancel(self): + for record in self: + if record.state != "sold": + record.state = "cancelled" + else: + raise exceptions.UserError("Sold Property can not be cancelled") + return True + + _expected_price_positive = models.Constraint( + 'CHECK(expected_price > 0.0)', + 'The expected price must be strictly positive.' + ) + + _selling_price_positive = models.Constraint( + 'CHECK(selling_price >= 0.0 or selling_price IS NULL)', + 'The selling price must be positive.' + ) + + @api.constrains("expected_price", "selling_price") + def _check_selling_price(self): + for record in self: + if record.selling_price == 0: + return False + if float_compare(record.selling_price, record.expected_price * 0.9, precision_digits=2) < 0: + raise exceptions.ValidationError("The selling price cannot be lower than 90 of the expected price.") diff --git a/estate/models/real_estate_property_offer.py b/estate/models/real_estate_property_offer.py index 2055fcd0d0c..51ec10c3659 100644 --- a/estate/models/real_estate_property_offer.py +++ b/estate/models/real_estate_property_offer.py @@ -1,4 +1,4 @@ -from odoo import api, fields, models +from odoo import exceptions, api, fields, models from dateutil.relativedelta import relativedelta @@ -7,6 +7,10 @@ class PropertyOffer(models.Model): _description = "Property Offers" price = fields.Float() + _offer_price_positive = models.Constraint( + 'CHECK(price > 0)', + 'The offer price must be positive.' + ) status = fields.Selection( selection=[ ("accepted", "Accepted"), @@ -24,9 +28,27 @@ class PropertyOffer(models.Model): @api.depends("validity", "create_date") def _compute_deadline(self): for record in self: - date = record.create_date.date() if record.create_date else fields.Date.today() - record.deadline = date + relativedelta(days=record.validity) + date = record.create_date.date() if record.create_date else fields.Date.today() + record.deadline = date + relativedelta(days=record.validity) def _inverse_validity(self): for record in self: - record.validity = ((record.deadline) - record.create_date.date()).days + record.validity = ((record.deadline) - record.create_date.date()).days + + def accept_offer(self): + for record in self: + if record.property_id.buyer_id: + raise exceptions.UserError("Only One Offer can be accepted") + else: + record.property_id.buyer_id = record.partner_id + record.property_id.selling_price = record.price + record.status = "accepted" + return True + + def reject_offer(self): + for record in self: + if record.property_id.buyer_id and record.status == "accepted": + raise exceptions.UserError("Accepted Offer can not be rejected") + else: + record.status = "refused" + return True diff --git a/estate/models/real_estate_property_tag.py b/estate/models/real_estate_property_tag.py index 7e741da3dfd..95f87cd3075 100644 --- a/estate/models/real_estate_property_tag.py +++ b/estate/models/real_estate_property_tag.py @@ -6,3 +6,8 @@ class PropertyTag(models.Model): _description = "Property Tags" name = fields.Char(string="Name") + + _name_unique = models.Constraint( + 'UNIQUE(name)', + 'The name must be unique' + ) diff --git a/estate/models/real_estate_property_type.py b/estate/models/real_estate_property_type.py index 2ba20eba638..7c12bc6948d 100644 --- a/estate/models/real_estate_property_type.py +++ b/estate/models/real_estate_property_type.py @@ -6,3 +6,8 @@ class PropertyType(models.Model): _description = "Property Types" name = fields.Char(string="Name") + + _name_unique = models.Constraint( + 'UNIQUE(name)', + 'The name must be unique' + ) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index d58eef71331..bbc83121ccd 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,5 +1,5 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink estate.access_real_estate,access_real_estate,model_real_estate,base.group_user,1,1,1,1 -estate.access.estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 -estate.access_estate_property_tag,access_estate_property_tag,estate.model_estate_property_tag,base.group_user,1,1,1,1 -estate.access_estate_property_offer,access_estate_property_offer,estate.model_estate_property_offer,base.group_user,1,1,1,1 +estate.access_estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 +estate.access_estate_property_tag,access_estate_property_tag,model_estate_property_tag,base.group_user,1,1,1,1 +estate.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_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 28e48ef845c..d4b46f2c1c2 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -17,6 +17,8 @@ + +

diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 02980a643aa..bb8efb2d4cc 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -4,7 +4,7 @@ real_estate.list real_estate - + @@ -63,9 +63,6 @@
- - - @@ -92,16 +89,18 @@ - +
+ Real Estate real_estate list,form + {'search_default_available': True}
From 37beac2d3cd0606159b70c988ef3237ff9a1a69c Mon Sep 17 00:00:00 2001 From: javek-odoo Date: Mon, 12 Jan 2026 18:17:34 +0530 Subject: [PATCH 17/17] [FIX] estate: corrected files order in manifest file add white space after if. changed order of offer_view.xml --- estate/__manifest__.py | 2 +- estate/models/real_estate_property_offer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index ea966ce2560..c68cc745b3c 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -10,10 +10,10 @@ 'license': 'LGPL-3', 'data': [ 'security/ir.model.access.csv', + 'views/estate_property_offer_views.xml', 'views/estate_property_tag_views.xml', 'views/estate_property_views.xml', 'views/estate_property_type_views.xml', - 'views/estate_property_offer_views.xml', 'views/estate_menus.xml' ] } diff --git a/estate/models/real_estate_property_offer.py b/estate/models/real_estate_property_offer.py index 6bec308391d..42a1afae906 100644 --- a/estate/models/real_estate_property_offer.py +++ b/estate/models/real_estate_property_offer.py @@ -46,7 +46,7 @@ def accept_offer(self): raise UserError("Only One Offer can be accepted") else: for ids in record.property_id.offer_ids: - if(record.id != ids.id): + if (record.id != ids.id): ids.status = "refused" record.property_id.buyer_id = record.partner_id record.property_id.selling_price = record.price