From 691a89a56fa5a998be2a4626d08d3a8bd3680960 Mon Sep 17 00:00:00 2001 From: "Valentyn Dementiev (vadem)" Date: Tue, 15 Sep 2026 15:05:03 +0200 Subject: [PATCH 1/9] [ADD] Estate: Finished 1-3 chapters of tutorial Created module, with manifest and 1 model (estate_property) Server Framework 101 (Chapter 1-3) --- estate/__init__.py | 1 + estate/__manifest__.py | 5 +++++ estate/models/__init__.py | 1 + estate/models/estate_property.py | 21 +++++++++++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 estate/__init__.py create mode 100644 estate/__manifest__.py create mode 100644 estate/models/__init__.py create mode 100644 estate/models/estate_property.py diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..9a7e03eded3 --- /dev/null +++ b/estate/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..f6d5abc5932 --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,5 @@ +{ + 'name': "Estate module", + 'depends': ['base'], + 'application' : True +} \ 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..7b9b2d9c124 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,21 @@ +from odoo import models, fields + +class EstateProperty(models.Model): + _name = "estate.property" + _description = "This is estate property model" + + 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( + selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], + ) From 11d2b68cce2a4106921be267650f3b5228d6b010 Mon Sep 17 00:00:00 2001 From: "Valentyn Dementiev (vadem)" Date: Tue, 15 Sep 2026 15:44:17 +0200 Subject: [PATCH 2/9] [ADD] Estate: Added access rights file, estate property model now accessible Added access rights file (ir.model.access.csv), estate property model now accessible Server Framework 101 (Chapter 4) --- estate/__manifest__.py | 5 ++++- estate/security/__init__.py | 0 estate/security/ir.model.access.csv | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 estate/security/__init__.py create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index f6d5abc5932..ad19effdf13 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,5 +1,8 @@ { 'name': "Estate module", 'depends': ['base'], - 'application' : True + 'application' : True, + 'data': [ + 'security/ir.model.access.csv', + ], } \ No newline at end of file diff --git a/estate/security/__init__.py b/estate/security/__init__.py 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..3eef86fe077 --- /dev/null +++ b/estate/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +estate.access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 \ No newline at end of file From ef50097859d05f8fcfaba2ca091cf3f69cd75c33 Mon Sep 17 00:00:00 2001 From: "Valentyn Dementiev (vadem)" Date: Tue, 15 Sep 2026 16:25:34 +0200 Subject: [PATCH 3/9] [CLN] Estate: Code cleanup Cleaned code due to C3PO commit checks Commit 11d2b68 --- .gitignore | 1 + estate/__init__.py | 2 +- estate/__manifest__.py | 4 ++-- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 5 +++-- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index b6e47617de1..433bf00f4af 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,4 @@ dmypy.json # Pyre type checker .pyre/ +estate/.vscode/settings.json 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 ad19effdf13..0f9d2c3204a 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,8 +1,8 @@ { 'name': "Estate module", 'depends': ['base'], - 'application' : True, + 'application': True, 'data': [ 'security/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 7b9b2d9c124..80d1e661544 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,14 +1,15 @@ from odoo import models, fields + class EstateProperty(models.Model): _name = "estate.property" _description = "This is estate property model" - name = fields.Char(required = True) + name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() date_availability = fields.Date() - expected_price = fields.Float(required = True) + expected_price = fields.Float(required=True) selling_price = fields.Float() bedrooms = fields.Integer() living_area = fields.Integer() From 06cb4e649cfe236555e0bbfaec44ed716eb91b08 Mon Sep 17 00:00:00 2001 From: "Valentyn Dementiev (vadem)" Date: Tue, 15 Sep 2026 17:28:06 +0200 Subject: [PATCH 4/9] [ADD] Estate: CRUD for estate model Added menus and view functionality for estate property model, and configured model with restrictions for better expirience of using it. (Finished Chapter 5) Server Framework 101 (Chapter 5) --- estate/__manifest__.py | 2 ++ estate/models/estate_property.py | 11 ++++++++--- estate/views/__init__.py | 1 + estate/views/estate_menus.xml | 8 ++++++++ estate/views/estate_property_views.xml | 8 ++++++++ 5 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 estate/views/__init__.py 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 0f9d2c3204a..bd075a5a257 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -4,5 +4,7 @@ 'application': True, '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 80d1e661544..3d3edbf7c97 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -8,10 +8,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=fields.Datetime.today().replace(month=fields.Datetime.today().month +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() @@ -20,3 +20,8 @@ class EstateProperty(models.Model): garden_orientation = fields.Selection( selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], ) + state = fields.Selection(required=True, copy=False, default='new', + selection=[('new', 'New'), ('offer_recieved', 'Offer Recieved'), ('offer_accepted', 'Offer Accepted'), + ('sold', 'Sold'),('cancelled','Cancelled')], + ) + active = fields.Boolean(default=True) \ No newline at end of file diff --git a/estate/views/__init__.py b/estate/views/__init__.py new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/estate/views/__init__.py @@ -0,0 +1 @@ + diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..b3f11a0a77c --- /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..819f012165b --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,8 @@ + + + + Properties + estate.property + list,form + + \ No newline at end of file From 5b448e481de6fbe763bfdd908bd74a8a910aaffb Mon Sep 17 00:00:00 2001 From: "Valentyn Dementiev (vadem)" Date: Wed, 16 Sep 2026 11:38:06 +0200 Subject: [PATCH 5/9] [ADD] Estate:New views and search options added Created new form-view for estate model, also changed list view for better displaying of data. Added new search options and few predefined filter/group-by options Chapter 6: Basic Views --- estate/views/estate_property_views.xml | 80 ++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 819f012165b..42067971a0e 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -5,4 +5,84 @@ estate.property list,form + + + Estate List + estate.property + + + + + + + + + + + + + + + Properties + estate.property + +
+ +

