From f5df5c55efff76e93707bbfd0c3a54ffe3213750 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 19 May 2025 13:47:12 +0200 Subject: [PATCH 01/53] [ADD] estate: finished chapter 3 --- estate/__init__.py | 2 ++ estate/__manifest__.py | 9 +++++++++ estate/models/__init__.py | 1 + estate/models/estate_property.py | 23 +++++++++++++++++++++++ 4 files changed, 35 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 diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..a0fdc10fe11 --- /dev/null +++ b/estate/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import models diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..ffb7e326e1c --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +{ + 'name': 'Estate', + 'depends': [ + 'base' + ], + 'installable': True, + 'application': True +} 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..60ece175e5a --- /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 = "its just an estate property" + + name = fields.Char(required=True) + description = fields.Text() + postcode = fields.Char() + date_availability = fields.Date() + expected_price = fields.Float(required=True) + selling_price = fields.Float() + bedrooms = fields.Integer() + living_area = fields.Integer() + facades = fields.Integer() + garage = fields.Boolean() + garden = fields.Boolean() + gardençarea = fields.Integer() + garden_orientation = fields.Selection( + selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], + ) + + \ No newline at end of file From 59e83b29fd4475f27d2b484f08cc3bf5c2a825f7 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 19 May 2025 14:07:08 +0200 Subject: [PATCH 02/53] [ADD] chapter 3 --- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/estate/models/__init__.py b/estate/models/__init__.py index f4c8fd6db6d..5e1963c9d2f 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1 @@ -from . import estate_property \ No newline at end of file +from . import estate_property diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 60ece175e5a..38bb4939f46 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -15,9 +15,8 @@ class EstateProperty(models.Model): facades = fields.Integer() garage = fields.Boolean() garden = fields.Boolean() - gardençarea = fields.Integer() + garden_area = fields.Integer() garden_orientation = fields.Selection( selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], ) - - \ No newline at end of file + \ No newline at end of file From 439c30dffd1a0cf9d4f7b72b427afff2eca0d2bc Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 19 May 2025 14:28:12 +0200 Subject: [PATCH 03/53] [ADD] chapter 4 --- estate/__init__.py | 1 - estate/__manifest__.py | 6 ++++-- estate/models/estate_property.py | 1 - estate/security/ir.model.access.csv | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 estate/security/ir.model.access.csv diff --git a/estate/__init__.py b/estate/__init__.py index a0fdc10fe11..0650744f6bc 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- from . import models diff --git a/estate/__manifest__.py b/estate/__manifest__.py index ffb7e326e1c..04f94d1382f 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,9 +1,11 @@ -# -*- coding: utf-8 -*- { 'name': 'Estate', 'depends': [ 'base' ], 'installable': True, - '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 38bb4939f46..ba7b66eee29 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -19,4 +19,3 @@ class EstateProperty(models.Model): 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..fe21e56c6d2 --- /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 From ef2e2055d9f4d2e85dcdb2b260f65431684cc030 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 19 May 2025 15:09:22 +0200 Subject: [PATCH 04/53] [ADD] chapter 5 first half --- estate/__manifest__.py | 6 ++++-- estate/views/estate_menus.xml | 9 +++++++++ estate/views/estate_property_views.xml | 8 ++++++++ 3 files changed, 21 insertions(+), 2 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 04f94d1382f..828e04b99e3 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,11 +1,13 @@ { - 'name': 'Estate', + 'name': 'estate', 'depends': [ 'base' ], 'installable': True, 'application': True, 'data': [ - 'security/ir.model.access.csv' + 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml', ] } diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..7d228e6512b --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ 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..5b2ea0fb5bc --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,8 @@ + + + + Property + estate.property + list,form + + From 3edc21bae453a941e0810c850673def34e002b5c Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 19 May 2025 15:44:02 +0200 Subject: [PATCH 05/53] [ADD] chapter 5 done --- estate/models/estate_property.py | 16 +++++++++++++--- estate/views/estate_menus.xml | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index ba7b66eee29..0ab90a8d7a6 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,6 @@ from odoo import fields, models +from datetime import datetime +from dateutil.relativedelta import relativedelta class EstateProperty(models.Model): _name = "estate.property" @@ -7,10 +9,10 @@ class EstateProperty(models.Model): name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date() + date_availability = fields.Date(default=datetime.now()+relativedelta(months=3),copy= False) 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() @@ -19,3 +21,11 @@ class EstateProperty(models.Model): garden_orientation = fields.Selection( selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], ) + active= fields.Boolean(default=True) + + state = fields.Selection( + selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancel', 'Cancel')], + required= True, + copy= False, + default= 'new' + ) diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 7d228e6512b..be6c7bcb084 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -2,7 +2,9 @@ + + From e6ce348c3dc6af90c95f444e28c31ab7a6ffc347 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 19 May 2025 17:28:03 +0200 Subject: [PATCH 06/53] [ADD] finished chapter 6 --- estate/views/estate_property_views.xml | 82 ++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 5b2ea0fb5bc..0080652490f 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -5,4 +5,86 @@ estate.property list,form + + + estate.property.list + estate.property + + + + + + + + + + + + + + + + estate.property.form + estate.property + +
+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ + + + estate.property.search + estate.property + + + + + + + + + + + + + + + + + +
From ca315f54aef8b3e3eeae212da107dea152ffaae6 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 20 May 2025 09:43:27 +0200 Subject: [PATCH 07/53] [FIX] chapter 6 fix --- estate/views/estate_property_views.xml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 0080652490f..9d207c3d234 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -61,8 +61,7 @@ - - + estate.property.search estate.property @@ -74,17 +73,11 @@ - - - + - + - From a46be7f2d5f27c6026bab7f449d58bf45129a8f2 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 20 May 2025 11:32:05 +0200 Subject: [PATCH 08/53] [ADD] chapter 7 done --- estate/__manifest__.py | 4 +++ estate/models/__init__.py | 3 ++ estate/models/estate_property.py | 7 +++- estate/models/estate_property_offer.py | 10 ++++++ estate/models/estate_property_tag.py | 7 ++++ estate/models/estate_property_type.py | 7 ++++ estate/security/ir.model.access.csv | 5 ++- estate/views/estate_menus.xml | 6 ++++ estate/views/estate_property_offer_views.xml | 36 ++++++++++++++++++++ estate/views/estate_property_tag_views.xml | 32 +++++++++++++++++ estate/views/estate_property_type_views.xml | 32 +++++++++++++++++ estate/views/estate_property_views.xml | 21 ++++++++++-- 12 files changed, 166 insertions(+), 4 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 828e04b99e3..3c42377f499 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -6,8 +6,12 @@ 'installable': True, 'application': True, 'data': [ + 'views/estate_property_type_views.xml', + 'views/estate_property_offer_views.xml', + 'views/estate_property_tag_views.xml', 'security/ir.model.access.csv', 'views/estate_property_views.xml', 'views/estate_menus.xml', + ] } diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 5e1963c9d2f..09b2099fe84 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,4 @@ from . import estate_property +from . import estate_property_type +from . import estate_property_tag +from . import estate_property_offer \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 0ab90a8d7a6..7c4c42be632 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -28,4 +28,9 @@ class EstateProperty(models.Model): required= True, copy= False, default= 'new' - ) + ) + + buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) + sales_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user) + 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..74e60ce740b --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,10 @@ +from odoo import fields, models + +class PropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "Offer made by a potential buyer" + + price = fields.Float() + status = fields.Selection(copy=False, 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/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..9d935786641 --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,7 @@ +from odoo import fields, models + +class PropertyTag(models.Model): + _name = "estate.property.tag" + _description = "used to add precision to a property" + + 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..313e68ba2ef --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,7 @@ +from odoo import fields, models + +class PropertyType(models.Model): + _name = "estate.property.type" + _description = "describe the type property" + + 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 fe21e56c6d2..c79331f2f1c 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,5 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink -estate.access_estate_property,access_estate_property,estate.model_estate_property,base.group_user,1,1,1,1 \ 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 \ No newline at end of file diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index be6c7bcb084..1343273e6b4 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -7,5 +7,11 @@ + + + + + + \ No newline at end of file diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..7223773ae71 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,36 @@ + + + + + + + estate.property.offer.list + estate.property.offer + + + + + + + + + + + estate.property.offer.form + estate.property.offer + +
+ + + + + + + + +
+
+
+ + +
diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 00000000000..4a1107afd08 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,32 @@ + + + + Property Tags + estate.property.tag + list,form + + + + estate.property.tag.list + estate.property.tag + + + + + + + + + estate.property.tag.form + estate.property.tag + +
+ +

+
+
+
+
+ + +
diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..ddec9bf6046 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,32 @@ + + + + Property Types + estate.property.type + list,form + + + + estate.property.type.list + estate.property.type + + + + + + + + + estate.property.type.form + estate.property.type + +
+ +

+
+
+
+
+ + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 9d207c3d234..fc529b30b14 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -6,6 +6,7 @@ list,form + estate.property.list estate.property @@ -22,14 +23,14 @@ - estate.property.form estate.property -
+

+ @@ -55,7 +56,23 @@ + + + + + + + + + + + + + + + +
From 6d7858dbc8f0cdc3dfa06841f2c54b89af0b2180 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 20 May 2025 11:32:05 +0200 Subject: [PATCH 09/53] [ADD] chapter 7 done --- estate/models/estate_property.py | 22 +++++++++++++++++++++- estate/views/estate_property_views.xml | 11 +++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 7c4c42be632..50d6cef232a 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 datetime import datetime from dateutil.relativedelta import relativedelta @@ -6,6 +6,9 @@ class EstateProperty(models.Model): _name = "estate.property" _description = "its just an estate property" + + # Basic fields + name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() @@ -30,7 +33,24 @@ class EstateProperty(models.Model): default= 'new' ) + + # Relational fields + property_type_id = fields.Many2one("estate.property.type", string="Property Type") buyer_id = fields.Many2one("res.partner", string="Buyer", copy=False) sales_id = fields.Many2one("res.users", string="Salesperson", default=lambda self: self.env.user) tag_ids = fields.Many2many("estate.property.tag", string="Tags") offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") + + + # Computed fields + total_area = fields.Integer(compute="_compute_total_area",readonly=True) + + + + + # COMPUTE METHODS + + @api.depends('living_area', 'garden_area') + def _compute_total_area(self): + for record in self: + record.total_area = record.living_area + record.garden_area \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index fc529b30b14..da6cfc5d09c 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -7,12 +7,14 @@
+ estate.property.list estate.property + @@ -27,12 +29,15 @@ estate.property.form estate.property +

+ + @@ -53,7 +58,7 @@ - + @@ -62,7 +67,7 @@ - + @@ -73,6 +78,7 @@ +
@@ -93,6 +99,7 @@ +
From 86c8ab964ca599dea080cd184d4062158d5b02b1 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 20 May 2025 13:17:42 +0200 Subject: [PATCH 10/53] [FIX] chapter 7 --- estate/views/estate_property_views.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index da6cfc5d09c..80b1bbc9965 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -29,7 +29,6 @@ estate.property.form estate.property -

From 27825b8b909ef9fa04535653a07480ae4f76a1bc Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 20 May 2025 15:10:00 +0200 Subject: [PATCH 11/53] [ADD] estate: chapter 8 done + lint --- .pre-commit-config.yaml | 6 +++ awesome_clicker/__init__.py | 1 - awesome_clicker/__manifest__.py | 1 - awesome_dashboard/__init__.py | 1 - awesome_dashboard/__manifest__.py | 1 - awesome_dashboard/controllers/__init__.py | 3 +- awesome_dashboard/controllers/controllers.py | 1 - awesome_gallery/__init__.py | 1 - awesome_gallery/__manifest__.py | 1 - awesome_gallery/models/__init__.py | 1 - awesome_gallery/models/ir_action.py | 1 - awesome_gallery/models/ir_ui_view.py | 1 - awesome_kanban/__init__.py | 1 - awesome_kanban/__manifest__.py | 1 - awesome_owl/__init__.py | 3 +- awesome_owl/__manifest__.py | 1 - awesome_owl/controllers/__init__.py | 3 +- estate/__manifest__.py | 1 - estate/models/__init__.py | 2 +- estate/models/estate_property.py | 45 +++++++++++++------- estate/models/estate_property_offer.py | 21 ++++++++- estate/models/estate_property_tag.py | 2 +- estate/models/estate_property_type.py | 2 +- estate/views/estate_property_offer_views.xml | 5 ++- estate/views/estate_property_views.xml | 3 +- ruff.toml | 42 ++++++++++++++++++ 26 files changed, 109 insertions(+), 42 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 ruff.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000000..0bed35823b1 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,6 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.3 # Use the latest Ruff version or the one that matches your setup + hooks: + - id: ruff + args: [ --fix] diff --git a/awesome_clicker/__init__.py b/awesome_clicker/__init__.py index 40a96afc6ff..e69de29bb2d 100644 --- a/awesome_clicker/__init__.py +++ b/awesome_clicker/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/awesome_clicker/__manifest__.py b/awesome_clicker/__manifest__.py index e57ef4d5bb0..1e5e36b0ec6 100644 --- a/awesome_clicker/__manifest__.py +++ b/awesome_clicker/__manifest__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- { 'name': "Awesome Clicker", diff --git a/awesome_dashboard/__init__.py b/awesome_dashboard/__init__.py index b0f26a9a602..f705942f8f1 100644 --- a/awesome_dashboard/__init__.py +++ b/awesome_dashboard/__init__.py @@ -1,3 +1,2 @@ -# -*- coding: utf-8 -*- from . import controllers diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py index 31406e8addb..18d9076a621 100644 --- a/awesome_dashboard/__manifest__.py +++ b/awesome_dashboard/__manifest__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- { 'name': "Awesome Dashboard", diff --git a/awesome_dashboard/controllers/__init__.py b/awesome_dashboard/controllers/__init__.py index 457bae27e11..f705942f8f1 100644 --- a/awesome_dashboard/controllers/__init__.py +++ b/awesome_dashboard/controllers/__init__.py @@ -1,3 +1,2 @@ -# -*- coding: utf-8 -*- -from . import controllers \ No newline at end of file +from . import controllers diff --git a/awesome_dashboard/controllers/controllers.py b/awesome_dashboard/controllers/controllers.py index 56d4a051287..869edc21dd2 100644 --- a/awesome_dashboard/controllers/controllers.py +++ b/awesome_dashboard/controllers/controllers.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import logging import random diff --git a/awesome_gallery/__init__.py b/awesome_gallery/__init__.py index a0fdc10fe11..0650744f6bc 100644 --- a/awesome_gallery/__init__.py +++ b/awesome_gallery/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- from . import models diff --git a/awesome_gallery/__manifest__.py b/awesome_gallery/__manifest__.py index 624766dca89..e17eda206f9 100644 --- a/awesome_gallery/__manifest__.py +++ b/awesome_gallery/__manifest__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- { 'name': "Gallery View", 'summary': """ diff --git a/awesome_gallery/models/__init__.py b/awesome_gallery/models/__init__.py index 7f0930ee744..54b9d8cd9fe 100644 --- a/awesome_gallery/models/__init__.py +++ b/awesome_gallery/models/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # import filename_python_file_within_folder_or_subfolder from . import ir_action from . import ir_ui_view diff --git a/awesome_gallery/models/ir_action.py b/awesome_gallery/models/ir_action.py index eae20acbf5c..aa9cd3da816 100644 --- a/awesome_gallery/models/ir_action.py +++ b/awesome_gallery/models/ir_action.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from odoo import fields, models diff --git a/awesome_gallery/models/ir_ui_view.py b/awesome_gallery/models/ir_ui_view.py index 0c11b8298ac..96120decb62 100644 --- a/awesome_gallery/models/ir_ui_view.py +++ b/awesome_gallery/models/ir_ui_view.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from odoo import fields, models diff --git a/awesome_kanban/__init__.py b/awesome_kanban/__init__.py index 40a96afc6ff..e69de29bb2d 100644 --- a/awesome_kanban/__init__.py +++ b/awesome_kanban/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/awesome_kanban/__manifest__.py b/awesome_kanban/__manifest__.py index affef78bb12..5e34244217d 100644 --- a/awesome_kanban/__manifest__.py +++ b/awesome_kanban/__manifest__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- { 'name': "Awesome Kanban", 'summary': """ diff --git a/awesome_owl/__init__.py b/awesome_owl/__init__.py index 457bae27e11..f705942f8f1 100644 --- a/awesome_owl/__init__.py +++ b/awesome_owl/__init__.py @@ -1,3 +1,2 @@ -# -*- coding: utf-8 -*- -from . import controllers \ No newline at end of file +from . import controllers diff --git a/awesome_owl/__manifest__.py b/awesome_owl/__manifest__.py index 77abad510ef..48e4cd63aa6 100644 --- a/awesome_owl/__manifest__.py +++ b/awesome_owl/__manifest__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- { 'name': "Awesome Owl", diff --git a/awesome_owl/controllers/__init__.py b/awesome_owl/controllers/__init__.py index 457bae27e11..f705942f8f1 100644 --- a/awesome_owl/controllers/__init__.py +++ b/awesome_owl/controllers/__init__.py @@ -1,3 +1,2 @@ -# -*- coding: utf-8 -*- -from . import controllers \ No newline at end of file +from . import controllers diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 3c42377f499..64709f5b322 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -12,6 +12,5 @@ 'security/ir.model.access.csv', 'views/estate_property_views.xml', 'views/estate_menus.xml', - ] } diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 09b2099fe84..2f1821a39c1 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1,4 +1,4 @@ from . import estate_property from . import estate_property_type from . import estate_property_tag -from . import estate_property_offer \ No newline at end of file +from . import estate_property_offer diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 50d6cef232a..116113bd267 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -6,13 +6,11 @@ class EstateProperty(models.Model): _name = "estate.property" _description = "its just an estate property" - # Basic fields - name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date(default=datetime.now()+relativedelta(months=3),copy= False) + date_availability = fields.Date(default=datetime.now() + relativedelta(months=3), copy=False) expected_price = fields.Float(required=True) selling_price = fields.Float(readonly=True, copy= False) bedrooms = fields.Integer(default=2) @@ -24,15 +22,14 @@ class EstateProperty(models.Model): garden_orientation = fields.Selection( selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], ) - active= fields.Boolean(default=True) + active=fields.Boolean(default=True) state = fields.Selection( selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancel', 'Cancel')], - required= True, - copy= False, - default= 'new' - ) - + required=True, + copy=False, + default='new' + ) # Relational fields property_type_id = fields.Many2one("estate.property.type", string="Property Type") @@ -41,16 +38,32 @@ class EstateProperty(models.Model): tag_ids = fields.Many2many("estate.property.tag", string="Tags") offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers") - # Computed fields - total_area = fields.Integer(compute="_compute_total_area",readonly=True) + total_area = fields.Integer(compute="_compute_total_area") + best_price = fields.Float(compute="_compute_best_offer", default=0) + # Compute Methods + @api.depends('living_area', 'garden_area') + def _compute_total_area(self): + for record in self: + record.total_area = record.living_area + record.garden_area + @api.depends('offer_ids.price') + def _compute_best_offer(self): + for record in self: + record.best_price = max(record.offer_ids.mapped('price')) - # COMPUTE METHODS - @api.depends('living_area', 'garden_area') - def _compute_total_area(self): - for record in self: - record.total_area = record.living_area + record.garden_area \ No newline at end of file + # On Changes + @api.onchange('garden') + def _onchange_garden(self): + #set default + if self.garden: + self.garden_area = 10 + self.garden_orientation = 'north' + + #clear values + 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 74e60ce740b..836c5ebec48 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,5 @@ -from odoo import fields, models +from odoo import api,fields, models +from dateutil.relativedelta import relativedelta class PropertyOffer(models.Model): _name = "estate.property.offer" @@ -8,3 +9,21 @@ class PropertyOffer(models.Model): status = fields.Selection(copy=False, selection=[('accepted', 'Accepted'), ('refused', 'Refused')]) partner_id = fields.Many2one("res.partner", required=True) property_id = fields.Many2one("estate.property", required=True) + + validity = fields.Integer(default=7) + date_deadline = fields.Datetime(compute="_compute_deadline", inverse="_inverse_deadline") + + + # Compute methods + + @api.depends('validity') + def _compute_deadline(self): + for record in self: + if record.create_date: + record.date_deadline = record.create_date + relativedelta(days=record.validity) + else: + record.date_deadline = fields.Date.today() + relativedelta(days=record.validity) + + def _inverse_deadline(self): + for record in self: + record.validity = (record.date_deadline - record.create_date).days diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py index 9d935786641..5595072489e 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -4,4 +4,4 @@ class PropertyTag(models.Model): _name = "estate.property.tag" _description = "used to add precision to a property" - name = fields.Char(required=True) \ No newline at end of file + name = fields.Char(required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index 313e68ba2ef..a2357643092 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -4,4 +4,4 @@ class PropertyType(models.Model): _name = "estate.property.type" _description = "describe the type property" - name = fields.Char(required=True) \ No newline at end of file + name = fields.Char(required=True) diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 7223773ae71..eb228660227 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -11,6 +11,8 @@ + + @@ -24,7 +26,8 @@ - + +
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 80b1bbc9965..72952055e45 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -42,6 +42,7 @@ + @@ -57,7 +58,7 @@ - + diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 00000000000..8c30b33515d --- /dev/null +++ b/ruff.toml @@ -0,0 +1,42 @@ +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", +] + +# Assume Python 3.12 +target-version = "py312" + +line-length = 255 +[lint] +# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. +select = ["ALL"] +ignore = ["A","ARG","ANN","B","C901","D","DTZ","E501","ERA001","FBT","N","PD","PERF","PIE790","PLR","PT","Q","RSE102","RUF001","RUF012","S","SIM102","SIM108","SLF001","TID252","UP031","TRY003","TRY300","UP038","E713","SIM117","PGH003","RUF005","FIX","TD","TRY400","C408","PLW2901","PTH","EM102","INP001","CPY001","E266","PIE808","PLC2701","RUF100","FA100","FURB","COM812","TRY002","B904","EM101","I001","UP006","UP007","RET","RUF021","E741","ASYNC","AIR","DJ","NPY","FA102","F401"] + +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = ["A","ARG","ANN","B","C901","D","DTZ","E501","ERA001","FBT","N","PD","PERF","PIE790","PLR","PT","Q","RSE102","RUF001","RUF012","S","SIM102","SIM108","SLF001","TID252","UP031","TRY003","TRY300","UP038","E713","SIM117","PGH003","RUF005","FIX","TD","TRY400","C408","PLW2901","PTH","EM102","INP001","CPY001","E266","PIE808","PLC2701","RUF100","FA100","FURB","COM812","TRY002","B904","EM101","I001","UP006","UP007","RET","RUF021","E741","ASYNC","AIR","DJ","NPY","FA102","F401"] From 7e69feff8e62d54b9f2691e7bc280e4eba59e28c Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 20 May 2025 15:15:28 +0200 Subject: [PATCH 12/53] [ADD] gitignore updated --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index b6e47617de1..0e4edeec64d 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,8 @@ dmypy.json # Pyre type checker .pyre/ + + +#pre commit +.pre-commit-config.yaml +ruff.toml From 3bb6ca46f9b1c8ae69ffc81b25094650e1e1a93a Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 20 May 2025 16:32:15 +0200 Subject: [PATCH 13/53] [ADD] estate: chapter 9 done --- .vscode/settings.json | 3 ++ estate/models/estate_property.py | 35 ++++++++++++++------ estate/models/estate_property_offer.py | 18 ++++++++-- estate/models/estate_property_tag.py | 1 + estate/models/estate_property_type.py | 1 + estate/views/estate_property_offer_views.xml | 4 ++- estate/views/estate_property_views.xml | 8 +++-- 7 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..ff5300ef481 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.languageServer": "None" +} \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 116113bd267..65064ac7f36 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,7 +1,8 @@ -from odoo import api, fields, models +from odoo import api, fields, models, exceptions from datetime import datetime from dateutil.relativedelta import relativedelta + class EstateProperty(models.Model): _name = "estate.property" _description = "its just an estate property" @@ -12,7 +13,7 @@ class EstateProperty(models.Model): postcode = fields.Char() date_availability = fields.Date(default=datetime.now() + relativedelta(months=3), copy=False) expected_price = fields.Float(required=True) - selling_price = fields.Float(readonly=True, copy= False) + selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) living_area = fields.Integer() facades = fields.Integer() @@ -22,14 +23,13 @@ class EstateProperty(models.Model): garden_orientation = fields.Selection( selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], ) - active=fields.Boolean(default=True) + active = fields.Boolean(default=True) state = fields.Selection( - selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancel', 'Cancel')], + selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('canceled', 'Canceled')], required=True, copy=False, - default='new' - ) + default='new') # Relational fields property_type_id = fields.Many2one("estate.property.type", string="Property Type") @@ -48,22 +48,37 @@ def _compute_total_area(self): for record in self: record.total_area = record.living_area + record.garden_area - @api.depends('offer_ids.price') def _compute_best_offer(self): for record in self: record.best_price = max(record.offer_ids.mapped('price')) - # On Changes @api.onchange('garden') def _onchange_garden(self): - #set default + # set default if self.garden: self.garden_area = 10 self.garden_orientation = 'north' - #clear values + # clear values else: self.garden_area = 0 self.garden_orientation = None + + # Buttons methods + def set_canceled(self): + for record in self: + if record.state == 'sold': + raise exceptions.UserError("Sold properties cannot be canceled") + + record.state = 'canceled' + return True + + def set_sold(self): + for record in self: + if record.state == 'canceled': + raise exceptions.UserError("Canceled properties cannot be sold") + + record.state = 'sold' + return True diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 836c5ebec48..0dfa49053b0 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,6 +1,7 @@ -from odoo import api,fields, models +from odoo import api, fields, models from dateutil.relativedelta import relativedelta + class PropertyOffer(models.Model): _name = "estate.property.offer" _description = "Offer made by a potential buyer" @@ -13,7 +14,6 @@ class PropertyOffer(models.Model): validity = fields.Integer(default=7) date_deadline = fields.Datetime(compute="_compute_deadline", inverse="_inverse_deadline") - # Compute methods @api.depends('validity') @@ -27,3 +27,17 @@ def _compute_deadline(self): def _inverse_deadline(self): for record in self: record.validity = (record.date_deadline - record.create_date).days + + + # Action methods + def action_accept(self): + for record in self: + record.status = 'accepted' + record.property_id.buyer_id = record.partner_id + record.property_id.selling_price = record.price + return True + + def action_refuse(self): + for record in self: + record.status = 'refused' + return True diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py index 5595072489e..e9fd6e1ae4d 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -1,5 +1,6 @@ from odoo import fields, models + class PropertyTag(models.Model): _name = "estate.property.tag" _description = "used to add precision to a property" diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index a2357643092..8828bd52808 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -1,5 +1,6 @@ from odoo import fields, models + class PropertyType(models.Model): _name = "estate.property.type" _description = "describe the type property" diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index eb228660227..72ee9f44559 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -10,9 +10,11 @@ - + +

From 9255a038daa01859e430c80a41836c2737e86e4a Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Thu, 22 May 2025 10:22:06 +0200 Subject: [PATCH 20/53] [ADD] estate: chapter 12 += Python Inheritance --- estate/models/estate_property.py | 7 +++++++ estate/models/estate_property_offer.py | 14 +++++++++++++- estate/views/estate_property_type_views.xml | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 97667602f5a..7764ec5e1d0 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -84,6 +84,13 @@ def _onchange_garden(self): self.garden_area = 0 self.garden_orientation = None + # CRUD methods + @api.ondelete(at_uninstall=False) + def _chek_state(self): + for record in self: + if record.state != 'new' and record.state != 'canceled': + raise exceptions.UserError("A property must be newly created or canceld to be deleted") + # Buttons methods def set_canceled(self): for record in self: diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index c734db44044..0ad7f111795 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,5 +1,6 @@ -from odoo import api, fields, models +from odoo import api, fields, models, exceptions from dateutil.relativedelta import relativedelta +from odoo.tools.float_utils import float_compare class PropertyOffer(models.Model): @@ -35,6 +36,17 @@ def _inverse_deadline(self): for record in self: record.validity = (record.date_deadline - record.create_date).days + # CRUD methods + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + prop = self.env['estate.property'].browse(vals['property_id']) + if float_compare(vals['price'], prop.best_price, precision_digits=2) == -1: + raise exceptions.UserError("Cannot create an offer with a lower amount than an existing offer") + prop.state = 'offer_received' + + return super().create(vals) + # Action methods def action_accept(self): for record in self: diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml index ce4a5d45d53..c931bc56492 100644 --- a/estate/views/estate_property_type_views.xml +++ b/estate/views/estate_property_type_views.xml @@ -24,7 +24,7 @@
- From d35f9ba9f394f8722dcff38af6b843e980fb193b Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Thu, 22 May 2025 11:17:28 +0200 Subject: [PATCH 21/53] [ADD] estate: chapter 12 done --- estate/__manifest__.py | 1 + estate/models/__init__.py | 1 + estate/models/estate_res_users.py | 7 +++++++ estate/views/estate_property_type_views.xml | 9 ++++++--- estate/views/estate_res_users.xml | 15 +++++++++++++++ 5 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 estate/models/estate_res_users.py create mode 100644 estate/views/estate_res_users.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 0018cfe2871..c1f9524e531 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -12,6 +12,7 @@ 'security/ir.model.access.csv', 'views/estate_property_views.xml', 'views/estate_menus.xml', + 'views/estate_res_users.xml', ], 'license': 'LGPL-3', } diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 2f1821a39c1..06001dca391 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 estate_res_users diff --git a/estate/models/estate_res_users.py b/estate/models/estate_res_users.py new file mode 100644 index 00000000000..47edfe2c527 --- /dev/null +++ b/estate/models/estate_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", "sales_id", domain="['|', ('state', '=', 'new'), ('state', '=', 'offer_received')]") diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml index c931bc56492..d096dab08bb 100644 --- a/estate/views/estate_property_type_views.xml +++ b/estate/views/estate_property_type_views.xml @@ -24,9 +24,12 @@
-

