From 48b008cedf2db501e08cd92deb568bfcd5b939c1 Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Tue, 18 Nov 2025 13:39:55 +0100 Subject: [PATCH 01/15] [ADD] estate: init commit for estate module --- estate/__init__.py | 0 estate/__manifest__.py | 12 ++++++++++++ 2 files changed, 12 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..e77658138d1 --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,12 @@ +{ + 'name': 'Real Estate', + 'description': 'Real Estate !', + 'version': '1.0', + 'summary': 'Track Real Estate', + 'website': 'https://www.odoo.com/app/realestate', + 'author': 'Odoo S.A.', + 'license': 'LGPL-3', + 'depends': [ + 'base', + ] +} \ No newline at end of file From 793dd90401d79b1331727f8d76c9654a6733b9cf Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Tue, 18 Nov 2025 14:51:52 +0100 Subject: [PATCH 02/15] [IMP] estate: database field creation added more fields to the database table with needed requirements --- estate/__init__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 36 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..9a5948f3180 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,34 @@ +from odoo import fields, models + +class Property(models.Model): + _name = "estate.property" + _description = "This is a estate property" + _order = "sequence" + + name = fields.Char('Name', required=True) + description = fields.Text('Description') + postcode = fields.Char('Postcode') + date_availability = fields.Date('Available From', copy=False) + + expected_price = fields.Float('Expected Price', required=True) + selling_price = fields.Float('Selling Price', readonly=True, copy=False) + + bedrooms = fields.Integer('Bedrooms', default=2) + living_area = fields.Integer('Living Area (sqm)') + facades = fields.Integer('Number of Facades') + + garage = fields.Boolean('Garage') + garden = fields.Boolean('Garden') + garden_area = fields.Integer('Garden Area (sqm)') + garden_orientation = fields.Selection( + selection=[ + ('north', 'North'), + ('south', 'South'), + ('east', 'East'), + ('west', 'West'), + ], + string='Garden Orientation' + ) + + active = fields.Boolean('Active', default=True) + \ No newline at end of file From 89f139a1572d5199f23971d6346a89746661eb41 Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Tue, 18 Nov 2025 15:43:05 +0100 Subject: [PATCH 03/15] [IMP] estate: access rights added access rights --- estate/__manifest__.py | 6 +++++- estate/data/ir.model.access.csv | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 estate/data/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index e77658138d1..384b841dc3d 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -8,5 +8,9 @@ 'license': 'LGPL-3', 'depends': [ 'base', - ] + ], + 'data': [ + 'data/ir.model.access.csv' + ], + } \ No newline at end of file diff --git a/estate/data/ir.model.access.csv b/estate/data/ir.model.access.csv new file mode 100644 index 00000000000..d9d6ba57cc5 --- /dev/null +++ b/estate/data/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 6e16ab753e38ae272924f6f3e8f93c0516ed2005 Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Wed, 19 Nov 2025 08:22:08 +0100 Subject: [PATCH 04/15] [IMP] estate: fixing linting issues fixed the issues on linting --- estate/__init__.py | 2 +- estate/__manifest__.py | 2 +- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 3 ++- 4 files changed, 5 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 384b841dc3d..fc3949c23cb 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -13,4 +13,4 @@ 'data/ir.model.access.csv' ], -} \ 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 9a5948f3180..cbc0c2a01d8 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,5 +1,6 @@ from odoo import fields, models + class Property(models.Model): _name = "estate.property" _description = "This is a estate property" @@ -31,4 +32,4 @@ class Property(models.Model): ) active = fields.Boolean('Active', default=True) - \ No newline at end of file + From 7de91aa4fd167a95c0d8dedb3ca35314c1cca36b Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Wed, 19 Nov 2025 08:39:33 +0100 Subject: [PATCH 05/15] [IMP] estate: Creating ui action actions menu view --- estate/__manifest__.py | 3 ++- estate/view/__init__.py | 0 estate/view/estate_property_views.xml | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 estate/view/__init__.py create mode 100644 estate/view/estate_property_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index fc3949c23cb..c0306574c5e 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -10,7 +10,8 @@ 'base', ], 'data': [ - 'data/ir.model.access.csv' + 'data/ir.model.access.csv', + 'view/estate_property_views.xml', ], } diff --git a/estate/view/__init__.py b/estate/view/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/estate/view/estate_property_views.xml b/estate/view/estate_property_views.xml new file mode 100644 index 00000000000..d63e5e7fcbc --- /dev/null +++ b/estate/view/estate_property_views.xml @@ -0,0 +1,18 @@ + + + Properties + estate.property + tree,form + + + + + + + + + \ No newline at end of file From 8a7f9f0dbf5b1492a7cf69c52376c5a9f321dad3 Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Wed, 19 Nov 2025 10:21:42 +0100 Subject: [PATCH 06/15] [IMP] estate: fix comments and apply suggestions --- estate/__manifest__.py | 5 +-- estate/models/estate_property.py | 31 ++++++++++++------- estate/{data => security}/ir.model.access.csv | 0 estate/view/__init__.py | 0 estate/view/estate_property_views.xml | 18 ----------- estate/views/estate_property_views.xml | 28 +++++++++++++++++ 6 files changed, 50 insertions(+), 32 deletions(-) rename estate/{data => security}/ir.model.access.csv (100%) delete mode 100644 estate/view/__init__.py delete mode 100644 estate/view/estate_property_views.xml create mode 100644 estate/views/estate_property_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index c0306574c5e..e91e79c24aa 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -5,13 +5,14 @@ 'summary': 'Track Real Estate', 'website': 'https://www.odoo.com/app/realestate', 'author': 'Odoo S.A.', + 'application': True, 'license': 'LGPL-3', 'depends': [ 'base', ], 'data': [ - 'data/ir.model.access.csv', - 'view/estate_property_views.xml', + 'security/ir.model.access.csv', + 'views/estate_property_views.xml', ], } diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index cbc0c2a01d8..91b1a52956a 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,23 +1,31 @@ +from datetime import date, timedelta + +from dateutil.relativedelta import relativedelta + from odoo import fields, models -class Property(models.Model): +class EstateProperty(models.Model): _name = "estate.property" - _description = "This is a estate property" - _order = "sequence" + _description = "Estate property" + _order = "" - name = fields.Char('Name', required=True) + name = fields.Char('Title', required=True) description = fields.Text('Description') postcode = fields.Char('Postcode') - date_availability = fields.Date('Available From', copy=False) - + date_availability = fields.Date( + 'Available From', + copy=False, + default=lambda self: date.today() + relativedelta(months=3), + ) + expected_price = fields.Float('Expected Price', required=True) selling_price = fields.Float('Selling Price', readonly=True, copy=False) - - bedrooms = fields.Integer('Bedrooms', default=2) + + bedrooms = fields.Integer('Bedrooms', default=0) living_area = fields.Integer('Living Area (sqm)') - facades = fields.Integer('Number of Facades') - + facades = fields.Integer('Facades') + garage = fields.Boolean('Garage') garden = fields.Boolean('Garden') garden_area = fields.Integer('Garden Area (sqm)') @@ -28,8 +36,7 @@ class Property(models.Model): ('east', 'East'), ('west', 'West'), ], - string='Garden Orientation' + string='Garden Orientation', ) active = fields.Boolean('Active', default=True) - diff --git a/estate/data/ir.model.access.csv b/estate/security/ir.model.access.csv similarity index 100% rename from estate/data/ir.model.access.csv rename to estate/security/ir.model.access.csv diff --git a/estate/view/__init__.py b/estate/view/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/estate/view/estate_property_views.xml b/estate/view/estate_property_views.xml deleted file mode 100644 index d63e5e7fcbc..00000000000 --- a/estate/view/estate_property_views.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - Properties - estate.property - tree,form - - - - - - - - - \ 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..36097c3f446 --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,28 @@ + + + estate.property.list + estate.property + + + + + + + + + + + + Properties + estate.property + list,form + + + + + + + + + From bad6fa4f63ee89fb092046ef46ec69e909cc22c5 Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Wed, 19 Nov 2025 11:26:05 +0100 Subject: [PATCH 07/15] [IMP] estate: improvement to the state form added improvement to the properties --- estate/__manifest__.py | 2 +- estate/models/estate_property.py | 15 +++++++++++++-- estate/views/estate_menus.xml | 7 +++++++ estate/views/estate_property_views.xml | 8 -------- 4 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 estate/views/estate_menus.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index e91e79c24aa..a702ad935f5 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -13,6 +13,6 @@ 'data': [ 'security/ir.model.access.csv', 'views/estate_property_views.xml', + 'views/estate_menus.xml', ], - } diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 91b1a52956a..e2e5030025b 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,4 @@ -from datetime import date, timedelta +from datetime import date from dateutil.relativedelta import relativedelta @@ -22,7 +22,7 @@ class EstateProperty(models.Model): expected_price = fields.Float('Expected Price', required=True) selling_price = fields.Float('Selling Price', readonly=True, copy=False) - bedrooms = fields.Integer('Bedrooms', default=0) + bedrooms = fields.Integer('Bedrooms', default=2) living_area = fields.Integer('Living Area (sqm)') facades = fields.Integer('Facades') @@ -38,5 +38,16 @@ class EstateProperty(models.Model): ], string='Garden Orientation', ) + state = fields.Selection( + selection=[ + ('new', 'New'), + ('offer', 'Offer'), + ('received', 'Received'), + ('offer Accepted', 'Offer Accepted'), + ('sold', 'Sold'), + ('cancelled', 'Cancelled'), + ], + string='State',default='new',required=True,copy=False + ) active = fields.Boolean('Active', default=True) diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..0876a7a26eb --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 36097c3f446..338a298ce13 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -17,12 +17,4 @@ estate.property list,form - - - - - - - From a6e8cf17ba41d645ba944515b6795da6ff0319f0 Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Wed, 19 Nov 2025 11:39:09 +0100 Subject: [PATCH 08/15] [IMP] estate: fixing styling issues --- estate/models/estate_property.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index e2e5030025b..03a6e2b6f40 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -47,7 +47,10 @@ class EstateProperty(models.Model): ('sold', 'Sold'), ('cancelled', 'Cancelled'), ], - string='State',default='new',required=True,copy=False + string='State', + default='new', + required=True, + copy=False, ) active = fields.Boolean('Active', default=True) From 331420f57b458131fdee0d8c3931b580e131a046 Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Wed, 19 Nov 2025 15:48:39 +0100 Subject: [PATCH 09/15] [IMP] adding features to the app added search / filter / form / header --- estate/__manifest__.py | 3 ++ estate/models/estate_property.py | 10 ++---- estate/views/estate_property_views.xml | 8 ----- estate/views/estate_tree.xml | 17 +++++++++ estate/views/estate_view_form.xml | 50 ++++++++++++++++++++++++++ estate/views/estate_view_search.xml | 28 +++++++++++++++ 6 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 estate/views/estate_tree.xml create mode 100644 estate/views/estate_view_form.xml create mode 100644 estate/views/estate_view_search.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index a702ad935f5..950f6e43d77 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -13,6 +13,9 @@ 'data': [ 'security/ir.model.access.csv', 'views/estate_property_views.xml', + 'views/estate_tree.xml', 'views/estate_menus.xml', + 'views/estate_view_form.xml', + 'views/estate_view_search.xml', ], } diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 03a6e2b6f40..cefd8fb505d 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,7 +1,5 @@ from datetime import date - from dateutil.relativedelta import relativedelta - from odoo import fields, models @@ -12,20 +10,17 @@ class EstateProperty(models.Model): name = fields.Char('Title', required=True) description = fields.Text('Description') - postcode = fields.Char('Postcode') + post_code = fields.Char('Postcode') date_availability = fields.Date( 'Available From', copy=False, default=lambda self: date.today() + relativedelta(months=3), ) - expected_price = fields.Float('Expected Price', required=True) selling_price = fields.Float('Selling Price', readonly=True, copy=False) - bedrooms = fields.Integer('Bedrooms', default=2) living_area = fields.Integer('Living Area (sqm)') facades = fields.Integer('Facades') - garage = fields.Boolean('Garage') garden = fields.Boolean('Garden') garden_area = fields.Integer('Garden Area (sqm)') @@ -43,7 +38,7 @@ class EstateProperty(models.Model): ('new', 'New'), ('offer', 'Offer'), ('received', 'Received'), - ('offer Accepted', 'Offer Accepted'), + ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled'), ], @@ -52,5 +47,4 @@ class EstateProperty(models.Model): required=True, copy=False, ) - active = fields.Boolean('Active', default=True) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 338a298ce13..3faad4288ab 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -2,14 +2,6 @@ estate.property.list estate.property - - - - - - - - diff --git a/estate/views/estate_tree.xml b/estate/views/estate_tree.xml new file mode 100644 index 00000000000..89106a95c17 --- /dev/null +++ b/estate/views/estate_tree.xml @@ -0,0 +1,17 @@ + + + Estate Property Tree + estate.property + + + + + + + + + + + + + \ No newline at end of file diff --git a/estate/views/estate_view_form.xml b/estate/views/estate_view_form.xml new file mode 100644 index 00000000000..0c50d7cc400 --- /dev/null +++ b/estate/views/estate_view_form.xml @@ -0,0 +1,50 @@ + + + estate.property.form + estate.property + +
+
+ +
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
\ No newline at end of file diff --git a/estate/views/estate_view_search.xml b/estate/views/estate_view_search.xml new file mode 100644 index 00000000000..5b75837daf2 --- /dev/null +++ b/estate/views/estate_view_search.xml @@ -0,0 +1,28 @@ + + + + estate.property.search + estate.property + + + + + + + + + + + + + + + + + + + + + + + From 566aad6ec5611d989726328f19b38f34b3a896db Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Thu, 20 Nov 2025 11:27:10 +0100 Subject: [PATCH 10/15] [FIX] estate: fix for ci checks fixed the issue for the styles and the tutorial syntax --- estate/models/estate_property.py | 2 +- estate/views/estate_property_views.xml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index cefd8fb505d..15c5f0c607c 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -38,7 +38,7 @@ class EstateProperty(models.Model): ('new', 'New'), ('offer', 'Offer'), ('received', 'Received'), - ('offer_accepted', 'Offer Accepted'), + ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled'), ], diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 3faad4288ab..bc1922fc19c 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -2,6 +2,11 @@ estate.property.list estate.property + + + + + From a5cf231508ac6702dd85eecbab388ea47f20338d Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Fri, 21 Nov 2025 11:13:39 +0100 Subject: [PATCH 11/15] [IMP] estate : Adding features to the estate app added tags types.. and accesses and infos in the form --- .gitignore | 3 ++ estate/__manifest__.py | 21 +++++++------ estate/models/__init__.py | 3 ++ estate/models/estate_property.py | 9 +++++- estate/models/estate_property_offer.py | 17 ++++++++++ estate/models/estate_property_tag.py | 9 ++++++ estate/models/estate_property_type.py | 14 +++++++++ estate/security/ir.model.access.csv | 7 +++-- .../{estate_tree.xml => estate_list.xml} | 1 + estate/views/estate_menus.xml | 8 +++-- estate/views/estate_property_form_views.xml | 26 ++++++++++++++++ estate/views/estate_property_offer_views.xml | 27 ++++++++++++++++ estate/views/estate_property_tag_views.xml | 18 +++++++++++ estate/views/estate_property_type_views.xml | 31 +++++++++++++++++++ estate/views/estate_property_views.xml | 1 + estate/views/estate_view_form.xml | 15 +++++++++ estate/views/estate_view_search.xml | 1 + 17 files changed, 196 insertions(+), 15 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 rename estate/views/{estate_tree.xml => estate_list.xml} (90%) create mode 100644 estate/views/estate_property_form_views.xml 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/.gitignore b/.gitignore index b6e47617de1..93a80466f11 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,9 @@ MANIFEST *.manifest *.spec +#editor +.vscode/ + # Installer logs pip-log.txt pip-delete-this-directory.txt diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 950f6e43d77..c35d38c0064 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,15 +7,16 @@ 'author': 'Odoo S.A.', 'application': True, 'license': 'LGPL-3', - 'depends': [ - 'base', + 'depends': ['base'], + 'data': [ + 'security/ir.model.access.csv', + 'views/estate_property_type_views.xml', + 'views/estate_property_tag_views.xml', + 'views/estate_property_offer_views.xml', + 'views/estate_property_views.xml', + 'views/estate_list.xml', + 'views/estate_view_form.xml', + 'views/estate_view_search.xml', + 'views/estate_menus.xml', ], - 'data': [ - 'security/ir.model.access.csv', - 'views/estate_property_views.xml', - 'views/estate_tree.xml', - 'views/estate_menus.xml', - 'views/estate_view_form.xml', - 'views/estate_view_search.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 15c5f0c607c..7fefb90f475 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -8,7 +8,7 @@ class EstateProperty(models.Model): _description = "Estate property" _order = "" - name = fields.Char('Title', required=True) + name = fields.Text('Title', required=True) description = fields.Text('Description') post_code = fields.Char('Postcode') date_availability = fields.Date( @@ -48,3 +48,10 @@ class EstateProperty(models.Model): copy=False, ) active = fields.Boolean('Active', default=True) + property_type_id = fields.Many2one("estate.property.type", string="Property Type") + user_id = fields.Many2one( + 'res.users', string='Salesman', default=lambda self: self.env.user + ) + buyer_id = fields.Many2one("res.partner", string="Buyer", readonly=True, copy=False) + tag_ids = fields.Many2many("estate.property.tag", string="Tags") + 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..0b14132add1 --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,17 @@ +from odoo import fields, models + + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Estate Property Offers" + _order = "price" + + price = fields.Float("Price", required=True) + state = fields.Selection( + [('accepted', 'Accepted'), ('refused', 'Refused')], + string="Status", + default=False, + copy=False, + ) + partner_id = fields.Many2one("res.partner", string="Partner", required=True) + property_id = fields.Many2one("estate.property", string="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..6edd4d45013 --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,9 @@ +from odoo import fields, models + + +class EstatePropertyTag(models.Model): + _name = "estate.property.tag" + _description = "Estate Property Tag" + _order = "name" + + name = fields.Char("Name", required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..12ec06fad19 --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,14 @@ +from odoo import fields, models + + +class EstatePropertyType(models.Model): + _name = "estate.property.type" + _description = "Estate Property Type" + _order = "sequence, name" + + name = fields.Char("Name", required=True) + sequence = fields.Integer("Sequence") + property_ids = fields.One2many( + "estate.property", "property_type_id", string="Properties" + ) + offer_count = fields.Integer(string="Offers count", compute="_compute_offer") diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index d9d6ba57cc5..bdc8b769cdd 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 +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 \ No newline at end of file diff --git a/estate/views/estate_tree.xml b/estate/views/estate_list.xml similarity index 90% rename from estate/views/estate_tree.xml rename to estate/views/estate_list.xml index 89106a95c17..7ccc766e0e5 100644 --- a/estate/views/estate_tree.xml +++ b/estate/views/estate_list.xml @@ -5,6 +5,7 @@ + diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 0876a7a26eb..518b45027d7 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,7 +1,11 @@ - + + + + + - + \ No newline at end of file diff --git a/estate/views/estate_property_form_views.xml b/estate/views/estate_property_form_views.xml new file mode 100644 index 00000000000..058391929a0 --- /dev/null +++ b/estate/views/estate_property_form_views.xml @@ -0,0 +1,26 @@ + + + estate.property.offer.form + estate.property.offer + +
+ + + + + + + + + + +
+
+
+ + + Property Offers + estate.property.offer + tree,form + +
\ 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..6c115f8329b --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,27 @@ + + + estate.property.offer.form + estate.property.offer + +
+ + + + + +
+
+
+ + + estate.property.offer.tree + 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..ceaea50ef75 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,18 @@ + + + estate.property.tag.tree + estate.property.tag + + + + + + + + + Property Tags + estate.property.tag + list,form + + + \ 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..943e10fa83a --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,31 @@ + + + estate.property.type.list + estate.property.type + + + + + + + + + estate.property.type.form + estate.property.type + +
+ + + + + +
+
+
+ + + Property Types + estate.property.type + list,form + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index bc1922fc19c..a6426e2cd27 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -5,6 +5,7 @@ +
diff --git a/estate/views/estate_view_form.xml b/estate/views/estate_view_form.xml index 0c50d7cc400..99fb9cd4d1f 100644 --- a/estate/views/estate_view_form.xml +++ b/estate/views/estate_view_form.xml @@ -13,6 +13,10 @@ + + + + @@ -42,6 +46,17 @@ + + + + + + + + + + + diff --git a/estate/views/estate_view_search.xml b/estate/views/estate_view_search.xml index 5b75837daf2..12ddf993e1e 100644 --- a/estate/views/estate_view_search.xml +++ b/estate/views/estate_view_search.xml @@ -16,6 +16,7 @@ + From a8c1bd40370a5f33d7fc8f9b74dfadefeac2f844 Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Fri, 21 Nov 2025 11:48:44 +0100 Subject: [PATCH 12/15] [IMP] estate: added feature to compute fields Chapter 8: Computed Fields And Onchanges count the oriontation depend of criteria using action --- estate/models/estate_property.py | 32 +++++++++++++++++++- estate/models/estate_property_offer.py | 17 ++++++++++- estate/views/estate_property_offer_views.xml | 2 ++ estate/views/estate_view_form.xml | 2 ++ 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 7fefb90f475..344d5accdf6 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,6 +1,6 @@ from datetime import date from dateutil.relativedelta import relativedelta -from odoo import fields, models +from odoo import api, fields, models class EstateProperty(models.Model): @@ -55,3 +55,33 @@ class EstateProperty(models.Model): buyer_id = fields.Many2one("res.partner", string="Buyer", readonly=True, copy=False) tag_ids = fields.Many2many("estate.property.tag", string="Tags") offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") + total_area = fields.Integer("Total Area (sqm)", compute="_compute_total_area") + best_price = fields.Float( + "Best Offer", + compute="_compute_best_price", readonly=True + ) + + @api.depends('living_area', 'garden_area') + def _compute_total_area(self): + for rec in self: + rec.total_area = (rec.living_area or 0) + (rec.garden_area or 0) + + @api.depends('offer_ids.price') + def _compute_best_price(self): + for rec in self: + prices = rec.offer_ids.mapped('price') + rec.best_price = max(prices) if prices else 0.0 + + @api.depends("living_area", "garden_area") + def _compute_total_area(self): + for prop in self: + prop.total_area = prop.living_area + prop.garden_area + + @api.onchange("garden") + def _onchange_garden(self): + if self.garden: + self.garden_area = 10 + self.garden_orientation = "north" + else: + self.garden_area = 0 + self.garden_orientation = False diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 0b14132add1..4027994c4ab 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): @@ -15,3 +15,18 @@ class EstatePropertyOffer(models.Model): ) partner_id = fields.Many2one("res.partner", string="Partner", required=True) property_id = fields.Many2one("estate.property", string="Property", required=True) + validity = fields.Integer( + "Validity (days)", default=7 + ) + date_deadline = fields.Date( + "Deadline", compute="_compute_date_deadline", store=True + ) + @api.depends('validity') + def _compute_date_deadline(self): + for offer in self: + if offer._origin.validity: + offer.date_deadline = fields.Date.add( + offer.create_date.date(), days=offer.validity + ) + else: + offer.date_deadline = False \ No newline at end of file diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 6c115f8329b..949e3df207d 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -21,6 +21,8 @@ + +
diff --git a/estate/views/estate_view_form.xml b/estate/views/estate_view_form.xml index 99fb9cd4d1f..e511632e936 100644 --- a/estate/views/estate_view_form.xml +++ b/estate/views/estate_view_form.xml @@ -25,6 +25,7 @@ + @@ -43,6 +44,7 @@ + From 1b7200efdf30769d45133db854aac0de0c06f566 Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Fri, 21 Nov 2025 12:51:55 +0100 Subject: [PATCH 13/15] [FIX] estate: fixed style issues --- estate/models/estate_property_offer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 4027994c4ab..113785b5e6b 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -21,6 +21,7 @@ class EstatePropertyOffer(models.Model): date_deadline = fields.Date( "Deadline", compute="_compute_date_deadline", store=True ) + @api.depends('validity') def _compute_date_deadline(self): for offer in self: @@ -29,4 +30,4 @@ def _compute_date_deadline(self): offer.create_date.date(), days=offer.validity ) else: - offer.date_deadline = False \ No newline at end of file + offer.date_deadline = False From 7758b15d8750b4b0fac6c2eaf3ef65b37dbd86f2 Mon Sep 17 00:00:00 2001 From: "youness benbraitit (yoben)" Date: Fri, 21 Nov 2025 13:57:05 +0100 Subject: [PATCH 14/15] [IMP] estate: added accept/refuse offer added requirement of chapter 9 --- estate/models/estate_property.py | 14 +++++++++++-- estate/models/estate_property_offer.py | 21 +++++++++++++++++--- estate/views/estate_property_offer_views.xml | 6 +++++- estate/views/estate_view_form.xml | 6 ++++++ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 344d5accdf6..3aa5bd71f62 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,5 +1,6 @@ from datetime import date from dateutil.relativedelta import relativedelta +from odoo.exceptions import UserError, ValidationError from odoo import api, fields, models @@ -57,8 +58,7 @@ class EstateProperty(models.Model): offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") total_area = fields.Integer("Total Area (sqm)", compute="_compute_total_area") best_price = fields.Float( - "Best Offer", - compute="_compute_best_price", readonly=True + "Best Offer", compute="_compute_best_price", readonly=True ) @api.depends('living_area', 'garden_area') @@ -85,3 +85,13 @@ def _onchange_garden(self): else: self.garden_area = 0 self.garden_orientation = False + + def action_sold(self): + if "cancelled" in self.mapped("state"): + raise UserError("Canceled property cannot be sold !") + return self.write({"state": "sold"}) + + def action_cancel(self): + if "sold" in self.mapped("state"): + raise UserError("Sold property cannot be canceled !") + return self.write({"state": "cancelled"}) diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 113785b5e6b..5415a54e429 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -15,9 +15,7 @@ class EstatePropertyOffer(models.Model): ) partner_id = fields.Many2one("res.partner", string="Partner", required=True) property_id = fields.Many2one("estate.property", string="Property", required=True) - validity = fields.Integer( - "Validity (days)", default=7 - ) + validity = fields.Integer("Validity (days)", default=7) date_deadline = fields.Date( "Deadline", compute="_compute_date_deadline", store=True ) @@ -31,3 +29,20 @@ def _compute_date_deadline(self): ) else: offer.date_deadline = False + + def action_accept(self): + for offer in self: + offer.state = 'accepted' + offer.property_id.selling_price = offer.price + offer.property_id.buyer_id = offer.partner_id.id + offer.property_id.state = 'offer_accepted' + other_offers = offer.property_id.offer_ids.filtered( + lambda o: o.id != offer.id and o.state != 'refused' + ) + other_offers.state = 'refused' + return True + + def action_refuse(self): + for offer in self: + offer.state = 'refused' + return True diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 949e3df207d..ca44687f9fa 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -12,7 +12,7 @@ - + estate.property.offer.tree estate.property.offer @@ -23,6 +23,10 @@ +