From c408da572cd2328531ed38c9f2fa264bca0c89c6 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Tue, 18 Nov 2025 13:36:55 +0100 Subject: [PATCH 01/34] [ADD] Estate: init --- estate/__init__.py | 0 estate/__manifest__.py | 10 ++++++++++ 2 files changed, 10 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..8f41337d3bb --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,10 @@ +{ + 'name': 'Estate', + 'version': '0.0', + 'depends': ['base'], + 'author': 'haall-odoo', + 'application': True, + 'installable': True, + 'category': '', + 'description': '' +} \ No newline at end of file From a946449d02821a2881021ef40d481b692becb475 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Tue, 18 Nov 2025 14:14:15 +0100 Subject: [PATCH 02/34] [IMP] estate: chapter 3 --- estate/__init__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 24 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+) 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..9a7e03eded3 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -0,0 +1 @@ +from . import models \ 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..739352bd4c1 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,24 @@ +from odoo import fields, models + + +class EstateProperty(models.Model): + _name = "estate.property" + _description = "An awesome estate module" + + name = fields.Char(required=True) + description = fields.Text() + postcode = fields.Char() + date_availability = fields.Date() + expected_price = fields.Float(required=True) + selling_price = fields.Float() + bedrooms = fields.Integer() + living_area = fields.Integer() + facades = fields.Integer() + garage = fields.Boolean() + garden = fields.Boolean() + garden_area = fields.Integer() + garden_orientation = fields.Selection( + string='Orientation', + selection=[('north', 'North'), ('west', 'West'), ('south', 'South'), ('east', 'East')], + help="Choose the appropriate orientation of the garden" + ) \ No newline at end of file From 6deb7a6ce6e20e1b6523d1ce67484ab4ba142825 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Tue, 18 Nov 2025 14:21:07 +0100 Subject: [PATCH 03/34] [FIX] estate: CI PEP8 conformity for EoF --- estate/__init__.py | 2 +- estate/__manifest__.py | 2 +- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 2 +- 4 files changed, 4 insertions(+), 4 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 8f41337d3bb..c6e8a1dcedb 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,4 +7,4 @@ 'installable': True, 'category': '', 'description': '' -} \ 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 739352bd4c1..df04e12c61c 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -21,4 +21,4 @@ class EstateProperty(models.Model): string='Orientation', selection=[('north', 'North'), ('west', 'West'), ('south', 'South'), ('east', 'East')], help="Choose the appropriate orientation of the garden" - ) \ No newline at end of file + ) From e429205f6296f88961c1d86dd0ce112c27790655 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Tue, 18 Nov 2025 14:57:52 +0100 Subject: [PATCH 04/34] [FIX] estate: PEP8 conformity\nestate_property.py whitespace in blankline (L7) deletation --- 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 df04e12c61c..8dc7d80f736 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -4,7 +4,7 @@ class EstateProperty(models.Model): _name = "estate.property" _description = "An awesome estate module" - + name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() From ffb822c3986555f9d2b2cd7d8ea91f958906ec4f Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Tue, 18 Nov 2025 15:35:24 +0100 Subject: [PATCH 05/34] [IMP] estate: Chapter 4 --- estate/__manifest__.py | 5 ++++- estate/data/.gitkeep | 0 estate/security/ir.model.access.csv | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 estate/data/.gitkeep create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index c6e8a1dcedb..b81ffed90c7 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -6,5 +6,8 @@ 'application': True, 'installable': True, 'category': '', - 'description': '' + 'description': '', + 'data': [ + 'security/ir.model.access.csv' + ] } diff --git a/estate/data/.gitkeep b/estate/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..29e50389adb --- /dev/null +++ b/estate/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +access_estate_model,estate_property,model_estate_property,base.group_user,1,1,1,1 +portal_access_estate_model,estate_property,model_estate_property,base.group_portal,1,0,0,0 \ No newline at end of file From c71e8806b413b776d70c48a52f3d0616e970e302 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Tue, 18 Nov 2025 15:36:34 +0100 Subject: [PATCH 06/34] [FIX] estate: fix whitespace in blank line --- 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 8dc7d80f736..9891c284435 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -4,7 +4,7 @@ class EstateProperty(models.Model): _name = "estate.property" _description = "An awesome estate module" - + name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() From e01993fe68bc7b256b7e8500634aa6883b6ad793 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Tue, 18 Nov 2025 16:12:59 +0100 Subject: [PATCH 07/34] [FIX] estate: license fix --- estate/__manifest__.py | 5 ++++- estate/views/estate_menus.xml | 8 ++++++++ estate/views/estate_property_views.xml | 8 ++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) 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 b81ffed90c7..5b11e6d0deb 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,7 +7,10 @@ 'installable': True, 'category': '', 'description': '', + 'license': 'GPL-3', 'data': [ - 'security/ir.model.access.csv' + 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml' ] } diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..d10bdc9c22e --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml new file mode 100644 index 00000000000..4696efa2404 --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,8 @@ + + + + Properties + estate.property + list + + From de4a3154eb070288ea84ace4b508b1eb90423151 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Tue, 18 Nov 2025 17:03:55 +0100 Subject: [PATCH 08/34] [IMP] estate: Chapter 5 --- estate/models/estate_property.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 9891c284435..15e7875f041 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,3 +1,5 @@ +import datetime as dt + from odoo import fields, models @@ -8,10 +10,10 @@ 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=dt.datetime.today() + dt.timedelta(days=90)) 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() @@ -22,3 +24,12 @@ class EstateProperty(models.Model): selection=[('north', 'North'), ('west', 'West'), ('south', 'South'), ('east', 'East')], help="Choose the appropriate orientation of the garden" ) + active = fields.Boolean(default=True) + state = fields.Selection( + string="Estate status", + selection=[('new', 'New'), ('offer received', 'Offer Received'), ('offer accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')], + help='This field explain the estate status.', + required=True, + copy=False, + default='new' + ) From de78e31a020c382442910f764f2c1b5368f818c5 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Wed, 19 Nov 2025 10:04:19 +0100 Subject: [PATCH 09/34] [IMP] Estate: Chapter 5 Sec 1 --- estate/views/estate_property_views.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 4696efa2404..a6f6926ba0d 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,5 +1,21 @@ + + estate.property.name + estate.property + + + + + + + + + + + + + Properties estate.property From adb33160a95a1ce24403a36fd009ad6013b1b396 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Wed, 19 Nov 2025 11:08:26 +0100 Subject: [PATCH 10/34] [IMP] Estate: Chapter 6 --- estate/views/estate_property_views.xml | 56 ++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index a6f6926ba0d..ec9ead5d5cb 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -16,6 +16,62 @@ + + estate.property.name + estate.property + +
+ + +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + estate.property.name + estate.property + + + + + + + + + + + + + + + Properties estate.property From e66dd36760a40db0c3f5b66cdb9cb7a8fea1c2f8 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Wed, 19 Nov 2025 13:21:07 +0100 Subject: [PATCH 11/34] [FIX] estate: review 1 --- estate/__manifest__.py | 7 ++-- estate/data/.gitkeep | 0 estate/models/estate_property.py | 16 ++++++--- estate/security/ir.model.access.csv | 5 +-- estate/views/estate_menus.xml | 7 ++-- estate/views/estate_property_type_views.xml | 22 ++++++++++++ estate/views/estate_property_views.xml | 37 +++++++++++++-------- 7 files changed, 69 insertions(+), 25 deletions(-) delete mode 100644 estate/data/.gitkeep create mode 100644 estate/views/estate_property_type_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 5b11e6d0deb..0f6f9233932 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,16 +1,17 @@ { 'name': 'Estate', - 'version': '0.0', + 'version': '1.0', 'depends': ['base'], - 'author': 'haall-odoo', + 'author': 'Odoo S.A.', 'application': True, 'installable': True, 'category': '', 'description': '', - 'license': 'GPL-3', + 'license': 'LGPL-3', 'data': [ 'security/ir.model.access.csv', 'views/estate_property_views.xml', + 'views/estate_property_type_views.xml', 'views/estate_menus.xml' ] } diff --git a/estate/data/.gitkeep b/estate/data/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 15e7875f041..411e100dcf6 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -5,12 +5,12 @@ class EstateProperty(models.Model): _name = "estate.property" - _description = "An awesome estate module" + _description = "Estate Property" name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date(copy=False, default=dt.datetime.today() + dt.timedelta(days=90)) + date_availability = fields.Date(copy=False, default=fields.Date.add(fields.Date.today(), months=3), string="Available From") expected_price = fields.Float(required=True) selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) @@ -21,15 +21,23 @@ class EstateProperty(models.Model): garden_area = fields.Integer() garden_orientation = fields.Selection( string='Orientation', - selection=[('north', 'North'), ('west', 'West'), ('south', 'South'), ('east', 'East')], + selection=[ + ('north', 'North'), + ('west', 'West'), + ('south', 'South'), + ('east', 'East') + ], help="Choose the appropriate orientation of the garden" ) active = fields.Boolean(default=True) state = fields.Selection( string="Estate status", - selection=[('new', 'New'), ('offer received', 'Offer Received'), ('offer accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')], + selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')], help='This field explain the estate status.', required=True, copy=False, default='new' ) + property_type_id = fields.Many2one("estate.property.type", string="Type") + seller_id = fields.Many2one("res.users", string="Salesman", default=lambda self: self.env.user, domain="[('type', '=', 'internal')]") + buyer_id = fields.Many2one("res.partner", string="Buyer", domain="[('type', '=', 'portal')]") diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 29e50389adb..d0eb72f0fc1 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,3 +1,4 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink -access_estate_model,estate_property,model_estate_property,base.group_user,1,1,1,1 -portal_access_estate_model,estate_property,model_estate_property,base.group_portal,1,0,0,0 \ No newline at end of file +access_estate_model,estate_property_users,model_estate_property,base.group_user,1,1,1,1 +access_estate_model_type,estate_property_type_users,model_estate_property_type,base.group_user,1,1,1,1 +portal_access_estate_model,estate_property_portal,model_estate_property,base.group_portal,1,0,0,0 diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index d10bdc9c22e..1b04e166d8f 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -2,7 +2,10 @@ - + + + + - \ No newline at end of file +
diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..dd393e37095 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,22 @@ + + + + estate.property.type.name + estate.property.type + +
+ + +

+
+
+
+
+
+ + + Property Types + estate.property.type + list + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index ec9ead5d5cb..5223ef32829 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,10 +1,10 @@ - - estate.property.name + + estate.property.list estate.property - + @@ -17,21 +17,22 @@ - estate.property.name + estate.property.form estate.property
-

+

- + + - + @@ -39,15 +40,21 @@ - + - + - + + + + + + +
@@ -55,19 +62,21 @@
- estate.property.name + estate.property.search estate.property - + + - + + @@ -75,6 +84,6 @@ Properties estate.property - list + list, form
From 55064b2cb762242dd5c012daabba3d6ad7aee298 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Wed, 19 Nov 2025 13:40:57 +0100 Subject: [PATCH 12/34] [FIX] estate: review fix 2 + chapter 7 part 1 --- estate/__manifest__.py | 1 + estate/models/__init__.py | 2 ++ estate/models/estate_property.py | 4 +--- estate/models/estate_property_tag.py | 8 ++++++++ estate/models/estate_property_type.py | 7 +++++++ estate/security/ir.model.access.csv | 1 + estate/views/estate_menus.xml | 4 +++- estate/views/estate_property_tag_views.xml | 22 +++++++++++++++++++++ estate/views/estate_property_type_views.xml | 6 +++--- estate/views/estate_property_views.xml | 4 ++-- 10 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 estate/models/estate_property_tag.py create mode 100644 estate/models/estate_property_type.py create mode 100644 estate/views/estate_property_tag_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 0f6f9233932..27020c34467 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -12,6 +12,7 @@ 'security/ir.model.access.csv', 'views/estate_property_views.xml', 'views/estate_property_type_views.xml', + 'views/estate_property_tag_views.xml', 'views/estate_menus.xml' ] } diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 5e1963c9d2f..fdab6f99948 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,3 @@ from . import estate_property +from . import estate_property_type +from . import estate_property_tag \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 411e100dcf6..f820cbdcb7d 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,5 +1,3 @@ -import datetime as dt - from odoo import fields, models @@ -39,5 +37,5 @@ class EstateProperty(models.Model): default='new' ) property_type_id = fields.Many2one("estate.property.type", string="Type") - seller_id = fields.Many2one("res.users", string="Salesman", default=lambda self: self.env.user, domain="[('type', '=', 'internal')]") + seller_id = fields.Many2one("res.users", string="Salesman", default=lambda self: self.env.user, domain="[('type', '=', 'internal')]") buyer_id = fields.Many2one("res.partner", string="Buyer", domain="[('type', '=', 'portal')]") diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..c7e1caaf155 --- /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 = "Estate Property Tag" + + name = fields.Char(required=True) \ 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..b6306e34aa1 --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,7 @@ +from odoo import fields, models + +class EstatePropertyType(models.Model): + _name = "estate.property.type" + _description = "Estate Property Types" + + name = fields.Char(required=True) \ No newline at end of file diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index d0eb72f0fc1..193b5d0e052 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -2,3 +2,4 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink access_estate_model,estate_property_users,model_estate_property,base.group_user,1,1,1,1 access_estate_model_type,estate_property_type_users,model_estate_property_type,base.group_user,1,1,1,1 portal_access_estate_model,estate_property_portal,model_estate_property,base.group_portal,1,0,0,0 +access_estate_model_tag,estate_property_tag_users,model_estate_property_tag,base.group_user,1,1,1,1 diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 1b04e166d8f..ba6a2f8f00a 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -4,8 +4,10 @@ - + + + diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 00000000000..b8d02cd0cc9 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,22 @@ + + + + estate.property.tag.form + estate.property.tag + +
+ + +

