From 1575d16898b73c12a820cea2f5005d1beb69d808 Mon Sep 17 00:00:00 2001 From: Jozef Sivek Date: Mon, 17 Aug 2026 18:16:51 +0200 Subject: [PATCH 01/12] [ADD] estate: add initial commit with module directory Chapter 1 --- estate/__init__.py | 0 estate/__manifest__.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) 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..e69de29bb2d From 9bd8644d611b4fee48f715872964cc40be55faa3 Mon Sep 17 00:00:00 2001 From: Jozef Sivek Date: Tue, 18 Aug 2026 11:53:30 +0200 Subject: [PATCH 02/12] [ADD] estate: add empty shell for 'estate' module Chapter 2 --- estate/__manifest__.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index e69de29bb2d..d8311652927 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -0,0 +1,19 @@ +{ + 'name': "A Real Estade Advestisement Demo", + 'version': '1.0', + 'depends': ['base'], + 'author': "Jozef Sivek (josiv)", + 'category': 'Sales', + 'description': """ + Test module for managing real estade advertisement + created as part of the onboarding. + """, + # data files always loaded at installation + 'data': [ + #'views/mymodule_view.xml', + ], + # data files containing optionally loaded demonstration data + 'demo': [ + #'demo/demo_data.xml', + ], +} \ No newline at end of file From ffa69da7d68c647153b70bb65b8fcc548fdacca0 Mon Sep 17 00:00:00 2001 From: Jozef Sivek Date: Tue, 18 Aug 2026 16:17:31 +0200 Subject: [PATCH 03/12] [ADD] estate: add estate_property model and basic fields Chapter 3 --- estate/__init__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 24 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 estate/models/__init__.py create mode 100644 estate/models/estate_property.py diff --git a/estate/__init__.py b/estate/__init__.py index e69de29bb2d..9a7e03eded3 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..f4c8fd6db6d --- /dev/null +++ b/estate/models/__init__.py @@ -0,0 +1 @@ +from . import estate_property \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py new file mode 100644 index 00000000000..0d937759a42 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,24 @@ +from odoo import fields, models + + +class EstateProperty(models.Model): + _name = "estate.property" + _description = "Estate property" + _order = "sequence" + + 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')], + help="garden orientation in respect to main compass directions") + From aac34e204987d3dce34dbf0f422c7e37907e1cd0 Mon Sep 17 00:00:00 2001 From: Jozef Sivek Date: Tue, 18 Aug 2026 17:17:59 +0200 Subject: [PATCH 04/12] [IMP] estate: add broad access rights to estate.property model Chapter 4 --- estate/__manifest__.py | 3 ++- estate/security/ir.model.access.csv | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index d8311652927..a370b7f62b7 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -10,10 +10,11 @@ """, # data files always loaded at installation 'data': [ + 'security/ir.model.access.csv', #'views/mymodule_view.xml', ], # data files containing optionally loaded demonstration data 'demo': [ #'demo/demo_data.xml', ], -} \ No newline at end of file +} diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..98f4671fb0d --- /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,estate.model_estate_property,base.group_user,1,1,1,1 From 28b3b079613806e42b0f2e9b80515d09af9a734c Mon Sep 17 00:00:00 2001 From: Jozef Sivek Date: Wed, 19 Aug 2026 15:30:27 +0200 Subject: [PATCH 05/12] [ADD] estate: add menus, default values, more fields Also fix errors on creation of the record. Chapter 5 --- estate/__init__.py | 2 +- estate/__manifest__.py | 6 +++++- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 21 ++++++++++++++++----- estate/views/estate_menus.xml | 8 ++++++++ estate/views/estate_property_views.xml | 17 +++++++++++++++++ 6 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 estate/views/estate_menus.xml create mode 100644 estate/views/estate_property_views.xml 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 a370b7f62b7..87c5f7b86ca 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -8,10 +8,14 @@ Test module for managing real estade advertisement created as part of the onboarding. """, + 'license': 'LGPL-3', # data files always loaded at installation 'data': [ 'security/ir.model.access.csv', - #'views/mymodule_view.xml', + + 'views/estate_property_views.xml', + + 'views/estate_menus.xml', ], # data files containing optionally loaded demonstration data 'demo': [ 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 0d937759a42..dfcb9e097d1 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -4,15 +4,16 @@ class EstateProperty(models.Model): _name = "estate.property" _description = "Estate property" - _order = "sequence" name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date() + date_availability = fields.Date( + copy=False, + default=fields.Date.add(fields.Date.today(), 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() @@ -21,4 +22,14 @@ class EstateProperty(models.Model): garden_orientation = fields.Selection( selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], help="garden orientation in respect to main compass directions") - + active = fields.Boolean(default=True) + state = fields.Selection( + selection=[ + ('new', 'New'), + ('offer_received', 'Offer Received'), + ('offer_accepted', 'Offer Accepted'), + ('sold', 'Sold'), + ('cancelled', 'Cancelled')], + default='new', + help="State of the estate property") + diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..e9f64e94e15 --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml new file mode 100644 index 00000000000..dea261add1d --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,17 @@ + + + + Properties + estate.property + list,form + +

+ Create a new estate property. +

+ The estate properties can be sold and followed by this application. +

+ ... go hunting for some open oportunities 🦌 +

+
+
+
From a0ae7a0567a53b4d0b3af5fc6a9c41c1a49c12f5 Mon Sep 17 00:00:00 2001 From: Jozef Sivek Date: Wed, 19 Aug 2026 17:36:39 +0200 Subject: [PATCH 06/12] [ADD] estate: add search defaults (filters, group by, etc.) Chapter 6 --- estate/models/estate_property.py | 5 +- estate/views/estate_menus.xml | 2 +- estate/views/estate_property_views.xml | 85 +++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 4 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index dfcb9e097d1..a579d581a86 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -9,16 +9,17 @@ class EstateProperty(models.Model): description = fields.Text() postcode = fields.Char() date_availability = fields.Date( + 'Availale From', copy=False, default=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) - living_area = fields.Integer() + living_area = fields.Integer('Living area (m²)') facades = fields.Integer() garage = fields.Boolean() garden = fields.Boolean() - garden_area = fields.Integer() + garden_area = fields.Integer('Garden area (m²)') garden_orientation = fields.Selection( selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], help="garden orientation in respect to main compass directions") diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index e9f64e94e15..28004930be7 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -2,7 +2,7 @@ - + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index dea261add1d..66f50da4e7c 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,6 +1,6 @@ - + Properties estate.property list,form @@ -14,4 +14,87 @@

