From c21c5ba7bea9e079ca3769ee5aa3131b7cc61ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Faruk=20Avc=C4=B1?= <55799734+Faruk372742@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:12:50 +0100 Subject: [PATCH 01/10] [ADD] estate: initialize the estate app - Chapter 2 Creating the manifest file. --- estate/__init__.py | 0 estate/__manifest__.py | 16 ++++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 estate/__init__.py create mode 100644 estate/__manifest__.py diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..b0f00a1cd33 --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +{ + 'name': "estate", + + 'author': "Faruk", + 'website': "", + 'category': 'Tutorials', + 'version': '0.1', + 'application': True, + 'installable': True, + 'application': True, + 'depends': ['base'], + + 'data': [], + 'assets': {}, +} From dd58b675fd2b85c5b269762cfe9876796d839aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Faruk=20Avc=C4=B1?= <55799734+Faruk372742@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:41:35 +0100 Subject: [PATCH 02/10] [ADD] estate: adding estate property table - Chapter 3 --- estate/__init__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 17 +++++++++++++++++ 3 files changed, 19 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..5eba9f6eca8 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,17 @@ +from odoo import fields, models +class EstateProperty(models.Model): + _name = "estate_property" + _description = "Estate Property" + name = fields.Char(required = True) + description = fields.Text() + postcode = fields.Char() + date_availability = fields.Date() + expected_price = fields.Float(required = True) + selling_price = fields.Float() + bedrooms = fields.Integer() + living_area = fields.Integer() + facades = fields.Integer() + garage = fields.Boolean() + garden = fields.Boolean() + garden_area = fields.Integer() + garden_orientation = fields.Selection(string="Orientation", selection = [("North", "North"), ("South", "South"), ("East", "East"), ("West", "West")]) \ No newline at end of file From b4bd38a6d29fbe6d619a1e6c69067dfbfe1f6714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Faruk=20Avc=C4=B1?= <55799734+Faruk372742@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:08:15 +0100 Subject: [PATCH 03/10] [ADD] estate: adding security for estate_property table - Chapter 4 New ir.model.access file to adding all kind of accesses to the base.group_user and connecting csv file to manifest [LINT] estate: fixing linter issues [LINT] estate: adding new lines to the end of the few file --- estate/__init__.py | 2 +- estate/__manifest__.py | 10 +++++----- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 9 ++++++--- estate/security/ir.model.access.csv | 2 ++ 5 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 estate/security/ir.model.access.csv 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 b0f00a1cd33..cc068a05f92 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,16 +1,16 @@ -# -*- coding: utf-8 -*- { 'name': "estate", - 'author': "Faruk", 'website': "", 'category': 'Tutorials', 'version': '0.1', 'application': True, 'installable': True, - 'application': True, 'depends': ['base'], - - 'data': [], + 'data': [ + 'security/ir.model.access.csv' + ], 'assets': {}, + 'author': 'Odoo S.A.', + 'license': 'LGPL-3', } 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 5eba9f6eca8..2dc8d58f9a6 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,12 +1,14 @@ from odoo import fields, models + + class EstateProperty(models.Model): _name = "estate_property" _description = "Estate Property" - 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() @@ -14,4 +16,5 @@ class EstateProperty(models.Model): garage = fields.Boolean() garden = fields.Boolean() garden_area = fields.Integer() - garden_orientation = fields.Selection(string="Orientation", selection = [("North", "North"), ("South", "South"), ("East", "East"), ("West", "West")]) \ No newline at end of file + garden_orientation = fields.Selection(string="Orientation", selection=[("North", "North"), ("South", "South"), ("East", "East"), ("West", "West")]) + \ 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..976b61e8cb3 --- /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 +access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 \ No newline at end of file From 923489a5b801a94d94ff56e4e8cf7ebaed7b7a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Faruk=20Avc=C4=B1?= Date: Tue, 16 Dec 2025 13:21:17 +0100 Subject: [PATCH 04/10] [ADD] estate: adding menus and changing fields - Chapter 5 [LINT] estate: linting all python files with ruff --- estate/__manifest__.py | 27 ++++++++++---------- estate/models/estate_property.py | 34 ++++++++++++++++++++++---- estate/views/estate_menus.xml | 8 ++++++ estate/views/estate_property_views.xml | 8 ++++++ 4 files changed, 59 insertions(+), 18 deletions(-) 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 cc068a05f92..0864d0ac4f0 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,16 +1,17 @@ { - 'name': "estate", - - 'website': "", - 'category': 'Tutorials', - 'version': '0.1', - 'application': True, - 'installable': True, - 'depends': ['base'], - 'data': [ - 'security/ir.model.access.csv' + "name": "estate", + "website": "", + "category": "Tutorials", + "version": "0.1", + "application": True, + "installable": True, + "depends": ["base"], + "data": [ + "security/ir.model.access.csv", + "views/estate_property_views.xml", + "views/estate_menus.xml", ], - 'assets': {}, - 'author': 'Odoo S.A.', - 'license': 'LGPL-3', + "assets": {}, + "author": "Odoo S.A.", + "license": "LGPL-3", } diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 2dc8d58f9a6..8264e3e691c 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,6 @@ from odoo import fields, models +from dateutil.relativedelta import relativedelta +from datetime import datetime class EstateProperty(models.Model): @@ -7,14 +9,36 @@ 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=datetime.now() + 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() garden = fields.Boolean() garden_area = fields.Integer() - garden_orientation = fields.Selection(string="Orientation", selection=[("North", "North"), ("South", "South"), ("East", "East"), ("West", "West")]) - \ No newline at end of file + garden_orientation = fields.Selection( + string="Orientation", + selection=[ + ("North", "North"), + ("South", "South"), + ("East", "East"), + ("West", "West"), + ], + ) + 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", + required=True, + copy=False, + ) diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..173b5299633 --- /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..825ae24d7d4 --- /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 7365fae260c6c9526fe58b25d88d5fec24b7dbfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Faruk=20Avc=C4=B1?= Date: Tue, 16 Dec 2025 21:19:46 +0100 Subject: [PATCH 05/10] [IMP] estate: adding list,form, search views (filters + group by) - Chapter 6 add: state field to the estate_property model security: readonly and all-rights security groups are created views: list, form, search views are created, in search view state filter and postcode groupby features are added manifest is updated with the security file --- estate/__manifest__.py | 1 + estate/models/estate_property.py | 24 +++---- estate/security/ir.model.access.csv | 3 +- estate/security/security.xml | 10 +++ estate/views/estate_property_views.xml | 93 ++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 13 deletions(-) create mode 100644 estate/security/security.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 0864d0ac4f0..6b00d13ca5f 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,6 +7,7 @@ "installable": True, "depends": ["base"], "data": [ + "security/security.xml", "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 8264e3e691c..5650d584826 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -6,7 +6,7 @@ class EstateProperty(models.Model): _name = "estate_property" _description = "Estate Property" - name = fields.Char(required=True) + name = fields.Char("Title", required=True) description = fields.Text() postcode = fields.Char() date_availability = fields.Date( @@ -15,7 +15,7 @@ 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("Living Area (sqm)") facades = fields.Integer() garage = fields.Boolean() garden = fields.Boolean() @@ -23,22 +23,22 @@ class EstateProperty(models.Model): garden_orientation = fields.Selection( string="Orientation", selection=[ - ("North", "North"), - ("South", "South"), - ("East", "East"), - ("West", "West"), + ("north", "North"), + ("south", "South"), + ("east", "East"), + ("west", "West"), ], ) active = fields.Boolean(default=True) state = fields.Selection( selection=[ - ("New", "New"), - ("Offer Received", "Offer Received"), - ("Offer Accepted", "Offer Accepted"), - ("Sold", "Sold"), - ("Cancelled", "Cancelled"), + ("new", "New"), + ("offer_received", "Offer Received"), + ("offer_accepted", "Offer Accepted"), + ("sold", "Sold"), + ("cancelled", "Cancelled"), ], - default="New", + default="new", required=True, copy=False, ) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 976b61e8cb3..2fd19e204e0 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,3 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink -access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 \ No newline at end of file +access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 +access_estate_property_readonly,access_estate_property_readonly,model_estate_property,group_readonly_user,1,0,0,0 \ No newline at end of file diff --git a/estate/security/security.xml b/estate/security/security.xml new file mode 100644 index 00000000000..9a3a82d065c --- /dev/null +++ b/estate/security/security.xml @@ -0,0 +1,10 @@ + + + + Complete User + + + Readonly User + + + \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 825ae24d7d4..b933be1ab55 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,5 +1,98 @@ + + estate_property.list + estate_property + + + + + + + + + + + + + + + estate_property.search + estate_property + + + + + + + + + + + + + + + + estate_property.form + estate_property + +
+ +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
Properties estate_property From 40660a84e6b0be8373af011203ae6cc01eb9ac23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Faruk=20Avc=C4=B1?= Date: Wed, 17 Dec 2025 13:46:34 +0100 Subject: [PATCH 06/10] [IMP] estate: adding relations between models - Chapter 7 new models: estate_property_offer, estate_property_tag estate_property: adding new fields (type, salesperson, buyer, tags, offers) estate_property_view: adding offers to form view, tags to both list and form views estate_property_offer_view: adding list and form views menu: settings menu for types and tags --- estate/__manifest__.py | 3 ++ estate/models/__init__.py | 3 ++ estate/models/estate_property.py | 7 +++++ estate/models/estate_property_offer.py | 12 ++++++++ estate/models/estate_property_tag.py | 7 +++++ estate/models/estate_property_type.py | 7 +++++ estate/security/ir.model.access.csv | 5 +++- estate/views/estate_menus.xml | 5 ++++ estate/views/estate_property_offer_views.xml | 30 ++++++++++++++++++++ estate/views/estate_property_tag_views.xml | 7 +++++ estate/views/estate_property_type_views.xml | 7 +++++ estate/views/estate_property_views.xml | 16 +++++++++++ 12 files changed, 108 insertions(+), 1 deletion(-) 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 6b00d13ca5f..6c0bfe94ed9 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -10,6 +10,9 @@ "security/security.xml", "security/ir.model.access.csv", "views/estate_property_views.xml", + "views/estate_property_type_views.xml", + "views/estate_property_tag_views.xml", + "views/estate_property_offer_views.xml", "views/estate_menus.xml", ], "assets": {}, 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 5650d584826..7ad47d9ec0c 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -42,3 +42,10 @@ class EstateProperty(models.Model): required=True, copy=False, ) + type_id = fields.Many2one("estate_property_type", string="Property Type") + salesperson_id = fields.Many2one( + "res.users", string="Salesperson", default=lambda self: self.env.user + ) + buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) + tag_ids = fields.Many2many("estate_property_tag") + 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..703ac03da10 --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,12 @@ +from odoo import fields, models + + +class EstatePropertyOffer(models.Model): + _name = "estate_property_offer" + _description = "Estate Property Offer" + price = fields.Float() + status = fields.Selection( + [("accepted", "Accepted"), ("refused", "Refused")], copy=False + ) + partner_id = fields.Many2one("res.partner", required=True) + property_id = fields.Many2one("estate_property", required=True) diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..29143419e64 --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,7 @@ +from odoo import fields, models + + +class EstatePropertyTag(models.Model): + _name = "estate_property_tag" + _description = "Estate Property Tag" + name = fields.Char("Name", required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..3b3f6207444 --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,7 @@ +from odoo import fields, models + + +class EstatePropertyType(models.Model): + _name = "estate_property_type" + _description = "Estate Property Type" + name = fields.Char(required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 2fd19e204e0..cafd639e6ba 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,3 +1,6 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 -access_estate_property_readonly,access_estate_property_readonly,model_estate_property,group_readonly_user,1,0,0,0 \ No newline at end of file +access_estate_property_readonly,access_estate_property_readonly,model_estate_property,group_readonly_user,1,0,0,0 +access_estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 +access_estate_property_tag,access_estate_property_tag,model_estate_property_tag,base.group_user,1,1,1,1 +access_estate_property_offer,access_estate_property_offer,model_estate_property_offer,base.group_user,1,1,1,1 \ No newline at end of file diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 173b5299633..3e12d38040c 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -4,5 +4,10 @@ + + + + +
\ 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..51b85b94dd8 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,30 @@ + + + estate_property_offer.list + estate_property_offer + + + + + + + + + + estate_property_offer.form + 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..5a2cfda32d3 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,7 @@ + + + Property Tags + estate_property_tag + list,form + + \ No newline at end of file diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..490becd9d6b --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,7 @@ + + + Property Types + estate_property_type + list,form + + \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index b933be1ab55..207d1641b30 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -12,6 +12,8 @@ + + @@ -27,6 +29,7 @@ + @@ -45,6 +48,7 @@ + @@ -58,8 +62,10 @@ + + @@ -88,6 +94,16 @@ + + + + + + + + + + From 2c596552e8f5a36880995cc8c69d08e33682fb03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Faruk=20Avc=C4=B1?= Date: Thu, 18 Dec 2025 10:27:23 +0100 Subject: [PATCH 07/10] [IMP] estate: add computed fields and onchanges - Chapter 8 computed fields: deadline of the offer, best price from many offers onchange: garden affects garden_area and garden_orientation --- estate/models/estate_property.py | 28 +++++++++++++++++++- estate/models/estate_property_offer.py | 23 +++++++++++++++- estate/views/estate_property_offer_views.xml | 4 +++ estate/views/estate_property_views.xml | 6 ++++- 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 7ad47d9ec0c..06a9c3529c6 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 from dateutil.relativedelta import relativedelta from datetime import datetime @@ -31,6 +31,7 @@ class EstateProperty(models.Model): ) active = fields.Boolean(default=True) state = fields.Selection( + string="State", selection=[ ("new", "New"), ("offer_received", "Offer Received"), @@ -49,3 +50,28 @@ class EstateProperty(models.Model): buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) tag_ids = fields.Many2many("estate_property_tag") offer_ids = fields.One2many("estate_property_offer", "property_id", string="Offers") + total_area = fields.Integer("Total Area (sqm)", compute="_compute_area") + best_price = fields.Float("Best Price", compute="_compute_best_price") + + @api.depends("living_area", "garden_area") + def _compute_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: + record.best_price = ( + 0 + if len(record.offer_ids) == 0 + else max(offer.price for offer in record.offer_ids) + ) + + @api.onchange("garden") + def _onchange_garden(self): + if self.garden: + self.garden_area = 10 + self.garden_orientation = "north" + else: + self.garden_area = False + self.garden_orientation = False diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 703ac03da10..0686294652a 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,5 @@ -from odoo import fields, models +from odoo import api, fields, models +from datetime import timedelta class EstatePropertyOffer(models.Model): @@ -10,3 +11,23 @@ class EstatePropertyOffer(models.Model): ) partner_id = fields.Many2one("res.partner", required=True) property_id = fields.Many2one("estate_property", required=True) + validity = fields.Integer("Validity", default=7) + date_deadline = fields.Date( + "Deadline", compute="_compute_date_deadline", inverse="_inverse_date_deadline" + ) + + @api.depends("validity", "create_date") + def _compute_date_deadline(self): + for record in self: + record.date_deadline = ( + record.create_date or fields.Datetime.now() + ) + timedelta(days=record.validity) + + # @api.depends("create_date", "date_deadline") Not working right now!!! + # def _inverse_date_deadline(self): + # print("Hello!") + # for record in self: + # record.validity = ( + # (record.date_deadline or fields.Datetime.now()) + # - (record.create_date or fields.Datetime.now()) + # ).days diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 51b85b94dd8..4591c556f87 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -7,6 +7,8 @@ + + @@ -21,6 +23,8 @@ + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 207d1641b30..7a7eeb892ca 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -50,6 +50,7 @@ + @@ -92,7 +93,10 @@ - + + + + From 79ff5047d316c4c27480fa846ccd8eedf94435c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Faruk=20Avc=C4=B1?= Date: Thu, 18 Dec 2025 15:17:56 +0100 Subject: [PATCH 08/10] [IMP] estate: adding actions to estate property and estate_property_offers - Chapter 9 estate_property: adding cancel and sold buttons and actions for those buttons estate_property_offer: adding accept and refuse buttons and actions for those buttons learned: actions, exception example, icons in buttons --- estate/models/estate_property.py | 16 +++++++++++ estate/models/estate_property_offer.py | 29 ++++++++++++++++++-- estate/views/estate_property_offer_views.xml | 5 ++++ estate/views/estate_property_views.xml | 7 +++++ 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 06a9c3529c6..1b3f2ae8b82 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,6 +1,7 @@ from odoo import api, fields, models from dateutil.relativedelta import relativedelta from datetime import datetime +from odoo.exceptions import UserError class EstateProperty(models.Model): @@ -31,6 +32,7 @@ class EstateProperty(models.Model): ) active = fields.Boolean(default=True) state = fields.Selection( + readonly=True, string="State", selection=[ ("new", "New"), @@ -75,3 +77,17 @@ def _onchange_garden(self): else: self.garden_area = False self.garden_orientation = False + + def action_cancel_property(self): + if self.state == "sold": + raise UserError("Sold property cannot be cancelled!") + + for record in self: + record.state = "cancelled" + + def action_sell_property(self): + if self.state == "cancelled": + raise UserError("Cancelled property cannot be sold!") + + for record in self: + record.state = "sold" diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 0686294652a..a2fb92431b5 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,5 +1,6 @@ from odoo import api, fields, models from datetime import timedelta +from odoo.exceptions import UserError class EstatePropertyOffer(models.Model): @@ -12,9 +13,7 @@ class EstatePropertyOffer(models.Model): partner_id = fields.Many2one("res.partner", required=True) property_id = fields.Many2one("estate_property", required=True) validity = fields.Integer("Validity", default=7) - date_deadline = fields.Date( - "Deadline", compute="_compute_date_deadline", inverse="_inverse_date_deadline" - ) + date_deadline = fields.Date("Deadline", compute="_compute_date_deadline") @api.depends("validity", "create_date") def _compute_date_deadline(self): @@ -23,6 +22,30 @@ def _compute_date_deadline(self): record.create_date or fields.Datetime.now() ) + timedelta(days=record.validity) + def action_accept_offer(self): + if self.status: + raise UserError("You cannot change the status!") + if self.property_id.state == "offer_accepted": + raise UserError("One offer has been already accepted, sorry!") + if self.property_id.state == "cancelled": + raise UserError("This property is cancelled") + if self.property_id.state == "sold": + raise UserError("This property is sold") + + for record in self: + record.status = "accepted" + record.property_id.selling_price = record.price + record.property_id.buyer_id = record.partner_id + record.property_id.state = "offer_accepted" + return True + + def action_refuse_offer(self): + if self.status: + raise UserError("You cannot change the status!") + for record in self: + record.status = "refused" + return True + # @api.depends("create_date", "date_deadline") Not working right now!!! # def _inverse_date_deadline(self): # print("Hello!") diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 4591c556f87..2488766f1cb 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -9,6 +9,11 @@ + +