From b027a64e873ef140b94ba43426bca2cc17ac3d63 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Tue, 22 Apr 2025 18:38:41 +0200 Subject: [PATCH 01/20] [ADD] estate: Added a new module named estate --- estate/__init__.py | 0 estate/__manifest__.py | 8 ++++++++ 2 files changed, 8 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..c837178bd59 --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,8 @@ +{ + 'name': 'CRM', + 'depends': + ['base'], + 'installable': True, + 'application': True, + 'auto_install': False +} From b33bf48452d191ae56d87278c4aa5102a453d048 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Tue, 22 Apr 2025 19:01:21 +0200 Subject: [PATCH 02/20] [FIX] estate: fixed the name of the module to Real Estate --- estate/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index c837178bd59..f2af8ff6e49 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,5 +1,5 @@ { - 'name': 'CRM', + 'name': 'Real Estate', 'depends': ['base'], 'installable': True, From 329a38133ca71de776689fd6653eeb963bfe6fbc Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Tue, 22 Apr 2025 22:12:48 +0200 Subject: [PATCH 03/20] [IMP] estate: created a model for estate_property in db --- estate/__init__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 23 +++++++++++++++++++++++ 3 files changed, 25 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..0650744f6bc 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -0,0 +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..973b9d540dc --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,23 @@ +from odoo import fields, models + + +class EstateProperty(models.Model): + _name = "estate.property" + _description = "Estate Property discription" + + name = fields.Char('name', required=True) + description = fields.Text('description') + postcode = fields.Char('postcode') + date_availability = fields.Date('availabilty date') + expected_price = fields.Float('expected price', required=True) + selling_price = fields.Float('selling price') + bedrooms = fields.Integer('bedrooms') + living_area = fields.Integer('living area') + facades = fields.Integer('facades') + garage = fields.Boolean('garage') + garden_area = fields.Integer('garden area') + garden_orientation = fields.Selection( + string='Garden Orientation', + selection=[('North', 'North'), ('South', 'South'), + ('East', 'East'), ('West', 'West')] + ) From 078c25808bc34b39229428727fa8790a941f4c1f Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Wed, 23 Apr 2025 09:27:44 +0200 Subject: [PATCH 04/20] [FIX] estate: added a licence key in manifest --- estate/__manifest__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index f2af8ff6e49..78c5a4d06b3 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -4,5 +4,6 @@ ['base'], 'installable': True, 'application': True, - 'auto_install': False + 'auto_install': False, + 'license': 'AGPL-3', } From c9b1decdfc97ca936199b40654361c2afbce3da9 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Wed, 23 Apr 2025 10:16:55 +0200 Subject: [PATCH 05/20] [IMP] estate: give all right access to base group user for estate_ proprty --- estate/__manifest__.py | 3 +++ estate/security/ir.model.access.csv | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 78c5a4d06b3..5a309d68fba 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -2,6 +2,9 @@ 'name': 'Real Estate', 'depends': ['base'], + 'data': [ + 'security/ir.model.access.csv', + ], 'installable': True, 'application': True, 'auto_install': False, diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..4204e66ff28 --- /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 365d98618bc4724eb204ccba7f965957d7ae3a57 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Wed, 23 Apr 2025 11:12:45 +0200 Subject: [PATCH 06/20] [IMP] estate: add root menu and action menu views for estate propery in UI --- estate/__manifest__.py | 2 ++ estate/views/estate_menu.xml | 7 +++++++ estate/views/estate_property_views.xml | 7 +++++++ 3 files changed, 16 insertions(+) create mode 100644 estate/views/estate_menu.xml create mode 100644 estate/views/estate_property_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 5a309d68fba..a6e845f7f0f 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -4,6 +4,8 @@ ['base'], 'data': [ 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menu.xml', ], 'installable': True, 'application': True, diff --git a/estate/views/estate_menu.xml b/estate/views/estate_menu.xml new file mode 100644 index 00000000000..6040a8a0954 --- /dev/null +++ b/estate/views/estate_menu.xml @@ -0,0 +1,7 @@ + + + + + + + \ 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..a81214e39f4 --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,7 @@ + + + Properties + estate.property + list,form + + \ No newline at end of file From 0c863ac7d261cefe0c258ce362cb67f67e2673a9 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Wed, 23 Apr 2025 11:51:51 +0200 Subject: [PATCH 07/20] [IMP] estate: add new fields and fileds default values to property form --- estate/models/estate_property.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 973b9d540dc..f04438f088b 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,5 @@ from odoo import fields, models +from dateutil.relativedelta import relativedelta class EstateProperty(models.Model): @@ -8,10 +9,11 @@ class EstateProperty(models.Model): name = fields.Char('name', required=True) description = fields.Text('description') postcode = fields.Char('postcode') - date_availability = fields.Date('availabilty date') + date_availability = fields.Date( + 'availabilty date', copy=False, default=fields.Date.today()+relativedelta(months=3)) expected_price = fields.Float('expected price', required=True) - selling_price = fields.Float('selling price') - bedrooms = fields.Integer('bedrooms') + selling_price = fields.Float('selling price', readonly=True, copy=False) + bedrooms = fields.Integer('bedrooms', default=2) living_area = fields.Integer('living area') facades = fields.Integer('facades') garage = fields.Boolean('garage') @@ -21,3 +23,11 @@ class EstateProperty(models.Model): selection=[('North', 'North'), ('South', 'South'), ('East', 'East'), ('West', 'West')] ) + active = fields.Boolean('active', default=True) + state = fields.Selection( + string='State', + selection=[('new', 'New'), ('offer_received', 'Offer Received'), + ('offer_accepted', 'Offer Acccepted'), ('sold', 'Sold'), + ('cancelled', 'Cancelled')], + default="new" + ) From 4bd1002edf9f2692d505e852e97cf85bec5bb217 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Wed, 23 Apr 2025 11:57:13 +0200 Subject: [PATCH 08/20] [FIX] estate: fix linting and EOF in xml and csv files --- estate/__manifest__.py | 2 +- estate/security/ir.model.access.csv | 2 +- estate/views/estate_menu.xml | 2 +- estate/views/estate_property_views.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index a6e845f7f0f..a77a1ca5825 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -6,7 +6,7 @@ 'security/ir.model.access.csv', 'views/estate_property_views.xml', 'views/estate_menu.xml', - ], + ], 'installable': True, 'application': True, 'auto_install': False, diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 4204e66ff28..4dbf6522cfc 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +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 +access_estate_property, access_estate_property,model_estate_property,base.group_user,1,1,1,1 diff --git a/estate/views/estate_menu.xml b/estate/views/estate_menu.xml index 6040a8a0954..c5d420ae545 100644 --- a/estate/views/estate_menu.xml +++ b/estate/views/estate_menu.xml @@ -4,4 +4,4 @@ - \ No newline at end of file + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index a81214e39f4..4d544c18597 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -4,4 +4,4 @@ estate.property list,form - \ No newline at end of file + From 450100adb16e42248fbbab8bb3ecc2109f525336 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Wed, 23 Apr 2025 13:08:43 +0200 Subject: [PATCH 09/20] [FIX] estate: add whitespace around arithmetic operator in estate property manifest --- estate/models/estate_property.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index f04438f088b..b81e91cd42a 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -10,7 +10,7 @@ class EstateProperty(models.Model): description = fields.Text('description') postcode = fields.Char('postcode') date_availability = fields.Date( - 'availabilty date', copy=False, default=fields.Date.today()+relativedelta(months=3)) + 'availabilty date', copy=False, default=fields.Date.today() + relativedelta(months=3)) expected_price = fields.Float('expected price', required=True) selling_price = fields.Float('selling price', readonly=True, copy=False) bedrooms = fields.Integer('bedrooms', default=2) From 8ae30b801c0641fdea789d305f84dcf4d6866183 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Wed, 23 Apr 2025 14:44:24 +0200 Subject: [PATCH 10/20] [IMP] estate: add custom filters and group by fields to estate property search --- estate/models/estate_property.py | 2 +- estate/views/estate_property_views.xml | 74 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index b81e91cd42a..2240cde51e5 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -9,7 +9,7 @@ class EstateProperty(models.Model): name = fields.Char('name', required=True) description = fields.Text('description') postcode = fields.Char('postcode') - date_availability = fields.Date( + availability_date = fields.Date( 'availabilty date', copy=False, default=fields.Date.today() + relativedelta(months=3)) expected_price = fields.Float('expected price', required=True) selling_price = fields.Float('selling price', readonly=True, copy=False) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 4d544c18597..f388a905269 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -4,4 +4,78 @@ estate.property list,form + + + properties.view.list + estate.property + + + + + + + + + + + + + + + properties.view.form + estate.property + +
+ +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + properties.search + estate.property + + + + + + + + + + + + + + + + From 8eb5b3716a0b6347b29ca811426fa08b010ed60b Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Wed, 23 Apr 2025 16:52:59 +0200 Subject: [PATCH 11/20] [IMP] estate: add a new model estate_property_type --- estate/__manifest__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 2 + estate/models/estate_property_type.py | 8 ++++ estate/security/ir.model.access.csv | 1 + estate/views/estate_menu.xml | 5 ++- estate/views/estate_property_type_views.xml | 41 +++++++++++++++++++++ estate/views/estate_property_views.xml | 1 + 8 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 estate/models/estate_property_type.py create mode 100644 estate/views/estate_property_type_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index a77a1ca5825..9a0bd302891 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -4,6 +4,7 @@ ['base'], 'data': [ 'security/ir.model.access.csv', + 'views/estate_property_type_views.xml', 'views/estate_property_views.xml', 'views/estate_menu.xml', ], diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 5e1963c9d2f..40092a2d810 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,2 @@ from . import estate_property +from . import estate_property_type diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 2240cde51e5..2133e904029 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -31,3 +31,5 @@ class EstateProperty(models.Model): ('cancelled', 'Cancelled')], default="new" ) + property_type_id = fields.Many2one( + "estate.property.type", string="property type") diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..d05b4518dc3 --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,8 @@ +from odoo import models, fields + + +class EstatePropertyType(models.Model): + _name = "estate.property.type" + _description = "Estate property type description" + + name = fields.Char('name', required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 4dbf6522cfc..67b3098b5bd 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 +access_estate_property_type, access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 diff --git a/estate/views/estate_menu.xml b/estate/views/estate_menu.xml index c5d420ae545..1a21a1e9266 100644 --- a/estate/views/estate_menu.xml +++ b/estate/views/estate_menu.xml @@ -1,7 +1,10 @@ - + + + + diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..4d6efd74e0f --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,41 @@ + + + Property Types + estate.property.type + list,form + + + + properties.view.type.list + estate.property.type + + + + + + + + + properties.view.type.form + estate.property.type + +
+ +

+ +

+
+
+
+
+ + + properties.type.search + estate.property.type + + + + + + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index f388a905269..4a1c5b6e280 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -32,6 +32,7 @@ + From 9b71df7e366c277ef04f15a333ae6a3983c1d79a Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Wed, 23 Apr 2025 17:24:10 +0200 Subject: [PATCH 12/20] [IMP] estate: add a new model estate_property_tag --- estate/__manifest__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 4 +++ estate/models/estate_property_tag.py | 8 +++++ estate/security/ir.model.access.csv | 1 + estate/views/estate_menu.xml | 1 + estate/views/estate_property_tag_views.xml | 41 ++++++++++++++++++++++ estate/views/estate_property_views.xml | 7 ++++ 8 files changed, 64 insertions(+) create mode 100644 estate/models/estate_property_tag.py create mode 100644 estate/views/estate_property_tag_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 9a0bd302891..ea48792e071 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -5,6 +5,7 @@ 'data': [ 'security/ir.model.access.csv', 'views/estate_property_type_views.xml', + 'views/estate_property_tag_views.xml', 'views/estate_property_views.xml', 'views/estate_menu.xml', ], diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 40092a2d810..c620ac481a3 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1,2 +1,3 @@ from . import estate_property 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 2133e904029..0330e7aa563 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -33,3 +33,7 @@ class EstateProperty(models.Model): ) property_type_id = fields.Many2one( "estate.property.type", string="property type") + user_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", string="Tags") diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..d8aefb1b3b6 --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,8 @@ +from odoo import models, fields + + +class EstatePropertyTag(models.Model): + _name = "estate.property.tag" + _description = "Estate property tag description" + + name = fields.Char('name', required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 67b3098b5bd..21297760394 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,3 +1,4 @@ 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_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 diff --git a/estate/views/estate_menu.xml b/estate/views/estate_menu.xml index 1a21a1e9266..fe1016debdf 100644 --- a/estate/views/estate_menu.xml +++ b/estate/views/estate_menu.xml @@ -5,6 +5,7 @@ + diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 00000000000..07a75c4b9bf --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,41 @@ + + + Property Tags + estate.property.tag + list,form + + + + properties.view.tag.list + estate.property.tag + + + + + + + + + properties.view.tag.form + estate.property.tag + +
+ +

