From 65a69d0d0342d5b0e0e3d81525dc6daeae06c4b5 Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Thu, 5 Feb 2026 17:43:40 +0530 Subject: [PATCH 01/12] [ADD] estate: add estate property module and basic fields --- estate/__init__.py | 1 + estate/__manifest__.py | 9 +++++++++ estate/models/__init__.py | 1 + estate/models/estate_property.py | 31 +++++++++++++++++++++++++++++++ 4 files changed, 42 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..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..44a45de9275 --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,9 @@ +{ + 'name':'estate', + 'verison':'1.0', + 'summary':'Estate Managment', + 'depends':['base'], + 'data':[], + 'application':True, + +} \ No newline at end of file diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..f4c8fd6db6d --- /dev/null +++ b/estate/models/__init__.py @@ -0,0 +1 @@ +from . import estate_property \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py new file mode 100644 index 00000000000..079eef76640 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,31 @@ +from odoo import models,fields + +class TestModal(models.Model): + _name = "estate.property" + _description = "Estate Property" + _postcode = "estate.postcode" + _date_avalilabilty = "estate.date_availability" + _expected_price = "estete.expected_price" + _selling_price = "estate.selling_price" + _bedrooms = "estate.bedrooms" + _living_area = "estate.living_area" + _facades = "estate.facades" + _garage = "estate.garage" + _garden = "estate.garden" + _garden_area = "estate.garden_area" + _garden_orientation = "estate.garden_orientation" + + name = fields.Char(required = True) + postcode = fields.Char(required = True) + date_availability = fields.Date(required = True) + expected_price = fields.Float(required = True) + selling_price = fields.Float(required = True) + bedrooms = fields.Integer(required = True) + living_area = fields.Integer(required = True) + facades = fields.Integer(required=True) + garage = fields.Boolean(required=True) + garden = fields.Boolean(required=True) + garden_area = fields.Integer(required=True) + garden_orientation = fields.Selection( + selection=[("north", "North"), ("south", "South")], required=True + ) From ab763971abd7249202bb3dad545b869372bc9b82 Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Thu, 5 Feb 2026 18:28:59 +0530 Subject: [PATCH 02/12] [LINT] estate: format estate module code --- estate/__init__.py | 2 +- estate/__manifest__.py | 15 +++++++-------- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 17 +++++++++-------- 4 files changed, 18 insertions(+), 18 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/__manifest__.py b/estate/__manifest__.py index 44a45de9275..f89c708131c 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,9 +1,8 @@ { - 'name':'estate', - 'verison':'1.0', - 'summary':'Estate Managment', - 'depends':['base'], - 'data':[], - 'application':True, - -} \ No newline at end of file + "name": "estate", + "verison": "1.0", + "summary": "Estate Managment", + "depends": ["base"], + "data": [], + "application": True, +} diff --git a/estate/models/__init__.py b/estate/models/__init__.py index f4c8fd6db6d..5e1963c9d2f 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1 @@ -from . import estate_property \ No newline at end of file +from . import estate_property diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 079eef76640..204ca7e95c3 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,5 @@ -from odoo import models,fields +from odoo import models, fields + class TestModal(models.Model): _name = "estate.property" @@ -15,13 +16,13 @@ class TestModal(models.Model): _garden_area = "estate.garden_area" _garden_orientation = "estate.garden_orientation" - name = fields.Char(required = True) - postcode = fields.Char(required = True) - date_availability = fields.Date(required = True) - expected_price = fields.Float(required = True) - selling_price = fields.Float(required = True) - bedrooms = fields.Integer(required = True) - living_area = fields.Integer(required = True) + name = fields.Char(required=True) + postcode = fields.Char(required=True) + date_availability = fields.Date(required=True) + expected_price = fields.Float(required=True) + selling_price = fields.Float(required=True) + bedrooms = fields.Integer(required=True) + living_area = fields.Integer(required=True) facades = fields.Integer(required=True) garage = fields.Boolean(required=True) garden = fields.Boolean(required=True) From 6c9ed3b65feefa8f4e338a9431afb04a05cdef9d Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Fri, 6 Feb 2026 11:05:38 +0530 Subject: [PATCH 03/12] [ADD] estate: add estate access rules --- estate/__manifest__.py | 7 ++++++- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 2 +- estate/security/ir.model.access.csv | 2 ++ 4 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index f89c708131c..7784de3582b 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,8 +1,13 @@ { "name": "estate", "verison": "1.0", + "category": "Estate", "summary": "Estate Managment", "depends": ["base"], - "data": [], + "data": [ + "security/ir.model.access.csv", + ], "application": True, + "author": "assri", + "license": "LGPL-3", } diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 5e1963c9d2f..f4c8fd6db6d 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1 @@ -from . import estate_property +from . import estate_property \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 204ca7e95c3..c60125e96bd 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -2,7 +2,7 @@ class TestModal(models.Model): - _name = "estate.property" + _name = "estate_property" _description = "Estate Property" _postcode = "estate.postcode" _date_avalilabilty = "estate.date_availability" diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..976b61e8cb3 --- /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 70c7b998bf6a498f1a20c4a8d2b9a50de45d46d6 Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Fri, 6 Feb 2026 11:58:47 +0530 Subject: [PATCH 04/12] [LINT] estate: format estate model code --- estate/models/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estate/models/__init__.py b/estate/models/__init__.py index f4c8fd6db6d..5e1963c9d2f 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1 @@ -from . import estate_property \ No newline at end of file +from . import estate_property From c12e3240119fc87c6ec52e0549540aefed96e93f Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Fri, 6 Feb 2026 18:31:18 +0530 Subject: [PATCH 05/12] [IMP] estate: add menus, actions, and default views --- estate/__manifest__.py | 2 ++ estate/models/estate_property.py | 10 ++++++---- estate/views/estate_menus.xml | 9 +++++++++ estate/views/estate_property_views.xml | 9 +++++++++ 4 files changed, 26 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 7784de3582b..cfe5a7cc9d8 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -6,6 +6,8 @@ "depends": ["base"], "data": [ "security/ir.model.access.csv", + "views/estate_property_views.xml", + "views/estate_menus.xml", ], "application": True, "author": "assri", diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index c60125e96bd..bfbf956e194 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -2,7 +2,7 @@ class TestModal(models.Model): - _name = "estate_property" + _name = "estate.property" _description = "Estate Property" _postcode = "estate.postcode" _date_avalilabilty = "estate.date_availability" @@ -18,10 +18,12 @@ class TestModal(models.Model): name = fields.Char(required=True) postcode = fields.Char(required=True) - date_availability = fields.Date(required=True) + date_availability = fields.Date( + copy=False, + ) expected_price = fields.Float(required=True) - selling_price = fields.Float(required=True) - bedrooms = fields.Integer(required=True) + selling_price = fields.Float(readonly=True, copy=False) + bedrooms = fields.Integer(default=2) living_area = fields.Integer(required=True) facades = fields.Integer(required=True) garage = fields.Boolean(required=True) diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..b7f799db85b --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml new file mode 100644 index 00000000000..f1ed942a799 --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,9 @@ + + + + + View Estate Property + estate.property + list,form + + From fc9656168a21624e1bf34264ce403b39bb78895d Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Mon, 9 Feb 2026 18:46:48 +0530 Subject: [PATCH 06/12] [IMP] estate: add list, form and serch views for estate properties --- estate/models/estate_property.py | 13 +++++ estate/views/estate_menus.xml | 10 ++-- estate/views/estate_property_views.xml | 73 ++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 4 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index bfbf956e194..457cc570252 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -32,3 +32,16 @@ class TestModal(models.Model): garden_orientation = fields.Selection( selection=[("north", "North"), ("south", "South")], required=True ) + description = fields.Text() + state = fields.Selection( + [ + ("new", "New"), + ("offer_received", "Offer Received"), + ("offer_accepted", "Offer Accepted"), + ("sold", "Sold"), + ("cancelled", "Cancelled"), + ], + default="new", + required=True, + copy=False, + ) diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index b7f799db85b..994e5ab4b8d 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,9 +1,11 @@ - - - + + + + + - + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index f1ed942a799..dfcd6e83621 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -6,4 +6,77 @@ estate.property list,form + + + estate.property.list + estate.property + + + + + + + + + + + + + estate.property.form + estate.property + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + estate.property.search + estate.property + + + + + + + + + + + + + + + From 81da83b9c0f57362423985850a5a0918e308c2ad Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Tue, 10 Feb 2026 18:33:50 +0530 Subject: [PATCH 07/12] [ADD] estate: add property types and tags --- estate/__manifest__.py | 2 ++ estate/models/__init__.py | 2 ++ estate/models/estate_property.py | 2 ++ estate/models/estate_property_tag.py | 8 ++++++ estate/models/estate_property_type.py | 8 ++++++ estate/security/ir.model.access.csv | 4 ++- estate/views/estate_menus.xml | 18 ++++++++---- estate/views/estate_property_tags_view.xml | 31 +++++++++++++++++++++ estate/views/estate_property_type_views.xml | 31 +++++++++++++++++++++ 9 files changed, 99 insertions(+), 7 deletions(-) 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_tags_view.xml create mode 100644 estate/views/estate_property_type_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index cfe5a7cc9d8..175bfbefe86 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,6 +7,8 @@ "data": [ "security/ir.model.access.csv", "views/estate_property_views.xml", + "views/estate_property_type_views.xml", + "views/estate_property_tags_view.xml", "views/estate_menus.xml", ], "application": True, diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 5e1963c9d2f..c620ac481a3 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,3 @@ from . import estate_property +from . import estate_property_type +from . import estate_property_tag diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 457cc570252..94954274f5a 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -45,3 +45,5 @@ class TestModal(models.Model): required=True, copy=False, ) + property_type_id = fields.Many2one("estate.property.type", string="Property Type") + tag_ids = fields.Many2many("estate.property.tag", string="Tags") diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..11d21768ebf --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,8 @@ +from odoo import models, fields + + +class EstatePropertyTag(models.Model): + _name = "estate.property.tag" + _description = "Estate 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..b08647d76bc --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,8 @@ +from odoo import models, fields + + +class EstatePropertyType(models.Model): + _name = "estate.property.type" + _description = "Estate Property Type" + + name = fields.Char(string="Property Type", required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 976b61e8cb3..f3e5fafdd4b 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,4 @@ 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,estate.property.type,model_estate_property_type,base.group_user,1,1,1,1 +access_estate_property_tag,estate.property.tag,model_estate_property_tag,base.group_user,1,1,1,1 diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 994e5ab4b8d..d1784d2a3cb 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,11 +1,17 @@ - - - - - + + + + + + + + + - + + + diff --git a/estate/views/estate_property_tags_view.xml b/estate/views/estate_property_tags_view.xml new file mode 100644 index 00000000000..a8944e5cd17 --- /dev/null +++ b/estate/views/estate_property_tags_view.xml @@ -0,0 +1,31 @@ + + + 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..80ba5e97326 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,31 @@ + + + Property Type + estate.property.type + list,form + + + + estate.property.type.list + estate.property.type + + + + + + + + + estate.property.type.form + estate.property.type + +
+ + + + + +
+
+
+
\ No newline at end of file From bcdfba1f25513c1b8446c1197c42db4bd669998e Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Thu, 12 Feb 2026 18:45:51 +0530 Subject: [PATCH 08/12] [CLN] estate: clean unnecessary attributes and improve UI structure (chapter 1 - 7) --- estate/models/estate_property.py | 22 +++--------- estate/models/estate_property_type.py | 1 + estate/security/ir.model.access.csv | 2 +- estate/views/estate_menus.xml | 2 -- estate/views/estate_property_type_views.xml | 10 ++++-- estate/views/estate_property_views.xml | 40 ++++++++++++--------- 6 files changed, 39 insertions(+), 38 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 94954274f5a..5b4b975a650 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,31 +1,21 @@ from odoo import models, fields -class TestModal(models.Model): +class EstateProperty(models.Model): _name = "estate.property" _description = "Estate Property" - _postcode = "estate.postcode" - _date_avalilabilty = "estate.date_availability" - _expected_price = "estete.expected_price" - _selling_price = "estate.selling_price" - _bedrooms = "estate.bedrooms" - _living_area = "estate.living_area" - _facades = "estate.facades" - _garage = "estate.garage" - _garden = "estate.garden" - _garden_area = "estate.garden_area" - _garden_orientation = "estate.garden_orientation" name = fields.Char(required=True) postcode = fields.Char(required=True) - date_availability = fields.Date( + available_from = fields.Date( + string="Availble From", copy=False, ) expected_price = fields.Float(required=True) - selling_price = fields.Float(readonly=True, copy=False) + selling_price = fields.Float(copy=False, readonly=True) bedrooms = fields.Integer(default=2) + facades = fields.Integer(default=0) living_area = fields.Integer(required=True) - facades = fields.Integer(required=True) garage = fields.Boolean(required=True) garden = fields.Boolean(required=True) garden_area = fields.Integer(required=True) @@ -41,8 +31,6 @@ class TestModal(models.Model): ("sold", "Sold"), ("cancelled", "Cancelled"), ], - default="new", - required=True, copy=False, ) property_type_id = fields.Many2one("estate.property.type", string="Property Type") diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index b08647d76bc..e93b1d4527c 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -6,3 +6,4 @@ class EstatePropertyType(models.Model): _description = "Estate Property Type" name = fields.Char(string="Property Type", required=True) + bedrooms = fields.Char(string="Bedrooms", required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index f3e5fafdd4b..256e84447e4 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,4 +1,4 @@ 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,estate.property,model_estate_property,base.group_user,1,1,1,1 access_estate_property_type,estate.property.type,model_estate_property_type,base.group_user,1,1,1,1 access_estate_property_tag,estate.property.tag,model_estate_property_tag,base.group_user,1,1,1,1 diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index d1784d2a3cb..b1a255f4a10 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -11,7 +11,5 @@ - - diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml index 80ba5e97326..97c4b608500 100644 --- a/estate/views/estate_property_type_views.xml +++ b/estate/views/estate_property_type_views.xml @@ -11,6 +11,7 @@ + @@ -22,10 +23,15 @@
- + + + + + +
- \ No newline at end of file + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index dfcd6e83621..159ad65d3d8 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -14,9 +14,10 @@ + - + @@ -27,29 +28,36 @@
+

+ +

+ - - - - + + - - - - - - - + + + - - - - + + + + + + + + + + + + +
From 49e0328cc1903631e62320830ad5344d871bbce9 Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Fri, 13 Feb 2026 19:51:02 +0530 Subject: [PATCH 09/12] [IMP] estate: add property offer model and computer fields exercises (chapter 7-8) --- estate/models/__init__.py | 1 + estate/models/estate_property.py | 28 +++++++++++++++++++++++--- estate/models/estate_property_offer.py | 13 ++++++++++++ estate/security/ir.model.access.csv | 1 + estate/views/estate_property_views.xml | 20 +++++++++++++++--- 5 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 estate/models/estate_property_offer.py diff --git a/estate/models/__init__.py b/estate/models/__init__.py index c620ac481a3..2f1821a39c1 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1,3 +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 5b4b975a650..03781ff439a 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,11 +1,12 @@ -from odoo import models, fields +from odoo import models, fields, api class EstateProperty(models.Model): _name = "estate.property" _description = "Estate Property" - name = fields.Char(required=True) + name = fields.Char(required=True, string="Title") + description = fields.Text(string="Description") postcode = fields.Char(required=True) available_from = fields.Date( string="Availble From", @@ -20,7 +21,13 @@ class EstateProperty(models.Model): garden = fields.Boolean(required=True) garden_area = fields.Integer(required=True) garden_orientation = fields.Selection( - selection=[("north", "North"), ("south", "South")], required=True + selection=[ + ("north", "North"), + ("south", "South"), + ("east", "East"), + ("west", "West"), + ], + required=True, ) description = fields.Text() state = fields.Selection( @@ -33,5 +40,20 @@ class EstateProperty(models.Model): ], copy=False, ) + total_area = fields.Float(compute="_compute_total_area") property_type_id = fields.Many2one("estate.property.type", string="Property Type") + buyer_id = fields.Many2one("res.partner", string="Buyer", readonly=True, copy=False) + user_id = fields.Many2one( + "res.users", string="SalesPerson", default=lambda self: self.env.user + ) + offer_ids = fields.One2many( + "estate.property.offer", + "property_id", + string="offers", + ) tag_ids = fields.Many2many("estate.property.tag", string="Tags") + + @api.depends("garden_area", "living_area") + def _compute_total_area(self): + for record in self: + record.total_area = record.living_area + record.garden_area diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py new file mode 100644 index 00000000000..5a45da3710b --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,13 @@ +from odoo import models, fields + + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Esate Property Offer" + + price = fields.Float(string="Price Offered") + status = fields.Selection( + copy=False, selection=[("accepted", "Accepted"), ("refused", "Refused")] + ) + partner_id = fields.Many2one("res.partner", required=True, string="Buyer") + property_id = fields.Many2one("estate.property", required=True, string="Property") diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 256e84447e4..c830e6484cc 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -2,3 +2,4 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink access_estate_property,estate.property,model_estate_property,base.group_user,1,1,1,1 access_estate_property_type,estate.property.type,model_estate_property_type,base.group_user,1,1,1,1 access_estate_property_tag,estate.property.tag,model_estate_property_tag,base.group_user,1,1,1,1 +access_estate_property_offer,estate.property.offer,model_estate_property_offer,base.group_user,1,1,1,1 diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 159ad65d3d8..9327697d2a2 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -29,7 +29,7 @@

- +

@@ -56,9 +56,25 @@ + + + + + + + + + + + + + + + +
@@ -75,14 +91,12 @@ - - From 998c2e12c8231d499a80ccfbaf9b05abb73f8d58 Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Fri, 13 Feb 2026 20:09:12 +0530 Subject: [PATCH 10/12] [LINT] estate: fixed duplicate field defination --- estate/models/estate_property.py | 1 - 1 file changed, 1 deletion(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 03781ff439a..dabf036e858 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -29,7 +29,6 @@ class EstateProperty(models.Model): ], required=True, ) - description = fields.Text() state = fields.Selection( [ ("new", "New"), From eb65c94ebc478da66b3f795f87726f5637dd62b7 Mon Sep 17 00:00:00 2001 From: assri-odoo Date: Mon, 16 Feb 2026 18:52:29 +0530 Subject: [PATCH 11/12] [IMP] estate: add property and offer actions buttons with business logic (chapter 8-9) --- estate/models/estate_property.py | 24 +++++++++ estate/models/estate_property_offer.py | 75 +++++++++++++++++++++++++- estate/views/estate_property_views.xml | 10 ++++ 3 files changed, 107 insertions(+), 2 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index dabf036e858..27dcc207c51 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,5 @@ from odoo import models, fields, api +from odoo.exceptions import UserError class EstateProperty(models.Model): @@ -56,3 +57,26 @@ class EstateProperty(models.Model): def _compute_total_area(self): for record in self: record.total_area = record.living_area + record.garden_area + + @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_sold(self): + for record in self: + if record.state == "cancelled": + raise UserError("Cancelled property cannot be sold.") + record.state = "sold" + return True + + def action_cancel(self): + for record in self: + if record.state == "sold": + raise UserError("Sold property cannot be cancelled.") + record.state = "cancelled" + return True diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 5a45da3710b..e09ecd053d4 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,6 @@ -from odoo import models, fields +from odoo import models, fields, api +from datetime import timedelta +from odoo.exceptions import UserError class EstatePropertyOffer(models.Model): @@ -7,7 +9,76 @@ class EstatePropertyOffer(models.Model): price = fields.Float(string="Price Offered") status = fields.Selection( - copy=False, selection=[("accepted", "Accepted"), ("refused", "Refused")] + copy=False, + selection=[ + ("accepted", "Accepted"), + ("refused", "Refused"), + ("pending", "Pending"), + ], ) partner_id = fields.Many2one("res.partner", required=True, string="Buyer") property_id = fields.Many2one("estate.property", required=True, string="Property") + validity = fields.Integer(default=7, string="Validity") + date_deadline = fields.Date( + compute="_compute_date_deadline", inverse="_inverse_date_deadline", store=True + ) + + @api.depends("create_date", "validity") + def _compute_date_deadline(self): + for record in self: + create_date = ( + record.create_date.date() if record.create_date else fields.Date.today() + ) + record.date_deadline = create_date + timedelta(days=record.validity) + + def _inverse_date_deadline(self): + for record in self: + create_date = ( + record.create_date.date() if record.create_date else fields.Date.today() + ) + record.validity = (record.date_deadline - create_date).days + + def accept_offer(self): + for offer in self: + if offer.property_id.state in ["sold", "cancelled"]: + raise UserError( + "you cannot accpet an offer on a solid or cancelled property." + ) + accepted_offer = offer.property_id.offer_ids.filtered( + lambda o: o.status == "accepted" and o != offer + ) + if accepted_offer: + raise UserError("only one offer can be accpeted for a property.") + offer.status = "accepted" + offer.property_id.write( + { + "selling_price": offer.price, + "buyer_id": offer.partner_id.id, + "state": "offer_accepted", + } + ) + + def reject_offer(self): + for offer in self: + property_rec = offer.property_id + if property_rec.state in ["sold", "cancelled"]: + raise UserError( + "you cannot refuse an offer on an sold or cancelled property." + ) + if offer.status == "accepted": + offer.status = "refused" + property_rec.write( + { + "selling_price": 0.0, + "buyer_id": False, + } + ) + other_pending = property_rec.offer_ids.filtered( + lambda o: o.status == "pending" + ) + if other_pending: + property_rec.state = "offer_received" + else: + property_rec.state = "new" + else: + offer.status = "refused" diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 9327697d2a2..cc816d25c90 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -28,6 +28,11 @@
+
+

@@ -72,6 +77,11 @@ + + + +