From f28308dbc12db402a7e3e525fa0f198272cebf96 Mon Sep 17 00:00:00 2001 From: Alexandre Navez Date: Tue, 15 Sep 2026 11:43:50 +0200 Subject: [PATCH 01/10] [ADD] Real estate module base files --- estate/__init__.py | 0 estate/__manifest__.py | 15 +++++++++++++++ 2 files changed, 15 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..4de392c7d23 --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,15 @@ +{ + 'name': "Real Estate", + 'version': '1.0', + 'depends': ['base'], + 'author': "alnav", + 'category': 'Productivity', + 'description': """ + Our brand new real estate app! + """, + 'application': True, + # data files always loaded at installation + 'data': [], + # data files containing optionally loaded demonstration data + 'demo': [], +} \ No newline at end of file From cdd3405ff62f5ee543a34983e637541cb98f53c1 Mon Sep 17 00:00:00 2001 From: Alexandre Navez Date: Tue, 15 Sep 2026 14:09:27 +0200 Subject: [PATCH 02/10] [FIX] estate: fixed manifest file and added newlines --- estate/__init__.py | 1 + estate/__manifest__.py | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/estate/__init__.py b/estate/__init__.py index e69de29bb2d..8b137891791 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -0,0 +1 @@ + diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 4de392c7d23..1876988e28b 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -2,14 +2,10 @@ 'name': "Real Estate", 'version': '1.0', 'depends': ['base'], - 'author': "alnav", + 'author': "Odoo S.A.", 'category': 'Productivity', 'description': """ Our brand new real estate app! """, 'application': True, - # data files always loaded at installation - 'data': [], - # data files containing optionally loaded demonstration data - 'demo': [], -} \ No newline at end of file +} From c5c3d742b7abf0e92937bd39dfdf7f6036856cb5 Mon Sep 17 00:00:00 2001 From: Alexandre Navez Date: Tue, 15 Sep 2026 14:11:44 +0200 Subject: [PATCH 03/10] [ADD] estate: created Property model --- estate/__init__.py | 2 +- estate/models/__init__.py | 1 + estate/models/estate_property.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) 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 8b137891791..0650744f6bc 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -1 +1 @@ - +from . import models diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..5e1963c9d2f --- /dev/null +++ b/estate/models/__init__.py @@ -0,0 +1 @@ +from . import estate_property diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py new file mode 100644 index 00000000000..943a5f3a2a8 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,28 @@ +from odoo import fields, models + + +class Property(models.Model): + _name = "estate.property" + _description = "Real Estate Property" + + name = fields.Char("Property Name", required=True) + descritpion = fields.Text("Property Description") + postcode = fields.Char("Postcode") + date_availability = fields.Date("Available Date") + expected_price = fields.Float("Expected Price") + selling_price = fields.Float("Selling Price", required=True) + bedrooms = fields.Integer("Number of Bedrooms") + living_area = fields.Integer("Living Area") + facades = fields.Integer("Number of Facades") + has_garage = fields.Boolean("Has a Garage") + has_garden = fields.Boolean("Has a Garden") + garden_area = fields.Integer("Garden Area") + garden_orientation = fields.Selection( + string="Garden Orientation", + selection=[ + ("north", "North"), + ("south", "South"), + ("east", "East"), + ("west", "West") + ] + ) From 5e35e5e4f98925827b7473f5800a4e9a345809f4 Mon Sep 17 00:00:00 2001 From: Alexandre Navez Date: Tue, 15 Sep 2026 15:10:03 +0200 Subject: [PATCH 04/10] [ADD] estate: added access rights to Property model --- estate/__manifest__.py | 17 ++++++++++------- estate/models/estate_property.py | 4 ++-- estate/security/ir.model.access.csv | 2 ++ 3 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 1876988e28b..9f8a6bd5be3 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,11 +1,14 @@ { - 'name': "Real Estate", - 'version': '1.0', - 'depends': ['base'], - 'author': "Odoo S.A.", - 'category': 'Productivity', - 'description': """ + "name": "Real Estate", + "version": "1.0", + "depends": ["base"], + "author": "Odoo S.A.", + "category": "Productivity", + "description": """ Our brand new real estate app! """, - 'application': True, + "application": True, + "data": [ + "security/ir.model.access.csv", + ], } diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 943a5f3a2a8..dc75ff828e6 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -21,8 +21,8 @@ class Property(models.Model): string="Garden Orientation", selection=[ ("north", "North"), - ("south", "South"), - ("east", "East"), + ("south", "South"), + ("east", "East"), ("west", "West") ] ) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..4bda9a1176e --- /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_model,access_estate_property_model,model_estate_property,base.group_user,1,1,1,1 From 8142e1b7b18dc4cd020ef8bcd709088d34bb1e35 Mon Sep 17 00:00:00 2001 From: Alexandre Navez Date: Tue, 15 Sep 2026 16:54:33 +0200 Subject: [PATCH 05/10] [ADD] estate: added Property model action and menus --- estate/__manifest__.py | 3 ++ estate/models/estate_property.py | 40 ++++++++++++++++++++------ estate/views/estate_menus.xml | 8 ++++++ estate/views/estate_property_views.xml | 8 ++++++ 4 files changed, 50 insertions(+), 9 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 9f8a6bd5be3..4d7378aa48b 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -10,5 +10,8 @@ "application": True, "data": [ "security/ir.model.access.csv", + "views/estate_property_views.xml", + "views/estate_menus.xml", ], + "license": "OPL-1", } diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index dc75ff828e6..70372386498 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,3 +1,7 @@ +from datetime import datetime + +from dateutil.relativedelta import relativedelta + from odoo import fields, models @@ -8,21 +12,39 @@ class Property(models.Model): name = fields.Char("Property Name", required=True) descritpion = fields.Text("Property Description") postcode = fields.Char("Postcode") - date_availability = fields.Date("Available Date") + + date_availability = fields.Date("Available Date", copy=False, default=lambda _x: datetime.now() + relativedelta(months=+3)) + expected_price = fields.Float("Expected Price") - selling_price = fields.Float("Selling Price", required=True) - bedrooms = fields.Integer("Number of Bedrooms") + selling_price = fields.Float("Selling Price", copy=False, readonly=True) + + bedrooms = fields.Integer("Number of Bedrooms", default=2) living_area = fields.Integer("Living Area") facades = fields.Integer("Number of Facades") + has_garage = fields.Boolean("Has a Garage") has_garden = fields.Boolean("Has a Garden") garden_area = fields.Integer("Garden Area") garden_orientation = fields.Selection( string="Garden Orientation", - selection=[ - ("north", "North"), - ("south", "South"), - ("east", "East"), - ("west", "West") - ] + selection=[ + ("north", "North"), + ("south", "South"), + ("east", "East"), + ("west", "West"), + ], + ) + + state = fields.Selection( + string="Property State", + selection=[ + ("new", "New"), + ("offer_received", "Offer Received"), + ("offer_accepted", "Offer Accepted"), + ("sold", "Sold"), + ("cancelled", "Cancelled"), + ], + default="new", ) + + active = fields.Boolean(default=True) diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..d61ee34ef85 --- /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..de6c08969de --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,8 @@ + + + + Properties + estate.property + list,form + + From 2dde3965a062b1769076fd4a3cbc834055d85641 Mon Sep 17 00:00:00 2001 From: Alexandre Navez Date: Wed, 16 Sep 2026 12:08:34 +0200 Subject: [PATCH 06/10] [ADD] add custom views for search, list and form views --- estate/models/estate_property.py | 2 +- estate/views/estate_menus.xml | 4 +- estate/views/estate_property_views.xml | 88 ++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 70372386498..686898160d9 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -10,7 +10,7 @@ class Property(models.Model): _description = "Real Estate Property" name = fields.Char("Property Name", required=True) - descritpion = fields.Text("Property Description") + description = fields.Text("Property Description") postcode = fields.Char("Postcode") date_availability = fields.Date("Available Date", copy=False, default=lambda _x: datetime.now() + relativedelta(months=+3)) diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index d61ee34ef85..3467f00e7b9 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,8 +1,8 @@ - + - + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index de6c08969de..97eb177f2d4 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,5 +1,93 @@ + + + Property Lookup + estate.property + + + + + + + + + + + + + + + + + + + + Properties + estate.property + + + + + + + + + + + + + + + Properties + estate.property + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ Properties estate.property From 8df348eb8d2ad2bb8279c05287f7008a4e8c944e Mon Sep 17 00:00:00 2001 From: Alexandre Navez Date: Thu, 17 Sep 2026 10:39:05 +0200 Subject: [PATCH 07/10] [IMP] add property tags, types and offers --- estate/__manifest__.py | 2 + estate/models/__init__.py | 3 ++ estate/models/estate_property.py | 10 ++++- estate/models/estate_property_offer.py | 19 ++++++++++ estate/models/estate_property_tag.py | 8 ++++ estate/models/estate_property_type.py | 8 ++++ estate/security/ir.model.access.csv | 3 ++ estate/views/estate_menus.xml | 10 +++-- estate/views/estate_property_tag_views.xml | 8 ++++ estate/views/estate_property_type_views.xml | 8 ++++ estate/views/estate_property_views.xml | 42 ++++++++++++++++----- 11 files changed, 108 insertions(+), 13 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_tag_views.xml create mode 100644 estate/views/estate_property_type_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 4d7378aa48b..59930d3e30e 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -11,6 +11,8 @@ "data": [ "security/ir.model.access.csv", "views/estate_property_views.xml", + "views/estate_property_type_views.xml", + "views/estate_property_tag_views.xml", "views/estate_menus.xml", ], "license": "OPL-1", diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 5e1963c9d2f..82c319c6537 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,4 @@ from . import estate_property +from . import estate_property_offer +from . import estate_property_type +from . import estate_property_tag diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 686898160d9..8b4a8168d43 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,5 +1,4 @@ from datetime import datetime - from dateutil.relativedelta import relativedelta from odoo import fields, models @@ -47,4 +46,13 @@ class Property(models.Model): default="new", ) + property_type_id = fields.Many2one("estate.property.type", string="Property Type") + + buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) + seller_id = fields.Many2one("res.users", string="Seller", default=lambda self: self.env.user) + + tags_ids = fields.Many2many("estate.property.tag", string="Property Tags") + + offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") + active = fields.Boolean(default=True) diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py new file mode 100644 index 00000000000..f38e489abab --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,19 @@ +from odoo import fields, models + + +class PropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Offer on a Real Estate Property" + + price = fields.Float("Price") + status = fields.Selection( + string="Status", + copy=False, + selection=[ + ("accepted", "Accepted"), + ("refused", "Refused"), + ], + ) + + partner_id = fields.Many2one("res.partner", string="Made by", 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..192cf8b58ee --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,8 @@ +from odoo import fields, models + + +class PropertyTag(models.Model): + _name = "estate.property.tag" + _description = "Real Estate Property Tag" + + name = fields.Char("Tag", required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..ab993856220 --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,8 @@ +from odoo import fields, models + + +class PropertyType(models.Model): + _name = "estate.property.type" + _description = "Real Estate Property Type" + + name = fields.Char(string="Type", required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 4bda9a1176e..4073dc03078 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,5 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink access_estate_property_model,access_estate_property_model,model_estate_property,base.group_user,1,1,1,1 +access_estate_property_type_model,access_estate_property_type_model,model_estate_property_type,base.group_user,1,1,1,1 +access_estate_property_tag_model,access_estate_property_tag_model,model_estate_property_tag,base.group_user,1,1,1,1 +access_estate_property_offer_model,access_estate_property_offer_model,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 3467f00e7b9..d517b995067 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,8 +1,12 @@ - - - + + + + + + + diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 00000000000..4dcd3674e34 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,8 @@ + + + + Property Tags + estate.property.tag + list,form + + diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..e50051fee30 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,8 @@ + + + + Property Types + estate.property.type + list,form + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 97eb177f2d4..c32cc6a4e83 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,7 +1,7 @@ - + Property Lookup estate.property @@ -13,16 +13,16 @@ - - + + - + - + Properties estate.property @@ -38,22 +38,29 @@ - + Properties estate.property
- +

+ + + + + - + + + @@ -82,13 +89,30 @@ + + + + + + + + + + + + + + + + +
- + Properties estate.property list,form From 192b36515d0eb6db6fd7ff04807540e4e1dcb646 Mon Sep 17 00:00:00 2001 From: Alexandre Navez Date: Thu, 17 Sep 2026 13:42:12 +0200 Subject: [PATCH 08/10] [IMP] estate: add fields on property and property offer models --- estate/models/estate_property.py | 25 ++++++++++++++++++++++++- estate/models/estate_property_offer.py | 24 +++++++++++++++++++++++- estate/security/ir.model.access.csv | 8 ++++---- estate/views/estate_menus.xml | 4 ++-- estate/views/estate_property_views.xml | 12 ++++++++---- 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 8b4a8168d43..2ce9ed1c9f6 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,7 +1,7 @@ from datetime import datetime from dateutil.relativedelta import relativedelta -from odoo import fields, models +from odoo import api, fields, models class Property(models.Model): @@ -16,6 +16,7 @@ class Property(models.Model): expected_price = fields.Float("Expected Price") selling_price = fields.Float("Selling Price", copy=False, readonly=True) + best_price = fields.Float("Best offer", compute="_compute_best_price") bedrooms = fields.Integer("Number of Bedrooms", default=2) living_area = fields.Integer("Living Area") @@ -46,6 +47,8 @@ class Property(models.Model): default="new", ) + total_area = fields.Integer("Total Area", compute="_compute_total_area") + property_type_id = fields.Many2one("estate.property.type", string="Property Type") buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) @@ -56,3 +59,23 @@ class Property(models.Model): offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") active = fields.Boolean(default=True) + + @api.depends("offer_ids") + def _compute_best_price(self): + for record in self: + record.best_price = max(record.offer_ids.mapped("price")) + + @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.onchange("has_garden") + def _onchange_has_garden(self): + if self.has_garden: + self.garden_area = 10 + self.garden_orientation = "north" + return + + self.garden_area = 0 + self.garden_orientation = "" diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index f38e489abab..5ac32a7b444 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,6 @@ -from odoo import fields, models +from datetime import datetime, timedelta + +from odoo import api, fields, models class PropertyOffer(models.Model): @@ -15,5 +17,25 @@ class PropertyOffer(models.Model): ], ) + validity = fields.Integer("Validity (in days)", default=7) + + date_deadline = fields.Date("Deadline", compute="_compute_date_deadline", inverse="_inverse_date_deadline") + partner_id = fields.Many2one("res.partner", string="Made by", required=True) property_id = fields.Many2one("estate.property", string="Property", required=True) + + @api.depends("validity") + def _compute_date_deadline(self): + for record in self: + offer_date = record.create_date + if not offer_date: + offer_date = datetime.now() + + record.date_deadline = offer_date.date() + timedelta(days=record.validity) + + def _inverse_date_deadline(self): + for record in self: + offer_date = record.create_date + if not offer_date: + offer_date = datetime.now() + record.validity = (record.date_deadline - offer_date.date()).days diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 4073dc03078..a42bd95f417 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,5 +1,5 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink -access_estate_property_model,access_estate_property_model,model_estate_property,base.group_user,1,1,1,1 -access_estate_property_type_model,access_estate_property_type_model,model_estate_property_type,base.group_user,1,1,1,1 -access_estate_property_tag_model,access_estate_property_tag_model,model_estate_property_tag,base.group_user,1,1,1,1 -access_estate_property_offer_model,access_estate_property_offer_model,model_estate_property_offer,base.group_user,1,1,1,1 +access_estate_property_user,access_estate_property_user,model_estate_property,base.group_user,1,1,1,1 +access_estate_property_type_user,access_estate_property_type_user,model_estate_property_type,base.group_user,1,1,1,1 +access_estate_property_tag_user,access_estate_property_tag_user,model_estate_property_tag,base.group_user,1,1,1,1 +access_estate_property_offer_user,access_estate_property_offer_user,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 d517b995067..c7fb9b1c48b 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,10 +1,10 @@ - + - + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index c32cc6a4e83..621c49f64e0 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -46,20 +46,19 @@

