From 017bfa2c0a3f5378c982b935e3c08445ade56b48 Mon Sep 17 00:00:00 2001 From: renol-odoo Date: Mon, 16 Feb 2026 10:38:20 +0100 Subject: [PATCH 01/10] tuto first commit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a0158d919ee..0aad0c8b003 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Odoo tutorials +# Odoo tutorials - renol technical training This repository hosts the code for the bases of the modules used in the [official Odoo tutorials](https://www.odoo.com/documentation/latest/developer/tutorials.html). From f0d1b514b54bc951c3def0b30c66d8c5b02ec546 Mon Sep 17 00:00:00 2001 From: renol-odoo Date: Mon, 16 Feb 2026 14:25:26 +0100 Subject: [PATCH 02/10] chapter3 --- chapter1_firstmodule/__init__.py | 1 + chapter1_firstmodule/__manifest__.py | 19 ++++ chapter1_firstmodule/data/books.xml | 120 ++++++++++++++++++++++ chapter1_firstmodule/models/__init__.py | 1 + chapter1_firstmodule/models/mymodel.py | 2 + chapter2_estate/__init__.py | 1 + chapter2_estate/__manifest__.py | 6 ++ chapter2_estate/models/__init__.py | 1 + chapter2_estate/models/estate_property.py | 23 +++++ 9 files changed, 174 insertions(+) create mode 100644 chapter1_firstmodule/__init__.py create mode 100644 chapter1_firstmodule/__manifest__.py create mode 100644 chapter1_firstmodule/data/books.xml create mode 100644 chapter1_firstmodule/models/__init__.py create mode 100644 chapter1_firstmodule/models/mymodel.py create mode 100644 chapter2_estate/__init__.py create mode 100644 chapter2_estate/__manifest__.py create mode 100644 chapter2_estate/models/__init__.py create mode 100644 chapter2_estate/models/estate_property.py diff --git a/chapter1_firstmodule/__init__.py b/chapter1_firstmodule/__init__.py new file mode 100644 index 00000000000..9a7e03eded3 --- /dev/null +++ b/chapter1_firstmodule/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/chapter1_firstmodule/__manifest__.py b/chapter1_firstmodule/__manifest__.py new file mode 100644 index 00000000000..80c3626a95d --- /dev/null +++ b/chapter1_firstmodule/__manifest__.py @@ -0,0 +1,19 @@ +{ + 'name': "My first module", + 'version': '1.0', + 'depends': ['base'], + 'author': "Olivier Renson", + 'website': "olivierrenson.be", + 'category': 'Training', + 'description': """ + Chapter1 test module + """, + # data files always loaded at installation + 'data': [ + 'data/books.xml', + ], + # data files containing optionally loaded demonstration data + 'data': [ + 'data/books.xml', + ], +} \ No newline at end of file diff --git a/chapter1_firstmodule/data/books.xml b/chapter1_firstmodule/data/books.xml new file mode 100644 index 00000000000..e3d1fe87605 --- /dev/null +++ b/chapter1_firstmodule/data/books.xml @@ -0,0 +1,120 @@ + + + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications + with XML. + + + Ralls, Kim + Midnight Rain + Fantasy + 5.95 + 2000-12-16 + A former architect battles corporate zombies, + an evil sorceress, and her own childhood to become queen + of the world. + + + Corets, Eva + Maeve Ascendant + Fantasy + 5.95 + 2000-11-17 + After the collapse of a nanotechnology + society in England, the young survivors lay the + foundation for a new society. + + + Corets, Eva + Oberon's Legacy + Fantasy + 5.95 + 2001-03-10 + In post-apocalypse England, the mysterious + agent known only as Oberon helps to create a new life + for the inhabitants of London. Sequel to Maeve + Ascendant. + + + Corets, Eva + The Sundered Grail + Fantasy + 5.95 + 2001-09-10 + The two daughters of Maeve, half-sisters, + battle one another for control of England. Sequel to + Oberon's Legacy. + + + Randall, Cynthia + Lover Birds + Romance + 4.95 + 2000-09-02 + When Carla meets Paul at an ornithology + conference, tempers fly as feathers get ruffled. + + + Thurman, Paula + Splish Splash + Romance + 4.95 + 2000-11-02 + A deep sea diver finds true love twenty + thousand leagues beneath the sea. + + + Knorr, Stefan + Creepy Crawlies + Horror + 4.95 + 2000-12-06 + An anthology of horror stories about roaches, + centipedes, scorpions and other insects. + + + Kress, Peter + Paradox Lost + Science Fiction + 6.95 + 2000-11-02 + After an inadvertant trip through a Heisenberg + Uncertainty Device, James Salway discovers the problems + of being quantum. + + + O'Brien, Tim + Microsoft .NET: The Programming Bible + Computer + 36.95 + 2000-12-09 + Microsoft's .NET initiative is explored in + detail in this deep programmer's reference. + + + O'Brien, Tim + MSXML3: A Comprehensive Guide + Computer + 36.95 + 2000-12-01 + The Microsoft MSXML3 parser is covered in + detail, with attention to XML DOM interfaces, XSLT processing, + SAX and more. + + + Galos, Mike + Visual Studio 7: A Comprehensive Guide + Computer + 49.95 + 2001-04-16 + Microsoft Visual Studio 7 is explored in depth, + looking at how Visual Basic, Visual C++, C#, and ASP+ are + integrated into a comprehensive development + environment. + + \ No newline at end of file diff --git a/chapter1_firstmodule/models/__init__.py b/chapter1_firstmodule/models/__init__.py new file mode 100644 index 00000000000..9da0dbda7cc --- /dev/null +++ b/chapter1_firstmodule/models/__init__.py @@ -0,0 +1 @@ +from . import mymodel \ No newline at end of file diff --git a/chapter1_firstmodule/models/mymodel.py b/chapter1_firstmodule/models/mymodel.py new file mode 100644 index 00000000000..c230dc35abb --- /dev/null +++ b/chapter1_firstmodule/models/mymodel.py @@ -0,0 +1,2 @@ +class mymodel(): + pass \ No newline at end of file diff --git a/chapter2_estate/__init__.py b/chapter2_estate/__init__.py new file mode 100644 index 00000000000..9a7e03eded3 --- /dev/null +++ b/chapter2_estate/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/chapter2_estate/__manifest__.py b/chapter2_estate/__manifest__.py new file mode 100644 index 00000000000..bc34260ce3c --- /dev/null +++ b/chapter2_estate/__manifest__.py @@ -0,0 +1,6 @@ +{ + 'name': "Real Estate Management", + 'depends': ['base'], + 'author': "Olivier Renson", + 'application': True, +} diff --git a/chapter2_estate/models/__init__.py b/chapter2_estate/models/__init__.py new file mode 100644 index 00000000000..5e1963c9d2f --- /dev/null +++ b/chapter2_estate/models/__init__.py @@ -0,0 +1 @@ +from . import estate_property diff --git a/chapter2_estate/models/estate_property.py b/chapter2_estate/models/estate_property.py new file mode 100644 index 00000000000..6315d2fee0e --- /dev/null +++ b/chapter2_estate/models/estate_property.py @@ -0,0 +1,23 @@ +from odoo import models, fields + +class EstateProperty(models.Model): + _name = "estate_property" + _description = "A new model to store real estate properties" + + name = fields.Char(required=True) + description = fields.Text() + postcode = fields.Char() + date_availability = fields.Date() + expected_price = fields.Float(required=True) + selling_price = fields.Float() + bedrooms = fields.Integer() + living_area = fields.Integer() + facades = fields.Integer() + garage = fields.Boolean() + garden = fields.Boolean() + garden_area = fields.Integer() + garden_orientation = fields.Selection( + string="Garden Orientation", + selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], + help="One of the four cardinal points (North, South, East, West).", + ) From 22b1a88d810ca28dd2f9b7c9090d999030de0589 Mon Sep 17 00:00:00 2001 From: renol-odoo Date: Mon, 16 Feb 2026 15:05:27 +0100 Subject: [PATCH 03/10] chapter4 --- chapter2_estate/__manifest__.py | 3 +++ chapter2_estate/security/ir.model.access.csv | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 chapter2_estate/security/ir.model.access.csv diff --git a/chapter2_estate/__manifest__.py b/chapter2_estate/__manifest__.py index bc34260ce3c..b4ff8a8d629 100644 --- a/chapter2_estate/__manifest__.py +++ b/chapter2_estate/__manifest__.py @@ -3,4 +3,7 @@ 'depends': ['base'], 'author': "Olivier Renson", 'application': True, + 'data': [ + 'security/ir.model.access.csv', + ] } diff --git a/chapter2_estate/security/ir.model.access.csv b/chapter2_estate/security/ir.model.access.csv new file mode 100644 index 00000000000..2386cd0763e --- /dev/null +++ b/chapter2_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,access_estate,model_estate_property,base.group_user,1,1,1,1 From 2317b4d2be500b21927a5a2fcd4a0c841b26b50b Mon Sep 17 00:00:00 2001 From: renol-odoo Date: Mon, 16 Feb 2026 16:36:45 +0100 Subject: [PATCH 04/10] chapter5 --- chapter2_estate/__manifest__.py | 2 ++ chapter2_estate/models/estate_property.py | 32 ++++++++++++++++--- chapter2_estate/views/estate_menus.xml | 10 ++++++ .../views/estate_property_views.xml | 10 ++++++ 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 chapter2_estate/views/estate_menus.xml create mode 100644 chapter2_estate/views/estate_property_views.xml diff --git a/chapter2_estate/__manifest__.py b/chapter2_estate/__manifest__.py index b4ff8a8d629..9f4a29bf7ca 100644 --- a/chapter2_estate/__manifest__.py +++ b/chapter2_estate/__manifest__.py @@ -5,5 +5,7 @@ 'application': True, 'data': [ 'security/ir.model.access.csv', + 'views/estate_menus.xml', + 'views/estate_property_views.xml', ] } diff --git a/chapter2_estate/models/estate_property.py b/chapter2_estate/models/estate_property.py index 6315d2fee0e..96ce4d84f4a 100644 --- a/chapter2_estate/models/estate_property.py +++ b/chapter2_estate/models/estate_property.py @@ -1,4 +1,6 @@ from odoo import models, fields +from datetime import date +from dateutil.relativedelta import relativedelta class EstateProperty(models.Model): _name = "estate_property" @@ -7,10 +9,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=date.today()+relativedelta(months=3)) expected_price = fields.Float(required=True) - selling_price = fields.Float() - bedrooms = fields.Integer() + selling_price = fields.Float(readonly=True, copy=False) + bedrooms = fields.Integer(default=2) living_area = fields.Integer() facades = fields.Integer() garage = fields.Boolean() @@ -18,6 +20,26 @@ class EstateProperty(models.Model): garden_area = fields.Integer() garden_orientation = fields.Selection( string="Garden Orientation", - selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], - help="One of the four cardinal points (North, South, East, West).", + selection=[ + ('north', 'North'), + ('south', 'South'), + ('east', 'East'), + ('west', 'West') + ], + help="Select one of the four cardinal points (North, South, East, West).", + ), + active = fields.Boolean(default=True), + state = fields.Selection( + string="Status", + selection=[ + ('new', 'New'), + ('offer_received', 'Offer Received'), + ('offer_accepted', 'Offer Accepted'), + ('sold', 'Sold'), + ('canceled', 'Canceled') + ], + default='new', + required=True, + copy=False, ) + diff --git a/chapter2_estate/views/estate_menus.xml b/chapter2_estate/views/estate_menus.xml new file mode 100644 index 00000000000..c72af343f02 --- /dev/null +++ b/chapter2_estate/views/estate_menus.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/chapter2_estate/views/estate_property_views.xml b/chapter2_estate/views/estate_property_views.xml new file mode 100644 index 00000000000..b49c60b91df --- /dev/null +++ b/chapter2_estate/views/estate_property_views.xml @@ -0,0 +1,10 @@ + + + + + Create + estate_property + list,form + + + From 069aec8940a01c3bf2b819378e81875c1b9015b3 Mon Sep 17 00:00:00 2001 From: renol-odoo Date: Tue, 17 Feb 2026 08:04:19 +0100 Subject: [PATCH 05/10] =?UTF-8?q?[MOV]=20estate:=20=C2=B4chapter2=5Festate?= =?UTF-8?q?=C2=B4=20renamed=20into=20=C2=B4estate=C2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Deleting module 'chapter1_firstmodule' - Moving module 'chapter2_estate' to 'estate' as it will be used through all chapters --- chapter1_firstmodule/__manifest__.py | 19 --- chapter1_firstmodule/data/books.xml | 120 ------------------ chapter1_firstmodule/models/__init__.py | 1 - chapter1_firstmodule/models/mymodel.py | 2 - chapter2_estate/__init__.py | 1 - {chapter1_firstmodule => estate}/__init__.py | 0 {chapter2_estate => estate}/__manifest__.py | 0 .../models/__init__.py | 0 .../models/estate_property.py | 1 - .../security/ir.model.access.csv | 0 .../views/estate_menus.xml | 0 .../views/estate_property_views.xml | 0 12 files changed, 144 deletions(-) delete mode 100644 chapter1_firstmodule/__manifest__.py delete mode 100644 chapter1_firstmodule/data/books.xml delete mode 100644 chapter1_firstmodule/models/__init__.py delete mode 100644 chapter1_firstmodule/models/mymodel.py delete mode 100644 chapter2_estate/__init__.py rename {chapter1_firstmodule => estate}/__init__.py (100%) rename {chapter2_estate => estate}/__manifest__.py (100%) rename {chapter2_estate => estate}/models/__init__.py (100%) rename {chapter2_estate => estate}/models/estate_property.py (94%) rename {chapter2_estate => estate}/security/ir.model.access.csv (100%) rename {chapter2_estate => estate}/views/estate_menus.xml (100%) rename {chapter2_estate => estate}/views/estate_property_views.xml (100%) diff --git a/chapter1_firstmodule/__manifest__.py b/chapter1_firstmodule/__manifest__.py deleted file mode 100644 index 80c3626a95d..00000000000 --- a/chapter1_firstmodule/__manifest__.py +++ /dev/null @@ -1,19 +0,0 @@ -{ - 'name': "My first module", - 'version': '1.0', - 'depends': ['base'], - 'author': "Olivier Renson", - 'website': "olivierrenson.be", - 'category': 'Training', - 'description': """ - Chapter1 test module - """, - # data files always loaded at installation - 'data': [ - 'data/books.xml', - ], - # data files containing optionally loaded demonstration data - 'data': [ - 'data/books.xml', - ], -} \ No newline at end of file diff --git a/chapter1_firstmodule/data/books.xml b/chapter1_firstmodule/data/books.xml deleted file mode 100644 index e3d1fe87605..00000000000 --- a/chapter1_firstmodule/data/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/chapter1_firstmodule/models/__init__.py b/chapter1_firstmodule/models/__init__.py deleted file mode 100644 index 9da0dbda7cc..00000000000 --- a/chapter1_firstmodule/models/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import mymodel \ No newline at end of file diff --git a/chapter1_firstmodule/models/mymodel.py b/chapter1_firstmodule/models/mymodel.py deleted file mode 100644 index c230dc35abb..00000000000 --- a/chapter1_firstmodule/models/mymodel.py +++ /dev/null @@ -1,2 +0,0 @@ -class mymodel(): - pass \ No newline at end of file diff --git a/chapter2_estate/__init__.py b/chapter2_estate/__init__.py deleted file mode 100644 index 9a7e03eded3..00000000000 --- a/chapter2_estate/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import models \ No newline at end of file diff --git a/chapter1_firstmodule/__init__.py b/estate/__init__.py similarity index 100% rename from chapter1_firstmodule/__init__.py rename to estate/__init__.py diff --git a/chapter2_estate/__manifest__.py b/estate/__manifest__.py similarity index 100% rename from chapter2_estate/__manifest__.py rename to estate/__manifest__.py diff --git a/chapter2_estate/models/__init__.py b/estate/models/__init__.py similarity index 100% rename from chapter2_estate/models/__init__.py rename to estate/models/__init__.py diff --git a/chapter2_estate/models/estate_property.py b/estate/models/estate_property.py similarity index 94% rename from chapter2_estate/models/estate_property.py rename to estate/models/estate_property.py index 96ce4d84f4a..96961e93d6c 100644 --- a/chapter2_estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -26,7 +26,6 @@ class EstateProperty(models.Model): ('east', 'East'), ('west', 'West') ], - help="Select one of the four cardinal points (North, South, East, West).", ), active = fields.Boolean(default=True), state = fields.Selection( diff --git a/chapter2_estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv similarity index 100% rename from chapter2_estate/security/ir.model.access.csv rename to estate/security/ir.model.access.csv diff --git a/chapter2_estate/views/estate_menus.xml b/estate/views/estate_menus.xml similarity index 100% rename from chapter2_estate/views/estate_menus.xml rename to estate/views/estate_menus.xml diff --git a/chapter2_estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml similarity index 100% rename from chapter2_estate/views/estate_property_views.xml rename to estate/views/estate_property_views.xml From 52e29ea6b2c960f211832dd42785aa949163cc52 Mon Sep 17 00:00:00 2001 From: renol-odoo Date: Tue, 17 Feb 2026 08:13:18 +0100 Subject: [PATCH 06/10] [FIX] estate: `__manifest__.py` data order fix Fixing `estate_property_action` id error on module installation due to wrong order in `__manifest__.py` --- estate/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 9f4a29bf7ca..4b33b9b23aa 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -5,7 +5,7 @@ 'application': True, 'data': [ 'security/ir.model.access.csv', - 'views/estate_menus.xml', 'views/estate_property_views.xml', + 'views/estate_menus.xml', ] } From 3899f9452b371703ee3368485614b027facabf6a Mon Sep 17 00:00:00 2001 From: renol-odoo Date: Tue, 17 Feb 2026 10:53:21 +0100 Subject: [PATCH 07/10] [IMP]estate: chapter6 - basic views Add/customize the following wiews : - property list - property search - property form --- estate/views/estate_property_views.xml | 85 +++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index b49c60b91df..faa997b4cfa 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -2,9 +2,92 @@ - Create + Property estate_property list,form + + estate_property_list + estate_property + + + + + + + + + + + + + + + estate_property_search + estate_property + + + + + + + + + + + + + + + + + + + + estate_property_form + estate_property + +
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + Empty for now ... + + +
+
+
+
+
From f22f582d324b55a59f8c3411ff937da7505e895e Mon Sep 17 00:00:00 2001 From: renol-odoo Date: Tue, 17 Feb 2026 11:07:42 +0100 Subject: [PATCH 08/10] [FIX] estate: model attributes fix 'active' and 'garden_orientation' fields were not creating in the DB due to comma at end of line --- estate/models/estate_property.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 96961e93d6c..e28e73650cb 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -26,8 +26,8 @@ class EstateProperty(models.Model): ('east', 'East'), ('west', 'West') ], - ), - active = fields.Boolean(default=True), + ) + active = fields.Boolean(default=True) state = fields.Selection( string="Status", selection=[ From 199051fb8e477f4ff54bad7065cfffb4864f493e Mon Sep 17 00:00:00 2001 From: renol-odoo Date: Tue, 17 Feb 2026 14:31:32 +0100 Subject: [PATCH 09/10] [IMP] estate: chapter7 - model relations Implementing new property related models : - Property type: M2O - Property tags: M2M - Property offers: O2M --- estate/__manifest__.py | 3 ++ estate/models/__init__.py | 3 ++ estate/models/estate_property.py | 6 +++- estate/models/estate_property_offer.py | 17 +++++++++++ estate/models/estate_property_tag.py | 7 +++++ estate/models/estate_property_type.py | 7 +++++ estate/security/ir.model.access.csv | 3 ++ estate/views/estate_menus.xml | 6 +++- estate/views/estate_property_offer_views.xml | 32 ++++++++++++++++++++ estate/views/estate_property_tag_views.xml | 26 ++++++++++++++++ estate/views/estate_property_type_views.xml | 26 ++++++++++++++++ estate/views/estate_property_views.xml | 17 +++++++++-- 12 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 estate/models/estate_property_offer.py create mode 100644 estate/models/estate_property_tag.py create mode 100644 estate/models/estate_property_type.py create mode 100644 estate/views/estate_property_offer_views.xml create mode 100644 estate/views/estate_property_tag_views.xml create mode 100644 estate/views/estate_property_type_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 4b33b9b23aa..836c3d78424 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -6,6 +6,9 @@ 'data': [ 'security/ir.model.access.csv', 'views/estate_property_views.xml', + 'views/estate_property_tag_views.xml', + 'views/estate_property_type_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 5e1963c9d2f..4b57c1674fc 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,4 @@ from . import estate_property +from . import estate_property_tag +from . import estate_property_type +from . import estate_property_offer diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index e28e73650cb..23146871bc7 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -41,4 +41,8 @@ class EstateProperty(models.Model): required=True, copy=False, ) - + property_type_id = fields.Many2one("estate.property.type", string="Property Type", required=True) + salesman_id = fields.Many2one("res.users", string="Salesman", default=lambda self: self.env.user) + buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) + tags_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..26f80192337 --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,17 @@ +from odoo import models, fields + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "An offer for a specific property, made by a specific buyer at lower or higher price than the expected price" + + price = fields.Float(required=True) + status = fields.Selection( + string="Status", + selection=[ + ('accepted', 'Accepted'), + ('refused', 'Refused') + ], + copy=False, + ) + partener_id = fields.Many2one("res.partner", string="Buyer", 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..c80b95fcdc0 --- /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 = "Tag describing a particular property characteristic" + + name = fields.Char(required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..f35dca22402 --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,7 @@ +from odoo import models, fields + +class EstatePropertyType(models.Model): + _name = "estate.property.type" + _description = "Group properties by type of building" + + name = fields.Char(required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 2386cd0763e..5aa520097f6 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,access_estate,model_estate_property,base.group_user,1,1,1,1 +access_estate_type,access_estate_type,model_estate_property_type,base.group_user,1,1,1,1 +access_estate_tag,access_estate_tag,model_estate_property_tag,base.group_user,1,1,1,1 +access_estate_offer,access_estate_offer,model_estate_property_offer,base.group_user,1,1,1,1 diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index c72af343f02..ee5745a0e4b 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -2,9 +2,13 @@ - + + + + + diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..c9b6c2cfe97 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,32 @@ + + + + + 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..4aeeb354b84 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,26 @@ + + + + + Property Tag + estate.property.tag + list,form + + + + estate_property_tag_form + estate.property.tag + +
+ +
+

+ +

+
+
+
+
+
+ +
diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..7c61fe8835f --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,26 @@ + + + + + Property Types + estate.property.type + list,form + + + + estate_property_type_form + estate.property.type + +
+ +
+

+ +

+
+
+
+
+
+ +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index faa997b4cfa..763837db9ae 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -19,6 +19,7 @@ + @@ -58,8 +59,12 @@ + + + + @@ -78,11 +83,17 @@ - + - - Empty for now ... + + + + + + + + From 39015359bbe1a94f6c9db8833c6d98c74b93f15c Mon Sep 17 00:00:00 2001 From: renol-odoo Date: Tue, 17 Feb 2026 17:00:39 +0100 Subject: [PATCH 10/10] [IMP] estate: chapter8 - computed & onchange - Property total area auto computed - Best offer selection - Offer validity & date auto update - Property garden onchange pre-filling - `partener_id` typo fix --- estate/models/estate_property.py | 30 ++++++++++++++++++-- estate/models/estate_property_offer.py | 18 ++++++++++-- estate/views/estate_property_offer_views.xml | 8 ++++-- estate/views/estate_property_views.xml | 2 ++ 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 23146871bc7..4ce3a1c9191 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,4 @@ -from odoo import models, fields +from odoo import models, fields, api from datetime import date from dateutil.relativedelta import relativedelta @@ -13,11 +13,11 @@ class EstateProperty(models.Model): expected_price = fields.Float(required=True) selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) - living_area = fields.Integer() + living_area = fields.Integer(string="Living Area (sqm)") facades = fields.Integer() garage = fields.Boolean() garden = fields.Boolean() - garden_area = fields.Integer() + garden_area = fields.Integer(string="Garden Area (sqm)") garden_orientation = fields.Selection( string="Garden Orientation", selection=[ @@ -46,3 +46,27 @@ class EstateProperty(models.Model): buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) tags_ids = fields.Many2many("estate.property.tag", string="Tags") offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") + total_area = fields.Integer(compute="_compute_total_area", string="Total Area (sqm)") + best_price = fields.Float(compute="_compute_best_price", string="Best Offer") + + @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: + if record.offer_ids: + record.best_price = max(record.offer_ids.mapped('price')) + else: + record.best_price = 0.0 + + @api.onchange('garden') + def _onchange_offer_ids(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 26f80192337..19c9002cb56 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,5 @@ -from odoo import models, fields +from odoo import models, fields, api +from datetime import date, timedelta class EstatePropertyOffer(models.Model): _name = "estate.property.offer" @@ -13,5 +14,18 @@ class EstatePropertyOffer(models.Model): ], copy=False, ) - partener_id = fields.Many2one("res.partner", string="Buyer", required=True) + partner_id = fields.Many2one("res.partner", string="Buyer", required=True) property_id = fields.Many2one("estate_property", string="Property", required=True) + + date_create = fields.Date(default=fields.Date.today) + validity = fields.Integer(string="Validity (days)", default=7) + date_deadline = fields.Date(compute="_compute_deadline", inverse="_inverse_deadline") + + @api.depends("validity") + def _compute_deadline(self): + for record in self: + record.date_deadline = record.date_create + timedelta(days=record.validity) + + def _inverse_deadline(self): + for record in self: + record.validity = (record.date_deadline - record.date_create).days \ 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 c9b6c2cfe97..14ca14d2f91 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -7,8 +7,10 @@ + + + - @@ -21,8 +23,10 @@ + + + - diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 763837db9ae..d79152ac204 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -70,6 +70,7 @@ + @@ -84,6 +85,7 @@ +