+ + + estate.property.list + estate.property + + + + + + + + + + + + + + + estate.property.search + estate.property + + + + + + + + + + + + + + + + + + + + estate.property.form + estate.property + +
+ +
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
From 01ca3f8a993701389c4c12e726244b98eb623c6f Mon Sep 17 00:00:00 2001 From: Jozef Sivek Date: Thu, 20 Aug 2026 14:44:04 +0200 Subject: [PATCH 07/12] [ADD] estate: add tags, types and offers models and views Chapter 7 --- estate/__manifest__.py | 3 + estate/models/__init__.py | 3 + estate/models/estate_property.py | 12 +++- estate/models/estate_property_offer.py | 15 +++++ estate/models/estate_property_tag.py | 8 +++ estate/models/estate_property_type.py | 9 +++ estate/security/ir.model.access.csv | 3 + estate/views/estate_menus.xml | 10 ++- estate/views/estate_property_offer_views.xml | 71 ++++++++++++++++++++ estate/views/estate_property_tag_views.xml | 68 +++++++++++++++++++ estate/views/estate_property_type_views.xml | 70 +++++++++++++++++++ estate/views/estate_property_views.xml | 25 ++++++- 12 files changed, 290 insertions(+), 7 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 87c5f7b86ca..b70325b5226 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -13,6 +13,9 @@ '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_menus.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 a579d581a86..a855faa2b87 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,10 +1,18 @@ from odoo import fields, models - class EstateProperty(models.Model): _name = "estate.property" _description = "Estate property" + property_type_id = fields.Many2one('estate.property.type', string='Property Type') + + buyer_id = fields.Many2one('res.partner', string='Buyer', copy=False) + salesperson_id = fields.Many2one('res.users', string='Saleswoman', default=lambda self: self.env.user) + + tag_ids = fields.Many2many('estate.property.tag', string='Property Tags') + + offer_ids = fields.One2many('estate.property.offer', 'property_id', string='Offers') + name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() @@ -22,7 +30,7 @@ class EstateProperty(models.Model): garden_area = fields.Integer('Garden area (m²)') garden_orientation = fields.Selection( selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], - help="garden orientation in respect to main compass directions") + help="Garden orientation in respect to main compass directions") active = fields.Boolean(default=True) state = fields.Selection( selection=[ diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py new file mode 100644 index 00000000000..d1f49361a1d --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,15 @@ +from odoo import fields, models + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Estate property offer" + + price = fields.Float() + status = fields.Selection( + selection=[ + ('accepted', 'Accepted'), + ('refused', 'Refused')], + copy=False, + help="State of the estate property offer") + 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..e3d1c0fe662 --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,8 @@ +from odoo import fields, models + +class EstatePropertyTag(models.Model): + _name = "estate.property.tag" + _description = "Estate property tag, i.e. simple boolean characteristics of the estate outside the normal properties" + + name = fields.Char(required=True) + visual_code = fields.Char(required=True, help="Visual character for purpose of brief visualization") diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..8dfc3b67473 --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,9 @@ +from odoo import fields, models + +class EstatePropertyType(models.Model): + _name = "estate.property.type" + _description = "Estate property type, i.e. type of the building accourding to the use" + + name = fields.Char(required=True) + description = fields.Text(help="Description of thus estate property type for better user understanding") + code = fields.Char(required=True, help="Single to double character code for identification when space is scarce") diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 98f4671fb0d..0c0b62b7fee 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,estate.model_estate_property,base.group_user,1,1,1,1 +estate.access_estate_property_type,access_estate_property_type,estate.model_estate_property_type,base.group_user,1,1,1,1 +estate.access_estate_property_tag,access_estate_property_tag,estate.model_estate_property_tag,base.group_user,1,1,1,1 +estate.access_estate_property_offer,access_estate_property_offer,estate.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 28004930be7..438c585b6f4 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,8 +1,12 @@ - - - + + + + + + + diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..2c118d61169 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,71 @@ + + + + Property Offers + estate.property.offer + list,form + +