+
+
+
+
+
+ + + Property Tags + estate.property.tag + list + +
\ No newline at end of file diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml index dd393e37095..d124ae8d555 100644 --- a/estate/views/estate_property_type_views.xml +++ b/estate/views/estate_property_type_views.xml @@ -1,20 +1,20 @@ - estate.property.type.name + estate.property.type.form estate.property.type
-

+

- + Property Types estate.property.type list diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 5223ef32829..fc7d8030783 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -81,9 +81,9 @@ - + Properties estate.property - list, form + list,form
From 218b8f0c75d60e811a9ccb6e17801a00895bdd37 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Wed, 19 Nov 2025 14:17:09 +0100 Subject: [PATCH 13/34] [IMP] estate: chapter 7 --- estate/__manifest__.py | 1 + estate/models/__init__.py | 3 ++- estate/models/estate_property.py | 2 ++ estate/models/estate_property_offer.py | 18 ++++++++++++++++++ estate/models/estate_property_tag.py | 2 +- estate/models/estate_property_type.py | 3 ++- estate/security/ir.model.access.csv | 1 + estate/views/estate_property_offer_views.xml | 14 ++++++++++++++ estate/views/estate_property_tag_views.xml | 2 +- estate/views/estate_property_views.xml | 6 ++++++ 10 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 estate/models/estate_property_offer.py create mode 100644 estate/views/estate_property_offer_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 27020c34467..93b455da68a 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -13,6 +13,7 @@ 'views/estate_property_views.xml', 'views/estate_property_type_views.xml', 'views/estate_property_tag_views.xml', + 'views/estate_property_offer_views.xml', 'views/estate_menus.xml' ] } diff --git a/estate/models/__init__.py b/estate/models/__init__.py index fdab6f99948..09b2099fe84 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1,3 +1,4 @@ from . import estate_property from . import estate_property_type -from . import estate_property_tag \ No newline at end of file +from . import estate_property_tag +from . import estate_property_offer \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index f820cbdcb7d..57beaa5d9f7 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -39,3 +39,5 @@ class EstateProperty(models.Model): property_type_id = fields.Many2one("estate.property.type", string="Type") seller_id = fields.Many2one("res.users", string="Salesman", default=lambda self: self.env.user, domain="[('type', '=', 'internal')]") buyer_id = fields.Many2one("res.partner", string="Buyer", domain="[('type', '=', 'portal')]") + tag_ids = fields.Many2many("estate.property.tag") + offer_ids = fields.One2many("estate.property.offer", "property_id") diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py new file mode 100644 index 00000000000..5238615fe1e --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,18 @@ +from odoo import fields, models + + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Estate Property Offer" + + price = fields.Float() + status = fields.Selection( + string="Status", + copy=False, + selection = [ + ('accepted', 'Accepted'), + ('refused', 'Refused') + ] + ) + 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 index c7e1caaf155..165132d19de 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -5,4 +5,4 @@ class EstatePropertyTag(models.Model): _name = "estate.property.tag" _description = "Estate Property Tag" - name = fields.Char(required=True) \ No newline at end of file + name = fields.Char(required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index b6306e34aa1..d7e69e557ef 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -1,7 +1,8 @@ from odoo import fields, models + class EstatePropertyType(models.Model): _name = "estate.property.type" _description = "Estate Property Types" - name = fields.Char(required=True) \ No newline at end of file + name = fields.Char(required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 193b5d0e052..d375e4a2ac5 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -3,3 +3,4 @@ access_estate_model,estate_property_users,model_estate_property,base.group_user, access_estate_model_type,estate_property_type_users,model_estate_property_type,base.group_user,1,1,1,1 portal_access_estate_model,estate_property_portal,model_estate_property,base.group_portal,1,0,0,0 access_estate_model_tag,estate_property_tag_users,model_estate_property_tag,base.group_user,1,1,1,1 +access_estate_model_offer,estate_property_offer_users,model_estate_property_offer,base.group_user,1,1,1,1 diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..e551a5243a9 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,14 @@ + + + + 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 index b8d02cd0cc9..8fb328889f9 100644 --- a/estate/views/estate_property_tag_views.xml +++ b/estate/views/estate_property_tag_views.xml @@ -19,4 +19,4 @@ estate.property.tag list - \ No newline at end of file + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index fc7d8030783..e042199fd17 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -26,6 +26,9 @@

