From 0ce5e44f700f5e517451d8606cc7317fee1f9d08 Mon Sep 17 00:00:00 2001 From: haman-odoo Date: Thu, 4 Dec 2025 11:10:33 +0530 Subject: [PATCH 1/9] [ADD] estate: Created base module structure and manifest Created the initial structure for the Estate module: - Added __init__.py file to initialize the module. - Added __manifest__.py file with basic module metadata like: - name - version - depends - data - description --- estate/__init__.py | 0 estate/__manifest__.py | 14 ++++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 estate/__init__.py create mode 100644 estate/__manifest__.py diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..abd3ce0aa0e --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,14 @@ +{ + 'name': "Real Estate", + 'version': '1.0', + 'license': 'LGPL-3', + 'summary': 'Real Estate advertisement tutorial module', + 'depends': ['base'], + 'author': "Harsh Maniya", + 'category': 'Sales/Real Estate', + 'installable': True, + 'auto_install': False, + 'description': """ + Description text + """, +} From 742a492c94e1bf418e3b7cba7c89310ab00c2138 Mon Sep 17 00:00:00 2001 From: haman-odoo Date: Thu, 4 Dec 2025 14:46:21 +0530 Subject: [PATCH 2/9] [IMP] estate: Added EstateProperty model with all required fields Chapter 3 : Added EstateProperty model with core fields. Updated __init__.py files to load new models. --- estate/__init__.py | 1 + estate/__manifest__.py | 4 +--- estate/models/__init__.py | 1 + estate/models/estate_property.py | 29 +++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) 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 index e69de29bb2d..0650744f6bc 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/estate/__manifest__.py b/estate/__manifest__.py index abd3ce0aa0e..0b7f5b3188c 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -8,7 +8,5 @@ 'category': 'Sales/Real Estate', 'installable': True, 'auto_install': False, - 'description': """ - Description text - """, + 'description': """Description text""", } diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..9d5e62fe812 --- /dev/null +++ b/estate/models/__init__.py @@ -0,0 +1 @@ +from . import estate_property # noqa: F401 diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py new file mode 100644 index 00000000000..ca65e3f4e6f --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,29 @@ +from odoo import models, fields + + +class EstateProperty(models.Model): + _name = "estate.property" + _description = "Real Estate Property" + + name = fields.Char(string="Property Title", required=True) + description = fields.Text(string="Description") + postcode = fields.Char(string="Postcode") + date_availability = fields.Date(string="Available From") + 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 (sqm)") + facades = fields.Integer(string="Number of Facades") + garage = fields.Boolean(string="Has Garage") + garden = fields.Boolean(string="Has Garden") + garden_area = fields.Integer(string="Garden Area (sqm)") + garden_orientation = fields.Selection( + selection=[ + ('north', 'North'), + ('south', 'South'), + ('east', 'East'), + ('west', 'West'), + ], + string="Garden Orientation" + ) From e197d7f9811d866b37596dbc225e16951be499b1 Mon Sep 17 00:00:00 2001 From: haman-odoo Date: Fri, 5 Dec 2025 12:55:30 +0530 Subject: [PATCH 3/9] [IMP] estate: Added access control for EstateProperty model Chapter 4 : Added ir.model.access.csv file for defining EstateProperty access rules. Granted basic read, write, create, and delete permissions to internal users. Updated __manifest__.py to load the security access file. --- estate/__manifest__.py | 3 +++ estate/security/ir.model.access.csv | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 0b7f5b3188c..e79e2f1f3db 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -5,6 +5,9 @@ 'summary': 'Real Estate advertisement tutorial module', 'depends': ['base'], 'author': "Harsh Maniya", + 'data': [ + 'security/ir.model.access.csv', + ], 'category': 'Sales/Real Estate', 'installable': True, 'auto_install': False, diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..a6992df6d34 --- /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_user,access_estate_property_user,model_estate_property,base.group_user,1,1,1,1 From 22d2d17813c877935b66df0e0902437fb4374688 Mon Sep 17 00:00:00 2001 From: haman-odoo Date: Sat, 6 Dec 2025 18:15:53 +0530 Subject: [PATCH 4/9] [IMP] estate: Added actions, menus and first list/form views Chapter 5 : Added EstateProperty list and form views to display and manage properties. Created ir.actions.act_window action to open EstateProperty records. Added Real Estate main menu, submenu, and Properties menu item linked to the action. --- estate/__manifest__.py | 2 ++ estate/models/estate_property.py | 30 +++++++++++++++++++++++--- estate/views/estate_menus.xml | 6 ++++++ estate/views/estate_property_views.xml | 25 +++++++++++++++++++++ 4 files changed, 60 insertions(+), 3 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 e79e2f1f3db..2391f4c9bf7 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,6 +7,8 @@ 'author': "Harsh Maniya", 'data': [ 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml', ], 'category': 'Sales/Real Estate', 'installable': True, diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index ca65e3f4e6f..35009ccabc6 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,6 @@ from odoo import models, fields +from dateutil.relativedelta import relativedelta +from datetime import date class EstateProperty(models.Model): @@ -8,11 +10,19 @@ class EstateProperty(models.Model): name = fields.Char(string="Property Title", required=True) description = fields.Text(string="Description") postcode = fields.Char(string="Postcode") - date_availability = fields.Date(string="Available From") + date_availability = fields.Date( + string="Available From", + default=lambda sself: date.today() + relativedelta(months=3), + copy=False + ) expected_price = fields.Float(string="Expected Price", required=True) - selling_price = fields.Float(string="Selling Price") + selling_price = fields.Float( + string="Selling Price", + readonly=True, + copy=False + ) - bedrooms = fields.Integer(string="Bedrooms") + bedrooms = fields.Integer(string="Bedrooms", default=2) living_area = fields.Integer(string="Living Area (sqm)") facades = fields.Integer(string="Number of Facades") garage = fields.Boolean(string="Has Garage") @@ -27,3 +37,17 @@ class EstateProperty(models.Model): ], string="Garden Orientation" ) + active = fields.Boolean(default=True) + state = fields.Selection( + selection=[ + ('new', 'New'), + ('offer_received', 'Offer Received'), + ('offer_accepted', 'Offer Accepted'), + ('sold', 'Sold'), + ('cancelled', 'Cancelled'), + ], + string="Status", + required=True, + copy=False, + default='new', +) diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..7154c53b30f --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml new file mode 100644 index 00000000000..62a46c36e54 --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,25 @@ + + + + + Properties + estate.property + list,form + + + + + estate.property.list + estate.property + + + + + + + + + + + + From c260137275148c320a0893c5dd711290ee133db5 Mon Sep 17 00:00:00 2001 From: haman-odoo Date: Mon, 8 Dec 2025 11:25:13 +0530 Subject: [PATCH 5/9] [IMP] estate: Added custom list, form and search views chapter 6 : Created list, form, and search views for the estate.property model. Added menu items and actions to open the property views in the Real Estate module. Created new model estate.property.type and added its list & form views, menu, and access rights. --- estate/models/__init__.py | 1 + estate/models/estate_property.py | 6 +- estate/models/estate_property_type.py | 8 ++ estate/security/ir.model.access.csv | 1 + estate/views/estate_menus.xml | 10 ++- estate/views/estate_property_views.xml | 103 +++++++++++++++++++++++++ 6 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 estate/models/estate_property_type.py diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 9d5e62fe812..1f794e0ceed 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,2 @@ from . import estate_property # noqa: F401 +from . import estate_property_type diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 35009ccabc6..9ef8a949409 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -50,4 +50,8 @@ class EstateProperty(models.Model): required=True, copy=False, default='new', -) + ) + 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 new file mode 100644 index 00000000000..34cb49bfbab --- /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 = "Real Estate Property Type" + + name = fields.Char(string="Name", required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index a6992df6d34..63152d35a14 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,3 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_estate_property_user,access_estate_property_user,model_estate_property,base.group_user,1,1,1,1 +access_estate_property_type_user,access_estate_property_type_user,model_estate_property_type,base.group_user,1,1,1,1 diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 7154c53b30f..693e92782fc 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,6 +1,12 @@ - - + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 62a46c36e54..33100975331 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -14,12 +14,115 @@ + + + + + estate.property.form + estate.property + +
+ +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + estate.property.search + estate.property + + + + + + + + + + + + + + + + + + estate.property.type.list + estate.property.type + + + + + + + + + estate.property.type.form + estate.property.type + +
+ +
+
+
+
+
+
+ + + Property Types + estate.property.type + list,form + From a6feab69eae18f687e1060875ae0700ad081302a Mon Sep 17 00:00:00 2001 From: haman-odoo Date: Tue, 9 Dec 2025 11:03:15 +0530 Subject: [PATCH 6/9] [IMP] estate: Added relations between property, type and offer models Chapter 7 : Added Many2many - tag_ids field for assigning multiple tags to a property. Added Many2one - salesperson_id, buyer_id, property_type_id fields. Added One2many - offer_ids field to show multiple offers linked to one property. --- estate/__manifest__.py | 7 +- estate/models/__init__.py | 4 +- estate/models/estate_property.py | 49 ++++++++---- estate/models/estate_property_offer.py | 22 ++++++ estate/models/estate_property_tag.py | 7 ++ estate/models/estate_property_type.py | 3 +- estate/security/ir.model.access.csv | 2 + estate/views/estate_menus.xml | 8 +- estate/views/estate_property_offer_views.xml | 29 ++++++++ estate/views/estate_property_tag_views.xml | 10 +++ estate/views/estate_property_type_views.xml | 7 ++ estate/views/estate_property_views.xml | 78 +++++++++----------- 12 files changed, 160 insertions(+), 66 deletions(-) create mode 100644 estate/models/estate_property_offer.py create mode 100644 estate/models/estate_property_tag.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 2391f4c9bf7..683694e82e9 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -8,10 +8,13 @@ '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', - ], +], 'category': 'Sales/Real Estate', 'installable': True, 'auto_install': False, - 'description': """Description text""", + 'description': """Real estate management tutorial module with properties, offers, types and tags.""", } diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 1f794e0ceed..2f1821a39c1 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1,2 +1,4 @@ -from . import estate_property # noqa: F401 +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 9ef8a949409..44a69cd8692 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,33 +1,30 @@ -from odoo import models, fields from dateutil.relativedelta import relativedelta from datetime import date +from odoo import models, fields, api class EstateProperty(models.Model): _name = "estate.property" _description = "Real Estate Property" - name = fields.Char(string="Property Title", required=True) - description = fields.Text(string="Description") - postcode = fields.Char(string="Postcode") + name = fields.Char(required=True) + description = fields.Text() + postcode = fields.Char() date_availability = fields.Date( - string="Available From", default=lambda sself: date.today() + relativedelta(months=3), copy=False ) expected_price = fields.Float(string="Expected Price", required=True) 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 (sqm)") - facades = fields.Integer(string="Number of Facades") - garage = fields.Boolean(string="Has Garage") - garden = fields.Boolean(string="Has Garden") - garden_area = fields.Integer(string="Garden Area (sqm)") + 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( selection=[ ('north', 'North'), @@ -35,7 +32,6 @@ class EstateProperty(models.Model): ('east', 'East'), ('west', 'West'), ], - string="Garden Orientation" ) active = fields.Boolean(default=True) state = fields.Selection( @@ -46,12 +42,33 @@ class EstateProperty(models.Model): ('sold', 'Sold'), ('cancelled', 'Cancelled'), ], - string="Status", required=True, copy=False, default='new', ) property_type_id = fields.Many2one( "estate.property.type", - string="Property Type", ) + salesperson_id = fields.Many2one( + "res.users", + default=lambda self: self.env.user, + ) + buyer_id = fields.Many2one( + "res.partner", + copy=False, + ) + tag_ids = fields.Many2many( + "estate.property.tag", + ) + offer_ids = fields.One2many( + "estate.property.offer", + "property_id", + ) + 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 diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py new file mode 100644 index 00000000000..414faddcd2c --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,22 @@ +from odoo import models, fields + + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Real Estate Property Offer" + price = fields.Float(string="Price") + status = fields.Selection( + [ + ("accepted", "Accepted"), + ("refused", "Refused"), + ], + 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..f993f42377e --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,7 @@ +from odoo import models, fields + + +class EstatePropertyTag(models.Model): + _name = "estate.property.tag" + _description = "Real Estate Property Tag" + name = fields.Char(required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index 34cb49bfbab..5b939f07f94 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -4,5 +4,4 @@ class EstatePropertyType(models.Model): _name = "estate.property.type" _description = "Real Estate Property Type" - - name = fields.Char(string="Name", required=True) + name = fields.Char(required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 63152d35a14..68c221e0dec 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,3 +1,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_estate_property_user,access_estate_property_user,model_estate_property,base.group_user,1,1,1,1 access_estate_property_type_user,access_estate_property_type_user,model_estate_property_type,base.group_user,1,1,1,1 +access_estate_property_tag_user,access_estate_property_tag_user,model_estate_property_tag,base.group_user,1,1,1,1 +access_estate_property_offer_user,access_estate_property_offer_user,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 693e92782fc..fdde020b4b8 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,12 +1,16 @@ - - + + + + diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..148247a7ebb --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,29 @@ + + + estate.property.offer.list + estate.property.offer + + + + + + + + + + + estate.property.offer.form + estate.property.offer + +
+ + + + + + + +
+
+
+
diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 00000000000..6d2984563ce --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,10 @@ + + + Property Tags + estate.property.tag + list,form + +