diff --git a/estate/views/estate_res_users.xml b/estate/views/estate_res_users.xml new file mode 100644 index 00000000000..d9e25246d26 --- /dev/null +++ b/estate/views/estate_res_users.xml @@ -0,0 +1,15 @@ + + + + Estate User Inherits form + res.users + + + + + + + + + + \ No newline at end of file From a3f718a3b25150eea484028cbfce783827ea7271 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Thu, 22 May 2025 13:41:34 +0200 Subject: [PATCH 22/53] [FIX] estate: chapter 12 done --- estate/views/estate_property_type_views.xml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml index d096dab08bb..7dba367059a 100644 --- a/estate/views/estate_property_type_views.xml +++ b/estate/views/estate_property_type_views.xml @@ -24,13 +24,14 @@
- +

From ab5f48123493d8a478912e47c545de1b555ce5eb Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Thu, 22 May 2025 14:24:19 +0200 Subject: [PATCH 23/53] [FIX] estate: chapter 12 actual final fix v2 final LAST fix --- estate/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index c1f9524e531..d6651af9ea9 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -6,8 +6,8 @@ 'installable': True, 'application': True, 'data': [ - 'views/estate_property_type_views.xml', 'views/estate_property_offer_views.xml', + 'views/estate_property_type_views.xml', 'views/estate_property_tag_views.xml', 'security/ir.model.access.csv', 'views/estate_property_views.xml', From 0b88c32aa438d228513c055817f21336b62c3552 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Thu, 22 May 2025 15:01:40 +0200 Subject: [PATCH 24/53] [FIX] estate: chapter 13 done + chapter 12 fix v4 (the last one) --- estate/models/estate_property.py | 4 +-- estate/models/estate_property_offer.py | 2 +- estate_account/__init__.py | 1 + estate_account/__manifest__.py | 14 ++++++++++ estate_account/models/__init__.py | 1 + estate_account/models/estate_property.py | 29 +++++++++++++++++++++ estate_account/security/ir.model.access.csv | 1 + 7 files changed, 49 insertions(+), 3 deletions(-) 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 create mode 100644 estate_account/security/ir.model.access.csv diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 7764ec5e1d0..f5f368ef824 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -98,7 +98,7 @@ def set_canceled(self): raise exceptions.UserError("Sold properties cannot be canceled") record.state = 'canceled' - return True + return True def set_sold(self): for record in self: @@ -106,4 +106,4 @@ def set_sold(self): raise exceptions.UserError("Canceled properties cannot be sold") record.state = 'sold' - return True + return True diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 0ad7f111795..fab0b6128d4 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -45,7 +45,7 @@ def create(self, vals_list): raise exceptions.UserError("Cannot create an offer with a lower amount than an existing offer") prop.state = 'offer_received' - return super().create(vals) + return super().create(vals_list) # Action methods def action_accept(self): 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..041b3b1e732 --- /dev/null +++ b/estate_account/__manifest__.py @@ -0,0 +1,14 @@ +{ + 'name': 'estate_account', + 'depends': [ + 'base', + 'account', + 'estate' + ], + 'installable': True, + 'application': True, + 'data': [ + 'security/ir.model.access.csv', + ], + 'license': 'LGPL-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..ae9efea629c --- /dev/null +++ b/estate_account/models/estate_property.py @@ -0,0 +1,29 @@ +from odoo import models, exceptions, Command + + +class EstateProperty(models.Model): + _inherit = 'estate.property' + + def set_sold(self): + # print("test") + if not self.buyer_id: + raise exceptions.UserError("A buyer is needed to sell a property") + + self.env['account.move'].with_context(default_move_type='out_invoice').create( + { + "partner_id": self.buyer_id.id, + "invoice_line_ids": [ + Command.create({ + "name": "Price Percentage", + "quantity": 1, + "price_unit": self.selling_price * 6 / 100, + }), + Command.create({ + "name": "Administrative Fees", + "quantity": 1, + "price_unit": 100.00, + }) + ] + }) + + return super().set_sold() diff --git a/estate_account/security/ir.model.access.csv b/estate_account/security/ir.model.access.csv new file mode 100644 index 00000000000..301b7dab167 --- /dev/null +++ b/estate_account/security/ir.model.access.csv @@ -0,0 +1 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink From 84710d97645eabefecbcd987341aacf53e936a13 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Thu, 22 May 2025 16:09:00 +0200 Subject: [PATCH 25/53] [FIX] estate: chapter 14 + 15 done --- estate/views/estate_property_views.xml | 29 +++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index ecfd93b05bd..33b7c3ea3e6 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -3,7 +3,7 @@ Property estate.property - list,form + list,form,kanban {'search_default_available': True} @@ -88,7 +88,34 @@
+ + + estate.property.kanban + estate.property + + + + + +
+

+
Expected Price: +
+
+ Offer Price: +
+
+ Selling Price: +
+
+ +
+
+
+
+
+
From 0356b6bed5067bc14fc1966d25135f065ad98cbe Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 23 May 2025 10:25:59 +0200 Subject: [PATCH 26/53] [REV] revised code on mathieu's comments --- .gitignore | 3 ++ .pre-commit-config.yaml | 6 --- .vscode/settings.json | 3 -- estate/models/estate_property.py | 10 ++--- estate/models/estate_property_offer.py | 7 ++-- estate/views/estate_property_offer_views.xml | 4 +- estate/views/estate_property_views.xml | 6 +-- estate_account/__manifest__.py | 1 - estate_account/models/estate_property.py | 1 - ruff.toml | 42 -------------------- 10 files changed, 16 insertions(+), 67 deletions(-) delete mode 100644 .pre-commit-config.yaml delete mode 100644 .vscode/settings.json delete mode 100644 ruff.toml diff --git a/.gitignore b/.gitignore index 0e4edeec64d..d469fbef6fb 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,6 @@ dmypy.json #pre commit .pre-commit-config.yaml ruff.toml + + +.vscode/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 0bed35823b1..00000000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -repos: - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.3 # Use the latest Ruff version or the one that matches your setup - hooks: - - id: ruff - args: [ --fix] diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ff5300ef481..00000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.languageServer": "None" -} \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index f5f368ef824..8e83927881d 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -14,7 +14,7 @@ class EstateProperty(models.Model): name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date(default=datetime.now() + relativedelta(months=3), copy=False) + date_availability = fields.Date(default=fields.Date.today()+ relativedelta(months=3), copy=False) expected_price = fields.Float(required=True) selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) @@ -53,11 +53,11 @@ class EstateProperty(models.Model): 'The selling price of a property should be positive') ] - @api.constrains('selling_price') + @api.constrains('selling_price', 'expected_price') def _check_selling_price(self): for record in self: if not float_is_zero(record.selling_price, precision_digits=2): - if float_compare(record.selling_price, record.expected_price * 0.9, precision_digits=2) == -1: + if float_compare(record.selling_price, record.expected_price * 0.9, precision_digits=2) < 0: raise ValidationError("The selling price cannot be less than 90% of the expected price") # Compute Methods @@ -82,13 +82,13 @@ def _onchange_garden(self): # clear values else: self.garden_area = 0 - self.garden_orientation = None + self.garden_orientation = False # CRUD methods @api.ondelete(at_uninstall=False) def _chek_state(self): for record in self: - if record.state != 'new' and record.state != 'canceled': + if record.state in ['new', 'canceled']: raise exceptions.UserError("A property must be newly created or canceld to be deleted") # Buttons methods diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index fab0b6128d4..e9c271074b3 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -15,7 +15,7 @@ class PropertyOffer(models.Model): property_type_id = fields.Many2one("estate.property.type", related="property_id.property_type_id", store=True) validity = fields.Integer(default=7) - date_deadline = fields.Datetime(compute="_compute_deadline", inverse="_inverse_deadline") + date_deadline = fields.Date(compute="_compute_deadline", inverse="_inverse_deadline") # Constraints _sql_constraints = [ @@ -34,14 +34,15 @@ def _compute_deadline(self): def _inverse_deadline(self): for record in self: - record.validity = (record.date_deadline - record.create_date).days + if record.create_date: + record.validity = (record.date_deadline - record.create_date.date()).days # CRUD methods @api.model_create_multi def create(self, vals_list): for vals in vals_list: prop = self.env['estate.property'].browse(vals['property_id']) - if float_compare(vals['price'], prop.best_price, precision_digits=2) == -1: + if float_compare(vals['price'], prop.best_price, precision_digits=2) < 0: raise exceptions.UserError("Cannot create an offer with a lower amount than an existing offer") prop.state = 'offer_received' diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index c2a815bf601..ec51ce0355e 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -16,8 +16,8 @@ -
@@ -69,9 +69,7 @@ - - diff --git a/estate_account/__manifest__.py b/estate_account/__manifest__.py index 041b3b1e732..ffec145e766 100644 --- a/estate_account/__manifest__.py +++ b/estate_account/__manifest__.py @@ -1,7 +1,6 @@ { 'name': 'estate_account', 'depends': [ - 'base', 'account', 'estate' ], diff --git a/estate_account/models/estate_property.py b/estate_account/models/estate_property.py index ae9efea629c..81f4a07b3d4 100644 --- a/estate_account/models/estate_property.py +++ b/estate_account/models/estate_property.py @@ -5,7 +5,6 @@ class EstateProperty(models.Model): _inherit = 'estate.property' def set_sold(self): - # print("test") if not self.buyer_id: raise exceptions.UserError("A buyer is needed to sell a property") diff --git a/ruff.toml b/ruff.toml deleted file mode 100644 index 8c30b33515d..00000000000 --- a/ruff.toml +++ /dev/null @@ -1,42 +0,0 @@ -# Exclude a variety of commonly ignored directories. -exclude = [ - ".bzr", - ".direnv", - ".eggs", - ".git", - ".git-rewrite", - ".hg", - ".ipynb_checkpoints", - ".mypy_cache", - ".nox", - ".pants.d", - ".pyenv", - ".pytest_cache", - ".pytype", - ".ruff_cache", - ".svn", - ".tox", - ".venv", - ".vscode", - "__pypackages__", - "_build", - "buck-out", - "build", - "dist", - "node_modules", - "site-packages", - "venv", -] - -# Assume Python 3.12 -target-version = "py312" - -line-length = 255 -[lint] -# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. -select = ["ALL"] -ignore = ["A","ARG","ANN","B","C901","D","DTZ","E501","ERA001","FBT","N","PD","PERF","PIE790","PLR","PT","Q","RSE102","RUF001","RUF012","S","SIM102","SIM108","SLF001","TID252","UP031","TRY003","TRY300","UP038","E713","SIM117","PGH003","RUF005","FIX","TD","TRY400","C408","PLW2901","PTH","EM102","INP001","CPY001","E266","PIE808","PLC2701","RUF100","FA100","FURB","COM812","TRY002","B904","EM101","I001","UP006","UP007","RET","RUF021","E741","ASYNC","AIR","DJ","NPY","FA102","F401"] - -# Allow fix for all enabled rules (when `--fix`) is provided. -fixable = ["ALL"] -unfixable = ["A","ARG","ANN","B","C901","D","DTZ","E501","ERA001","FBT","N","PD","PERF","PIE790","PLR","PT","Q","RSE102","RUF001","RUF012","S","SIM102","SIM108","SLF001","TID252","UP031","TRY003","TRY300","UP038","E713","SIM117","PGH003","RUF005","FIX","TD","TRY400","C408","PLW2901","PTH","EM102","INP001","CPY001","E266","PIE808","PLC2701","RUF100","FA100","FURB","COM812","TRY002","B904","EM101","I001","UP006","UP007","RET","RUF021","E741","ASYNC","AIR","DJ","NPY","FA102","F401"] From e9b64100ebce1a45a52ac6c2a4fdb27474b466cc Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 23 May 2025 10:25:59 +0200 Subject: [PATCH 27/53] [REV] revised code on mathieu's comments --- estate/models/estate_property.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 8e83927881d..1621750cd1b 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,5 +1,4 @@ from odoo import api, fields, models, exceptions -from datetime import datetime from dateutil.relativedelta import relativedelta from odoo.tools.float_utils import float_compare, float_is_zero from odoo.exceptions import ValidationError @@ -14,7 +13,7 @@ class EstateProperty(models.Model): name = fields.Char(required=True) description = fields.Text() postcode = fields.Char() - date_availability = fields.Date(default=fields.Date.today()+ relativedelta(months=3), copy=False) + date_availability = fields.Date(default=fields.Date.today() + relativedelta(months=3), copy=False) expected_price = fields.Float(required=True) selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) @@ -53,10 +52,12 @@ class EstateProperty(models.Model): 'The selling price of a property should be positive') ] + @api.constrains('selling_price', 'expected_price') @api.constrains('selling_price', 'expected_price') def _check_selling_price(self): for record in self: if not float_is_zero(record.selling_price, precision_digits=2): + if float_compare(record.selling_price, record.expected_price * 0.9, precision_digits=2) < 0: if float_compare(record.selling_price, record.expected_price * 0.9, precision_digits=2) < 0: raise ValidationError("The selling price cannot be less than 90% of the expected price") @@ -83,12 +84,13 @@ def _onchange_garden(self): else: self.garden_area = 0 self.garden_orientation = False + self.garden_orientation = False # CRUD methods @api.ondelete(at_uninstall=False) def _chek_state(self): for record in self: - if record.state in ['new', 'canceled']: + if record.state in ['new', 'canceled']: raise exceptions.UserError("A property must be newly created or canceld to be deleted") # Buttons methods From 6c3ab74c3703f9b7a9e1f7bca8e5d07563c80940 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 23 May 2025 10:43:39 +0200 Subject: [PATCH 28/53] [REV] revised code on mathieu's comments --- estate/models/estate_property.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 1621750cd1b..16e83e816a6 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -52,12 +52,10 @@ class EstateProperty(models.Model): 'The selling price of a property should be positive') ] - @api.constrains('selling_price', 'expected_price') @api.constrains('selling_price', 'expected_price') def _check_selling_price(self): for record in self: if not float_is_zero(record.selling_price, precision_digits=2): - if float_compare(record.selling_price, record.expected_price * 0.9, precision_digits=2) < 0: if float_compare(record.selling_price, record.expected_price * 0.9, precision_digits=2) < 0: raise ValidationError("The selling price cannot be less than 90% of the expected price") @@ -84,7 +82,6 @@ def _onchange_garden(self): else: self.garden_area = 0 self.garden_orientation = False - self.garden_orientation = False # CRUD methods @api.ondelete(at_uninstall=False) From 546e9773389c007ed855ff62d26d7e3d4ffb4069 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 23 May 2025 13:33:57 +0200 Subject: [PATCH 29/53] [ADD] awesome_owl: 1.2 extract the counter in a sub component --- awesome_owl/static/src/counter/counter.js | 15 +++++++++++++++ awesome_owl/static/src/counter/counter.xml | 10 ++++++++++ awesome_owl/static/src/main.js | 3 ++- awesome_owl/static/src/playground.js | 3 +++ awesome_owl/static/src/playground.xml | 3 ++- 5 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 awesome_owl/static/src/counter/counter.js create mode 100644 awesome_owl/static/src/counter/counter.xml diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js new file mode 100644 index 00000000000..0ed8e955a0e --- /dev/null +++ b/awesome_owl/static/src/counter/counter.js @@ -0,0 +1,15 @@ +/** @odoo-module **/ + +import { useState, Component } from "@odoo/owl"; + +export class Counter extends Component { + static template = "awesome_owl.counter"; + + setup() { + this.state = useState({ value: 0 }); + } + + increment() { + this.state.value++; + } +} diff --git a/awesome_owl/static/src/counter/counter.xml b/awesome_owl/static/src/counter/counter.xml new file mode 100644 index 00000000000..666c051075b --- /dev/null +++ b/awesome_owl/static/src/counter/counter.xml @@ -0,0 +1,10 @@ + + + + +

Counter: + +

+
+ +
diff --git a/awesome_owl/static/src/main.js b/awesome_owl/static/src/main.js index 1af6c827e0b..5b8c630daff 100644 --- a/awesome_owl/static/src/main.js +++ b/awesome_owl/static/src/main.js @@ -1,6 +1,7 @@ import { whenReady } from "@odoo/owl"; import { mountComponent } from "@web/env"; import { Playground } from "./playground"; +import { Counter } from "./counter/counter" const config = { dev: true, @@ -8,4 +9,4 @@ const config = { }; // Mount the Playground component when the document.body is ready -whenReady(() => mountComponent(Playground, document.body, config)); +whenReady(() => mountComponent(Playground, document.body, config)); diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 657fb8b07bb..e8101806068 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,7 +1,10 @@ /** @odoo-module **/ import { Component } from "@odoo/owl"; +import { Counter } from "./counter/counter"; export class Playground extends Component { static template = "awesome_owl.playground"; + + static components = { Counter }; } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 4fb905d59f9..173964a14d3 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -3,7 +3,8 @@
- hello world + +
From c98f3679de6b9d36c07cde97f469b52c55d2a30b Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 23 May 2025 14:07:37 +0200 Subject: [PATCH 30/53] [ADD] awesome_owl: 1.3 add a simple card component --- awesome_owl/static/src/card/card.js | 15 +++++++++++++++ awesome_owl/static/src/card/card.xml | 13 +++++++++++++ awesome_owl/static/src/main.js | 1 - awesome_owl/static/src/playground.js | 3 ++- awesome_owl/static/src/playground.xml | 5 +++++ 5 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 awesome_owl/static/src/card/card.js create mode 100644 awesome_owl/static/src/card/card.xml diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js new file mode 100644 index 00000000000..b67003281af --- /dev/null +++ b/awesome_owl/static/src/card/card.js @@ -0,0 +1,15 @@ +/** @odoo-module **/ + +import { useState, Component } from "@odoo/owl"; + +export class Card extends Component { + static template = "awesome_owl.card"; + + setup() { + this.state = useState({ value: 0 }); + } + + increment() { + this.state.value++; + } +} diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml new file mode 100644 index 00000000000..e3eda032a19 --- /dev/null +++ b/awesome_owl/static/src/card/card.xml @@ -0,0 +1,13 @@ + + + + +
+
+
+

+
+
+
+ +
diff --git a/awesome_owl/static/src/main.js b/awesome_owl/static/src/main.js index 5b8c630daff..d7c6588ab71 100644 --- a/awesome_owl/static/src/main.js +++ b/awesome_owl/static/src/main.js @@ -1,7 +1,6 @@ import { whenReady } from "@odoo/owl"; import { mountComponent } from "@web/env"; import { Playground } from "./playground"; -import { Counter } from "./counter/counter" const config = { dev: true, diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index e8101806068..e4a49fdf60e 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -2,9 +2,10 @@ import { Component } from "@odoo/owl"; import { Counter } from "./counter/counter"; +import { Card } from "./card/card"; export class Playground extends Component { static template = "awesome_owl.playground"; - static components = { Counter }; + static components = { Counter, Card }; } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 173964a14d3..535c7a31278 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -6,6 +6,11 @@ + +
+ + +
From 40c68a9f8279a7106942e10021cfd0b714789821 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 23 May 2025 14:25:51 +0200 Subject: [PATCH 31/53] [ADD] awesome_owl: 1.4 markup to display html --- awesome_owl/static/src/card/card.js | 8 -------- awesome_owl/static/src/card/card.xml | 4 ++-- awesome_owl/static/src/playground.js | 7 ++++++- awesome_owl/static/src/playground.xml | 4 ++-- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index b67003281af..836a765ff07 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -4,12 +4,4 @@ import { useState, Component } from "@odoo/owl"; export class Card extends Component { static template = "awesome_owl.card"; - - setup() { - this.state = useState({ value: 0 }); - } - - increment() { - this.state.value++; - } } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index e3eda032a19..0ea8bd2d305 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -4,8 +4,8 @@
-
-

+
+

diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index e4a49fdf60e..5e7a8516357 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Component } from "@odoo/owl"; +import { Component, markup } from "@odoo/owl"; import { Counter } from "./counter/counter"; import { Card } from "./card/card"; @@ -8,4 +8,9 @@ export class Playground extends Component { static template = "awesome_owl.playground"; static components = { Counter, Card }; + + setup() { + this.content = "
some content
"; + this.content2 = markup("
some content
"); + } } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 535c7a31278..3ea43d9ee79 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -8,8 +8,8 @@
- - + +
From 4a2ce3368dfe1ef5d14c09e7b5f4a65c4b60dbcb Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 23 May 2025 14:47:41 +0200 Subject: [PATCH 32/53] [ADD] awesome_owl: 1.5 + 1.6 props validation and sum oftwo Counter --- awesome_owl/static/src/card/card.js | 5 +++++ awesome_owl/static/src/counter/counter.js | 6 ++++++ awesome_owl/static/src/playground.js | 7 ++++++- awesome_owl/static/src/playground.xml | 5 +++-- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index 836a765ff07..09010f223c7 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -4,4 +4,9 @@ import { useState, Component } from "@odoo/owl"; export class Card extends Component { static template = "awesome_owl.card"; + + static props = { + title: String, + content: String + }; } diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js index 0ed8e955a0e..be6faa010e6 100644 --- a/awesome_owl/static/src/counter/counter.js +++ b/awesome_owl/static/src/counter/counter.js @@ -4,6 +4,9 @@ import { useState, Component } from "@odoo/owl"; export class Counter extends Component { static template = "awesome_owl.counter"; + static props = { + onChange: { type: Function, optional: true } + }; setup() { this.state = useState({ value: 0 }); @@ -11,5 +14,8 @@ export class Counter extends Component { increment() { this.state.value++; + if (this.props.onChange) { + this.props.onChange(); + } } } diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 5e7a8516357..7e95127ba95 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Component, markup } from "@odoo/owl"; +import { Component, markup, useState } from "@odoo/owl"; import { Counter } from "./counter/counter"; import { Card } from "./card/card"; @@ -12,5 +12,10 @@ export class Playground extends Component { setup() { this.content = "
some content
"; this.content2 = markup("
some content
"); + this.sum = useState({ value: 0 }); + } + + incrementSum() { + this.sum.value++; } } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 3ea43d9ee79..48e93cf986e 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -3,8 +3,9 @@
- - + + +
Sum:
From c3713d8a1c0c3a7f8c9c67ca6958060fc7af3831 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 26 May 2025 11:43:39 +0200 Subject: [PATCH 33/53] [ADD] awesome_owl: 1.7 little todolist --- awesome_owl/static/src/playground.js | 3 ++- awesome_owl/static/src/playground.xml | 4 ++++ awesome_owl/static/src/todolist/todoitem.js | 15 +++++++++++++++ awesome_owl/static/src/todolist/todoitem.xml | 11 +++++++++++ awesome_owl/static/src/todolist/todolist.js | 16 ++++++++++++++++ awesome_owl/static/src/todolist/todolist.xml | 12 ++++++++++++ 6 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 awesome_owl/static/src/todolist/todoitem.js create mode 100644 awesome_owl/static/src/todolist/todoitem.xml create mode 100644 awesome_owl/static/src/todolist/todolist.js create mode 100644 awesome_owl/static/src/todolist/todolist.xml diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 7e95127ba95..809a89aba84 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -3,11 +3,12 @@ import { Component, markup, useState } from "@odoo/owl"; import { Counter } from "./counter/counter"; import { Card } from "./card/card"; +import { TodoList } from "./todolist/todolist"; export class Playground extends Component { static template = "awesome_owl.playground"; - static components = { Counter, Card }; + static components = { Counter, Card, TodoList }; setup() { this.content = "
some content
"; diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 48e93cf986e..6ec556f8ea6 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -12,6 +12,10 @@
+ + + +
diff --git a/awesome_owl/static/src/todolist/todoitem.js b/awesome_owl/static/src/todolist/todoitem.js new file mode 100644 index 00000000000..fcce0a71158 --- /dev/null +++ b/awesome_owl/static/src/todolist/todoitem.js @@ -0,0 +1,15 @@ +/** @odoo-module **/ + +import { Component } from "@odoo/owl"; + +export class TodoItem extends Component { + static template = "awesome_owl.todoitem"; + + static props = { + todo: { + type: Object, + shape: { id: Number, description: String, isCompleted: Boolean } + } + }; + +} diff --git a/awesome_owl/static/src/todolist/todoitem.xml b/awesome_owl/static/src/todolist/todoitem.xml new file mode 100644 index 00000000000..7345a54c605 --- /dev/null +++ b/awesome_owl/static/src/todolist/todoitem.xml @@ -0,0 +1,11 @@ + + + + +
+ . + +
+
+ +
diff --git a/awesome_owl/static/src/todolist/todolist.js b/awesome_owl/static/src/todolist/todolist.js new file mode 100644 index 00000000000..1c1d9fdd8f3 --- /dev/null +++ b/awesome_owl/static/src/todolist/todolist.js @@ -0,0 +1,16 @@ +/** @odoo-module **/ + +import { useState, Component } from "@odoo/owl"; +import { TodoItem } from "./todoitem"; + +export class TodoList extends Component { + static template = "awesome_owl.todolist"; + static components = { TodoItem }; + + setup() { + this.todos = useState([ + { id: 1, description: "write tutorial", isCompleted: true }, + { id: 2, description: "buy milk", isCompleted: false }, + ]); + } +} diff --git a/awesome_owl/static/src/todolist/todolist.xml b/awesome_owl/static/src/todolist/todolist.xml new file mode 100644 index 00000000000..8353593bd2d --- /dev/null +++ b/awesome_owl/static/src/todolist/todolist.xml @@ -0,0 +1,12 @@ + + + + +
+ + + +
+
+ +
From 933b27716784129464204232ad3f758e9bcdbecd Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 26 May 2025 13:51:28 +0200 Subject: [PATCH 34/53] [ADD] awesome_owl: 1.8 +1.9 dynamic attributes & user can add todos --- awesome_owl/static/src/todolist/todoitem.xml | 2 +- awesome_owl/static/src/todolist/todolist.js | 18 ++++++++++++++---- awesome_owl/static/src/todolist/todolist.xml | 7 ++++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/awesome_owl/static/src/todolist/todoitem.xml b/awesome_owl/static/src/todolist/todoitem.xml index 7345a54c605..8652aacb7f1 100644 --- a/awesome_owl/static/src/todolist/todoitem.xml +++ b/awesome_owl/static/src/todolist/todoitem.xml @@ -2,7 +2,7 @@ -
+
.
diff --git a/awesome_owl/static/src/todolist/todolist.js b/awesome_owl/static/src/todolist/todolist.js index 1c1d9fdd8f3..52dc1733ab0 100644 --- a/awesome_owl/static/src/todolist/todolist.js +++ b/awesome_owl/static/src/todolist/todolist.js @@ -8,9 +8,19 @@ export class TodoList extends Component { static components = { TodoItem }; setup() { - this.todos = useState([ - { id: 1, description: "write tutorial", isCompleted: true }, - { id: 2, description: "buy milk", isCompleted: false }, - ]); + this.nextId = 1; + this.todos = useState([]); + } + + addTodo(ev){ + const value = ev.target.value.trim() + if (value !== "" && ev.keyCode === 13) { + this.todos.push({ + id: this.nextId++, + description: value, + isCompleted: false + }); + ev.target.value = ""; + } } } diff --git a/awesome_owl/static/src/todolist/todolist.xml b/awesome_owl/static/src/todolist/todolist.xml index 8353593bd2d..107aa04da31 100644 --- a/awesome_owl/static/src/todolist/todolist.xml +++ b/awesome_owl/static/src/todolist/todolist.xml @@ -3,9 +3,10 @@
- - - + + + +
From 588ea02ebdfd6d248dccdb54cf08f100129b3c28 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 26 May 2025 15:05:56 +0200 Subject: [PATCH 35/53] [ADD] awesome_owl: 1.10 auto focus on input --- awesome_owl/static/src/todolist/todolist.js | 2 ++ awesome_owl/static/src/todolist/todolist.xml | 2 +- awesome_owl/static/src/utils.js | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 awesome_owl/static/src/utils.js diff --git a/awesome_owl/static/src/todolist/todolist.js b/awesome_owl/static/src/todolist/todolist.js index 52dc1733ab0..31d497f6996 100644 --- a/awesome_owl/static/src/todolist/todolist.js +++ b/awesome_owl/static/src/todolist/todolist.js @@ -2,6 +2,7 @@ import { useState, Component } from "@odoo/owl"; import { TodoItem } from "./todoitem"; +import { useAutofocus } from "../utils"; export class TodoList extends Component { static template = "awesome_owl.todolist"; @@ -10,6 +11,7 @@ export class TodoList extends Component { setup() { this.nextId = 1; this.todos = useState([]); + useAutofocus("input") } addTodo(ev){ diff --git a/awesome_owl/static/src/todolist/todolist.xml b/awesome_owl/static/src/todolist/todolist.xml index 107aa04da31..7b03252922a 100644 --- a/awesome_owl/static/src/todolist/todolist.xml +++ b/awesome_owl/static/src/todolist/todolist.xml @@ -3,7 +3,7 @@
- + diff --git a/awesome_owl/static/src/utils.js b/awesome_owl/static/src/utils.js new file mode 100644 index 00000000000..8e29548799a --- /dev/null +++ b/awesome_owl/static/src/utils.js @@ -0,0 +1,8 @@ +import { useRef, onMounted } from "@odoo/owl"; + +export function useAutofocus(refName) { + const myref = useRef(refName); + onMounted(() => { + myref.el.focus(); + }); +} \ No newline at end of file From 7b3aeb8ac6894fcee23b9e46df192bd0ab81ac36 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 26 May 2025 16:45:09 +0200 Subject: [PATCH 36/53] [ADD] awesome_owl: 1.11 toggling todos --- awesome_owl/static/src/playground.xml | 3 +-- awesome_owl/static/src/todolist/todoitem.js | 7 ++++++- awesome_owl/static/src/todolist/todoitem.xml | 9 ++++++--- awesome_owl/static/src/todolist/todolist.js | 7 +++++++ awesome_owl/static/src/todolist/todolist.xml | 4 ++-- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 6ec556f8ea6..fab532e36c8 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -13,9 +13,8 @@
- - +
diff --git a/awesome_owl/static/src/todolist/todoitem.js b/awesome_owl/static/src/todolist/todoitem.js index fcce0a71158..362e3176ad1 100644 --- a/awesome_owl/static/src/todolist/todoitem.js +++ b/awesome_owl/static/src/todolist/todoitem.js @@ -9,7 +9,12 @@ export class TodoItem extends Component { todo: { type: Object, shape: { id: Number, description: String, isCompleted: Boolean } - } + }, + toggleState: Function }; + onChange() { + this.props.toggleState(this.props.todo.id); + } + } diff --git a/awesome_owl/static/src/todolist/todoitem.xml b/awesome_owl/static/src/todolist/todoitem.xml index 8652aacb7f1..8f55d27787a 100644 --- a/awesome_owl/static/src/todolist/todoitem.xml +++ b/awesome_owl/static/src/todolist/todoitem.xml @@ -2,9 +2,12 @@ -
- . - +
+ +
diff --git a/awesome_owl/static/src/todolist/todolist.js b/awesome_owl/static/src/todolist/todolist.js index 31d497f6996..fe6259cf5ea 100644 --- a/awesome_owl/static/src/todolist/todolist.js +++ b/awesome_owl/static/src/todolist/todolist.js @@ -25,4 +25,11 @@ export class TodoList extends Component { ev.target.value = ""; } } + + toggleTodo(todoId) { + const todo = this.todos.find((todo) => todo.id === todoId); + if (todo) { + todo.isCompleted = !todo.isCompleted; + } + } } diff --git a/awesome_owl/static/src/todolist/todolist.xml b/awesome_owl/static/src/todolist/todolist.xml index 7b03252922a..b816f391dc7 100644 --- a/awesome_owl/static/src/todolist/todolist.xml +++ b/awesome_owl/static/src/todolist/todolist.xml @@ -3,9 +3,9 @@
- + - +
From 2fa0f723dff36f8b689373ecdbc0ab1c1d3d0f2e Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Mon, 26 May 2025 17:10:25 +0200 Subject: [PATCH 37/53] [ADD] awesome_owl: 1.12 deleting todos --- awesome_owl/static/src/todolist/todoitem.js | 7 ++++++- awesome_owl/static/src/todolist/todoitem.xml | 2 ++ awesome_owl/static/src/todolist/todolist.js | 7 +++++++ awesome_owl/static/src/todolist/todolist.xml | 2 +- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/awesome_owl/static/src/todolist/todoitem.js b/awesome_owl/static/src/todolist/todoitem.js index 362e3176ad1..c355a96df46 100644 --- a/awesome_owl/static/src/todolist/todoitem.js +++ b/awesome_owl/static/src/todolist/todoitem.js @@ -10,11 +10,16 @@ export class TodoItem extends Component { type: Object, shape: { id: Number, description: String, isCompleted: Boolean } }, - toggleState: Function + toggleState: Function, + removeTodo: Function }; onChange() { this.props.toggleState(this.props.todo.id); } + onRemove() { + this.props.removeTodo(this.props.todo.id) + } + } diff --git a/awesome_owl/static/src/todolist/todoitem.xml b/awesome_owl/static/src/todolist/todoitem.xml index 8f55d27787a..9cd8ed957f3 100644 --- a/awesome_owl/static/src/todolist/todoitem.xml +++ b/awesome_owl/static/src/todolist/todoitem.xml @@ -8,7 +8,9 @@ . +
+
diff --git a/awesome_owl/static/src/todolist/todolist.js b/awesome_owl/static/src/todolist/todolist.js index fe6259cf5ea..2a6d0c6f70d 100644 --- a/awesome_owl/static/src/todolist/todolist.js +++ b/awesome_owl/static/src/todolist/todolist.js @@ -32,4 +32,11 @@ export class TodoList extends Component { todo.isCompleted = !todo.isCompleted; } } + + removeTodo(todoId) { + const todoIndex = this.todos.findIndex((todo) => todo.id === todoId); + if (todoIndex >= 0) { + this.todos.splice(todoIndex, 1); + } + } } diff --git a/awesome_owl/static/src/todolist/todolist.xml b/awesome_owl/static/src/todolist/todolist.xml index b816f391dc7..a3446db8f74 100644 --- a/awesome_owl/static/src/todolist/todolist.xml +++ b/awesome_owl/static/src/todolist/todolist.xml @@ -5,7 +5,7 @@
- +
From 8e654630fa5aee839a9bba3db969b56846f60ab6 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 27 May 2025 15:08:30 +0200 Subject: [PATCH 38/53] [ADD] awesome_owl: 1.13 generic card with slots --- awesome_owl/static/src/card/card.js | 7 ++++++- awesome_owl/static/src/card/card.xml | 2 +- awesome_owl/static/src/playground.xml | 8 ++++++-- awesome_owl/static/src/todolist/todoitem.xml | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index 09010f223c7..a266a59808b 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -7,6 +7,11 @@ export class Card extends Component { static props = { title: String, - content: String + slots: { + type: Object, + shape: { + default: true + } + }, }; } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 0ea8bd2d305..98f8d7dbca9 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -5,7 +5,7 @@
-

+

diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index fab532e36c8..bb098f116de 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -9,8 +9,12 @@
- - + + Content of card 1 + + + +
diff --git a/awesome_owl/static/src/todolist/todoitem.xml b/awesome_owl/static/src/todolist/todoitem.xml index 9cd8ed957f3..ac1b5f1a7ce 100644 --- a/awesome_owl/static/src/todolist/todoitem.xml +++ b/awesome_owl/static/src/todolist/todoitem.xml @@ -12,5 +12,5 @@
- +
From 63d1d12ee454bdc8f279eb5ce3735cf3341dda15 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 27 May 2025 15:48:28 +0200 Subject: [PATCH 39/53] [ADD] awesome_owl: 1.14 minimizing card content --- awesome_owl/static/src/card/card.js | 11 +++++++++++ awesome_owl/static/src/card/card.xml | 12 ++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index a266a59808b..9b55df76a50 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -14,4 +14,15 @@ export class Card extends Component { } }, }; + + + setup() { + this.state = useState({ + isOpen: false, + }); + } + + toggle() { + this.state.isOpen = !this.state.isOpen; + } } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 98f8d7dbca9..db5e9480fb4 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -4,8 +4,16 @@
-
-

+
+ + +
+

+ +

From e078e49d2d064c4398d69b9e62c325259054d1a4 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 27 May 2025 16:19:17 +0200 Subject: [PATCH 40/53] [ADD] awesome_dashboard 2.1 new layout --- awesome_dashboard/static/src/dashboard.js | 8 ++++++++ awesome_dashboard/static/src/dashboard.scss | 3 +++ awesome_dashboard/static/src/dashboard.xml | 4 ++++ 3 files changed, 15 insertions(+) create mode 100644 awesome_dashboard/static/src/dashboard.scss diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 637fa4bb972..15d810af683 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -2,9 +2,17 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; +import { Layout } from "@web/search/layout"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; + static components = { Layout }; + + setup() { + this.display = { + controlPanel: {}, + }; + } } registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.scss b/awesome_dashboard/static/src/dashboard.scss new file mode 100644 index 00000000000..29ae86e257c --- /dev/null +++ b/awesome_dashboard/static/src/dashboard.scss @@ -0,0 +1,3 @@ +.o_dashboard { + background-color: #a17d98; +} \ No newline at end of file diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 1a2ac9a2fed..a8ed07c5fc4 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -3,6 +3,10 @@ hello dashboard + + Some content here + + From 9e76c58da5234790d3a29d9ccc0dd6b7a78ea71e Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Tue, 27 May 2025 17:12:00 +0200 Subject: [PATCH 41/53] [ADD] awesome_dashboard 2.2 Open leads and CRM view --- awesome_dashboard/static/src/dashboard.js | 19 +++++++++++++++++++ awesome_dashboard/static/src/dashboard.xml | 5 ++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 15d810af683..7a2adc18c51 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -3,6 +3,7 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; +import { useService } from "@web/core/utils/hooks"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; @@ -12,6 +13,24 @@ class AwesomeDashboard extends Component { this.display = { controlPanel: {}, }; + + this.action = useService("action"); + } + + openCustomers() { + this.action.doAction("base.action_partner_form"); + } + + openLeads() { + this.action.doAction({ + type: "ir.actions.act_window", + name: "All leads", + res_model: "crm.lead", + views: [ + [false, "list"], + [false, "form"], + ], + }); } } diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index a8ed07c5fc4..42ff95a8a7e 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -4,7 +4,10 @@ hello dashboard - Some content here + + + + From 029dc4dfcc8197d23474cd217a2c31d76f7e2763 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Wed, 28 May 2025 10:57:10 +0200 Subject: [PATCH 42/53] [ADD] awesome_dashboard 2.3 add dashboard item --- awesome_dashboard/static/src/dashboard.js | 3 ++- awesome_dashboard/static/src/dashboard.xml | 9 +++++++++ .../static/src/dashboard_item.js | 19 +++++++++++++++++++ .../static/src/dashboard_item.xml | 12 ++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 awesome_dashboard/static/src/dashboard_item.js create mode 100644 awesome_dashboard/static/src/dashboard_item.xml diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 7a2adc18c51..28cd0fcac0f 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -4,10 +4,11 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; +import { DashboardItem } from "./dashboard_item"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; - static components = { Layout }; + static components = { Layout, DashboardItem }; setup() { this.display = { diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 42ff95a8a7e..fbec0615692 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -8,6 +8,15 @@ + +
+ + Card with no size + + + Card with size 2 + +
diff --git a/awesome_dashboard/static/src/dashboard_item.js b/awesome_dashboard/static/src/dashboard_item.js new file mode 100644 index 00000000000..6a0e53f4fd2 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_item.js @@ -0,0 +1,19 @@ +import { Component } from "@odoo/owl"; + +export class DashboardItem extends Component { + static template = "awesome_dashboard.DashboardItem"; + + static props = { + slots: { + type: Object, + shape: { + default: Object + }, + }, + size: { + type: Number, + default: 1, // Ensure default value is applied + optional: true + }, + }; +} \ No newline at end of file diff --git a/awesome_dashboard/static/src/dashboard_item.xml b/awesome_dashboard/static/src/dashboard_item.xml new file mode 100644 index 00000000000..c8574babbe6 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_item.xml @@ -0,0 +1,12 @@ + + + + +
+
+ +
+
+
+ +
\ No newline at end of file From 36d82b4f51eb4ba7a9d7d8db418772003eb1c3ef Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Wed, 28 May 2025 11:40:05 +0200 Subject: [PATCH 43/53] [ADD] awesome_dashboard 2.4 add some statistics --- awesome_dashboard/static/src/dashboard.js | 7 +++- awesome_dashboard/static/src/dashboard.xml | 38 +++++++++++++++++----- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 28cd0fcac0f..6e4af1e00f9 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,10 +1,11 @@ /** @odoo-module **/ -import { Component } from "@odoo/owl"; +import { Component, onWillStart } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item"; +import { rpc } from "@web/core/network/rpc"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; @@ -16,6 +17,10 @@ class AwesomeDashboard extends Component { }; this.action = useService("action"); + + onWillStart(async () => { + this.stats = await rpc("/awesome_dashboard/statistics") + }); } openCustomers() { diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index fbec0615692..9a478fcd10c 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -9,16 +9,38 @@ -
- - Card with no size +
+ +
+

Number of new orders this month:

+
+
- - Card with size 2 + +
+

Total amount of new orders this month:

+
+
+
+ +
+

Average amount of t-shirts per order this month:

+
+
+
+ +
+

Number of cancelled orders this month:

+
+
+
+ +
+

Average time for an order to go from 'new' to 'sent' or 'cancelled':

+
+
- - - + \ No newline at end of file From 2c9c67cbdeedadfca7ae19671b56f1a6d4e683d4 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Wed, 28 May 2025 13:42:13 +0200 Subject: [PATCH 44/53] [ADD] awesome_dashboard 2.5 cache network calls --- awesome_dashboard/static/src/dashboard.js | 4 ++-- awesome_dashboard/static/src/statistics_service.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 awesome_dashboard/static/src/statistics_service.js diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 6e4af1e00f9..15818761b8d 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -5,7 +5,6 @@ import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item"; -import { rpc } from "@web/core/network/rpc"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; @@ -17,9 +16,10 @@ class AwesomeDashboard extends Component { }; this.action = useService("action"); + this.statisticsService = useService("awesome_dashboard.statistics"); onWillStart(async () => { - this.stats = await rpc("/awesome_dashboard/statistics") + this.stats = await this.statisticsService.loadStatistics(); }); } diff --git a/awesome_dashboard/static/src/statistics_service.js b/awesome_dashboard/static/src/statistics_service.js new file mode 100644 index 00000000000..1ac4d3ba52f --- /dev/null +++ b/awesome_dashboard/static/src/statistics_service.js @@ -0,0 +1,14 @@ +import { registry } from "@web/core/registry"; +import { memoize } from "@web/core/utils/functions"; +import { rpc } from "@web/core/network/rpc"; + +const statisticsService = { + async: ["loadStatistics"], + start() { + return { + loadStatistics: memoize(() => rpc("/awesome_dashboard/statistics")), + }; + }, +}; + +registry.category("services").add("awesome_dashboard.statistics", statisticsService); \ No newline at end of file From 14d073607613c92a3a5bd50d63fab6e182735565 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Wed, 28 May 2025 15:38:24 +0200 Subject: [PATCH 45/53] [ADD] awesome_dashboard 2.6 pie charts --- awesome_dashboard/static/src/dashboard.js | 3 +- awesome_dashboard/static/src/dashboard.xml | 4 ++ .../static/src/dashboard_item.js | 1 + .../static/src/pie_chart/pie_chart.js | 41 +++++++++++++++++++ .../static/src/pie_chart/pie_chart.xml | 10 +++++ 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 awesome_dashboard/static/src/pie_chart/pie_chart.js create mode 100644 awesome_dashboard/static/src/pie_chart/pie_chart.xml diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 15818761b8d..0986deff90b 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -5,10 +5,11 @@ import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item"; +import { PieChart } from "./pie_chart/pie_chart"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; - static components = { Layout, DashboardItem }; + static components = { Layout, DashboardItem, PieChart }; setup() { this.display = { diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 9a478fcd10c..dc4380ee444 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -40,6 +40,10 @@
+ + Shirt orders by size + + diff --git a/awesome_dashboard/static/src/dashboard_item.js b/awesome_dashboard/static/src/dashboard_item.js index 6a0e53f4fd2..a8d22c3f5f8 100644 --- a/awesome_dashboard/static/src/dashboard_item.js +++ b/awesome_dashboard/static/src/dashboard_item.js @@ -1,5 +1,6 @@ import { Component } from "@odoo/owl"; + export class DashboardItem extends Component { static template = "awesome_dashboard.DashboardItem"; diff --git a/awesome_dashboard/static/src/pie_chart/pie_chart.js b/awesome_dashboard/static/src/pie_chart/pie_chart.js new file mode 100644 index 00000000000..21ae725ad4a --- /dev/null +++ b/awesome_dashboard/static/src/pie_chart/pie_chart.js @@ -0,0 +1,41 @@ +import { loadJS } from "@web/core/assets"; +import { getColor } from "@web/core/colors/colors"; +import { Component, onWillStart, useRef, onMounted, onWillUnmount } from "@odoo/owl"; + +export class PieChart extends Component { + static template = "awesome_dashboard.PieChart"; + static props = { + label: String, + data: Object, + }; + + setup() { + this.canvasRef = useRef("canvas"); + onWillStart(() => loadJS("/web/static/lib/Chart/Chart.js")); + onMounted(() => { + this.renderChart(); + }); + onWillUnmount(() => { + this.chart.destroy(); + }); + } + + renderChart() { + const labels = Object.keys(this.props.data); + const data = Object.values(this.props.data); + const color = labels.map((_, index) => getColor(index)); + this.chart = new Chart(this.canvasRef.el, { + type: "pie", + data: { + labels: labels, + datasets: [ + { + label: this.props.label, + data: data, + backgroundColor: color, + }, + ], + }, + }); + } +} \ No newline at end of file diff --git a/awesome_dashboard/static/src/pie_chart/pie_chart.xml b/awesome_dashboard/static/src/pie_chart/pie_chart.xml new file mode 100644 index 00000000000..18416e9a223 --- /dev/null +++ b/awesome_dashboard/static/src/pie_chart/pie_chart.xml @@ -0,0 +1,10 @@ + + + +
+
+ +
+
+
+
\ No newline at end of file From aedd799347acc58978661d5d558ee6aabc0ac84b Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 30 May 2025 10:13:07 +0200 Subject: [PATCH 46/53] [ADD] estate : Add some standart Real estate property (tuto Define module Data) --- estate/__manifest__.py | 5 ++++- estate/demo/estate.property.type.csv | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 estate/demo/estate.property.type.csv diff --git a/estate/__manifest__.py b/estate/__manifest__.py index d6651af9ea9..60a9d668d07 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -6,13 +6,16 @@ 'installable': True, 'application': True, 'data': [ + 'security/ir.model.access.csv', 'views/estate_property_offer_views.xml', 'views/estate_property_type_views.xml', 'views/estate_property_tag_views.xml', - 'security/ir.model.access.csv', 'views/estate_property_views.xml', 'views/estate_menus.xml', 'views/estate_res_users.xml', ], + 'demo': [ + 'demo/estate.property.type.csv', + ], 'license': 'LGPL-3', } diff --git a/estate/demo/estate.property.type.csv b/estate/demo/estate.property.type.csv new file mode 100644 index 00000000000..ffd8031f6c0 --- /dev/null +++ b/estate/demo/estate.property.type.csv @@ -0,0 +1,5 @@ +"id","name" +"1","Residential" +"2","Commercial" +"3","Industrial" +"4","Land" From c3f2718fc2a873c6588cf3aa998fa58cd8d2b381 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 30 May 2025 10:45:37 +0200 Subject: [PATCH 47/53] [ADD] estate : demo data for estate. property --- estate/__manifest__.py | 1 + estate/demo/estate.property.xml | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 estate/demo/estate.property.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 60a9d668d07..2e3965c7efd 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -16,6 +16,7 @@ ], 'demo': [ 'demo/estate.property.type.csv', + 'demo/estate.property.xml', ], 'license': 'LGPL-3', } diff --git a/estate/demo/estate.property.xml b/estate/demo/estate.property.xml new file mode 100644 index 00000000000..8443404b349 --- /dev/null +++ b/estate/demo/estate.property.xml @@ -0,0 +1,33 @@ + + + Big Villa + new + A nice and big villa + 12345 + 2020-02-02 + 1600000 + 6 + 100 + 4 + True + True + 100000 + south + + + + Trailer home + canceled + Home in a trailer park + 54321 + 1970-01-01 + 100000 + 120000 + 1 + 10 + 4 + False + False + + + \ No newline at end of file From caf2b1aaba4d34f888f068bf71f45268bbb8a229 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 30 May 2025 13:13:40 +0200 Subject: [PATCH 48/53] [ADD] estate : demo data for property offers --- estate/__manifest__.py | 1 + estate/demo/estate.property.offer.xml | 23 +++++++++++++++++++++++ estate/demo/estate.property.type.csv | 8 ++++---- estate/demo/estate.property.xml | 8 +++++--- 4 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 estate/demo/estate.property.offer.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 2e3965c7efd..68698fdb240 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -17,6 +17,7 @@ 'demo': [ 'demo/estate.property.type.csv', 'demo/estate.property.xml', + 'demo/estate.property.offer.xml', ], 'license': 'LGPL-3', } diff --git a/estate/demo/estate.property.offer.xml b/estate/demo/estate.property.offer.xml new file mode 100644 index 00000000000..984109d159e --- /dev/null +++ b/estate/demo/estate.property.offer.xml @@ -0,0 +1,23 @@ + + + + + 10000 + 14 + + + + + + 1500000 + 14 + + + + + + 1500001 + 14 + + + \ No newline at end of file diff --git a/estate/demo/estate.property.type.csv b/estate/demo/estate.property.type.csv index ffd8031f6c0..b7831762159 100644 --- a/estate/demo/estate.property.type.csv +++ b/estate/demo/estate.property.type.csv @@ -1,5 +1,5 @@ "id","name" -"1","Residential" -"2","Commercial" -"3","Industrial" -"4","Land" +"type_1","Residential" +"type_2","Commercial" +"type_3","Industrial" +"type_4","Land" diff --git a/estate/demo/estate.property.xml b/estate/demo/estate.property.xml index 8443404b349..7da1566b420 100644 --- a/estate/demo/estate.property.xml +++ b/estate/demo/estate.property.xml @@ -1,5 +1,5 @@ - + Big Villa new A nice and big villa @@ -13,9 +13,10 @@ True 100000 south + - + Trailer home canceled Home in a trailer park @@ -28,6 +29,7 @@ 4 False False + - + \ No newline at end of file From e4115af085b28efb9894b74b48ad89471691c90a Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Fri, 30 May 2025 14:00:09 +0200 Subject: [PATCH 49/53] [ADD] estate : add new demo property with offers directly defined in the xml --- estate/demo/estate.property.offer.xml | 12 ++++++++++++ estate/demo/estate.property.xml | 26 +++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/estate/demo/estate.property.offer.xml b/estate/demo/estate.property.offer.xml index 984109d159e..9826e5f5185 100644 --- a/estate/demo/estate.property.offer.xml +++ b/estate/demo/estate.property.offer.xml @@ -20,4 +20,16 @@ 14
+ + + + + + + + + + + + \ No newline at end of file diff --git a/estate/demo/estate.property.xml b/estate/demo/estate.property.xml index 7da1566b420..9f100189a02 100644 --- a/estate/demo/estate.property.xml +++ b/estate/demo/estate.property.xml @@ -28,8 +28,32 @@ 10 4 False - False + + + Small Hut + new + Small hut with nothing in it + 5062 + 2024-01-01 + 99 + 0 + 10 + 2 + + + \ No newline at end of file From 6e8d8acaa3cb8472fef155e78ff14c4df9e8daa4 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Wed, 4 Jun 2025 13:01:40 +0200 Subject: [PATCH 50/53] [ADD] estate : update XML files to include noupdate attribute and enhance offer validation logic --- estate/demo/estate.property.offer.xml | 2 +- estate/demo/estate.property.xml | 2 +- estate/models/estate_property.py | 3 +++ estate/models/estate_property_offer.py | 4 ++++ estate/tests/__init__.py | 1 + estate/tests/test_etate_property.py | 3 +++ 6 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 estate/tests/__init__.py create mode 100644 estate/tests/test_etate_property.py diff --git a/estate/demo/estate.property.offer.xml b/estate/demo/estate.property.offer.xml index 9826e5f5185..94402c62142 100644 --- a/estate/demo/estate.property.offer.xml +++ b/estate/demo/estate.property.offer.xml @@ -1,4 +1,4 @@ - + diff --git a/estate/demo/estate.property.xml b/estate/demo/estate.property.xml index 9f100189a02..da5b7a02a46 100644 --- a/estate/demo/estate.property.xml +++ b/estate/demo/estate.property.xml @@ -1,4 +1,4 @@ - + Big Villa new diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 16e83e816a6..7e7445b1791 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -104,5 +104,8 @@ def set_sold(self): if record.state == 'canceled': raise exceptions.UserError("Canceled properties cannot be sold") + if len(record.offer_ids.filtered(lambda o: o.status == 'accepted')) == 0: + raise exceptions.UserError("A property must have an accepted offer to be sold") + record.state = 'sold' return True diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index e9c271074b3..b32e9709be2 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -51,6 +51,10 @@ def create(self, vals_list): # Action methods def action_accept(self): for record in self: + for offer in record.property_id.offer_ids: + if offer.status == 'accepted': + raise exceptions.UserError("There is already an accepted offer for this property.") + offer.status = 'refused' record.status = 'accepted' record.property_id.buyer_id = record.partner_id record.property_id.selling_price = record.price diff --git a/estate/tests/__init__.py b/estate/tests/__init__.py new file mode 100644 index 00000000000..576617cccff --- /dev/null +++ b/estate/tests/__init__.py @@ -0,0 +1 @@ +from . import test_estate_property diff --git a/estate/tests/test_etate_property.py b/estate/tests/test_etate_property.py new file mode 100644 index 00000000000..1f9ebb16b46 --- /dev/null +++ b/estate/tests/test_etate_property.py @@ -0,0 +1,3 @@ +from odoo.tests.common import TransactionCase +from odoo.exceptions import UserError +from odoo.tests import tagged From 127db3d2ee543ed9023b7644e6188dff642dd03a Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Wed, 4 Jun 2025 15:26:31 +0200 Subject: [PATCH 51/53] [ADD] estate : implement unit tests for estate property offers --- estate/tests/test_estate_property.py | 52 ++++++++++++++++++++++++++++ estate/tests/test_etate_property.py | 3 -- 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 estate/tests/test_estate_property.py delete mode 100644 estate/tests/test_etate_property.py diff --git a/estate/tests/test_estate_property.py b/estate/tests/test_estate_property.py new file mode 100644 index 00000000000..c005f2d0132 --- /dev/null +++ b/estate/tests/test_estate_property.py @@ -0,0 +1,52 @@ +from odoo.tests.common import TransactionCase +from odoo.exceptions import UserError +from odoo.exceptions import ValidationError +from odoo.tests import tagged + + +# The CI will run these tests after all the modules are installed, +# not right after installing the one defining it. +@tagged('post_install', '-at_install') +class EstateOfferTestCase(TransactionCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + + # create the data for each tests. By doing it in the setUpClass instead + # of in a setUp or in each test case, we reduce the testing time and + # the duplication of code. + cls.properties = cls.env['estate.property'].create([ + { + 'name': 'Property 1', + 'expected_price': 100000, + 'state': 'new', + + }, + { + 'name': 'Property 2', + 'expected_price': 150000, + 'offer_ids': [ + (0, 0, { + 'partner_id': cls.env.ref('base.res_partner_1').id, + 'price': 120000, + 'status': 'refused', + }), + (0, 0, { + 'partner_id': cls.env.ref('base.res_partner_2').id, + 'price': 130000, + }), + ], + + }, + ]) + + def create_offer_after_sold_property(self): + """Test that creating an offer on a sold property raises an error.""" + with self.assertRaises(ValidationError): + self.env['estate.property.offer'].create({ + 'property_id': self.properties[0].id, + 'partner_id': self.env.ref('base.res_partner_1').id, + 'price': 110000, + }) + diff --git a/estate/tests/test_etate_property.py b/estate/tests/test_etate_property.py deleted file mode 100644 index 1f9ebb16b46..00000000000 --- a/estate/tests/test_etate_property.py +++ /dev/null @@ -1,3 +0,0 @@ -from odoo.tests.common import TransactionCase -from odoo.exceptions import UserError -from odoo.tests import tagged From c50088673c01bdf6f5da1444f3c19ad404fd7052 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Wed, 4 Jun 2025 16:31:50 +0200 Subject: [PATCH 52/53] [ADD] estate : unit tests for offer creation and property set_sold action --- estate/models/estate_property_offer.py | 5 ++ estate/tests/__init__.py | 1 + estate/tests/test_estate_property.py | 35 +++++-------- estate/tests/test_estate_property_offer.py | 57 ++++++++++++++++++++++ 4 files changed, 74 insertions(+), 24 deletions(-) create mode 100644 estate/tests/test_estate_property_offer.py diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index b32e9709be2..ee244bbea36 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -41,7 +41,12 @@ def _inverse_deadline(self): @api.model_create_multi def create(self, vals_list): for vals in vals_list: + if 'status' in vals: + raise exceptions.ValidationError("Status should not be set directly. Use action_accept or action_refuse methods instead.") + prop = self.env['estate.property'].browse(vals['property_id']) + if prop.state == 'sold': + raise exceptions.UserError("Cannot create an offer for a sold property") if float_compare(vals['price'], prop.best_price, precision_digits=2) < 0: raise exceptions.UserError("Cannot create an offer with a lower amount than an existing offer") prop.state = 'offer_received' diff --git a/estate/tests/__init__.py b/estate/tests/__init__.py index 576617cccff..5092333224b 100644 --- a/estate/tests/__init__.py +++ b/estate/tests/__init__.py @@ -1 +1,2 @@ +from . import test_estate_property_offer from . import test_estate_property diff --git a/estate/tests/test_estate_property.py b/estate/tests/test_estate_property.py index c005f2d0132..ad2d90ff323 100644 --- a/estate/tests/test_estate_property.py +++ b/estate/tests/test_estate_property.py @@ -1,13 +1,12 @@ from odoo.tests.common import TransactionCase from odoo.exceptions import UserError -from odoo.exceptions import ValidationError from odoo.tests import tagged # The CI will run these tests after all the modules are installed, # not right after installing the one defining it. @tagged('post_install', '-at_install') -class EstateOfferTestCase(TransactionCase): +class EstatePropertyTestCase(TransactionCase): @classmethod def setUpClass(cls): @@ -20,33 +19,21 @@ def setUpClass(cls): { 'name': 'Property 1', 'expected_price': 100000, - 'state': 'new', - - }, - { - 'name': 'Property 2', - 'expected_price': 150000, + 'state': 'offer_accepted', 'offer_ids': [ (0, 0, { 'partner_id': cls.env.ref('base.res_partner_1').id, - 'price': 120000, - 'status': 'refused', - }), - (0, 0, { - 'partner_id': cls.env.ref('base.res_partner_2').id, - 'price': 130000, + 'price': 110000, }), ], - }, ]) - - def create_offer_after_sold_property(self): - """Test that creating an offer on a sold property raises an error.""" - with self.assertRaises(ValidationError): - self.env['estate.property.offer'].create({ - 'property_id': self.properties[0].id, - 'partner_id': self.env.ref('base.res_partner_1').id, - 'price': 110000, - }) + cls.properties[0].offer_ids[0].action_accept() + + def test_sell_property(self): + """Test that selling a property that can be sold updates the right fields.""" + self.properties[0].set_sold() + self.assertEqual(self.properties[0].state, 'sold') + self.assertEqual(self.properties[0].buyer_id, self.env.ref('base.res_partner_1')) + self.assertEqual(self.properties[0].selling_price, 110000) diff --git a/estate/tests/test_estate_property_offer.py b/estate/tests/test_estate_property_offer.py new file mode 100644 index 00000000000..9618a66fd91 --- /dev/null +++ b/estate/tests/test_estate_property_offer.py @@ -0,0 +1,57 @@ +from odoo.tests.common import TransactionCase +from odoo.exceptions import UserError +from odoo.tests import tagged + + +# The CI will run these tests after all the modules are installed, +# not right after installing the one defining it. +@tagged('post_install', '-at_install') +class EstateOfferTestCase(TransactionCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + + # create the data for each tests. By doing it in the setUpClass instead + # of in a setUp or in each test case, we reduce the testing time and + # the duplication of code. + cls.properties = cls.env['estate.property'].create([ + { + 'name': 'Property 1', + 'expected_price': 100000, + 'state': 'sold', + + }, + { + 'name': 'Property 2', + 'expected_price': 110000, + 'offer_ids': [ + (0, 0, { + 'partner_id': cls.env.ref('base.res_partner_1').id, + 'price': 120000, + }), + (0, 0, { + 'partner_id': cls.env.ref('base.res_partner_2').id, + 'price': 130000, + }), + ], + + }, + ]) + + cls.properties[1].offer_ids[0].action_refuse() + + def test_create_offer_after_sold_property(self): + """Test that creating an offer on a sold property raises an error.""" + with self.assertRaises(UserError): + self.env['estate.property.offer'].create({ + 'property_id': self.properties[0].id, + 'partner_id': self.env.ref('base.res_partner_1').id, + 'price': 110000, + }) + + def test_sell_no_accepted_offer(self): + """Test that selling a property without an accepted offer raises an error.""" + with self.assertRaises(UserError): + self.properties[1].set_sold() + From 8756ca1480f2a296668d85a92f71a1b3274e9f34 Mon Sep 17 00:00:00 2001 From: Arthur Mermet Date: Wed, 4 Jun 2025 17:02:01 +0200 Subject: [PATCH 53/53] [ADD] estate : add tests for garden field on form view --- estate/demo/estate.property.xml | 1 - estate/tests/test_estate_property.py | 17 +++++++++++++++++ estate/tests/test_estate_property_offer.py | 1 - 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/estate/demo/estate.property.xml b/estate/demo/estate.property.xml index da5b7a02a46..ec60d843766 100644 --- a/estate/demo/estate.property.xml +++ b/estate/demo/estate.property.xml @@ -56,4 +56,3 @@ ]"/> - \ No newline at end of file diff --git a/estate/tests/test_estate_property.py b/estate/tests/test_estate_property.py index ad2d90ff323..82e8fd3b332 100644 --- a/estate/tests/test_estate_property.py +++ b/estate/tests/test_estate_property.py @@ -1,6 +1,7 @@ from odoo.tests.common import TransactionCase from odoo.exceptions import UserError from odoo.tests import tagged +from odoo.tests import Form # The CI will run these tests after all the modules are installed, @@ -37,3 +38,19 @@ def test_sell_property(self): self.assertEqual(self.properties[0].buyer_id, self.env.ref('base.res_partner_1')) self.assertEqual(self.properties[0].selling_price, 110000) + def test_check_uncheck_garden(self): + """Test that checking and unchecking the garden field on the view updates the garden area and orientation.""" + with Form(self.env['estate.property']) as form: + form.name = 'Property with Garden' + form.expected_price = 150000 + form.garden = True + self.assertEqual(form.garden_area, 10) + self.assertEqual(form.garden_orientation, 'north') + + form.garden = False + self.assertEqual(form.garden_area, 0) + self.assertFalse(form.garden_orientation) + + form.garden = True + self.assertEqual(form.garden_area, 10) + self.assertEqual(form.garden_orientation, 'north') diff --git a/estate/tests/test_estate_property_offer.py b/estate/tests/test_estate_property_offer.py index 9618a66fd91..08b5dd3cd44 100644 --- a/estate/tests/test_estate_property_offer.py +++ b/estate/tests/test_estate_property_offer.py @@ -54,4 +54,3 @@ def test_sell_no_accepted_offer(self): """Test that selling a property without an accepted offer raises an error.""" with self.assertRaises(UserError): self.properties[1].set_sold() -