+ +

+
+
+ + + + +
+
+ + + + +
+
+ + + +
+
+ + + + + + + + + + +
+
+
+
+
+
+
+
+ + + Properties + estate.property + + + + + + + + + + + + + \ No newline at end of file From e3f80050be3337fd1eb3f32f243ddc0e29989610 Mon Sep 17 00:00:00 2001 From: "Valentyn Dementiev (vadem)" Date: Thu, 17 Sep 2026 11:52:44 +0200 Subject: [PATCH 6/9] [ADD] Estate:relations between models added Added new models (tag, type and offer for estate), and established relations between those models. Also some minor fixes due to PR commits and ci/style Server framework 101 - Chapter 7 --- .gitignore | 1 - estate/__manifest__.py | 3 +++ estate/models/__init__.py | 3 +++ estate/models/estate_property.py | 14 ++++++++++--- estate/models/estate_property_offer.py | 13 ++++++++++++ estate/models/estate_property_tag.py | 9 ++++++++ estate/models/estate_property_type.py | 9 ++++++++ estate/security/ir.model.access.csv | 5 ++++- estate/views/__init__.py | 1 - estate/views/estate_menus.xml | 4 ++++ estate/views/estate_property_offer_views.xml | 15 +++++++++++++ estate/views/estate_property_tag_views.xml | 22 ++++++++++++++++++++ estate/views/estate_property_type_views.xml | 22 ++++++++++++++++++++ estate/views/estate_property_views.xml | 20 ++++++++++++++++++ 14 files changed, 135 insertions(+), 6 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 delete mode 100644 estate/views/__init__.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/.gitignore b/.gitignore index 433bf00f4af..b6e47617de1 100644 --- a/.gitignore +++ b/.gitignore @@ -127,4 +127,3 @@ dmypy.json # Pyre type checker .pyre/ -estate/.vscode/settings.json diff --git a/estate/__manifest__.py b/estate/__manifest__.py index bd075a5a257..39492064009 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -4,7 +4,10 @@ 'application': True, 'data': [ 'security/ir.model.access.csv', + 'views/estate_property_tag_views.xml', + 'views/estate_property_type_views.xml', 'views/estate_property_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..09b2099fe84 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 \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 3d3edbf7c97..7d168be8d14 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -5,10 +5,11 @@ class EstateProperty(models.Model): _name = "estate.property" _description = "This is estate property model" + property_type_id = fields.Many2one("estate.property.type", string="Type") name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date(copy=False, default=fields.Datetime.today().replace(month=fields.Datetime.today().month +3)) + date_availability = fields.Date(copy=False, default=lambda self: fields.Date.add(fields.Date.today(), months=3)) expected_price = fields.Float(required=True) selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) @@ -22,6 +23,13 @@ class EstateProperty(models.Model): ) state = fields.Selection(required=True, copy=False, default='new', selection=[('new', 'New'), ('offer_recieved', 'Offer Recieved'), ('offer_accepted', 'Offer Accepted'), - ('sold', 'Sold'),('cancelled','Cancelled')], + ('sold', 'Sold'),('cancelled', 'Cancelled')], ) - active = fields.Boolean(default=True) \ No newline at end of file + active = fields.Boolean(default=True) + + buyer_id =fields.Many2one("res.partner", string="Buyer", copy=False) + salesperson_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user) + + tag_ids = fields.Many2many("estate.property.tag") + offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") + \ No newline at end of file diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py new file mode 100644 index 00000000000..6169cc339c1 --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,13 @@ +from odoo import models, fields + + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Estate property offer" + + price = fields.Float() + status = fields.Selection(copy=False, selection=[('accepted', 'Accepted'), ('refused', 'Refused')],) + + partner_id = fields.Many2one("res.partner", required=True) + property_id = fields.Many2one("estate.property", required=True) + \ No newline at end of file diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..16c1d45383d --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,9 @@ +from odoo import models, fields + + +class EstatePropertyTag(models.Model): + _name = "estate.property.tag" + _description = "Tag for estate property" + + 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..9eefc5eef4e --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,9 @@ +from odoo import models, fields + + +class EstatePropertyType(models.Model): + _name = "estate.property.type" + _description = "Type of estate property" + + 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 3eef86fe077..ae34870f243 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 -estate.access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 \ No newline at end of file +estate.access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 +estate.access_estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 +estate.access_estate_property_tag,access_estate_property_tag,model_estate_property_tag,base.group_user,1,1,1,1 +estate.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/__init__.py b/estate/views/__init__.py deleted file mode 100644 index 8b137891791..00000000000 --- a/estate/views/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index b3f11a0a77c..1230676b167 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -4,5 +4,9 @@ + + + + \ 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..1c2eff2ad65 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,15 @@ + + + + Estate Offers + estate.property.offer + + + + + + + + + + \ No newline at end of file diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 00000000000..b16f0c15a67 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,22 @@ + + + + Property tags + estate.property.tag + list,form + + + + Properties + estate.property.tag + +
+ +

