From cad7fe58289b783ddf78cd52501d9b4d1f25e7c0 Mon Sep 17 00:00:00 2001 From: nsirjacobs Date: Mon, 15 Sep 2025 16:13:00 +0200 Subject: [PATCH 1/7] Estate Beginning --- estate/__init__.py | 2 ++ estate/__manifest__.py | 24 ++++++++++++++++++++++++ estate/models/__init__.py | 1 + estate/models/estate_property.py | 19 +++++++++++++++++++ estate/security/ir.model.access.csv | 2 ++ estate/views/estate_property_views.xml | 12 ++++++++++++ estate/views/menuitems.xml | 8 ++++++++ 7 files changed, 68 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 create mode 100644 estate/security/ir.model.access.csv create mode 100644 estate/views/estate_property_views.xml create mode 100644 estate/views/menuitems.xml diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..899bcc97f0f --- /dev/null +++ b/estate/__init__.py @@ -0,0 +1,2 @@ +from . import models + diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..0a4822534a4 --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Estate Machin", + + 'summary': """ + TO BE DEF" + """, + + 'description': """ + TO BE DEF" + """, + + # any module necessary for this one to work correctly + 'depends': ['base'], + 'application': True, + 'installable': True, + + 'data':[ + 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/menuitems.xml', + ] + +} 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..833b23f74a0 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,19 @@ +from odoo import fields, models + +class estate_property(models.Model): + _name = "estate.property" + _description = "estate thingie" + + 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')]) \ 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..ab63520e22b --- /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 \ 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..6d94b9f162d --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,12 @@ + + + + + + Properties + estate.property + tree + + + + \ No newline at end of file diff --git a/estate/views/menuitems.xml b/estate/views/menuitems.xml new file mode 100644 index 00000000000..b52d1252b78 --- /dev/null +++ b/estate/views/menuitems.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file From 1ca5e462b7ce7ad57a15faaf320bdc5aa1aa7843 Mon Sep 17 00:00:00 2001 From: nsirjacobs Date: Mon, 15 Sep 2025 17:28:15 +0200 Subject: [PATCH 2/7] Added views and fields to Estate --- estate/models/estate_property.py | 11 +++++++---- estate/views/estate_property_views.xml | 23 ++++++++++++++++++++--- estate/views/menuitems.xml | 2 +- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 833b23f74a0..b0427469691 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,5 @@ from odoo import fields, models +from datetime import date, timedelta class estate_property(models.Model): _name = "estate.property" @@ -7,13 +8,15 @@ class estate_property(models.Model): name = fields.Char(required = True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date() + date_availability = fields.Date(copy=False,string="Available From", default=lambda self: date.today() + timedelta(days=90)) 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(selection = [('North', 'North'), ('South', 'South'),('East', 'East'),('West', 'West')]) \ No newline at end of file + garden_orientation = fields.Selection(selection = [('North', 'North'), ('South', 'South'),('East', 'East'),('West', 'West')]) + active = fields.Boolean(default = True) + state = fields.Selection(required = True, default = 'New', copy = False, selection = [('New','New'),('Offer Received','Offer Received'),('Offer Accepted','Offer Accepted'),('Sold','Sold'),('Cancelled','Cancelled')]) \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 6d94b9f162d..efe32109416 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,11 +1,28 @@ - + + + estate.property.list + estate.property + + + + + + + + + + + + + + - + Properties estate.property - tree + list,form diff --git a/estate/views/menuitems.xml b/estate/views/menuitems.xml index b52d1252b78..59fd2960819 100644 --- a/estate/views/menuitems.xml +++ b/estate/views/menuitems.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file From 510961724574689ae8acb6f5127d7e9e86eba4c2 Mon Sep 17 00:00:00 2001 From: nsirjacobs Date: Tue, 16 Sep 2025 15:45:09 +0200 Subject: [PATCH 3/7] Chapter 6 -> 7 Done --- estate/__manifest__.py | 3 + estate/models/__init__.py | 2 +- estate/models/estate_property.py | 7 +- estate/models/estate_property_offer.py | 14 +++ estate/models/estate_property_tag.py | 8 ++ estate/models/estate_property_type.py | 8 ++ estate/security/ir.model.access.csv | 6 +- estate/views/estate_property_offer_views.xml | 39 +++++++++ estate/views/estate_property_tag_views.xml | 38 +++++++++ estate/views/estate_property_type_views.xml | 40 +++++++++ estate/views/estate_property_views.xml | 90 +++++++++++++++++++- estate/views/menuitems.xml | 9 +- 12 files changed, 258 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 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 0a4822534a4..407abbc74e6 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -18,6 +18,9 @@ '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_property_offer_views.xml', 'views/menuitems.xml', ] diff --git a/estate/models/__init__.py b/estate/models/__init__.py index f4c8fd6db6d..e5f89221b05 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, estate_property_type, estate_property_tag, estate_property_offer \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index b0427469691..666a702dea9 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -19,4 +19,9 @@ class estate_property(models.Model): garden_area = fields.Integer() garden_orientation = fields.Selection(selection = [('North', 'North'), ('South', 'South'),('East', 'East'),('West', 'West')]) active = fields.Boolean(default = True) - state = fields.Selection(required = True, default = 'New', copy = False, selection = [('New','New'),('Offer Received','Offer Received'),('Offer Accepted','Offer Accepted'),('Sold','Sold'),('Cancelled','Cancelled')]) \ No newline at end of file + state = fields.Selection(required = True, default = 'New', copy = False, selection = [('New','New'),('Offer Received','Offer Received'),('Offer Accepted','Offer Accepted'),('Sold','Sold'),('Cancelled','Cancelled')]) + property_type_id = fields.Many2one("estate.property.type", string="Model") + sales_user_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user) + buyer_partner_id = fields.Many2one("res.partner", string="Buyer", copy=False) + tags_ids = fields.Many2many("estate.property.tag", string="Tags") + offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") \ 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..b01a16c4ef2 --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,14 @@ +from odoo import fields, models + +class estate_property_offer(models.Model): + _name = "estate.property.offer" + _description = "Estate Offer" + + price = fields.Float(string="Offer Price") + status = fields.Selection( + selection=[('accepted', 'Accepted'), ('refused', 'Refused')], + copy=False, + string="Status" + ) + 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..0cad32401e5 --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,8 @@ +from odoo import fields, models + +class estate_property_tag(models.Model): + _name = "estate.property.tag" + _description = "estate tag" + + 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..cb4f1cbe538 --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,8 @@ +from odoo import fields, models + +class estate_property_type(models.Model): + _name = "estate.property.type" + _description = "estate types" + + 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 ab63520e22b..234df87d330 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,6 @@ 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 \ No newline at end of file +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_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..8bb6f06eda6 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,39 @@ + + + + + + + estate.property.offer.form + estate.property.offer + +
+ + + + + + + + + +
+
+
+ + + + estate.property.offer.list + 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..a9bd14f851f --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,38 @@ + + + + + + + + + estate.property.tag.form + estate.property.tag + +
+ + + + + +
+
+
+ + + + + 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..8931ca76adc --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,40 @@ + + + + + + estate.property.type.list + estate.property.type + + + + + + + + + + estate.property.type.form + estate.property.type + +
+ +
+