+ +

+
+
+
+
+ + + properties.tag.search + estate.property.tag + + + + + + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 4a1c5b6e280..e97c4cd4936 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -30,6 +30,7 @@

+ @@ -54,6 +55,12 @@ + + + + + + From f09e8e439c256d241f272724bbc1b272ceee5de3 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Wed, 23 Apr 2025 18:01:18 +0200 Subject: [PATCH 13/20] [IMP] estate: add a new model estate_property_offer --- estate/__manifest__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 2 ++ estate/models/estate_property_offer.py | 14 ++++++++++ estate/security/ir.model.access.csv | 1 + estate/views/estate_property_offer_views.xml | 29 ++++++++++++++++++++ estate/views/estate_property_views.xml | 3 ++ 7 files changed, 51 insertions(+) create mode 100644 estate/models/estate_property_offer.py create mode 100644 estate/views/estate_property_offer_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index ea48792e071..95e4f49209d 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -6,6 +6,7 @@ '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_menu.xml', ], diff --git a/estate/models/__init__.py b/estate/models/__init__.py index c620ac481a3..2f1821a39c1 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1,3 +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 0330e7aa563..9616372b698 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -37,3 +37,5 @@ class EstateProperty(models.Model): "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", string="Tags") + 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..be9cd68e8d8 --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,14 @@ +from odoo import models, fields + + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Estate property offer description" + + price = fields.Float('price') + status = fields.Selection( + string='status', + selection=[('accepted', 'Accepted'), ('refused', 'Refused')] + ) + partner_id = fields.Many2one('res.partner', required=True) + property_id = fields.Many2one('estate.property', required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 21297760394..cd2d4edf51b 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -2,3 +2,4 @@ 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_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 diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..012c2af6091 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,29 @@ + + + properties.view.offer.list + estate.property.offer + + + + + + + + + + + properties.view.offer.form + estate.property.offer + +
+ + + + + + + +
+
+
+
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index e97c4cd4936..e8b86571f3e 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -55,6 +55,9 @@
+ + + From 1120d88c88a65f5bedf70bd3f5ea2c8e731e98e3 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Thu, 24 Apr 2025 11:15:04 +0200 Subject: [PATCH 14/20] [IMP] estate: add compute fields for estate_property and estate_property_offer --- estate/models/estate_property.py | 41 ++++++++++++++++++-- estate/models/estate_property_offer.py | 22 ++++++++++- estate/views/estate_property_offer_views.xml | 14 +++++-- estate/views/estate_property_views.xml | 3 ++ 4 files changed, 72 insertions(+), 8 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 9616372b698..5db55a41bcd 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 @@ -7,7 +7,7 @@ class EstateProperty(models.Model): _description = "Estate Property discription" name = fields.Char('name', required=True) - description = fields.Text('description') + description = fields.Text('description', compute="_compute_description") postcode = fields.Char('postcode') availability_date = fields.Date( 'availabilty date', copy=False, default=fields.Date.today() + relativedelta(months=3)) @@ -17,11 +17,12 @@ class EstateProperty(models.Model): living_area = fields.Integer('living area') facades = fields.Integer('facades') garage = fields.Boolean('garage') + garden = fields.Boolean('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')] ) active = fields.Boolean('active', default=True) state = fields.Selection( @@ -39,3 +40,35 @@ class EstateProperty(models.Model): tag_ids = fields.Many2many("estate.property.tag", string="Tags") offer_ids = fields.One2many( "estate.property.offer", "property_id", string="Offers") + total_area = fields.Integer(compute='_compute_total_area') + best_offer = fields.Float(compute="_compute_best_offer") + + @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("buyer_id") + def _compute_description(self): + for record in self: + record.description = "Description for buyer %s" % record.buyer_id.name + + @api.depends("offer_ids") + def _compute_best_offer(self): + try: + for record in self: + if len(record.offer_ids) > 0: + record.best_offer = max(record.offer_ids.mapped("price")) + else: + record.best_offer = 0.0 + except Exception as e: + print(e) + + @api.onchange("garden") + def _onchange_garden(self): + if self.garden: + self.garden_area = 10 + self.garden_orientation = "north" + else: + self.garden_area = 0 + self.garden_orientation = None diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index be9cd68e8d8..aa208ed9873 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,5 @@ -from odoo import models, fields +from odoo import api, models, fields +from dateutil.relativedelta import relativedelta class EstatePropertyOffer(models.Model): @@ -12,3 +13,22 @@ class EstatePropertyOffer(models.Model): ) partner_id = fields.Many2one('res.partner', required=True) property_id = fields.Many2one('estate.property', required=True) + validity = fields.Integer(default=7) + date_deadline = fields.Date( + compute="_compute_date_deadline", inverse="_inverse_date_deadline") + + @api.depends("validity") + def _compute_date_deadline(self): + for record in self: + start_date = fields.Date.today() + if record.create_date: + start_date = record.create_date + record.date_deadline = start_date + \ + relativedelta(days=record.validity) + + def _inverse_date_deadline(self): + for record in self: + start_date = fields.Date.today() + if record.create_date: + start_date = record.create_date + record.validity = (record.date_deadline - fields.Date.today()).days diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 012c2af6091..ff6fea1e7cc 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -6,6 +6,8 @@ + + @@ -18,9 +20,15 @@
- - - + + + + + + + + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index e8b86571f3e..ebfa92c532c 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -38,6 +38,7 @@
+ @@ -50,9 +51,11 @@ + +
From fc150fb7ccad4df2b15c478b0c7d7659f4746503 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Thu, 24 Apr 2025 11:56:18 +0200 Subject: [PATCH 15/20] [IMP] estate: added accept and refuse offer buttons --- estate/models/estate_property.py | 35 ++++++++++++-------- estate/models/estate_property_offer.py | 29 +++++++++++----- estate/views/estate_property_offer_views.xml | 4 ++- estate/views/estate_property_views.xml | 4 +++ 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 5db55a41bcd..5f6ceefbd9e 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,5 @@ from odoo import api, fields, models +from odoo.exceptions import UserError from dateutil.relativedelta import relativedelta @@ -7,7 +8,7 @@ class EstateProperty(models.Model): _description = "Estate Property discription" name = fields.Char('name', required=True) - description = fields.Text('description', compute="_compute_description") + description = fields.Text('description') postcode = fields.Char('postcode') availability_date = fields.Date( 'availabilty date', copy=False, default=fields.Date.today() + relativedelta(months=3)) @@ -48,21 +49,11 @@ def _compute_total_area(self): for record in self: record.total_area = record.living_area + record.garden_area - @api.depends("buyer_id") - def _compute_description(self): - for record in self: - record.description = "Description for buyer %s" % record.buyer_id.name - @api.depends("offer_ids") def _compute_best_offer(self): - try: - for record in self: - if len(record.offer_ids) > 0: - record.best_offer = max(record.offer_ids.mapped("price")) - else: - record.best_offer = 0.0 - except Exception as e: - print(e) + for record in self: + record.best_offer = max(record.offer_ids.mapped( + "price")) if record.offer_ids else 0.0 @api.onchange("garden") def _onchange_garden(self): @@ -72,3 +63,19 @@ def _onchange_garden(self): else: self.garden_area = 0 self.garden_orientation = None + + def action_sell(self): + for record in self: + if record.state == "cancelled": + raise UserError("You can't sell a cancelled property") + record.state = "sold" + + return True + + def action_cancel(self): + for record in self: + if record.state == "sold": + raise UserError("You can't cancel a sold property") + record.state = "cancelled" + + return True diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index aa208ed9873..21516f1a2e0 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,5 @@ from odoo import api, models, fields +from odoo.exceptions import UserError from dateutil.relativedelta import relativedelta @@ -17,18 +18,30 @@ class EstatePropertyOffer(models.Model): date_deadline = fields.Date( compute="_compute_date_deadline", inverse="_inverse_date_deadline") - @api.depends("validity") + @api.depends("validity", "create_date") def _compute_date_deadline(self): for record in self: - start_date = fields.Date.today() - if record.create_date: - start_date = record.create_date + start_date = record.create_date.date() if record.create_date else fields.Date.today() record.date_deadline = start_date + \ relativedelta(days=record.validity) def _inverse_date_deadline(self): for record in self: - start_date = fields.Date.today() - if record.create_date: - start_date = record.create_date - record.validity = (record.date_deadline - fields.Date.today()).days + start_date = record.create_date.date() if record.create_date else fields.Date.today() + record.validity = (record.date_deadline - start_date).days + + def action_accept(self): + for record in self: + if record.property_id.buyer_id: + raise UserError("You already accepted an offer") + if record.status == "refused": + raise UserError("You already refused this offer") + record.status = "accepted" + record.property_id.selling_price = record.price + record.property_id.buyer_id = record.partner_id + + def action_refuse(self): + for record in self: + if record.status == "accepted": + raise UserError("You already accepted this offer") + record.status = "refused" diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index ff6fea1e7cc..f92cb63863d 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -5,10 +5,12 @@ - +

+ + + + + + + + + + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 52a8e002503..56b3b25c349 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -3,20 +3,24 @@ Properties estate.property list,form + {'search_default_available': True} properties.view.list estate.property - + + + + - + @@ -27,17 +31,18 @@
-

- + - + @@ -56,14 +61,13 @@ - - - + + - + @@ -85,11 +89,11 @@ - + - + From 57d42f03d0531c709c1501b472084bcbad373392 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Mon, 28 Apr 2025 10:49:52 +0200 Subject: [PATCH 18/20] [IMP] estate: add inherit model for res_users and link offers to user views --- estate/__manifest__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_property.py | 6 +++++- estate/models/estate_property_offer.py | 9 +++++++++ estate/models/res_users.py | 7 +++++++ estate/views/res_users_views.xml | 14 ++++++++++++++ 6 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 estate/models/res_users.py create mode 100644 estate/views/res_users_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 8fbac61b332..d6d2d0232d1 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -8,6 +8,7 @@ 'views/estate_property_tag_views.xml', 'views/estate_property_offer_views.xml', 'views/estate_property_views.xml', + 'views/res_users_views.xml', 'views/estate_menu.xml', ], 'installable': True, diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 2f1821a39c1..9a2189b6382 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -2,3 +2,4 @@ from . import estate_property_type from . import estate_property_tag from . import estate_property_offer +from . import res_users diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index cbb693f282b..5f9019b5426 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -87,7 +87,6 @@ def action_cancel(self): if "sold" in self.mapped('state'): raise UserError("You can't cancel a sold property") self.state = "cancelled" - return True @api.constrains("selling_price", "expected_price") @@ -96,3 +95,8 @@ def _check_selling_price(self): if not float_is_zero(record.selling_price, 2) and \ float_compare(record.selling_price, 0.9 * record.expected_price, 2) < 0: raise ValidationError("The selling price has to be at least 90% of the expected price") + + @api.ondelete(at_uninstall=False) + def _unlink_if_new_or_cancelled(self): + if any(x in self.mapped("state") for x in ["offer_received", "offer_accepted", "sold"]): + raise UserError("You can only delete a new or cancelled property") diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index ad735de3238..a8eb0f73152 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -53,3 +53,12 @@ def action_refuse(self): if record.status == "accepted": raise UserError("You already accepted this offer") record.status = "refused" + + @api.model + def create(self, vals): + property_record = self.env["estate.property"].browse(vals["property_id"]) + if vals["price"] < property_record.best_offer: + raise UserError(f"Your offer can't be lower than {property_record.best_offer}") + + property_record.state = "offer_received" + return super().create(vals) diff --git a/estate/models/res_users.py b/estate/models/res_users.py new file mode 100644 index 00000000000..990aa0ae285 --- /dev/null +++ b/estate/models/res_users.py @@ -0,0 +1,7 @@ +from odoo import fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + property_ids = fields.One2many("estate.property", "user_id", domain=[('state', 'in', ['new', 'offer_received'])]) diff --git a/estate/views/res_users_views.xml b/estate/views/res_users_views.xml new file mode 100644 index 00000000000..d640bd1c211 --- /dev/null +++ b/estate/views/res_users_views.xml @@ -0,0 +1,14 @@ + + + users.properties.view.list + res.users + + + + + + + + + + \ No newline at end of file From 8acd0f132979851a90302969bf80e8f884b7b199 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Mon, 28 Apr 2025 15:52:20 +0200 Subject: [PATCH 19/20] [IMP] estate: create invoices for sold properties --- estate_account/__init__.py | 1 + estate_account/__manifest__.py | 9 ++++++++ estate_account/models/__init__.py | 1 + estate_account/models/estate_property.py | 26 ++++++++++++++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 estate_account/__init__.py create mode 100644 estate_account/__manifest__.py create mode 100644 estate_account/models/__init__.py create mode 100644 estate_account/models/estate_property.py diff --git a/estate_account/__init__.py b/estate_account/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/estate_account/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/estate_account/__manifest__.py b/estate_account/__manifest__.py new file mode 100644 index 00000000000..68f4235d892 --- /dev/null +++ b/estate_account/__manifest__.py @@ -0,0 +1,9 @@ +{ + 'name': 'Estate Account', + 'depends': + ['estate', 'account'], + 'data': [], + 'installable': True, + 'application': True, + 'license': 'AGPL-3', +} diff --git a/estate_account/models/__init__.py b/estate_account/models/__init__.py new file mode 100644 index 00000000000..5e1963c9d2f --- /dev/null +++ b/estate_account/models/__init__.py @@ -0,0 +1 @@ +from . import estate_property diff --git a/estate_account/models/estate_property.py b/estate_account/models/estate_property.py new file mode 100644 index 00000000000..12ddbd18f1c --- /dev/null +++ b/estate_account/models/estate_property.py @@ -0,0 +1,26 @@ +from odoo import fields, models, Command + + +class EstateProperty(models.Model): + _inherit = "estate.property" + + def action_sell(self): + is_sold = super().action_sell() + for record in self: + self.env["account.move"].create({ + "partner_id" : record.buyer_id.id, + "move_type" : "out_invoice", + "line_ids": [ + Command.create({ + "name": "Down payment 6%", + "quantity": 1, + "price_unit": 0.06 * record.selling_price, + }), + Command.create({ + "name": "Administrative Fees", + "quantity": 1, + "price_unit": 100.00, + }), + ], + }) + return is_sold From 83aa04c1d8fee69a5a5ac02ad028a9b275cdee79 Mon Sep 17 00:00:00 2001 From: msho-odoo Date: Mon, 28 Apr 2025 17:12:20 +0200 Subject: [PATCH 20/20] [IMP] estate: add kanban view to estate_property --- estate/models/estate_property_offer.py | 11 ++++---- estate/models/estate_property_tag.py | 2 +- estate/views/estate_property_views.xml | 34 +++++++++++++++++++++++- estate_account/__manifest__.py | 3 +-- estate_account/models/estate_property.py | 6 ++--- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index a8eb0f73152..b0242a7736d 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -54,11 +54,12 @@ def action_refuse(self): raise UserError("You already accepted this offer") record.status = "refused" - @api.model + @api.model_create_multi def create(self, vals): - property_record = self.env["estate.property"].browse(vals["property_id"]) - if vals["price"] < property_record.best_offer: - raise UserError(f"Your offer can't be lower than {property_record.best_offer}") + for val in vals: + property_record = self.env["estate.property"].browse(val["property_id"]) + if val["price"] < property_record.best_offer: + raise UserError(f"Your offer can't be lower than {property_record.best_offer}") - property_record.state = "offer_received" + property_record.state = "offer_received" return super().create(vals) diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py index f76fe33de05..d3058338341 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -5,7 +5,7 @@ class EstatePropertyTag(models.Model): _name = "estate.property.tag" _description = "Estate property tag" _sql_constraints = [ - ("check_unique_name", "UNIQUE(name)", "Property tag must be unqie") + ("check_unique_name", "UNIQUE(name)", "Property tag must be unqiue") ] _order = "name" diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 56b3b25c349..73a7146dabf 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -2,7 +2,7 @@ Properties estate.property - list,form + kanban,list,form {'search_default_available': True} @@ -100,4 +100,36 @@ + + + properties.view.kanban + estate.property + + + + + +
+ +
+ Expected Price: + +
+
+ Best Price: + +
+
+ Selling Price: + +
+
+ +
+
+
+
+
+
+
diff --git a/estate_account/__manifest__.py b/estate_account/__manifest__.py index 68f4235d892..5c6e0b924c9 100644 --- a/estate_account/__manifest__.py +++ b/estate_account/__manifest__.py @@ -2,8 +2,7 @@ 'name': 'Estate Account', 'depends': ['estate', 'account'], - 'data': [], - 'installable': True, + 'auto_install': True, 'application': True, 'license': 'AGPL-3', } diff --git a/estate_account/models/estate_property.py b/estate_account/models/estate_property.py index 12ddbd18f1c..1b9cfb1efb8 100644 --- a/estate_account/models/estate_property.py +++ b/estate_account/models/estate_property.py @@ -1,4 +1,4 @@ -from odoo import fields, models, Command +from odoo import models, Command class EstateProperty(models.Model): @@ -8,8 +8,8 @@ def action_sell(self): is_sold = super().action_sell() for record in self: self.env["account.move"].create({ - "partner_id" : record.buyer_id.id, - "move_type" : "out_invoice", + "partner_id": record.buyer_id.id, + "move_type": "out_invoice", "line_ids": [ Command.create({ "name": "Down payment 6%",