From ef3fde4a2ff7a4ca0d0ac5964f432906ea53e553 Mon Sep 17 00:00:00 2001 From: habar Date: Tue, 10 Mar 2026 19:06:07 +0530 Subject: [PATCH 01/12] [ADD] estate:estate module creation and model implementation.1.Configured manifest with required metadata. 2.Covers chapter 2 and 3. 3.Added all the required fields & attributes. --- estate/__init__.py | 1 + estate/__manifest__.py | 11 +++++++++++ estate/models/__init__.py | 1 + estate/models/estate_property.py | 24 ++++++++++++++++++++++++ 4 files changed, 37 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..f29ccaf8e52 --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,11 @@ +{ + 'name': "estate", + 'version': '1.0', + 'depends': ['base'], + 'author': "Harshvardhan", + 'category': 'Category', + 'description': """ + This is the sample module for practise + """, + '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..86e579fa3e8 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,24 @@ +from odoo import models,fields + +class EstateProperty(models.Model): + _name = 'estate.property' + _description = 'Real Estate Property' + + name = fields.Char(String="Name",required=True) + description = fields.Text(String="Description") + postcode = fields.Char(String="Postcode") + date_availability = fields.Date(String="Date") + expected_price = fields.Float(String="Expected Price",required=True) + selling_price = fields.Float(String="Selling Price") + bedrooms = fields.Integer(String="Bedrooms") + living_area = fields.Integer(String="Living Area") + facades = fields.Integer(String="Facades") + garage = fields.Boolean(String="Garage") + garden = fields.Boolean(String="Garden") + garden_area = fields.Integer(String="Garden Area") + garden_orientation = fields.Selection([ + ('north','North'), + ('east','East'), + ('west','West'), + ('south','South') + ]) \ No newline at end of file From bcb5cb6d837a7e19cfd0e7b4ad151fbafc0287cd Mon Sep 17 00:00:00 2001 From: habar Date: Wed, 11 Mar 2026 10:42:18 +0530 Subject: [PATCH 02/12] [FIX] estate : improve manifest and EstateProperty model 1) Add missing white spaces after ','. 2) Update parameter String to string. 3) Update manifest file. --- estate/__init__.py | 2 +- estate/__manifest__.py | 5 +++-- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 34 ++++++++++++++------------------ 4 files changed, 20 insertions(+), 23 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 f29ccaf8e52..9c14ad3b6fc 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,5 +7,6 @@ 'description': """ This is the sample module for practise """, - 'application': True -} \ No newline at end of file + 'application': True, + 'license': 'LGPL-3', +} 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 86e579fa3e8..6f1e77bfd26 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,24 +1,20 @@ -from odoo import models,fields +from odoo import models, fields class EstateProperty(models.Model): _name = 'estate.property' _description = 'Real Estate Property' - name = fields.Char(String="Name",required=True) - description = fields.Text(String="Description") - postcode = fields.Char(String="Postcode") - date_availability = fields.Date(String="Date") - expected_price = fields.Float(String="Expected Price",required=True) - selling_price = fields.Float(String="Selling Price") - bedrooms = fields.Integer(String="Bedrooms") - living_area = fields.Integer(String="Living Area") - facades = fields.Integer(String="Facades") - garage = fields.Boolean(String="Garage") - garden = fields.Boolean(String="Garden") - garden_area = fields.Integer(String="Garden Area") - garden_orientation = fields.Selection([ - ('north','North'), - ('east','East'), - ('west','West'), - ('south','South') - ]) \ No newline at end of file + name = fields.Char(string="Name", required=True) + description = fields.Text(string="Description") + postcode = fields.Char(string="Postcode") + date_availability = fields.Date(string="Date") + expected_price = fields.Float(string="Expected Price", required=True) + selling_price = fields.Float(string="Selling Price") + bedrooms = fields.Integer(string="Bedrooms") + living_area = fields.Integer(string="Living Area") + facades = fields.Integer(string="Facades") + garage = fields.Boolean(string="Garage") + garden = fields.Boolean(string="Garden") + garden_area = fields.Integer(string="Garden Area") + garden_orientation = fields.Selection([('north','North'), ('east','East'), ('west','West'), ('south','South')]) + \ No newline at end of file From 4d1520c1ba10b7b710260d2c245a8f301405fc61 Mon Sep 17 00:00:00 2001 From: habar Date: Wed, 11 Mar 2026 10:50:23 +0530 Subject: [PATCH 03/12] [FIX] estate : EstateProperty model 1) Add missing white spaces after ','. --- estate/models/estate_property.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 6f1e77bfd26..e408a012f7d 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -16,5 +16,5 @@ class EstateProperty(models.Model): garage = fields.Boolean(string="Garage") garden = fields.Boolean(string="Garden") garden_area = fields.Integer(string="Garden Area") - garden_orientation = fields.Selection([('north','North'), ('east','East'), ('west','West'), ('south','South')]) + garden_orientation = fields.Selection([('north', 'North'), ('east', 'East'), ('west', 'West'), ('south', 'South')]) \ No newline at end of file From 2260a7289ee1b8bd4e3cfa5eca9c935b04fec2d1 Mon Sep 17 00:00:00 2001 From: habar Date: Wed, 11 Mar 2026 18:32:14 +0530 Subject: [PATCH 04/12] [ADD] estate: implement security file define access rights 1) Add security file give access rules 2) Update manifest --- estate/__manifest__.py | 10 +++++++--- estate/models/estate_property.py | 11 ++++++++--- estate/security/ir.model.access.csv | 2 ++ 3 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 9c14ad3b6fc..6dac6179e27 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -2,11 +2,15 @@ 'name': "estate", 'version': '1.0', 'depends': ['base'], - 'author': "Harshvardhan", - 'category': 'Category', + 'author': "habar", + 'category': 'Tutorials', 'description': """ - This is the sample module for practise + This is the sample module for practise. """, + 'data': [ + 'security/ir.model.access.csv' + ], 'application': True, 'license': 'LGPL-3', + 'installable': True, } diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index e408a012f7d..268ee66e8e0 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,9 +1,10 @@ from odoo import models, fields + class EstateProperty(models.Model): _name = 'estate.property' _description = 'Real Estate Property' - + name = fields.Char(string="Name", required=True) description = fields.Text(string="Description") postcode = fields.Char(string="Postcode") @@ -16,5 +17,9 @@ class EstateProperty(models.Model): garage = fields.Boolean(string="Garage") garden = fields.Boolean(string="Garden") garden_area = fields.Integer(string="Garden Area") - garden_orientation = fields.Selection([('north', 'North'), ('east', 'East'), ('west', 'West'), ('south', 'South')]) - \ No newline at end of file + garden_orientation = fields.Selection([ + ('north', 'North'), + ('east', 'East'), + ('west', 'West'), + ('south', 'South') + ]) 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 4ff2297778607de8bb822e5cd1d57d05b6204179 Mon Sep 17 00:00:00 2001 From: habar Date: Wed, 11 Mar 2026 18:57:44 +0530 Subject: [PATCH 05/12] [ADD] estate: implement security file define access rights 1) remove trailing space --- estate/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 6dac6179e27..05273d27a5d 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -8,7 +8,7 @@ This is the sample module for practise. """, 'data': [ - 'security/ir.model.access.csv' + 'security/ir.model.access.csv', ], 'application': True, 'license': 'LGPL-3', From 32023a3fef1070a6e9019bcd44d36720e7b30175 Mon Sep 17 00:00:00 2001 From: habar Date: Thu, 12 Mar 2026 18:46:41 +0530 Subject: [PATCH 06/12] [ADD] estate: Cover chapter 5 ( actions & menus) for estate model Create views folder and define actions & menus for the model Declare it in the manifest --- estate/__manifest__.py | 4 +++- estate/models/estate_property.py | 23 ++++++++++++++++------- estate/views/estate_menus.xml | 8 ++++++++ estate/views/estate_property_views.xml | 24 ++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 8 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 05273d27a5d..59f3f604002 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,5 +1,5 @@ { - 'name': "estate", + 'name': "Estate", 'version': '1.0', 'depends': ['base'], 'author': "habar", @@ -9,6 +9,8 @@ """, 'data': [ 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml', ], 'application': True, 'license': 'LGPL-3', diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 268ee66e8e0..d5a08f3a51b 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,25 +1,34 @@ from odoo import models, fields +from dateutil.relativedelta import relativedelta class EstateProperty(models.Model): _name = 'estate.property' _description = 'Real Estate Property' - - name = fields.Char(string="Name", required=True) + + name = fields.Char(string="Title", required=True) description = fields.Text(string="Description") postcode = fields.Char(string="Postcode") - date_availability = fields.Date(string="Date") + date_availability = fields.Date(string="Available From", copy=False, default=fields.Date.today() + relativedelta(months=3)) expected_price = fields.Float(string="Expected Price", required=True) - selling_price = fields.Float(string="Selling Price") - bedrooms = fields.Integer(string="Bedrooms") - living_area = fields.Integer(string="Living Area") + selling_price = fields.Float(string="Selling Price", readonly=True, copy=False) + bedrooms = fields.Integer(string="Bedrooms", default=2) + living_area = fields.Integer(string="Living Area (spm)") facades = fields.Integer(string="Facades") garage = fields.Boolean(string="Garage") garden = fields.Boolean(string="Garden") - garden_area = fields.Integer(string="Garden Area") + garden_area = fields.Integer(string="Garden Area (spm)") garden_orientation = fields.Selection([ ('north', 'North'), ('east', 'East'), ('west', 'West'), ('south', 'South') ]) + active = fields.Boolean(string="Active", default=True) + state = fields.Selection([ + ('new', 'New'), + ('offerreceived', 'Offer Received'), + ('offeraccepted', 'Offer Accepted'), + ('sold', 'Sold'), + ('cancelled', 'Cancelled') + ], string="State", copy=False, default='new') diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..99abf1350f5 --- /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..35db6dafd91 --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,24 @@ + + + + estate.property.list + estate.property + + + + + + + + + + + + + + + Properties + estate.property + list,form + + From da481a45d567c7eeeb966c885df4b9410452ec8d Mon Sep 17 00:00:00 2001 From: habar Date: Mon, 16 Mar 2026 18:45:04 +0530 Subject: [PATCH 07/12] [ADD] estate: Design form,search view 1) Create Form view & Search view for the estate model. --- estate/__manifest__.py | 6 +-- estate/models/estate_property.py | 8 ++-- estate/security/ir.model.access.csv | 2 +- estate/views/estate_property_views.xml | 56 ++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 59f3f604002..c238e0514cd 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -8,9 +8,9 @@ This is the sample module for practise. """, 'data': [ - 'security/ir.model.access.csv', - 'views/estate_property_views.xml', - 'views/estate_menus.xml', + 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml', ], 'application': True, 'license': 'LGPL-3', diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index d5a08f3a51b..7aba45c36e2 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,5 +1,5 @@ -from odoo import models, fields from dateutil.relativedelta import relativedelta +from odoo import fields, models class EstateProperty(models.Model): @@ -11,7 +11,7 @@ class EstateProperty(models.Model): postcode = fields.Char(string="Postcode") date_availability = fields.Date(string="Available From", copy=False, default=fields.Date.today() + relativedelta(months=3)) expected_price = fields.Float(string="Expected Price", required=True) - selling_price = fields.Float(string="Selling Price", readonly=True, copy=False) + selling_price = fields.Float(string="Selling Price", copy=False) bedrooms = fields.Integer(string="Bedrooms", default=2) living_area = fields.Integer(string="Living Area (spm)") facades = fields.Integer(string="Facades") @@ -27,8 +27,8 @@ class EstateProperty(models.Model): active = fields.Boolean(string="Active", default=True) state = fields.Selection([ ('new', 'New'), - ('offerreceived', 'Offer Received'), - ('offeraccepted', 'Offer Accepted'), + ('offer_received', 'Offer Received'), + ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled') ], string="State", copy=False, default='new') diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 0e11f47e58d..32389642d4f 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 -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 diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 35db6dafd91..14e416db34c 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,5 +1,44 @@ + + estate.property.form + estate.property + +
+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ estate.property.list estate.property @@ -16,6 +55,23 @@ + + estate.property.search + estate.property + + + + + + + + + + + + + + Properties estate.property From cfce128f89d33e2a305b659e305ced2f97d1d444 Mon Sep 17 00:00:00 2001 From: habar Date: Tue, 17 Mar 2026 18:59:42 +0530 Subject: [PATCH 08/12] [ADD] estate: Complete chapter 7 (Relations between models) 1) create estate property type, estate property tag & estate property offer models. 2) creates relations between them using m2o, m2m & o2m. 3) create views, actions & menus. --- estate/__manifest__.py | 3 +++ estate/models/__init__.py | 3 +++ estate/models/estate_property.py | 25 +++++++++++-------- 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 | 3 +++ estate/views/estate_menus.xml | 4 +++ estate/views/estate_property_offer_views.xml | 26 ++++++++++++++++++++ estate/views/estate_property_tag_views.xml | 8 ++++++ estate/views/estate_property_type_views.xml | 8 ++++++ estate/views/estate_property_views.xml | 25 +++++++++++++------ 12 files changed, 117 insertions(+), 18 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 c238e0514cd..4f106ce9382 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -10,6 +10,9 @@ '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_property_offer_views.xml', 'views/estate_menus.xml', ], 'application': True, 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 7aba45c36e2..fc9b7e100f5 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -5,7 +5,7 @@ class EstateProperty(models.Model): _name = 'estate.property' _description = 'Real Estate Property' - + name = fields.Char(string="Title", required=True) description = fields.Text(string="Description") postcode = fields.Char(string="Postcode") @@ -19,16 +19,21 @@ class EstateProperty(models.Model): garden = fields.Boolean(string="Garden") garden_area = fields.Integer(string="Garden Area (spm)") garden_orientation = fields.Selection([ - ('north', 'North'), - ('east', 'East'), - ('west', 'West'), - ('south', 'South') + ('north', "North"), + ('east', "East"), + ('west', "West"), + ('south', "South") ]) active = fields.Boolean(string="Active", default=True) state = fields.Selection([ - ('new', 'New'), - ('offer_received', 'Offer Received'), - ('offer_accepted', 'Offer Accepted'), - ('sold', 'Sold'), - ('cancelled', 'Cancelled') + ('new', "New"), + ('offer_received', "Offer Received"), + ('offer_accepted', "Offer Accepted"), + ('sold', "Sold"), + ('cancelled', "Cancelled") ], string="State", copy=False, default='new') + property_type_id = fields.Many2one('estate.property.type', string="Property Type", ondelete="cascade") + sales_person_id = fields.Many2one('res.users', string='Salesman', ondelete='cascade') + buyer_id = fields.Many2one('res.partner', string='Buyer', ondelete='cascade') + property_tag_ids = fields.Many2many('estate.property.tag') + 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..aacaf0e29a0 --- /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 = "Real Estate Offer" + + price = fields.Float(string='Price') + status = fields.Selection([ + ('accepted', 'Accepted'), + ('refused', 'Refused') + ], string='Status', copy=False) + partner_id = fields.Many2one('res.partner', required=True) + property_id = fields.Many2one('estate.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..01da11e0ec2 --- /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 Tag' + + name = fields.Char(string='Tag', required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..1f90b1c59e2 --- /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" + + name = fields.Char(string="Type", required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 32389642d4f..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 +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 99abf1350f5..a40ec4a5649 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -4,5 +4,9 @@ + + + +
diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..88694b2f445 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,26 @@ + + + + estate.property.offer.form + estate.property.offer + +
+ + + + + +
+ + + 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..4dcd3674e34 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,8 @@ + + + + Property Tags + estate.property.tag + list,form + + diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..dd480955e4e --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,8 @@ + + + + Property Type + estate.property.type + list,form + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 14e416db34c..031276ee7a0 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -7,16 +7,16 @@

+

- - - - - - - - + + + + + + + @@ -33,6 +33,15 @@ + + + + + + + + +
From 3c705218319ac46ae43b2d3d00b2862a4a4377f4 Mon Sep 17 00:00:00 2001 From: habar Date: Tue, 24 Mar 2026 18:17:37 +0530 Subject: [PATCH 09/12] [ADD] estate: define compute method for calculating total area 1) add total area field set compute method inside. 2) apply logic, used decorator for dependent fields. --- estate/models/estate_property.py | 10 ++++++++-- estate/views/estate_property_views.xml | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index fc9b7e100f5..2076549bbbe 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,5 +1,5 @@ from dateutil.relativedelta import relativedelta -from odoo import fields, models +from odoo import api, fields, models class EstateProperty(models.Model): @@ -9,7 +9,7 @@ class EstateProperty(models.Model): name = fields.Char(string="Title", required=True) description = fields.Text(string="Description") postcode = fields.Char(string="Postcode") - date_availability = fields.Date(string="Available From", copy=False, default=fields.Date.today() + relativedelta(months=3)) + date_availability = fields.Date(string="Available From", copy=False, default=lambda self: fields.Date.today() + relativedelta(months=3)) expected_price = fields.Float(string="Expected Price", required=True) selling_price = fields.Float(string="Selling Price", copy=False) bedrooms = fields.Integer(string="Bedrooms", default=2) @@ -18,6 +18,7 @@ class EstateProperty(models.Model): garage = fields.Boolean(string="Garage") garden = fields.Boolean(string="Garden") garden_area = fields.Integer(string="Garden Area (spm)") + total_area = fields.Float(string="Total Area (sqm)", compute="_computed_total_area", store=True) garden_orientation = fields.Selection([ ('north', "North"), ('east', "East"), @@ -37,3 +38,8 @@ class EstateProperty(models.Model): buyer_id = fields.Many2one('res.partner', string='Buyer', ondelete='cascade') property_tag_ids = fields.Many2many('estate.property.tag') offer_ids = fields.One2many('estate.property.offer', 'property_id', string="Offers") + + @api.depends("living_area", "garden_area") + def _computed_total_area(self): + for rec in self: + rec.total_area = rec.living_area + rec.garden_area diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 031276ee7a0..20b248a9b01 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -30,6 +30,7 @@ + @@ -52,7 +53,7 @@ estate.property.list estate.property - + From 3677135b8a7942f4c6e4e7bb96d8eda3ac35387c Mon Sep 17 00:00:00 2001 From: habar Date: Wed, 25 Mar 2026 21:53:29 +0530 Subject: [PATCH 10/12] [IMP] estate: Add best price offers for estate property model 1) add best price offers field 2) define logic set computed field --- estate/models/estate_property.py | 8 ++++++++ estate/views/estate_property_views.xml | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 2076549bbbe..04d155d0350 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,5 @@ from dateutil.relativedelta import relativedelta + from odoo import api, fields, models @@ -38,8 +39,15 @@ class EstateProperty(models.Model): buyer_id = fields.Many2one('res.partner', string='Buyer', ondelete='cascade') property_tag_ids = fields.Many2many('estate.property.tag') offer_ids = fields.One2many('estate.property.offer', 'property_id', string="Offers") + best_price = fields.Float(string="Best Offer", compute="_computed_best_offer", store=True) @api.depends("living_area", "garden_area") def _computed_total_area(self): for rec in self: rec.total_area = rec.living_area + rec.garden_area + + @api.depends("offer_ids.price") + def _computed_best_offer(self): + for rec in self: + prices = rec.offer_ids.mapped("price") + rec.best_price = max(prices) if prices else 0.0 diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 20b248a9b01..2324e6ae535 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -16,6 +16,7 @@ + @@ -35,7 +36,7 @@ - + @@ -61,6 +62,8 @@ + + @@ -76,6 +79,8 @@ + + From 41768c17f4bdce6f396baa3d8fa19a4bca2de3c2 Mon Sep 17 00:00:00 2001 From: habar Date: Thu, 26 Mar 2026 18:38:55 +0530 Subject: [PATCH 11/12] [IMP] estate: added validity & deadline in estate property offer model. 1) Define two fields validity and deadline. 2) Create compute & inverse method for them 3) Also added search functionality in the estate property model for best offers. --- estate/models/estate_property.py | 25 +++++++++++++------- estate/models/estate_property_offer.py | 19 +++++++++++++-- estate/views/estate_property_offer_views.xml | 4 ++++ 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 04d155d0350..679d9ae0cdd 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -8,18 +8,18 @@ class EstateProperty(models.Model): _description = 'Real Estate Property' name = fields.Char(string="Title", required=True) - description = fields.Text(string="Description") - postcode = fields.Char(string="Postcode") + description = fields.Text() + postcode = fields.Char() date_availability = fields.Date(string="Available From", copy=False, default=lambda self: fields.Date.today() + relativedelta(months=3)) expected_price = fields.Float(string="Expected Price", required=True) selling_price = fields.Float(string="Selling Price", copy=False) - bedrooms = fields.Integer(string="Bedrooms", default=2) + bedrooms = fields.Integer(default=2) living_area = fields.Integer(string="Living Area (spm)") - facades = fields.Integer(string="Facades") - garage = fields.Boolean(string="Garage") - garden = fields.Boolean(string="Garden") + facades = fields.Integer() + garage = fields.Boolean() + garden = fields.Boolean() garden_area = fields.Integer(string="Garden Area (spm)") - total_area = fields.Float(string="Total Area (sqm)", compute="_computed_total_area", store=True) + total_area = fields.Float(string="Total Area (sqm)", compute="_computed_total_area") garden_orientation = fields.Selection([ ('north', "North"), ('east', "East"), @@ -33,13 +33,13 @@ class EstateProperty(models.Model): ('offer_accepted', "Offer Accepted"), ('sold', "Sold"), ('cancelled', "Cancelled") - ], string="State", copy=False, default='new') + ], copy=False, default='new') property_type_id = fields.Many2one('estate.property.type', string="Property Type", ondelete="cascade") sales_person_id = fields.Many2one('res.users', string='Salesman', ondelete='cascade') buyer_id = fields.Many2one('res.partner', string='Buyer', ondelete='cascade') property_tag_ids = fields.Many2many('estate.property.tag') offer_ids = fields.One2many('estate.property.offer', 'property_id', string="Offers") - best_price = fields.Float(string="Best Offer", compute="_computed_best_offer", store=True) + best_price = fields.Float(string="Best Offer", compute="_computed_best_offer", search="_search_best_offer", store=False) @api.depends("living_area", "garden_area") def _computed_total_area(self): @@ -51,3 +51,10 @@ def _computed_best_offer(self): for rec in self: prices = rec.offer_ids.mapped("price") rec.best_price = max(prices) if prices else 0.0 + + def _search_best_offer(self, operator, value): + return [ + '&', + ('offer_ids.price', '>', 10000), + ('offer_ids.price', operator, value) + ] diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index aacaf0e29a0..2c08b12128c 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,6 @@ -from odoo import fields, models +from dateutil.relativedelta import relativedelta + +from odoo import api, fields, models class EstatePropertyOffer(models.Model): @@ -9,6 +11,19 @@ class EstatePropertyOffer(models.Model): status = fields.Selection([ ('accepted', 'Accepted'), ('refused', 'Refused') - ], string='Status', copy=False) + ], copy=False) partner_id = fields.Many2one('res.partner', required=True) property_id = fields.Many2one('estate.property', required=True) + validity = fields.Integer(default=7) + date_deadline = fields.Date(string="Deadline", compute="_compute_deadline_method", inverse="_inverse_deadline_method") + + @api.depends("create_date", "validity") + def _compute_deadline_method(self): + for rec in self: + create_date = rec.create_date.date() if rec.create_date else fields.Date.today() + rec.date_deadline = create_date + relativedelta(days=rec.validity) + + def _inverse_deadline_method(self): + for rec in self: + create_date = rec.create_date.date() if rec.create_date else fields.Date.today() + rec.validity = relativedelta(rec.date_deadline, create_date).days diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 88694b2f445..f25a16099dd 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -7,6 +7,8 @@
+ + @@ -19,6 +21,8 @@ + + From 57fb096c6721dd24598b914c6fc71d8395d3e4d3 Mon Sep 17 00:00:00 2001 From: habar Date: Fri, 27 Mar 2026 18:44:18 +0530 Subject: [PATCH 12/12] [IMP] estate: added onchange method in the estate property model 1) Define _onchange_garden() to automatically set default garden_area and garden_orientation when the garden is enabled. 2) Clear these fields when the garden is disabled. 3) Add a warning notification when the garden checkbox is checked. --- estate/models/estate_property.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 679d9ae0cdd..39d10d115fd 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -14,11 +14,11 @@ class EstateProperty(models.Model): expected_price = fields.Float(string="Expected Price", required=True) selling_price = fields.Float(string="Selling Price", copy=False) bedrooms = fields.Integer(default=2) - living_area = fields.Integer(string="Living Area (spm)") + living_area = fields.Float(string="Living Area (spm)") facades = fields.Integer() garage = fields.Boolean() garden = fields.Boolean() - garden_area = fields.Integer(string="Garden Area (spm)") + garden_area = fields.Float(string="Garden Area (spm)") total_area = fields.Float(string="Total Area (sqm)", compute="_computed_total_area") garden_orientation = fields.Selection([ ('north', "North"), @@ -48,9 +48,8 @@ def _computed_total_area(self): @api.depends("offer_ids.price") def _computed_best_offer(self): - for rec in self: - prices = rec.offer_ids.mapped("price") - rec.best_price = max(prices) if prices else 0.0 + prices = self.offer_ids.mapped("price") + self.best_price = max(prices) if prices else 0.0 def _search_best_offer(self, operator, value): return [ @@ -58,3 +57,20 @@ def _search_best_offer(self, operator, value): ('offer_ids.price', '>', 10000), ('offer_ids.price', operator, value) ] + + @api.onchange("garden") + def _onchange_garden(self): + if self.garden: + self.garden_area = 10 + self.garden_orientation = 'north' + + return { + 'warning': { + 'title': "Garden Enabled", + 'message': "Default area set to 10 and orientation north", + 'type': "notification" + } + } + else: + self.garden_area = 0 + self.garden_orientation = False