From ce05c66cef0be7edebe482ac1c6ead325a1767f9 Mon Sep 17 00:00:00 2001 From: utpat-odoo Date: Mon, 27 Oct 2025 17:26:51 +0530 Subject: [PATCH 01/10] [ADD] estate: create new module create new module estate and create model for new module and add security --- estate/__init__.py | 4 ++++ estate/__manifest__.py | 7 +++++++ estate/models/__init__.py | 1 + estate/models/estate_property.py | 19 +++++++++++++++++++ estate/security/ir.model.access.csv | 2 ++ 5 files changed, 33 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 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..6bf0d7404bc --- /dev/null +++ b/estate/__init__.py @@ -0,0 +1,4 @@ +# empty + +from . import models + diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..ceb1a628b9b --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,7 @@ +{ + 'name':'Estate', + 'depends': ['base'], + 'license': 'AGPL-3', + 'data':['security/ir.model.access.csv'] +} + 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..3fa5246f540 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,19 @@ +from odoo import models, fields + +class EstateProperty(models.Model): + _name = 'estate_property' + _description = "Real Estate Property" + + 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='Garden Orientation',selection=[('north', 'North'), ('south', 'South'), ('east','East'), ('west','West')]) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..46162d67e6b --- /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 From d636571f3e62387b56175ad9653d7e8897f923a5 Mon Sep 17 00:00:00 2001 From: utpat-odoo Date: Tue, 28 Oct 2025 19:18:13 +0530 Subject: [PATCH 02/10] [ADD] estate: create views and security folder Create module Real Estate add menu list set column default, read-only --- estate/__manifest__.py | 9 ++++++--- estate/models/estate_property.py | 10 +++++++--- estate/security/ir.model.access.csv | 4 ++-- estate/views/estate_menus.xml | 8 ++++++++ estate/views/estate_property_views.xml | 9 +++++++++ 5 files changed, 32 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 ceb1a628b9b..f67a68514bb 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -2,6 +2,9 @@ 'name':'Estate', 'depends': ['base'], 'license': 'AGPL-3', - 'data':['security/ir.model.access.csv'] -} - + 'data':[ + 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml' + ] +} \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 3fa5246f540..88bf5af1d49 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,5 @@ from odoo import models, fields +from dateutil.relativedelta import relativedelta class EstateProperty(models.Model): _name = 'estate_property' @@ -7,13 +8,16 @@ class EstateProperty(models.Model): name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date() + date_availability = fields.Date(copy=False, default=fields.Date.today() + relativedelta(months=3)) expected_price = fields.Float(required=True) - selling_price = fields.Float() - bedrooms = fields.Integer() + selling_price = fields.Float(readonly=True, copy=False) + bedrooms = fields.Integer(default=2) living_area = fields.Integer() facades = fields.Integer() garage = fields.Boolean() garden = fields.Boolean() garden_area = fields.Integer() garden_orientation=fields.Selection(string='Garden Orientation',selection=[('north', 'North'), ('south', 'South'), ('east','East'), ('west','West')]) + active=fields.Boolean(default=False) + state=fields.Selection(selection=[('new','New'),('offer_received','Offer Received'),('offer_accepted','Offer Accepted'),('sold','Sold'),('cancelled','Cancelled')]) + diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 46162d67e6b..cbc96ebdb5e 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 +"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 diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..9704219c01c --- /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..d7f601ed66b --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,9 @@ + + + + Properties + estate_property + list,form + {"search_default_available":1} + + \ No newline at end of file From f586eb5668432b47131eadda93a9eb2cccd84d5d Mon Sep 17 00:00:00 2001 From: utpat-odoo Date: Wed, 29 Oct 2025 16:19:58 +0530 Subject: [PATCH 03/10] [IMP] estate: add list view and form view In estate module add basic views list view and form view Also add filter for new or offer received stage --- estate/__init__.py | 3 +- estate/__manifest__.py | 2 +- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 7 +-- estate/views/estate_menus.xml | 4 +- estate/views/estate_property_views.xml | 74 +++++++++++++++++++++++++- 6 files changed, 81 insertions(+), 11 deletions(-) diff --git a/estate/__init__.py b/estate/__init__.py index 6bf0d7404bc..5f02092a243 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -1,4 +1,3 @@ -# empty - from . import models + diff --git a/estate/__manifest__.py b/estate/__manifest__.py index f67a68514bb..8941080adff 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,4 +7,4 @@ 'views/estate_property_views.xml', 'views/estate_menus.xml' ] -} \ No newline at end of file +} 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 88bf5af1d49..23f4cd78b2a 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,6 +1,7 @@ from odoo import models, fields from dateutil.relativedelta import relativedelta + class EstateProperty(models.Model): _name = 'estate_property' _description = "Real Estate Property" @@ -12,12 +13,12 @@ class EstateProperty(models.Model): expected_price = fields.Float(required=True) selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) - living_area = fields.Integer() + living_area = fields.Integer(string="Living Area (sqm)") facades = fields.Integer() garage = fields.Boolean() garden = fields.Boolean() - garden_area = fields.Integer() + garden_area = fields.Integer(string="Garden Area (sqm)") garden_orientation=fields.Selection(string='Garden Orientation',selection=[('north', 'North'), ('south', 'South'), ('east','East'), ('west','West')]) active=fields.Boolean(default=False) state=fields.Selection(selection=[('new','New'),('offer_received','Offer Received'),('offer_accepted','Offer Accepted'),('sold','Sold'),('cancelled','Cancelled')]) - + diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 9704219c01c..ade7018ec8f 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,8 +1,8 @@ - - + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index d7f601ed66b..7fb7b76c9a3 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,9 +1,79 @@ - + + + estate_property + + + + + + + + + + + + + + + + + estate_property + + + + + + + + + + + + + + + estate_property + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + Properties estate_property list,form {"search_default_available":1} -
\ No newline at end of file + From c17a37d4a5c9e3a07c42ad3d9e18e233c5a20dc4 Mon Sep 17 00:00:00 2001 From: utpat-odoo Date: Wed, 29 Oct 2025 16:32:05 +0530 Subject: [PATCH 04/10] [IMP] estate: add list view and form view and improve syntax In estate module add basic views list view and form view Also add filter for new or offer received stage improve syntax in estate_property model --- estate/models/estate_property.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 23f4cd78b2a..aac5d7e3151 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -18,7 +18,22 @@ class EstateProperty(models.Model): garage = fields.Boolean() garden = fields.Boolean() garden_area = fields.Integer(string="Garden Area (sqm)") - garden_orientation=fields.Selection(string='Garden Orientation',selection=[('north', 'North'), ('south', 'South'), ('east','East'), ('west','West')]) + garden_orientation=fields.Selection( + string='Garden Orientation', + selection=[('north', 'North'), + ('south', 'South'), + ('east','East'), + ('west','West') + ] + ) active=fields.Boolean(default=False) - state=fields.Selection(selection=[('new','New'),('offer_received','Offer Received'),('offer_accepted','Offer Accepted'),('sold','Sold'),('cancelled','Cancelled')]) + state=fields.Selection( + selection=[ + ('new','New'), + ('offer_received','Offer Received'), + ('offer_accepted','Offer Accepted'), + ('sold','Sold'), + ('cancelled','Cancelled') + ] + ) From d0ab7e7da218e31b21b3b036d8c65a65cf688ad6 Mon Sep 17 00:00:00 2001 From: utpat-odoo Date: Thu, 30 Oct 2025 18:09:36 +0530 Subject: [PATCH 05/10] [IMP] estate: add property type,tag, offers, buyer and salesperson Add new menu item property type and tags Add buyer and salesperson fields Add offer section --- estate/__init__.py | 2 - estate/__manifest__.py | 8 ++- estate/models/__init__.py | 3 + estate/models/estate_property.py | 30 +++++---- estate/models/estate_property_offer.py | 17 ++++++ estate/models/estate_property_tag.py | 10 +++ estate/models/estate_property_type.py | 9 +++ estate/security/ir.model.access.csv | 3 + estate/views/estate_menus.xml | 12 +++- estate/views/estate_property_tag_views.xml | 44 ++++++++++++++ estate/views/estate_property_type_views.xml | 44 ++++++++++++++ estate/views/estate_property_views.xml | 67 +++++++++++++++------ 12 files changed, 208 insertions(+), 41 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_tag_views.xml create mode 100644 estate/views/estate_property_type_views.xml diff --git a/estate/__init__.py b/estate/__init__.py index 5f02092a243..0a45e674f6a 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -1,3 +1 @@ from . import models - - diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 8941080adff..a4474c78986 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,10 +1,12 @@ { - 'name':'Estate', + 'name': 'Estate', 'depends': ['base'], 'license': 'AGPL-3', - 'data':[ + 'data': [ 'security/ir.model.access.csv', 'views/estate_property_views.xml', - 'views/estate_menus.xml' + 'views/estate_menus.xml', + 'views/estate_property_type_views.xml', + 'views/estate_property_tag_views.xml' ] } diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 5e1963c9d2f..2f1821a39c1 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,4 @@ from . import estate_property +from . import estate_property_type +from . import estate_property_tag +from . import estate_property_offer diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index aac5d7e3151..0927d860df2 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -3,7 +3,7 @@ class EstateProperty(models.Model): - _name = 'estate_property' + _name = 'estate.property' _description = "Real Estate Property" name = fields.Char(required=True) @@ -18,22 +18,26 @@ class EstateProperty(models.Model): garage = fields.Boolean() garden = fields.Boolean() garden_area = fields.Integer(string="Garden Area (sqm)") - garden_orientation=fields.Selection( - string='Garden Orientation', + garden_orientation = fields.Selection( + string="Garden Orientation", selection=[('north', 'North'), ('south', 'South'), - ('east','East'), - ('west','West') + ('east', 'East'), + ('west', 'West') ] ) - active=fields.Boolean(default=False) - state=fields.Selection( + active = fields.Boolean(default=False) + state = fields.Selection( 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') ] ) - + property_type_id = fields.Many2one("estate.property.type") + buyer = fields.Many2one("res.partner", copy=False) + salesperson = fields.Many2one("res.users") + 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..0302933e4af --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,17 @@ +from odoo import models,fields + + +class EstatePropertyOffer(models.Model): + _name='estate.property.offer' + _description="Estate Property Offer" + + price=fields.Float() + status=fields.Selection( + selection=[ + ('accepted', 'Accepted'), + ('refused', 'Refused') + ] + ) + partner_id = fields.Many2one("res.partner", required=True) + property_id = fields.Many2one("estate.property", required=True) + \ No newline at end of file diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..e83a34f7ab6 --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,10 @@ +from odoo import models,fields + + +class EstatePropertyTag(models.Model): + _name='estate.property.tag' + _description="Estate Property Tag" + + name=fields.Char() + property_ids = fields.Many2many('estate.property') + \ No newline at end of file diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..6a324ab4d31 --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,9 @@ +from odoo import models, fields + + +class EstatePropertyType(models.Model): + _name = 'estate.property.type' + _description = "Real Estate Property Type" + + name = fields.Char(required=True) + property_ids = fields.One2many('estate.property','property_type_id') diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index cbc96ebdb5e..f301ea324b8 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 ade7018ec8f..f9dd60a2b2e 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,8 +1,14 @@ - - - + + + + + + + + + diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 00000000000..b4497f24ec1 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,44 @@ + + + + estate.property.tag + + + + + + + + + estate.property.tag + + + + + + + + + estate.property.tag + +
+ + + + + + + + + +
+
+
+ + + Property tag + estate.property.tag + list,form + {"search_default_available":1} + +
diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..bb0fc6b2dd6 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,44 @@ + + + + estate.property.type + + + + + + + + + estate.property.type + + + + + + + + + estate.property.type + +
+ + + + + + + + + +
+
+
+ + + Property type + estate.property.type + list,form + {"search_default_available":1} + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 7fb7b76c9a3..e642b77888c 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,8 +1,7 @@ - - estate_property + estate.property @@ -11,15 +10,14 @@ + - - - estate_property + estate.property @@ -27,23 +25,25 @@ - + + - - estate_property + estate.property
+ + @@ -51,16 +51,44 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -69,10 +97,9 @@
- Properties - estate_property + estate.property list,form {"search_default_available":1} From 155c62741de55727fa06e1056a1ae7121249a67a Mon Sep 17 00:00:00 2001 From: utpat-odoo Date: Fri, 31 Oct 2025 17:23:26 +0530 Subject: [PATCH 06/10] [IMP] estate: add compute and on change field and add object type action compute field like total area best offer add validate and deadline fields with computation add object type action on sold and cancel button and buyer field add accept and refuse button in offer form --- estate/__manifest__.py | 7 ++- estate/models/estate_property.py | 48 ++++++++++++++++++-- estate/models/estate_property_offer.py | 35 +++++++++++++- estate/views/estate_property_offer_views.xml | 34 ++++++++++++++ estate/views/estate_property_tag_views.xml | 2 +- estate/views/estate_property_type_views.xml | 2 +- estate/views/estate_property_views.xml | 32 ++++++------- 7 files changed, 132 insertions(+), 28 deletions(-) create mode 100644 estate/views/estate_property_offer_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index a4474c78986..c32e2fb857f 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,6 +7,9 @@ 'views/estate_property_views.xml', 'views/estate_menus.xml', 'views/estate_property_type_views.xml', - 'views/estate_property_tag_views.xml' - ] + 'views/estate_property_tag_views.xml', + 'views/estate_property_offer_views.xml' + ], + 'application': True, + 'installable': True } diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 0927d860df2..f92f6303853 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,5 +1,6 @@ -from odoo import models, fields +from odoo import models, fields, api from dateutil.relativedelta import relativedelta +from odoo.exceptions import UserError class EstateProperty(models.Model): @@ -13,11 +14,11 @@ class EstateProperty(models.Model): expected_price = fields.Float(required=True) selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) - living_area = fields.Integer(string="Living Area (sqm)") + living_area = fields.Float(string="Living Area (sqm)") facades = fields.Integer() garage = fields.Boolean() garden = fields.Boolean() - garden_area = fields.Integer(string="Garden Area (sqm)") + garden_area = fields.Float(string="Garden Area (sqm)") garden_orientation = fields.Selection( string="Garden Orientation", selection=[('north', 'North'), @@ -38,6 +39,45 @@ class EstateProperty(models.Model): ) property_type_id = fields.Many2one("estate.property.type") buyer = fields.Many2one("res.partner", copy=False) - salesperson = fields.Many2one("res.users") + salesperson = fields.Many2one("res.users", default=lambda self: self.env.user) tag_ids = fields.Many2many("estate.property.tag") offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") + + total_area = fields.Float(compute="_compute_total_area") + @api.depends('living_area', 'garden_area') + def _compute_total_area(self): + for record in self: + record.total_area = record.living_area + record.garden_area + + best_offer = fields.Float(compute="_compute_best_offer") + @api.depends('offer_ids.price') + def _compute_best_offer(self): + for record in self: + if not record.mapped('offer_ids.price'): + record.best_offer = 0 + else: + record.best_offer = max(record.mapped('offer_ids.price')) + + @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 = None + + def cancel_property(self): + for record in self: + if record.state == 'sold': + raise UserError("sold property cannot be cancelled.") + else: + record.state = 'cancelled' + + def sold_property(self): + for record in self: + if record.state == 'cancelled': + raise UserError("cancelled property cannot be sold.") + else: + record.state = 'sold' + \ No newline at end of file diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 0302933e4af..69bae7a78bc 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 dateutil.relativedelta import relativedelta +from odoo.exceptions import UserError class EstatePropertyOffer(models.Model): @@ -14,4 +16,35 @@ class EstatePropertyOffer(models.Model): ) 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(compute="_compute_deadline", inverse="_inverse_deadline") + + @api.depends('validity') + def _compute_deadline(self): + for record in self: + if record.create_date: + record.date_deadline = fields.Date.to_date(record.create_date) + relativedelta(days=record.validity) + else: + record.date_deadline = 0 + + def _inverse_deadline(self): + for record in self: + if record.create_date: + record.validity = (record.date_deadline - fields.Date.to_date(record.create_date)).days + else: + record.validity = 0 + + def action_accept(self): + for record in self: + if record.property_id.buyer: + raise UserError("Property already accepted") + else: + record.status = 'accepted' + record.property_id.selling_price = record.price + record.property_id.state = 'offer_accepted' + record.property_id.buyer = record.partner_id + + def action_refuse(self): + for record in self: + record.status = 'refused' \ No newline at end of file diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..bc6bef1ca2f --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,34 @@ + + + + estate.property.offer + + + + + + + + @@ -37,6 +42,12 @@ Property type estate.property.type list,form - {"search_default_available":1} + + + + Property type Offer + estate.property.offer + list + [("property_id.type_id", "=", active_id)] diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index a8133819547..f078cc65615 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -10,8 +10,9 @@ - - + + + @@ -19,14 +20,15 @@ estate.property - + - - - + + + + @@ -36,15 +38,15 @@
-
- + @@ -71,14 +73,14 @@ - - + + - + From 78e37ccfcb80e1739f268dfca4906b183dcd6759 Mon Sep 17 00:00:00 2001 From: utpat-odoo Date: Thu, 6 Nov 2025 18:02:53 +0530 Subject: [PATCH 10/10] [IMP] estate: add python, model, view inheritance restrict user to delete property which is not in new or sold state add property id field in user model using inheritance --- estate/__manifest__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 18 ++++++++++++++++++ estate/models/estate_property_offer.py | 10 ++++++++++ estate/models/estate_property_type.py | 4 ++-- estate/models/res_users.py | 12 ++++++++++++ estate/views/estate_property_type_views.xml | 8 ++++---- estate/views/res_users_views.xml | 15 +++++++++++++++ 8 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 estate/models/res_users.py create mode 100644 estate/views/res_users_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index b54ea6d0630..eb22a4b48a6 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -9,6 +9,7 @@ 'views/estate_property_type_views.xml', 'views/estate_property_tag_views.xml', 'views/estate_property_offer_views.xml', + 'views/res_users_views.xml', 'views/estate_menus.xml' ], 'application': True, diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 2f1821a39c1..9a2189b6382 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -2,3 +2,4 @@ from . import estate_property_type from . import estate_property_tag from . import estate_property_offer +from . import res_users diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 4cd109d9569..0a036c8e1a4 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -101,3 +101,21 @@ def _check_selling_price(self): if record.state in ['sold', 'offer_accepted']: if float_compare(record.selling_price, 0.9 * record.expected_price, precision_digits=2) < 0: raise ValidationError("the selling price is lower") + + @api.ondelete(at_uninstall=True) + def _unlink_check_state_of_property(self): + for record in self: + if record.state in ('offer_received', 'offer_accepted', 'sold'): + raise UserError("You cannot delete a new or cancelled property !") + + @api.model + def write(self, vals): + for record in self: + if 'state' in vals: + new_state = vals['state'] + current_state = record.state + if current_state == 'sold' and new_state == 'cancelled': + raise UserError("sold property cannot be cancelled.") + if current_state == 'cancelled' and new_state == 'sold': + raise UserError("cancelled property cannot be sold.") + return super().write(vals) diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 7d35588a48d..3bf4a03275a 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -54,3 +54,13 @@ def action_refuse(self): 'CHECK(price>=0)', 'offer price must be positive', ) + + @api.model + def create(self,value): + for record in value: + property = self.env['estate.property'].browse(record['property_id']) + if property.state == 'new': + property.state = 'offer_received' + if record['price'] < property.best_offer: + raise UserError("Offer must be higher or equal than %d" % property.best_offer) + return super().create(value) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index 87f906d64aa..e6126c8e422 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -9,8 +9,8 @@ class EstatePropertyType(models.Model): name = fields.Char(required=True) property_ids = fields.One2many('estate.property', 'type_id') sequence = fields.Integer(string="Sequence", default=1) - offer_count = fields.Integer(compute="_compute_total_offers") - offer_ids = fields.One2many("estate.property.offer","property_type_id") + offer_count = fields.Integer(compute="_compute_total_offers") + offer_ids = fields.One2many("estate.property.offer", "property_type_id") @api.depends("offer_ids") def _compute_total_offers(self): diff --git a/estate/models/res_users.py b/estate/models/res_users.py new file mode 100644 index 00000000000..25c99c1cb2b --- /dev/null +++ b/estate/models/res_users.py @@ -0,0 +1,12 @@ +from odoo import fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + property_ids = fields.One2many( + "estate.property", + "salesperson", + string="Estate Properties", + domain=[("state", "!=", "sold")], + ) diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml index c379d1dfbe4..84af9bfb54e 100644 --- a/estate/views/estate_property_type_views.xml +++ b/estate/views/estate_property_type_views.xml @@ -16,11 +16,11 @@ -
- -
+ @@ -30,7 +30,7 @@ - +
diff --git a/estate/views/res_users_views.xml b/estate/views/res_users_views.xml new file mode 100644 index 00000000000..cd482a99be2 --- /dev/null +++ b/estate/views/res_users_views.xml @@ -0,0 +1,15 @@ + + + + res.users.view.form.inherit + res.users + + + + + + + + + +