+ +
+
@@ -49,6 +52,9 @@ + + + From ff73e1baa819d60b32c41070e5113d704d28cab3 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Wed, 19 Nov 2025 14:45:44 +0100 Subject: [PATCH 14/34] [FIX] estate: PEP8 fix --- estate/models/__init__.py | 2 +- estate/models/estate_property_offer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 09b2099fe84..2f1821a39c1 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1,4 +1,4 @@ from . import estate_property from . import estate_property_type from . import estate_property_tag -from . import estate_property_offer \ No newline at end of file +from . import estate_property_offer diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 5238615fe1e..5ff9ea236ff 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -9,7 +9,7 @@ class EstatePropertyOffer(models.Model): status = fields.Selection( string="Status", copy=False, - selection = [ + selection=[ ('accepted', 'Accepted'), ('refused', 'Refused') ] From 871dc8d6dbd6eb0e5dfd7c3d80a9898e1c3a1217 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Wed, 19 Nov 2025 15:33:45 +0100 Subject: [PATCH 15/34] [IMP] estate: add computed field for total_area and best_price --- estate/models/estate_property.py | 14 +++++++++++++- estate/views/estate_property_offer_views.xml | 2 +- estate/views/estate_property_views.xml | 2 ++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 57beaa5d9f7..27d0a2b93be 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,4 @@ -from odoo import fields, models +from odoo import api, fields, models class EstateProperty(models.Model): @@ -41,3 +41,15 @@ class EstateProperty(models.Model): buyer_id = fields.Many2one("res.partner", string="Buyer", domain="[('type', '=', 'portal')]") tag_ids = fields.Many2many("estate.property.tag") offer_ids = fields.One2many("estate.property.offer", "property_id") + total_area = fields.Float(compute="_compute_total_area", string="Total Area (sqm)") + best_price = fields.Float(compute="_compute_best_offer", string="Best Offer") + + @api.depends("garden_area", "living_area") + def _compute_total_area(self): + for record in self: + record.total_area = record.garden_area + record.living_area + + @api.depends("offer_ids") + def _compute_best_offer(self): + for record in self: + record.best_price = max(record.offer_ids.mapped("price")) diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index e551a5243a9..e3e1106bb6b 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -4,7 +4,7 @@ estate.property.offer.list estate.property.offer - + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index e042199fd17..aad30042a6b 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -36,6 +36,7 @@ +
@@ -50,6 +51,7 @@ + From 640793564044cafbf84a7e2873e043523f6095b7 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Wed, 19 Nov 2025 16:15:59 +0100 Subject: [PATCH 16/34] [IMP] estate: chapter 8 reversed field --- estate/models/estate_property.py | 2 +- estate/models/estate_property_offer.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 27d0a2b93be..77c047a0e91 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -52,4 +52,4 @@ def _compute_total_area(self): @api.depends("offer_ids") def _compute_best_offer(self): for record in self: - record.best_price = max(record.offer_ids.mapped("price")) + record.best_price = max(record.offer_ids.mapped("price")) if len(record.offer_ids) > 0 else 0.0 diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 5ff9ea236ff..a7352849bba 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,4 @@ -from odoo import fields, models +from odoo import api, fields, models class EstatePropertyOffer(models.Model): @@ -16,3 +16,15 @@ class EstatePropertyOffer(models.Model): ) partner_id = fields.Many2one("res.partner", required=True) property_id = fields.Many2one("estate.property", required=True) + create_date = fields.Date(readonly=True, default=fields.Date.today()) + validity = fields.Integer(default=7) + date_deadline = fields.Date(compute="_compute_date_deadline", inverse="_reverse_date_deadline") + + @api.depends("validity") + def _compute_date_deadline(self): + for record in self: + record.date_deadline = fields.Date.add(record.create_date if record.create_date is not None else fields.Date.today(), days=record.validity) + + def _reverse_date_deadline(self): + for record in self: + record.validity = fields.Date.substract(record.date_deadline, ) From 0b791abb168ce5bd0efedf771f992866620e380a Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Thu, 20 Nov 2025 09:28:27 +0100 Subject: [PATCH 17/34] [FIX] gitignore: ignore vscode config --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index b6e47617de1..61a0ca00289 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,6 @@ dmypy.json # Pyre type checker .pyre/ + + +.vscode/ From b5fc120fa81ae82e612e274fc08d3c61445c1eae Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Thu, 20 Nov 2025 09:30:49 +0100 Subject: [PATCH 18/34] [IMP] estate: chapter 8 --- estate/models/estate_property.py | 10 ++++++++++ estate/models/estate_property_offer.py | 10 +++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 77c047a0e91..a1139d4ea75 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -53,3 +53,13 @@ def _compute_total_area(self): def _compute_best_offer(self): for record in self: record.best_price = max(record.offer_ids.mapped("price")) if len(record.offer_ids) > 0 else 0.0 + + @api.onchange("garden") + def _onchange_garden(self): + for record in self: + if not record.garden: + record.garden_area = 0 + record.garden_orientation = '' + else: + record.garden_area = 10 + record.garden_orientation = 'north' \ No newline at end of file diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index a7352849bba..efd66819837 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -16,15 +16,15 @@ class EstatePropertyOffer(models.Model): ) partner_id = fields.Many2one("res.partner", required=True) property_id = fields.Many2one("estate.property", required=True) - create_date = fields.Date(readonly=True, default=fields.Date.today()) validity = fields.Integer(default=7) - date_deadline = fields.Date(compute="_compute_date_deadline", inverse="_reverse_date_deadline") + date_deadline = fields.Date(compute="_compute_date_deadline", inverse="_inverse_date_deadline") @api.depends("validity") def _compute_date_deadline(self): for record in self: - record.date_deadline = fields.Date.add(record.create_date if record.create_date is not None else fields.Date.today(), days=record.validity) + record.date_deadline = fields.Date.add(fields.Date.today(), days=record.validity) - def _reverse_date_deadline(self): + @api.onchange("date_deadline") + def _inverse_date_deadline(self): for record in self: - record.validity = fields.Date.substract(record.date_deadline, ) + record.validity = (record.date_deadline - fields.Date.today()).days From ac39bedc01f688d366e8bf5ea87906a6c2909587 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Thu, 20 Nov 2025 09:35:43 +0100 Subject: [PATCH 19/34] [FIX] estate: estate_property.py - EOL --- 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 a1139d4ea75..327dafea56c 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -62,4 +62,4 @@ def _onchange_garden(self): record.garden_orientation = '' else: record.garden_area = 10 - record.garden_orientation = 'north' \ No newline at end of file + record.garden_orientation = 'north' From ee8a1bee732a55a74f506812fc883fa22f464e12 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Thu, 20 Nov 2025 11:22:47 +0100 Subject: [PATCH 20/34] [IMP] estate: chapter 9 --- estate/models/estate_property.py | 19 +++++++++++++++++++ estate/models/estate_property_offer.py | 17 +++++++++++++++++ estate/views/estate_property_offer_views.xml | 2 ++ estate/views/estate_property_views.xml | 4 ++++ 4 files changed, 42 insertions(+) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 327dafea56c..61f6a1b04d0 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,5 @@ from odoo import api, fields, models +from odoo.exceptions import UserError class EstateProperty(models.Model): @@ -63,3 +64,21 @@ def _onchange_garden(self): else: record.garden_area = 10 record.garden_orientation = 'north' + + def estate_property_action_sold(self): + self.__estate_property_action_sold_cancel('sold', "A cancelled property cannot be sold!", "This property is already sold!") + + def estate_property_action_cancel(self): + self.__estate_property_action_sold_cancel('cancelled', "A sold property cannot be cancelled!", "This property is already cancelled!") + + def __estate_property_action_sold_cancel(self, target, error_message, error_same_target_message): + for record in self: + # exclude target from next condition + if record.state == target: + raise UserError(error_same_target_message) + # easiest way to exclude the other state + elif record.state in ('sold', 'cancelled'): + raise UserError(error_message) + # the property can be sold/cancelled + else: + record.state = target diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index efd66819837..9e4b2194530 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -28,3 +28,20 @@ def _compute_date_deadline(self): def _inverse_date_deadline(self): for record in self: record.validity = (record.date_deadline - fields.Date.today()).days + + def action_accept_offer(self): + for record in self: + record.property_id.selling_price = record.price + record.property_id.buyer_id = record.partner_id + for offer in record.property_id.offer_ids: + offer.status = "refused" + record.status = 'accepted' + return True + + def action_refuse_offer(self): + for record in self: + if record.status == 'accepted': + record.property_id.selling_price = 0.0 + record.property_id.buyer_id = None + record.status = 'refused' + return True diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index e3e1106bb6b..e76bab386dd 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -7,6 +7,8 @@ + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index c1b43ec18ec..6036828434b 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -87,13 +87,13 @@ - + - - - + + + @@ -102,5 +102,6 @@ Properties estate.property list,form + {'search_default_available':1} From 09fdf455e4bb079117d31ca3174381237131bbf3 Mon Sep 17 00:00:00 2001 From: haall-odoo Date: Fri, 21 Nov 2025 12:14:29 +0100 Subject: [PATCH 34/34] [FIX] estate: estate.property.offer stored -> store --- estate/models/estate_property_offer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 2f0a1285ed0..c5a65b2fdfe 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -21,7 +21,7 @@ class EstatePropertyOffer(models.Model): ) partner_id = fields.Many2one("res.partner", required=True) property_id = fields.Many2one("estate.property", required=True) - property_type_id = fields.Many2one(related="property_id.property_type_id", stored=True) + property_type_id = fields.Many2one(related="property_id.property_type_id", store=True) validity = fields.Integer(default=7) date_deadline = fields.Date(compute="_compute_date_deadline", inverse="_inverse_date_deadline")