+ +

+
+
+
+
+
\ 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..2a4d96a9bd9 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,22 @@ + + + + Property types + estate.property.type + list,form + + + + Properties + estate.property.type + +
+ +

+ +

+
+
+
+
+
\ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 42067971a0e..623d3106da9 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -12,6 +12,7 @@ + @@ -31,6 +32,9 @@

+
+ +
@@ -52,6 +56,7 @@
+ @@ -63,6 +68,21 @@
+ + + + + + +
+
+ + + + +
+
+
From 904f5a592541902f34c80fb67f48d44cc86358fd Mon Sep 17 00:00:00 2001 From: "Valentyn Dementiev (vadem)" Date: Thu, 17 Sep 2026 13:12:50 +0200 Subject: [PATCH 7/9] [CLN] Estste: code cleanup Cleaned code - trying to make runbot green. Used ruff PR #1430 --- estate/__manifest__.py | 20 +++--- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 36 ++++++---- estate/models/estate_property_offer.py | 8 ++- estate/models/estate_property_tag.py | 1 - estate/models/estate_property_type.py | 1 - estate/views/estate_menus.xml | 6 +- estate/views/estate_property_offer_views.xml | 6 +- estate/views/estate_property_tag_views.xml | 2 +- estate/views/estate_property_type_views.xml | 2 +- estate/views/estate_property_views.xml | 69 ++++++++++---------- 11 files changed, 84 insertions(+), 69 deletions(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 39492064009..ce26a3e9a33 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,13 +1,13 @@ { - 'name': "Estate module", - 'depends': ['base'], - 'application': True, - 'data': [ - 'security/ir.model.access.csv', - 'views/estate_property_tag_views.xml', - 'views/estate_property_type_views.xml', - 'views/estate_property_views.xml', - 'views/estate_property_offer_views.xml', - 'views/estate_menus.xml' + "name": "Estate module", + "depends": ["base"], + "application": True, + "data": [ + "security/ir.model.access.csv", + "views/estate_property_tag_views.xml", + "views/estate_property_type_views.xml", + "views/estate_property_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 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.py b/estate/models/estate_property.py index 7d168be8d14..6bf307eb73b 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -9,7 +9,9 @@ class EstateProperty(models.Model): name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date(copy=False, default=lambda self: fields.Date.add(fields.Date.today(), months=3)) + date_availability = fields.Date( + copy=False, default=lambda self: fields.Date.add(fields.Date.today(), months=3) + ) expected_price = fields.Float(required=True) selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) @@ -19,17 +21,29 @@ class EstateProperty(models.Model): garden = fields.Boolean() garden_area = fields.Integer() garden_orientation = fields.Selection( - selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], + selection=[ + ("north", "North"), + ("south", "South"), + ("east", "East"), + ("west", "West"), + ], + ) + state = fields.Selection( + required=True, + copy=False, + default="new", + selection=[ + ("new", "New"), + ("offer_recieved", "Offer Recieved"), + ("offer_accepted", "Offer Accepted"), + ("sold", "Sold"), + ("cancelled", "Cancelled"), + ], ) - state = fields.Selection(required=True, copy=False, default='new', - selection=[('new', 'New'), ('offer_recieved', 'Offer Recieved'), ('offer_accepted', 'Offer Accepted'), - ('sold', 'Sold'),('cancelled', 'Cancelled')], - ) active = fields.Boolean(default=True) - - buyer_id =fields.Many2one("res.partner", string="Buyer", copy=False) - salesperson_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user) - + buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) + salesperson_id = fields.Many2one( + "res.users", string="Salesperson", default=lambda self: self.env.user + ) tag_ids = fields.Many2many("estate.property.tag") offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") - \ No newline at end of file diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 6169cc339c1..f207748dfa7 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -6,8 +6,10 @@ class EstatePropertyOffer(models.Model): _description = "Estate property offer" price = fields.Float() - status = fields.Selection(copy=False, selection=[('accepted', 'Accepted'), ('refused', 'Refused')],) - + status = fields.Selection( + copy=False, + selection=[("accepted", "Accepted"), ("refused", "Refused")], + ) + partner_id = fields.Many2one("res.partner", required=True) property_id = fields.Many2one("estate.property", required=True) - \ No newline at end of file diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py index 16c1d45383d..f4b6d4c6f11 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -6,4 +6,3 @@ class EstatePropertyTag(models.Model): _description = "Tag for estate property" 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 index 9eefc5eef4e..97f445a9523 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -6,4 +6,3 @@ class EstatePropertyType(models.Model): _description = "Type of estate property" name = fields.Char(required=True) - \ No newline at end of file diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 1230676b167..a3c796652dd 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -2,11 +2,11 @@ - + - - + + \ 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 1c2eff2ad65..12e29d432ab 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -5,9 +5,9 @@ estate.property.offer - - - + + + diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml index b16f0c15a67..11122174470 100644 --- a/estate/views/estate_property_tag_views.xml +++ b/estate/views/estate_property_tag_views.xml @@ -13,7 +13,7 @@