+ +

+
+
+
+
+
+ + + + + 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 efe32109416..696ef7efe5b 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -7,23 +7,111 @@ + +
+ + + estate.property.form + estate.property + +
+ +
+

+ +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + + estate.property.search + estate.property + + + + + + + + + + + + + + + + + + + - + Properties estate.property list,form +
\ No newline at end of file diff --git a/estate/views/menuitems.xml b/estate/views/menuitems.xml index 59fd2960819..27699ef3dfb 100644 --- a/estate/views/menuitems.xml +++ b/estate/views/menuitems.xml @@ -1,8 +1,13 @@ - - + + + + + + + \ No newline at end of file From e47b32b835a036aedd827a6b66d0a8618df3ee7a Mon Sep 17 00:00:00 2001 From: nsirjacobs Date: Tue, 16 Sep 2025 17:34:05 +0200 Subject: [PATCH 4/7] Chapter 8 Done --- estate/__init__.py | 1 - estate/__manifest__.py | 33 ++++----- estate/models/__init__.py | 7 +- estate/models/estate_property.py | 73 ++++++++++++++++---- estate/models/estate_property_offer.py | 34 +++++++-- estate/security/ir.model.access.csv | 1 - estate/views/estate_property_offer_views.xml | 15 ++-- estate/views/estate_property_tag_views.xml | 16 +---- estate/views/estate_property_type_views.xml | 6 +- estate/views/estate_property_views.xml | 18 ++--- estate/views/menuitems.xml | 13 ---- estate/views/menus.xml | 13 ++++ 12 files changed, 135 insertions(+), 95 deletions(-) delete mode 100644 estate/views/menuitems.xml create mode 100644 estate/views/menus.xml diff --git a/estate/__init__.py b/estate/__init__.py index 899bcc97f0f..0650744f6bc 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -1,2 +1 @@ from . import models - diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 407abbc74e6..61d8fb77561 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,27 +1,22 @@ # -*- coding: utf-8 -*- { - 'name': "Estate Machin", - - 'summary': """ + "name": "Estate Module", + "summary": """ TO BE DEF" """, - - 'description': """ + "description": """ TO BE DEF" """, - # any module necessary for this one to work correctly - 'depends': ['base'], - 'application': True, - 'installable': True, - - '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_property_offer_views.xml', - 'views/menuitems.xml', - ] - + "depends": ["base"], + "application": True, + "installable": True, + "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_property_offer_views.xml", + "views/menus.xml", + ], } diff --git a/estate/models/__init__.py b/estate/models/__init__.py index e5f89221b05..a0a8b8c501c 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,6 @@ -from . import estate_property, estate_property_type, estate_property_tag, estate_property_offer \ No newline at end of file +from . import ( + estate_property, + estate_property_type, + estate_property_tag, + estate_property_offer, +) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 666a702dea9..1283e0c5642 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,27 +1,74 @@ -from odoo import fields, models -from datetime import date, timedelta +from odoo import fields, models, api +from datetime import timedelta + class estate_property(models.Model): _name = "estate.property" _description = "estate thingie" - name = fields.Char(required = True) - description = fields.Text() + name = fields.Char(required=True) + description = fields.Text() postcode = fields.Char() - date_availability = fields.Date(copy=False,string="Available From", default=lambda self: date.today() + timedelta(days=90)) - expected_price = fields.Float(required = True) - selling_price = fields.Float(readonly = True,copy=False) - bedrooms = fields.Integer(default = 2) + date_availability = fields.Date( + copy=False, + string="Available From", + default=lambda self: fields.Date.today() + timedelta(days=90), + ) + expected_price = fields.Float(required=True) + 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(selection = [('North', 'North'), ('South', 'South'),('East', 'East'),('West', 'West')]) - active = fields.Boolean(default = True) - state = fields.Selection(required = True, default = 'New', copy = False, selection = [('New','New'),('Offer Received','Offer Received'),('Offer Accepted','Offer Accepted'),('Sold','Sold'),('Cancelled','Cancelled')]) + total_area = fields.Float(compute="_compute_total_area") + garden_orientation = fields.Selection( + selection=[ + ("north", "North"), + ("south", "South"), + ("east", "East"), + ("west", "West"), + ] + ) + active = fields.Boolean(default=True) + state = fields.Selection( + required=True, + default="new", + copy=False, + selection=[ + ("new", "New"), + ("offer Received", "Offer Received"), + ("offer Accepted", "Offer Accepted"), + ("sold", "Sold"), + ("cancelled", "Cancelled"), + ], + ) property_type_id = fields.Many2one("estate.property.type", string="Model") - sales_user_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user) + sales_user_id = fields.Many2one( + "res.users", string="Salesperson", default=lambda self: self.env.user + ) buyer_partner_id = fields.Many2one("res.partner", string="Buyer", copy=False) tags_ids = fields.Many2many("estate.property.tag", string="Tags") - offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") \ No newline at end of file + offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") + best_price = fields.Float(compute="_get_highest_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.depends("offer_ids.price") + def _get_highest_price(self): + for record in self: + record.best_price = max(record.mapped("offer_ids.price"), default=0) + + @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 = "" diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index b01a16c4ef2..5c646ab238d 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 odoo import fields, models, api +from datetime import timedelta + class estate_property_offer(models.Model): _name = "estate.property.offer" @@ -6,9 +8,33 @@ class estate_property_offer(models.Model): price = fields.Float(string="Offer Price") status = fields.Selection( - selection=[('accepted', 'Accepted'), ('refused', 'Refused')], + selection=[("accepted", "Accepted"), ("refused", "Refused")], copy=False, - string="Status" + string="Status", ) partner_id = fields.Many2one("res.partner", required=True) - property_id = fields.Many2one("estate.property", required=True) \ No newline at end of file + property_id = fields.Many2one("estate.property", required=True) + validity = fields.Integer(default=7) + date_deadline = fields.Date( + compute="_compute_deadline", inverse="_inverse_deadline" + ) + + @api.depends("validity", "create_date") + def _compute_deadline(self): + for offer in self: + print("B") + if offer.create_date: + offer.date_deadline = offer.create_date.date() + timedelta( + days=offer.validity + ) + else: + offer.date_deadline = fields.Date.today() + timedelta( + days=offer.validity + ) + + def _inverse_deadline(self): + for offer in self: + if offer.create_date: + offer.validity = (offer.date_deadline - offer.create_date.date()).days + else: + offer.validity = (offer.date_deadline - fields.Date.today()).days diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 234df87d330..0c0b62b7fee 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -3,4 +3,3 @@ estate.access_estate_property,access_estate_property,estate.model_estate_propert 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_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 8bb6f06eda6..bd87d9ec983 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -1,8 +1,6 @@ - - estate.property.offer.form estate.property.offer @@ -10,18 +8,17 @@
+ - - - + +
- estate.property.offer.list estate.property.offer @@ -30,10 +27,10 @@ + + - - -
\ No newline at end of file + diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml index a9bd14f851f..e6075ec33fe 100644 --- a/estate/views/estate_property_tag_views.xml +++ b/estate/views/estate_property_tag_views.xml @@ -1,18 +1,6 @@ - - - - estate.property.tag.form estate.property.tag @@ -27,12 +15,10 @@ - - 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 index 8931ca76adc..44d3a82a744 100644 --- a/estate/views/estate_property_type_views.xml +++ b/estate/views/estate_property_type_views.xml @@ -1,7 +1,6 @@ - estate.property.type.list estate.property.type @@ -12,7 +11,6 @@ - estate.property.type.form estate.property.type @@ -29,12 +27,10 @@ - - 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 696ef7efe5b..d816d9b28f7 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -19,8 +19,6 @@ - - estate.property.form estate.property @@ -42,6 +40,7 @@ + @@ -54,6 +53,8 @@ + + @@ -81,8 +82,6 @@ - - estate.property.search estate.property @@ -99,19 +98,10 @@ - - - - - - - Properties estate.property list,form - - - \ No newline at end of file + diff --git a/estate/views/menuitems.xml b/estate/views/menuitems.xml deleted file mode 100644 index 27699ef3dfb..00000000000 --- a/estate/views/menuitems.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/estate/views/menus.xml b/estate/views/menus.xml new file mode 100644 index 00000000000..7b35278830e --- /dev/null +++ b/estate/views/menus.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + From cbf84a61b3cc9cbb2237ed0a66d3d3dc33a6413d Mon Sep 17 00:00:00 2001 From: nsirjacobs Date: Wed, 17 Sep 2025 11:17:22 +0200 Subject: [PATCH 5/7] [IMP] Estate: Added business logic to set selling price according to accepted offers --- estate/models/estate_property.py | 54 ++++++++++++++++++-- estate/models/estate_property_offer.py | 16 +++++- estate/views/estate_property_offer_views.xml | 4 +- estate/views/estate_property_views.xml | 11 ++-- 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 1283e0c5642..5f54559a829 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,10 +1,10 @@ -from odoo import fields, models, api +from odoo import fields, models, api, exceptions from datetime import timedelta class estate_property(models.Model): _name = "estate.property" - _description = "estate thingie" + _description = "estate.property" name = fields.Char(required=True) description = fields.Text() @@ -15,7 +15,9 @@ class estate_property(models.Model): default=lambda self: fields.Date.today() + timedelta(days=90), ) expected_price = fields.Float(required=True) - selling_price = fields.Float(readonly=True, copy=False) + selling_price = fields.Float( + readonly=True, copy=False, compute="_set_selling_price" + ) bedrooms = fields.Integer(default=2) living_area = fields.Integer() facades = fields.Integer() @@ -52,6 +54,10 @@ class estate_property(models.Model): tags_ids = fields.Many2many("estate.property.tag", string="Tags") offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") best_price = fields.Float(compute="_get_highest_price") + has_accepted_offer = fields.Boolean(default=False) + + # --------------------------------------------------------------------------------------------------------- + # Compute Functions @api.depends("living_area", "garden_area") def _compute_total_area(self): @@ -72,3 +78,45 @@ def _onchange_garden(self): else: record.garden_area = 0 record.garden_orientation = "" + + @api.depends("offer_ids.status", "has_accepted_offer") + def _set_selling_price(self): + for record in self: + if not len(record.offer_ids): + record.selling_price = 0 + else: + if len(set(record.mapped("offer_ids.status"))) == 1: + record.selling_price = 0 + record.has_accepted_offer = False + else: + id = record.mapped("offer_ids.status").index("accepted") + record.selling_price = record.mapped("offer_ids.price")[id] + record.has_accepted_offer = True + + # --------------------------------------------------------------------------------------------------------- + # Public Functions + + def set_state_cancelled(self): + for record in self: + if record.state != "sold": + record.state = "cancelled" + else: + raise exceptions.UserError( + ( + "You can't change the offer's state to Cancelled after the offer has been sold" + ) + ) + + return True + + def set_state_sold(self): + for record in self: + if record.state != "cancelled": + record.state = "sold" + else: + raise exceptions.UserError( + ( + "You can't change the offer's state to Sold after the offer has been cancelled" + ) + ) + return True diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 5c646ab238d..f6ff6f5b1b7 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,4 @@ -from odoo import fields, models, api +from odoo import fields, models, api, exceptions from datetime import timedelta @@ -22,7 +22,6 @@ class estate_property_offer(models.Model): @api.depends("validity", "create_date") def _compute_deadline(self): for offer in self: - print("B") if offer.create_date: offer.date_deadline = offer.create_date.date() + timedelta( days=offer.validity @@ -38,3 +37,16 @@ def _inverse_deadline(self): offer.validity = (offer.date_deadline - offer.create_date.date()).days else: offer.validity = (offer.date_deadline - fields.Date.today()).days + + def set_status_accepted(self): + for offer in self: + if not offer.property_id.has_accepted_offer: + offer.status = "accepted" + else: + raise exceptions.UserError(("You can't accept multiple offers")) + return True + + def set_status_refused(self): + for offer in self: + offer.status = "refused" + return True diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index bd87d9ec983..27da0ddf12c 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -25,10 +25,12 @@ - + +

+ + + + + + + + + + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 923309eae22..0fec66e96b2 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -5,15 +5,16 @@ estate.property.list estate.property - + + - + - + @@ -24,20 +25,21 @@
-

- +
- - + + @@ -55,8 +57,8 @@ - - + + @@ -71,8 +73,8 @@ - - + + @@ -97,8 +99,10 @@ - - + + + + @@ -106,6 +110,7 @@ Properties estate.property list,form + {'search_default_Available': True}