- + + - - - + @@ -88,6 +87,9 @@ + + + @@ -95,6 +97,8 @@ + + From 034c73b0772ad2e5a589510fcff76b33c15c3f98 Mon Sep 17 00:00:00 2001 From: Alexandre Navez Date: Thu, 17 Sep 2026 15:03:52 +0200 Subject: [PATCH 09/10] [IMP] estate: add buttons to manage properties and offers status --- estate/models/estate_property.py | 21 ++++++++++++++++++++- estate/models/estate_property_offer.py | 25 +++++++++++++++++++++++++ estate/views/estate_property_views.xml | 7 +++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 2ce9ed1c9f6..f5f6e700ffe 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -2,6 +2,7 @@ from dateutil.relativedelta import relativedelta from odoo import api, fields, models +from odoo.exceptions import UserError class Property(models.Model): @@ -60,10 +61,28 @@ class Property(models.Model): active = fields.Boolean(default=True) + def action_mark_as_sold(self): + for record in self: + if record.state == "cancelled": + raise UserError(message="Can't sell a cancelled auction.") + + record.state = "sold" + + return True + + def action_cancel_selling(self): + for record in self: + if record.state == "sold": + raise UserError(message="Can't cancel a sold auction.") + + record.state = "cancelled" + + return True + @api.depends("offer_ids") def _compute_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"), default=0.0) @api.depends("living_area", "garden_area") def _compute_total_area(self): diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 5ac32a7b444..eec8f1a3fe8 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,6 +1,7 @@ from datetime import datetime, timedelta from odoo import api, fields, models +from odoo.exceptions import UserError class PropertyOffer(models.Model): @@ -24,6 +25,30 @@ class PropertyOffer(models.Model): partner_id = fields.Many2one("res.partner", string="Made by", required=True) property_id = fields.Many2one("estate.property", string="Property", required=True) + def action_accept_offer(self): + for record in self: + linked_property = record.property_id + states = linked_property.offer_ids.mapped("status") + + if "accepted" in states: + raise UserError(message="An offer was already accepted") + + if linked_property.state == "cancelled": + raise UserError(message="Can't accept offers on cancelled auctions") + + record.status = "accepted" + linked_property.selling_price = record.price + linked_property.buyer_id = record.partner_id + linked_property.state = "sold" + + return True + + def action_reject_offer(self): + for record in self: + record.status = "refused" + + return True + @api.depends("validity") def _compute_date_deadline(self): for record in self: diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 621c49f64e0..b1e1c88cc35 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -43,6 +43,10 @@ estate.property
+
+

@@ -51,6 +55,7 @@ + @@ -99,6 +104,8 @@ +