- +

diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml index 2a4d96a9bd9..6a01daccf0c 100644 --- a/estate/views/estate_property_type_views.xml +++ b/estate/views/estate_property_type_views.xml @@ -13,7 +13,7 @@

- +

diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 623d3106da9..1d8a430a987 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -11,14 +11,14 @@ estate.property - - - - - - - - + + + + + + + + @@ -30,22 +30,22 @@

- +

- +
- - + +
- - + +
@@ -55,30 +55,30 @@
- - - - - - - - - + + + + + + + + +
- +
- - + +
@@ -94,14 +94,15 @@ estate.property - - - - - - - - + + + + + + + + From 8bbe449c7b2fee4c52256bd34d4ef42f9150571c Mon Sep 17 00:00:00 2001 From: "Valentyn Dementiev (vadem)" Date: Fri, 18 Sep 2026 09:20:32 +0200 Subject: [PATCH 8/9] [ADD] Estate: added some computed fields added logic to compute some fields (such as total area and best offer price) Finished Chapter 8 Server framework 101 - Chapter 8 --- estate/__manifest__.py | 2 ++ estate/models/estate_property.py | 23 +++++++++++++++++++- estate/models/estate_property_offer.py | 19 +++++++++++++++- estate/views/estate_property_offer_views.xml | 3 ++- estate/views/estate_property_views.xml | 6 +++-- 5 files changed, 48 insertions(+), 5 deletions(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index ce26a3e9a33..628bdce0424 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -2,6 +2,8 @@ "name": "Estate module", "depends": ["base"], "application": True, + "author": "vadem", + "license": "LGPL-3", "data": [ "security/ir.model.access.csv", "views/estate_property_tag_views.xml", diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 6bf307eb73b..5a7b0cab5ef 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 api, models, fields class EstateProperty(models.Model): @@ -13,6 +13,7 @@ class EstateProperty(models.Model): copy=False, default=lambda self: fields.Date.add(fields.Date.today(), months=3) ) expected_price = fields.Float(required=True) + best_price = fields.Float(compute="_find_best_price") selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) living_area = fields.Integer() @@ -41,9 +42,29 @@ class EstateProperty(models.Model): ], ) active = fields.Boolean(default=True) + total_area = fields.Integer(compute="_compute_total_area") buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) salesperson_id = fields.Many2one( "res.users", string="Salesperson", default=lambda self: self.env.user ) tag_ids = fields.Many2many("estate.property.tag") offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") + + @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("salesperson_id") + def _find_best_price(self): + for record in self: + record.best_price = max(record.offer_ids.mapped('price')) + + @api.onchange("garden") + def _onchange_garden(self): + if self.garden == True: + self.garden_area = 10 + self.garden_orientation = "north" + else: + self.garden_area = 0 + self.garden_orientation = "" \ No newline at end of file diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index f207748dfa7..9ff371109b2 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,4 @@ -from odoo import models, fields +from odoo import api, models, fields class EstatePropertyOffer(models.Model): @@ -10,6 +10,23 @@ class EstatePropertyOffer(models.Model): copy=False, selection=[("accepted", "Accepted"), ("refused", "Refused")], ) + validity = fields.Integer(default=7) + date_deadline = fields.Date( + compute="_compute_deadline", inverse="_inverse_deadline" + ) partner_id = fields.Many2one("res.partner", required=True) property_id = fields.Many2one("estate.property", required=True) + + @api.depends("validity","create_date") + def _compute_deadline(self): + for record in self: + base_date = record.create_date.date() if record.create_date else fields.Date.today() + record.date_deadline = fields.Date.add(base_date, days=record.validity) + + def _inverse_deadline(self): + for record in self: + if not record.date_deadline: + continue + base_date = record.create_date.date() if record.create_date else fields.Date.today() + record.validity = (record.date_deadline - base_date).days diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 12e29d432ab..e2fe5866f8e 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -7,8 +7,9 @@ + + - diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 1d8a430a987..ccff0d64f6c 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -38,6 +38,7 @@
+ @@ -45,6 +46,7 @@
+
@@ -56,12 +58,12 @@
- - + + From 1b4a28d1014823b639d7f69110ef6ffb041e2ebc Mon Sep 17 00:00:00 2001 From: "Valentyn Dementiev (vadem)" Date: Fri, 18 Sep 2026 09:30:42 +0200 Subject: [PATCH 9/9] [CLN] Estate: cleaned models code --- estate/models/estate_property.py | 12 ++++++------ estate/models/estate_property_offer.py | 10 +++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 5a7b0cab5ef..866ef7ed996 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -49,22 +49,22 @@ class EstateProperty(models.Model): ) tag_ids = fields.Many2many("estate.property.tag") offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") - + @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("salesperson_id") def _find_best_price(self): for record in self: - record.best_price = max(record.offer_ids.mapped('price')) - + record.best_price = max(record.offer_ids.mapped("price")) + @api.onchange("garden") def _onchange_garden(self): - if self.garden == True: + if self.garden: self.garden_area = 10 self.garden_orientation = "north" else: self.garden_area = 0 - self.garden_orientation = "" \ No newline at end of file + self.garden_orientation = "" diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 9ff371109b2..07a8b958d36 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -18,15 +18,19 @@ class EstatePropertyOffer(models.Model): partner_id = fields.Many2one("res.partner", required=True) property_id = fields.Many2one("estate.property", required=True) - @api.depends("validity","create_date") + @api.depends("validity", "create_date") def _compute_deadline(self): for record in self: - base_date = record.create_date.date() if record.create_date else fields.Date.today() + base_date = ( + record.create_date.date() if record.create_date else fields.Date.today() + ) record.date_deadline = fields.Date.add(base_date, days=record.validity) def _inverse_deadline(self): for record in self: if not record.date_deadline: continue - base_date = record.create_date.date() if record.create_date else fields.Date.today() + base_date = ( + record.create_date.date() if record.create_date else fields.Date.today() + ) record.validity = (record.date_deadline - base_date).days