+ Create a new estate property offer. +

+ The estate properties offers are bids for estate buy. +

+ ... go and create some 🔏 +

+
+
+ + + estate.property.offer.list + estate.property.offer + + + + + + + + + + + estate.property.offer.search + 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..8c79426d7fc --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,68 @@ + + + + Property Tags + estate.property.tag + list,form + +

+ Create a new estate property tag. +

+ The estate properties tags characterize estates in additional ways. +

+ ... go and create some 🐈‍⬛ +

+
+
+ + + estate.property.tag.list + estate.property.tag + + + + + + + + + + estate.property.tag.search + estate.property.tag + + + + + + + + + + + + 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..fcec0b509ae --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,70 @@ + + + + Property Types + estate.property.type + list,form + +

+ Create a new estate property type. +

+ The estate properties types which can be sold and followed by this application. +

+ ... go and create some 🏘️ +

+
+
+ + + estate.property.type.list + estate.property.type + + + + + + + + + + estate.property.type.search + estate.property.type + + + + + + + + + + + + + estate.property.type.form + estate.property.type + +
+ +
+

+
+ + + + +
+
+
+
+ +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 66f50da4e7c..1989b724114 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -19,7 +19,7 @@ estate.property.list estate.property - + @@ -27,6 +27,7 @@ + @@ -42,6 +43,7 @@ + estate.property.form estate.property -
+