Create and manage tags for your properties.

+
+
+
diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..bf711b13d96 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,7 @@ + + + Property Types + estate.property.type + list,form + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 33100975331..b9f866392b8 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,20 +1,17 @@ - - Properties estate.property list,form - estate.property.list estate.property - + @@ -34,7 +31,7 @@

- + @@ -63,11 +60,38 @@ + + - + + + + + + + + + + + + + + +
+ + + + + + + +
+
+
+
@@ -78,51 +102,19 @@ estate.property - - + - + domain="['|', ('state', '=', 'new'), ('state', '=', 'offer_received')]" /> + +
- - - estate.property.type.list - estate.property.type - - - - - - - - - estate.property.type.form - estate.property.type - -
- -
-
-
-
-
-
- - - Property Types - estate.property.type - list,form -
From b048a7d3a4ad8eb7a96c5253bf6f3e220771bde6 Mon Sep 17 00:00:00 2001 From: haman-odoo Date: Wed, 10 Dec 2025 12:30:06 +0530 Subject: [PATCH 7/9] [IMP] estate: Compute total area, best price and add onchange for garden fields Chapter 8 : Added compute, inverse, and onchange methods for dynamic field updates. Implemented automatic offer price, total area, and deadline calculations. Added Tag and Offer models with validity and date deadline logic. --- estate/models/estate_property.py | 18 +++++++++++++++ estate/models/estate_property_offer.py | 23 +++++++++++++++++++- estate/models/estate_property_tag.py | 1 + estate/models/estate_property_type.py | 1 + estate/views/estate_property_offer_views.xml | 4 ++++ estate/views/estate_property_views.xml | 5 +++++ 6 files changed, 51 insertions(+), 1 deletion(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 44a69cd8692..00c9c424b87 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -67,8 +67,26 @@ class EstateProperty(models.Model): total_area = fields.Float( compute="_compute_total_area" ) + best_price = fields.Float( + compute="_compute_best_price", + ) @api.depends('living_area', 'garden_area') def _compute_total_area(self): for record in self: record.total_area = record.living_area + record.garden_area + + @api.depends('offer_ids.price') + def _compute_best_price(self): + for record in self: + prices = record.offer_ids.mapped('price') + record.best_price = max(prices) if prices else 0.0 + + @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 diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 414faddcd2c..2d2f1d00a9f 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,9 +1,11 @@ -from odoo import models, fields +from dateutil.relativedelta import relativedelta +from odoo import models, fields, api class EstatePropertyOffer(models.Model): _name = "estate.property.offer" _description = "Real Estate Property Offer" + price = fields.Float(string="Price") status = fields.Selection( [ @@ -20,3 +22,22 @@ class EstatePropertyOffer(models.Model): "estate.property", required=True, ) + validity = fields.Integer( + default=7, + ) + date_deadline = fields.Date( + compute="_compute_date_deadline", + inverse="_inverse_date_deadline", + store=True, + ) + + @api.depends("validity") + def _compute_date_deadline(self): + for rec in self: + create = rec.create_date or fields.Date.today() + rec.date_deadline = (create + relativedelta(days=rec.validity)) + + def _inverse_date_deadline(self): + for rec in self: + create = rec.create_date or fields.Date.today() + rec.validity = (rec.date_deadline - fields.Date.today(create)).days diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py index f993f42377e..3f730299abb 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -4,4 +4,5 @@ class EstatePropertyTag(models.Model): _name = "estate.property.tag" _description = "Real Estate Property Tag" + name = fields.Char(required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index 5b939f07f94..ad121b33163 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -4,4 +4,5 @@ class EstatePropertyType(models.Model): _name = "estate.property.type" _description = "Real Estate Property Type" + name = fields.Char(required=True) diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 148247a7ebb..4d0b122c29d 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -6,6 +6,8 @@ + + @@ -20,6 +22,8 @@ + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index b9f866392b8..f119e013599 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -40,6 +40,7 @@ + @@ -78,6 +79,8 @@ + +
@@ -85,6 +88,8 @@ + + From f21c9e7fc2ed18f3c7c8acc148ad6c937a8a364e Mon Sep 17 00:00:00 2001 From: haman-odoo Date: Thu, 11 Dec 2025 10:37:40 +0530 Subject: [PATCH 8/9] [IMP] estate: Added action buttons to manage property and offer status Chapter 9 : Added Sold/Cancel buttons on properties. Added Accept/Refuse buttons on offers. Set selling price and buyer when an offer is accepted. --- estate/models/estate_property.py | 17 ++++++++++++++ estate/models/estate_property_offer.py | 15 ++++++++++++ estate/views/estate_property_offer_views.xml | 2 ++ estate/views/estate_property_views.xml | 24 +++++--------------- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 00c9c424b87..81f728ab33c 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,6 +1,7 @@ from dateutil.relativedelta import relativedelta from datetime import date from odoo import models, fields, api +from odoo.exceptions import UserError class EstateProperty(models.Model): @@ -90,3 +91,19 @@ def _onchange_garden(self): else: self.garden_area = 0 self.garden_orientation = None + + def action_cancel(self): + for rec in self: + if rec.state == "sold": + raise UserError("Sold properties cannot be cancelled.") + else: + rec.state = "cancelled" + return True + + def action_set_sold(self): + for rec in self: + if rec.state == "cancelled": + raise UserError("Canceled properties cannot be sold.") + else: + rec.state = "sold" + return True diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 2d2f1d00a9f..6a2dad791f0 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,5 +1,6 @@ from dateutil.relativedelta import relativedelta from odoo import models, fields, api +from odoo.exceptions import UserError class EstatePropertyOffer(models.Model): @@ -41,3 +42,17 @@ def _inverse_date_deadline(self): for rec in self: create = rec.create_date or fields.Date.today() rec.validity = (rec.date_deadline - fields.Date.today(create)).days + + def action_accept(self): + for offer in self: + if offer.property_id.buyer_id: + raise UserError('Only one offer can be accepted for a property.') + offer.status = 'accepted' + offer.property_id.selling_price = offer.price + offer.property_id.buyer_id = offer.partner_id + return True + + def action_refuse(self): + for offer in self: + offer.status = 'refused' + return True diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 4d0b122c29d..77b45d65eb9 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -8,6 +8,8 @@ +