+ + @@ -91,6 +95,23 @@ + + + + + + + + + + + + + + + + +
From 7af916b0e281126d382542dad1ef3a8ba6dfd718 Mon Sep 17 00:00:00 2001 From: Jozef Sivek Date: Fri, 21 Aug 2026 11:31:43 +0200 Subject: [PATCH 08/12] [IMP] estate: add computed fields and onchanges to improve UI Add computed total area for an estate. Set defaults for garden related fields when selected and clean them when garden is unselected. Chapter 8 --- estate/__manifest__.py | 6 +--- estate/models/estate_property.py | 37 ++++++++++++++++++-- estate/models/estate_property_offer.py | 24 ++++++++++++- estate/views/estate_property_offer_views.xml | 5 +-- estate/views/estate_property_views.xml | 10 +++++- 5 files changed, 71 insertions(+), 11 deletions(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index b70325b5226..4de8b7cd357 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -2,7 +2,7 @@ 'name': "A Real Estade Advestisement Demo", 'version': '1.0', 'depends': ['base'], - 'author': "Jozef Sivek (josiv)", + 'author': "Odoo S.A.", 'category': 'Sales', 'description': """ Test module for managing real estade advertisement @@ -20,8 +20,4 @@ 'views/estate_menus.xml', ], - # data files containing optionally loaded demonstration data - 'demo': [ - #'demo/demo_data.xml', - ], } diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index a855faa2b87..4c6d02c73f4 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,4 @@ -from odoo import fields, models +from odoo import api, fields, models class EstateProperty(models.Model): _name = "estate.property" @@ -41,4 +41,37 @@ class EstateProperty(models.Model): ('cancelled', 'Cancelled')], default='new', help="State of the estate property") - + + total_area = fields.Integer( + 'Total area (m²)', + compute='_compute_total_area', + help='Total area of the estate defined as a sum of living and garden area') + + best_price = fields.Float( + 'Best Offer', + compute='_compute_best_price', + help='Best offer from the availale offers or zero') + + @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): + if len(self.offer_ids) == 0: + for record in self: + record.best_price = 0.0 + else: + for record in self: + record.best_price = min([offer.price for offer in record.offer_ids]) + + @api.onchange('garden') + def _onchange_garden(self): + for record in self: + if record.garden: + record.garden_area = 10 + record.garden_orientation = 'north' + else: + record.garden_area = 0 + record.garden_orientation = None diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index d1f49361a1d..ccce4c7c7c7 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): _name = "estate.property.offer" @@ -13,3 +13,25 @@ class EstatePropertyOffer(models.Model): help="State of the estate property offer") 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', + inverse='_onchange_date_deadline', + help='Deadline defined as date from creation separated by validy dates') + + @api.depends('validity') + def _compute_date_deadline(self): + for record in self: + if record.create_date: + record.date_deadline = fields.Date.add(record.create_date, days=record.validity) + else: + record.date_deadline = fields.Date.add(fields.Datetime.now(), days=record.validity) + + @api.onchange('date_deadline') + def _onchange_date_deadline(self): + for record in self: + if record.create_date: + record.validity = (record.date_deadline - record.create_date.date()).days + diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 2c118d61169..4232f6c8b32 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -59,9 +59,10 @@ - - + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 1989b724114..e7d27bb59ac 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -28,6 +28,7 @@ + @@ -49,7 +50,7 @@ string="Available" name="available" help="display only available estates" - domain="['|', ('state', '=', 'new'), ('state', '=', 'offer_received')]"/> + domain="[('state', 'in', ['new', 'offer_received'])]"/> estate.property
+
+ +

@@ -79,6 +83,7 @@ + @@ -93,6 +98,7 @@ + @@ -101,6 +107,8 @@ + + From 9d25c1b786e32f2e340feb53b54a4df67ed2b41c Mon Sep 17 00:00:00 2001 From: Jozef Sivek Date: Fri, 21 Aug 2026 14:38:42 +0200 Subject: [PATCH 09/12] [IMP] estate: allow estate property offer to be accepted or refused Chapter 9 --- estate/models/estate_property.py | 22 +++++++++++++++++++- estate/models/estate_property_offer.py | 15 ++++++++++++- estate/views/estate_property_offer_views.xml | 4 ++++ estate/views/estate_property_views.xml | 5 +++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 4c6d02c73f4..7700aff0943 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,6 @@ -from odoo import api, fields, models +from odoo import _, api, fields, models +from odoo.exceptions import UserError + class EstateProperty(models.Model): _name = "estate.property" @@ -75,3 +77,21 @@ def _onchange_garden(self): else: record.garden_area = 0 record.garden_orientation = None + + def action_set_property_as_sold(self): + for record in self: + if record.state == 'cancelled': + raise UserError(_("Estate property can not be marked as sold if it was cancelled")) + + record.state = "sold" + + return True + + def action_cancel_property(self): + for record in self: + if record.state == 'sold': + raise UserError(_("Estate property can not be marked as cancelled if it was already sold")) + + record.state = "cancelled" + + return True diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index ccce4c7c7c7..843cb92d77d 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,5 @@ -from odoo import api, fields, models +from odoo import _, api, fields, models +from odoo.exceptions import UserError class EstatePropertyOffer(models.Model): _name = "estate.property.offer" @@ -35,3 +36,15 @@ def _onchange_date_deadline(self): if record.create_date: record.validity = (record.date_deadline - record.create_date.date()).days + def action_accept_offer(self): + for record in self: + if any(o.status == 'accepted' for o in record.property_id.offer_ids): + raise UserError(_("One does not simply accept multiple offers on the property")) + + record.status = 'accepted' + record.property_id.buyer_id = record.partner_id + record.property_id.selling_price = record.price + + def action_refuse_offer(self): + for record in self: + record.status = 'refused' diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 4232f6c8b32..7adcb6dfacb 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -56,6 +56,10 @@ estate.property.offer +
+
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index e7d27bb59ac..f2f7912f104 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -68,6 +68,8 @@
+
@@ -109,6 +111,9 @@ + + +
+

@@ -62,6 +74,17 @@ + + + + + + + + + + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index f2f7912f104..c73f4a9bd73 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -4,6 +4,11 @@ Properties estate.property list,form + + { + 'search_default_available': True + } +

Create a new estate property. @@ -19,14 +24,24 @@ estate.property.list estate.property - + + - + @@ -42,7 +57,11 @@ - + @@ -57,7 +76,6 @@ name="groupby_postcode" context="{'group_by': 'postcode'}"/> - @@ -68,18 +86,35 @@

-
+

- + - + @@ -98,23 +133,45 @@ + + + + + + - - - + + -