From 129eddcf1a849f85280d2f14a461656ee266164c Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Wed, 5 Feb 2025 17:13:09 +0530 Subject: [PATCH 01/27] [ADD] estate: Completed exercies and task upto Chapter 5 --- estate/__init__.py | 1 + estate/__manifest__.py | 24 +++++++++++++++++++ estate/models/__init__.py | 1 + estate/models/estate_property.py | 32 ++++++++++++++++++++++++++ estate/security/ir.model.access.csv | 2 ++ estate/views/estate_menus.xml | 8 +++++++ estate/views/estate_property_views.xml | 10 ++++++++ 7 files changed, 78 insertions(+) create mode 100644 estate/__init__.py create mode 100644 estate/__manifest__.py create mode 100644 estate/models/__init__.py create mode 100644 estate/models/estate_property.py create mode 100644 estate/security/ir.model.access.csv create mode 100644 estate/views/estate_menus.xml create mode 100644 estate/views/estate_property_views.xml diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..9a7e03eded3 --- /dev/null +++ b/estate/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..8912879b28f --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,24 @@ +{ + 'name': "Real Estate", + 'version': '1.0', + 'depends': ['base'], + 'author': "Author Name", + 'category': 'Category', + 'application': True, + 'installable': True, + 'sequence': 0, + + 'description': """ + Description text + """, + # data files always loaded at installation + 'data': [ + 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml' + ], + # data files containing optionally loaded demonstration data + 'demo': [ + # 'demo/demo_data.xml', + ], +} \ No newline at end of file diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..f4c8fd6db6d --- /dev/null +++ b/estate/models/__init__.py @@ -0,0 +1 @@ +from . import estate_property \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py new file mode 100644 index 00000000000..1c87e70a310 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,32 @@ +from odoo import fields, models +from datetime import timedelta + +class Estateproperty(models.Model): + _name = "estate.property" + _description = "Estate property table" + + name = fields.Char('Property Name', required=True, default="unknown") + description = fields.Text() + postcode= fields.Char() + date_availability= fields.Date(copy=False, default= lambda self: fields.Datetime.today() + timedelta(days=90)) + expected_price= fields.Float(required=True) + selling_price= fields.Float(readonly=True, copy=False) + bedrooms= fields.Integer(default=2) + living_area= fields.Integer() + facades= fields.Integer() + garage= fields.Boolean() + garden= fields.Boolean() + garden_area= fields.Integer() + garden_orientation= fields.Selection( + string='Type', + selection=[('north', 'North'),('south', 'South'),('east', 'East'),('west', 'West')] + ) + active = fields.Boolean(default=True) + state= fields.Selection( + string='Type', + selection=[('new', 'New'),('offered_rec', 'Offer recieved'),('offer_acc', 'Offer Accepted'),('sold', 'Sold'),('cancel', 'Cancelled')], + required=True, + copy=False, + default='new' + + ) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..976b61e8cb3 --- /dev/null +++ b/estate/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 \ No newline at end of file diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..904ed4cedcf --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml new file mode 100644 index 00000000000..c13ebcc7b7e --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,10 @@ + + + + + test something +estate.property +list,form + + + \ No newline at end of file From ba18491a9fb24f05a5db3ce9332bdf61238b42bb Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Wed, 5 Feb 2025 18:20:23 +0530 Subject: [PATCH 02/27] [IMP] estate: Solved all the warnings and added licence in manifest file --- estate/__manifest__.py | 1 + estate/models/estate_property.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 8912879b28f..cc748ace396 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,6 +7,7 @@ 'application': True, 'installable': True, 'sequence': 0, + 'license': 'LGPL-3', 'description': """ Description text diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 1c87e70a310..8768b98a0ca 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -23,7 +23,7 @@ class Estateproperty(models.Model): ) active = fields.Boolean(default=True) state= fields.Selection( - string='Type', + string='State', selection=[('new', 'New'),('offered_rec', 'Offer recieved'),('offer_acc', 'Offer Accepted'),('sold', 'Sold'),('cancel', 'Cancelled')], required=True, copy=False, From b2a6d4f18f25a6ccdbe486c6ad46cbfd8e283bbd Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Thu, 6 Feb 2025 19:01:55 +0530 Subject: [PATCH 03/27] [IMP] estate: Completed with chapter 8 and added required models and view changes --- estate/models/__init__.py | 5 +- estate/models/estate_property.py | 59 ++++++++--- estate/models/estate_property_offer.py | 35 +++++++ 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 | 4 +- estate/views/estate_property_views.xml | 136 ++++++++++++++++++++++++- 8 files changed, 238 insertions(+), 20 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 diff --git a/estate/models/__init__.py b/estate/models/__init__.py index f4c8fd6db6d..09b2099fe84 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,4 @@ -from . import estate_property \ No newline at end of file +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 8768b98a0ca..09f17e4cb9c 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 fields, models, api from datetime import timedelta class Estateproperty(models.Model): @@ -6,17 +6,33 @@ class Estateproperty(models.Model): _description = "Estate property table" name = fields.Char('Property Name', required=True, default="unknown") - description = fields.Text() - postcode= fields.Char() - date_availability= fields.Date(copy=False, default= lambda self: fields.Datetime.today() + timedelta(days=90)) - expected_price= fields.Float(required=True) - selling_price= fields.Float(readonly=True, copy=False) - bedrooms= fields.Integer(default=2) - living_area= fields.Integer() - facades= fields.Integer() - garage= fields.Boolean() - garden= fields.Boolean() - garden_area= fields.Integer() + + property_type_id = fields.Many2one('estate.property.type', "Property Type") + + salesperson_id = fields.Many2one('res.users', string='Salesperson', default= lambda self: self.env.user) + buyer_id= fields.Many2one('res.partner', string='Buyer', copy=False) + + tag_ids= fields.Many2many('estate.property.tag', "Tags") + + offer_ids = fields.One2many('estate.property.offer', 'property_id', 'Offers') + + description = fields.Text('Description', compute='_compute_desc') + + @api.depends("salesperson_id.name") + def _compute_desc(self): + for record in self: + record.description = "Test for salesperson %s" % record.salesperson_id.name + + postcode= fields.Char('PostCode') + date_availability= fields.Date('Available From',copy=False, default= lambda self: fields.Datetime.today() + timedelta(days=90)) + expected_price= fields.Float('Expected Price',required=True) + selling_price= fields.Float('Selling Price',readonly=True, copy=False) + bedrooms= fields.Integer('Bedrooms',default=2) + living_area= fields.Integer('Living Area') + facades= fields.Integer('Facades') + garage= fields.Boolean('Garage') + garden= fields.Boolean('Garden') + garden_area= fields.Integer('Garden Area') garden_orientation= fields.Selection( string='Type', selection=[('north', 'North'),('south', 'South'),('east', 'East'),('west', 'West')] @@ -30,3 +46,22 @@ class Estateproperty(models.Model): default='new' ) + + #computed fields + + total_area = fields.Integer('Total Area', compute='_compute_total_area') + + @api.depends('living_area','garden_area') + def _compute_total_area(self): + for record in self: + record.total_area = record.living_area + record.garden_area + + + best_price = fields.Float('Best Price', compute='_compute_best_price') + + @api.depends('offer_ids.price') + def _compute_best_price(self): + for property in self: + prices = property.offer_ids.mapped('price') + property.best_price = max(prices) + diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py new file mode 100644 index 00000000000..1248940f0de --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,35 @@ +from odoo import models,fields, api +from datetime import timedelta + +class EstatePropertyOffer(models.Model): + _name="estate.property.offer" + _description="estate property offer table" + + price = fields.Float("Price") + status = fields.Selection( + string='Status', + selection=[('accepted', "Accepted"), ('refused', 'Refused')], + copy=False + ) + partner_id = fields.Many2one('res.partner', required=True) + property_id = fields.Many2one('estate.property', required=True) + create_date = fields.Date() + + validity =fields.Integer('Validity', default=7) + date_deadline = fields.Date('Deadline', compute='_compute_deadline', inverse='_inverse_deadline') + + @api.depends('create_date', 'validity') + def _compute_deadline(self): + for offer in self: + if offer.create_date: + offer.date_deadline = offer.create_date + timedelta(days=offer.validity) + + else: + offer.date_deadline = False + + def _inverse_deadline(self): + for offer in self: + if offer.create_date and offer.date_deadline: + dayys = (offer.date_deadline - offer.create_date).days + offer.validity = dayys + diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..c27b7276c3b --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,7 @@ +from odoo import fields,models + +class EstatePropertyTag(models.Model): + _name="estate.property.tag" + _description="estate property tag table" + + name = fields.Char('Tags', 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..5362e672ced --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,7 @@ +from odoo import fields, models + +class EstatePropertyType(models.Model): + _name="estate.property.type" + _description="estate property type table" + + name= fields.Char("Property Type", 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 976b61e8cb3..4c593ed42e4 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,5 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink -access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 \ No newline at end of file +access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 +access_estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 +access_estate_property_tag,access_estate_property_tag,model_estate_property_tag,base.group_user,1,1,1,1 +access_estate_property_offer,access_estate_property_offer,model_estate_property_offer,base.group_user,1,1,1,1 \ No newline at end of file diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 904ed4cedcf..8c1a33c65b6 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,8 +1,10 @@ - + + + \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index c13ebcc7b7e..497fa0c8a78 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,10 +1,136 @@ - + + Properties + estate.property + list,form + + + Properties Type + estate.property.type + list,form + + + Properties Tags + estate.property.tag + list,form + - test something -estate.property -list,form - + + + + estate.property.list + estate.property + + + + + + + + + + + + + + + + estate.property.list + estate.property + +
+ + + +
+
+
+

+ +

+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + estate.property.list + estate.property + + + + + + + + + + + + + +
\ No newline at end of file From 511cf796da39bfcf7b24433ae137c148e887e382 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Sun, 9 Feb 2025 15:42:35 +0530 Subject: [PATCH 04/27] [IMP] estate: added onchanges, model object and action and sql constraints, completed till chapter 10 --- estate/models/estate_property.py | 58 +++++++++++++++++++++++++- estate/models/estate_property_offer.py | 24 +++++++++++ estate/models/estate_property_tag.py | 6 ++- estate/models/estate_property_type.py | 6 ++- estate/views/estate_menus.xml | 2 +- estate/views/estate_property_views.xml | 52 +++++++++++------------ 6 files changed, 117 insertions(+), 31 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 09f17e4cb9c..fa39b82bc3e 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,5 +1,7 @@ from odoo import fields, models, api from datetime import timedelta +from odoo.exceptions import UserError, ValidationError +from odoo.tools.float_utils import float_compare, float_is_zero class Estateproperty(models.Model): _name = "estate.property" @@ -25,8 +27,37 @@ def _compute_desc(self): postcode= fields.Char('PostCode') date_availability= fields.Date('Available From',copy=False, default= lambda self: fields.Datetime.today() + timedelta(days=90)) + expected_price= fields.Float('Expected Price',required=True) selling_price= fields.Float('Selling Price',readonly=True, copy=False) + + _sql_constraints = [ + ('check_expected_price', 'CHECK(expected_price > 0)', 'The expected price must be strictly positive.'), + ('check_selling_price', 'CHECK(selling_price >= 0)', 'The selling price must be positive.'), + ] + + @api.constrains('selling_price') + def _check_selling_price(self): + for record in self: + if record.selling_price < 0: + raise ValidationError("The selling price must be positive.") + + @api.constrains('expected_price') + def _check_expected_price(self): + for record in self: + if record.expected_price < 0: + raise ValidationError("The expected price must be positive.") + + + @api.constrains('expected_price', 'selling_price') + def _check_selling_price(self): + """Vérifie que le prix de vente n'est pas inférieur à 90% du prix attendu.""" + for record in self: + if not float_is_zero(record.selling_price, precision_digits=2): + min_acceptable_price = record.expected_price * 0.9 + if float_compare(record.selling_price, min_acceptable_price, precision_digits=2) == -1: + raise ValidationError("The selling price cannot be lower than 90% of the expected price.") + bedrooms= fields.Integer('Bedrooms',default=2) living_area= fields.Integer('Living Area') facades= fields.Integer('Facades') @@ -63,5 +94,30 @@ def _compute_total_area(self): def _compute_best_price(self): for property in self: prices = property.offer_ids.mapped('price') - property.best_price = max(prices) + property.best_price = max(prices, default=0) + + #onchange + @api.onchange('garden') + def _onchange_garden(self): + if self.garden: + self.garden_area = 10 + self.garden_orientation = 'north' + else: + self.garden_area = 0 + self.garden_orientation = False + + #object type and action + def action_cancel(self): + for property in self: + if property.state== 'sold': + raise UserError("A sold property cannot be cancelled.") + property.state = 'cancel' + + def action_sold(self): + for property in self: + if property.state == 'cancel': + raise UserError("A cancelled property cannot be sold.") + if not property.offer_ids: + raise UserError("Cannot sold without any offer.") + property.state = 'sold' \ No newline at end of file diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 1248940f0de..3fdcdf28220 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,11 +1,18 @@ from odoo import models,fields, api from datetime import timedelta +from odoo.exceptions import UserError class EstatePropertyOffer(models.Model): _name="estate.property.offer" _description="estate property offer table" price = fields.Float("Price") + + _sql_constraints = [ + ('check_offer_price', 'CHECK(price > 0)', 'The offer price must be strictly positive.'), + ] + + status = fields.Selection( string='Status', selection=[('accepted', "Accepted"), ('refused', 'Refused')], @@ -33,3 +40,20 @@ def _inverse_deadline(self): dayys = (offer.date_deadline - offer.create_date).days offer.validity = dayys + + def action_accept(self): + for offer in self: + if offer.property_id.state == 'sold': + raise UserError("You cannot accept an offer for a sold property.") + existing_accepted_offer = offer.property_id.offer_ids.filtered(lambda o: o.status == 'accepted') + if existing_accepted_offer: + raise UserError("Only one offer can be accepted for a given property.") + + offer.status = 'accepted' + offer.property_id.selling_price = offer.price + offer.property_id.buyer_id = offer.partner_id + offer.property_id.state = 'offered_rec' + + def action_refuse(self): + for offer in self: + offer.status = 'refused' \ No newline at end of file diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py index c27b7276c3b..d842ae1711d 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -4,4 +4,8 @@ class EstatePropertyTag(models.Model): _name="estate.property.tag" _description="estate property tag table" - name = fields.Char('Tags', required=True) \ No newline at end of file + name = fields.Char('Tags', required=True) + + _sql_constraints = [ + ('unique_tag_name', 'UNIQUE(name)', 'The property tag name must be unique.'), + ] \ No newline at end of file diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index 5362e672ced..549218ee85f 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -4,4 +4,8 @@ class EstatePropertyType(models.Model): _name="estate.property.type" _description="estate property type table" - name= fields.Char("Property Type", required=True) \ No newline at end of file + name= fields.Char("Property Type", required=True) + + _sql_constraints = [ + ('unique_type_name', 'UNIQUE(name)', 'The property type name must be unique.'), + ] \ No newline at end of file diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 8c1a33c65b6..9360b67538e 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 497fa0c8a78..56c1aead0ef 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -5,20 +5,19 @@ estate.property list,form + Properties Type estate.property.type list,form + Properties Tags estate.property.tag list,form - - - estate.property.list estate.property @@ -33,14 +32,15 @@ - - - estate.property.list estate.property -
+ +
+ + +
@@ -59,7 +59,7 @@ - + @@ -68,7 +68,6 @@ - @@ -84,31 +83,29 @@ - + - - - - - - - - - - - - - - - + + + + + + + + + - + + + @@ -53,14 +59,14 @@ - + - - + + @@ -80,24 +86,24 @@ - - + + - - + + - + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 49f1dc900f4..74c346677f7 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,204 +1,133 @@ - - Properties - estate.property - list,form - {'search_default_state': True} - - - - Properties Type - estate.property.type - list,form - - - - Properties Tags - estate.property.tag - list,form - - - - estate.property.list - estate.property - - - - - - - - - - - - - - - - - estate.property.list.view - estate.property - -
-
- - - -
- - - -
-
-
-

- -

- -
- -
- - + + + Properties + estate.property + list,form + {'search_default_state': True} + + + + + estate.property.list + estate.property + + + + + + + + + + + + + + + + + + estate.property.form.view + estate.property + + +
+ + + +
+ - - - - +
+
+
+

+ +

+ +
+
- - - -
-
- - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 74c346677f7..cbc614240da 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,108 +1,108 @@ - + - - Properties - estate.property - list,form - {'search_default_state': True} + + Properties + estate.property + list,form + {'search_default_state': True} - - estate.property.list - estate.property - - - - - - - - - - - + + estate.property.list + estate.property + + + + + + + + + + + - - estate.property.form.view - estate.property - - + + estate.property.form.view + estate.property + +
- - - + + +
-
-
-
-
- - - - - - + + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 60c6b19f947..7c9ffe57080 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,108 +1,108 @@ - - Properties - estate.property - list,form - {'search_default_state': True} + + Properties + estate.property + list,form + {'search_default_state': True} - - estate.property.list - estate.property - - - - - - - - - - - + + estate.property.list + estate.property + + + + + + + + + + + - - estate.property.form.view - estate.property - - + + estate.property.form.view + estate.property + +
- - - + + +
-
-
-
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 01eb2a8e9e1..e49b72d64f1 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -10,7 +10,7 @@ - estate.property.list + estate.property.view.list estate.property @@ -29,7 +29,7 @@ - estate.property.form.view + estate.property.view.form estate.property @@ -37,13 +37,11 @@ + -
-

ok

-
+ + \ No newline at end of file diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 657fb8b07bb..2cca97053b0 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,7 +1,28 @@ /** @odoo-module **/ -import { Component } from "@odoo/owl"; +import { Component, markup, useState } from "@odoo/owl"; +import { Counter } from "./counter/counter"; +import { Card } from "./card/card"; +import { TodoList } from "./todolist/todo_list"; export class Playground extends Component { - static template = "awesome_owl.playground"; + static components = { Card, Counter, TodoList }; + setup() { + this.plainText = "
Plain text content
"; + this.htmlContent = markup("
Markup content
"); + + this.state = useState({ + counter1: 0, + counter2: 0, + }); + + this.incrementSum = (counterNumber, newValue) => { + this.state[counterNumber] = newValue; + }; + } + get sum() { + return this.state.counter1 + this.state.counter2; + } } + +Playground.template = "awesome_owl.playground"; diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 4fb905d59f9..c0454986178 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -1,10 +1,20 @@ -
- hello world +

Playground

+ + +

Total Sum: +

+
+
+ + + +
+
+
- -
+ \ No newline at end of file diff --git a/awesome_owl/static/src/todolist/todo_item.js b/awesome_owl/static/src/todolist/todo_item.js new file mode 100644 index 00000000000..9761d0984bc --- /dev/null +++ b/awesome_owl/static/src/todolist/todo_item.js @@ -0,0 +1,11 @@ +import {Component} from "@odoo/owl"; + +export class TodoItem extends Component{ + static props={ + todo:{id: Number, description: String, isCompleted: Boolean} + }; + setup() { + console.log("TodoItem received todo:", this.props.todo); + } + static template = "awesome_owl.todo_item"; +} \ No newline at end of file diff --git a/awesome_owl/static/src/todolist/todo_item.xml b/awesome_owl/static/src/todolist/todo_item.xml new file mode 100644 index 00000000000..1f090f8a98d --- /dev/null +++ b/awesome_owl/static/src/todolist/todo_item.xml @@ -0,0 +1,10 @@ + + + +
+ - + - + +
+
+
diff --git a/awesome_owl/static/src/todolist/todo_list.js b/awesome_owl/static/src/todolist/todo_list.js new file mode 100644 index 00000000000..3773b39891d --- /dev/null +++ b/awesome_owl/static/src/todolist/todo_list.js @@ -0,0 +1,17 @@ +import {Component, useState} from "@odoo/owl"; +import { TodoItem } from "./todo_item"; + +export class TodoList extends Component{ + static components = {TodoItem}; + + setup(){ + this.todos = useState([ + {id: 1, description: "Buy Milk", isCompleted: false}, + {id: 2, description: "Completd Owl tutorial", isCompleted: false}, + {id: 3, description: "Exercise completed", isCompleted: false}, + ]); + console.log(this.todos); + } +} + +TodoList.template = "awesome_owl.todo_list"; \ No newline at end of file diff --git a/awesome_owl/static/src/todolist/todo_list.xml b/awesome_owl/static/src/todolist/todo_list.xml new file mode 100644 index 00000000000..7da93ec9c79 --- /dev/null +++ b/awesome_owl/static/src/todolist/todo_list.xml @@ -0,0 +1,13 @@ + + + +
+

Todo List

+
+ + + +
+
+
+
\ No newline at end of file diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 55d9c1a76c9..364e0e3f74b 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -73,9 +73,9 @@ def create(self, vals_list): def action_accept(self): for offer in self: - if offer.property_id.state == 'sold' or 'cancel': + if offer.property_id.state == 'sold': raise UserError( - 'You cannot accept an offer for a sold/cancelled property.') + 'You cannot accept an offer for a sold property.') existing_accepted_offer = offer.property_id.offer_ids.filtered( lambda o: o.status == 'accepted') if existing_accepted_offer: From 6333cd5ca21a4f6031759714947a1b4e0a9a00d9 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Mon, 24 Feb 2025 16:26:17 +0530 Subject: [PATCH 16/27] [IMP] awesome_owl: added dynamic todo-list, generic cards with slots. Competed basic OWL components. Added dynamic todo list with add,toggle,delete functionality. Added Cards with slots. Made changes in the code according to PR. --- awesome_owl/static/src/card/card.js | 21 +++++--- awesome_owl/static/src/card/card.xml | 7 +-- awesome_owl/static/src/playground.js | 1 - awesome_owl/static/src/playground.xml | 9 ++-- awesome_owl/static/src/todolist/todo_item.js | 27 ++++++---- awesome_owl/static/src/todolist/todo_item.xml | 7 +-- awesome_owl/static/src/todolist/todo_list.js | 51 ++++++++++++++----- awesome_owl/static/src/todolist/todo_list.xml | 3 +- awesome_owl/static/src/utils.js | 9 ++++ estate/models/estate_property_offer.py | 13 +++-- estate/report/estate_property_templates.xml | 2 +- .../report/estate_property_user_templates.xml | 2 +- estate/security/ir.model.access.csv | 5 +- estate/wizard/estate_offer_wizard.py | 3 +- estate_account/__manifest__.py | 9 +--- estate_account/models/estate_property.py | 2 +- 16 files changed, 111 insertions(+), 60 deletions(-) create mode 100644 awesome_owl/static/src/utils.js diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index 60030ac2ed9..5740c3e253c 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -1,10 +1,17 @@ -import { Component } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; -export class Card extends Component{ - static props = { - title: {type: String, optional: false}, - content: {type: [String,Object], optional: false}, - }; +export class Card extends Component { + static props = { + title: { type: String, optional: false }, + slots: { type: Object, optional: true }, + }; + setup() { + this.state = useState({ visibility: true }); + } + + toggleState() { + this.state.visibility = !this.state.visibility; + } } -Card.template = "awesome_owl.card"; \ No newline at end of file +Card.template = "awesome_owl.card"; diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 50c492d5559..c80de7e9c92 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -4,10 +4,11 @@
+
-

- -

+
+ +
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 2cca97053b0..7fd6121b5e4 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -24,5 +24,4 @@ export class Playground extends Component { return this.state.counter1 + this.state.counter2; } } - Playground.template = "awesome_owl.playground"; diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index c0454986178..1ef8886edd7 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -9,9 +9,12 @@
- - - + +

This is basic card.

+
+ + +
diff --git a/awesome_owl/static/src/todolist/todo_item.js b/awesome_owl/static/src/todolist/todo_item.js index 9761d0984bc..6f9bcd68809 100644 --- a/awesome_owl/static/src/todolist/todo_item.js +++ b/awesome_owl/static/src/todolist/todo_item.js @@ -1,11 +1,18 @@ -import {Component} from "@odoo/owl"; +import { Component } from "@odoo/owl"; -export class TodoItem extends Component{ - static props={ - todo:{id: Number, description: String, isCompleted: Boolean} - }; - setup() { - console.log("TodoItem received todo:", this.props.todo); - } - static template = "awesome_owl.todo_item"; -} \ No newline at end of file +export class TodoItem extends Component { + static props = { + todo: { id: Number, description: String, isCompleted: Boolean }, + toggleState: { type: Function }, + removeTodo: { type: Function }, + }; + + toggleCompleted() { + this.props.toggleState(this.props.todo.id); + } + + deleteTodo() { + this.props.removeTodo(this.props.todo.id); + } + static template = "awesome_owl.todo_item"; +} diff --git a/awesome_owl/static/src/todolist/todo_item.xml b/awesome_owl/static/src/todolist/todo_item.xml index 1f090f8a98d..770d4f6a310 100644 --- a/awesome_owl/static/src/todolist/todo_item.xml +++ b/awesome_owl/static/src/todolist/todo_item.xml @@ -1,10 +1,11 @@ -
+
+ - - - - + +
diff --git a/awesome_owl/static/src/todolist/todo_list.js b/awesome_owl/static/src/todolist/todo_list.js index 3773b39891d..715b175e445 100644 --- a/awesome_owl/static/src/todolist/todo_list.js +++ b/awesome_owl/static/src/todolist/todo_list.js @@ -1,17 +1,44 @@ -import {Component, useState} from "@odoo/owl"; +import { Component, useState, useRef, onMounted } from "@odoo/owl"; import { TodoItem } from "./todo_item"; +import { useAutofocus } from "../utils"; -export class TodoList extends Component{ - static components = {TodoItem}; - - setup(){ - this.todos = useState([ - {id: 1, description: "Buy Milk", isCompleted: false}, - {id: 2, description: "Completd Owl tutorial", isCompleted: false}, - {id: 3, description: "Exercise completed", isCompleted: false}, - ]); - console.log(this.todos); +export class TodoList extends Component { + static components = { TodoItem }; + + setup() { + this.todos = useState([]); + this.todoCounter = 1; + // this.inputRef = useRef("taskInput"); + useAutofocus(this.inputRef); + } + + addTodo(ev) { + if (ev.keyCode === 13) { + const description = ev.target.value.trim(); + if (description) { + this.todos.push({ + id: this.todoCounter++, + description, + isCompleted: false, + }); + ev.target.value = ""; + } + } + } + + toggleState = (todoId) => { + const todo = this.todos.find((t) => t.id === todoId); + if (todo) { + todo.isCompleted = !todo.isCompleted; + } + }; + + removeTodo = (todoId) => { + const index = this.todos.findIndex((t) => t.id === todoId); + if (index >= 0) { + this.todos.splice(index, 1); } + }; } -TodoList.template = "awesome_owl.todo_list"; \ No newline at end of file +TodoList.template = "awesome_owl.todo_list"; diff --git a/awesome_owl/static/src/todolist/todo_list.xml b/awesome_owl/static/src/todolist/todo_list.xml index 7da93ec9c79..78a60a6650e 100644 --- a/awesome_owl/static/src/todolist/todo_list.xml +++ b/awesome_owl/static/src/todolist/todo_list.xml @@ -3,9 +3,10 @@

Todo List

+
- +
diff --git a/awesome_owl/static/src/utils.js b/awesome_owl/static/src/utils.js new file mode 100644 index 00000000000..f1338862301 --- /dev/null +++ b/awesome_owl/static/src/utils.js @@ -0,0 +1,9 @@ +import {onMounted} from "@odoo/owl"; + +export function useAutofocus(ref){ + onMounted(()=>{ + if(ref.el){ + ref.el.focus(); + } + }); +} \ No newline at end of file diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 364e0e3f74b..734f0596c81 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -82,6 +82,11 @@ def action_accept(self): raise UserError( 'Only one offer can be accepted for a given property.') offer.status = 'accepted' + offer.property_id.write({ + 'selling_price': offer.price, + 'buyer_id': offer.partner_id, + 'state': 'offer_accepted', + }) offer.property_id.selling_price = offer.price offer.property_id.buyer_id = offer.partner_id offer.property_id.state = 'offer_accepted' @@ -89,7 +94,7 @@ def action_accept(self): def action_refuse(self): for offer in self: offer.status = 'refused' - offer.property_id.selling_price = 0.00 - offer.property_id.buyer_id = False - if offer.property_id.state == 'offer_received': - offer.property_id.state = 'new' + offer.property_id.write({ + 'selling_price': 0.00, + 'buyer_id': False, + }) diff --git a/estate/report/estate_property_templates.xml b/estate/report/estate_property_templates.xml index 8ba0353034c..08f760bb9dc 100644 --- a/estate/report/estate_property_templates.xml +++ b/estate/report/estate_property_templates.xml @@ -61,7 +61,7 @@ Invoice Status: Invoice Created
- +
diff --git a/estate/report/estate_property_user_templates.xml b/estate/report/estate_property_user_templates.xml index 2e53294a4ce..8ec237dc873 100644 --- a/estate/report/estate_property_user_templates.xml +++ b/estate/report/estate_property_user_templates.xml @@ -24,7 +24,7 @@ Property Status:
- + diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 332a9756f3b..9ecd4d53e2c 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -11,7 +11,4 @@ access_estate_property_offer_manager,access_estate_property_offer_manager,model_ access_estate_property_agent,access_estate_property_agent,model_estate_property,estate_group_user,1,1,1,0 access_estate_property_type_agent,access_estate_property_type_agent,model_estate_property_type,estate_group_user,1,0,0,0 access_estate_property_tag_agent,access_estate_property_tag_agent,model_estate_property_tag,estate_group_user,1,0,0,0 -access_estate_property_offer_agent,access_estate_property_offer_agent,model_estate_property_offer,estate_group_user,1,1,1,0 - - - +access_estate_property_offer_agent,access_estate_property_offer_agent,model_estate_property_offer,estate_group_user,1,1,1,0 \ No newline at end of file diff --git a/estate/wizard/estate_offer_wizard.py b/estate/wizard/estate_offer_wizard.py index 5e875d95c10..ee976c70344 100644 --- a/estate/wizard/estate_offer_wizard.py +++ b/estate/wizard/estate_offer_wizard.py @@ -14,9 +14,8 @@ class EstateOfferWizard(models.Model): 'estate.property', string="Properties", domain=[("state", "in", ["new", "offer_received"])]) def action_make_offer(self): - offer = self.env['estate.property.offer'] for property in self.property_ids: - offer.create({ + self.env['estate.property.offer'].create({ 'price': self.price, 'partner_id': self.partner_id.id, 'property_id': property.id diff --git a/estate_account/__manifest__.py b/estate_account/__manifest__.py index 541aaaf01db..448df6d6fcc 100644 --- a/estate_account/__manifest__.py +++ b/estate_account/__manifest__.py @@ -13,11 +13,6 @@ 'license': 'LGPL-3', 'description': ''' - Description text - ''', - 'data': [ - - ], - 'demo': [ - ], + Estate Account + ''' } diff --git a/estate_account/models/estate_property.py b/estate_account/models/estate_property.py index 1ef6b8e330e..fbbb40986fa 100644 --- a/estate_account/models/estate_property.py +++ b/estate_account/models/estate_property.py @@ -27,7 +27,7 @@ def action_sold(self): Command.create({ 'name': 'Administrative Fees', 'quantity': 1, - 'price_unit': '100.00' + 'price_unit': 100.00 }) ] }) From d6f850745f6a17b53b43f64bb775acb55612be49 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Mon, 24 Feb 2025 18:44:37 +0530 Subject: [PATCH 17/27] [IMP] awesome_dashboard: added new layout and buttons. Added a layout for the dashboard. Added customer and leads buttons. --- awesome_dashboard/static/src/dashboard.js | 22 ++++++++++++++++++++ awesome_dashboard/static/src/dashboard.scss | 4 ++++ awesome_dashboard/static/src/dashboard.xml | 11 ++++++++-- awesome_owl/controllers/__init__.py | 3 ++- awesome_owl/controllers/controllers.py | 4 ++++ awesome_owl/static/src/card/card.js | 8 ++++--- awesome_owl/static/src/card/card.xml | 1 + awesome_owl/static/src/counter/counter.js | 7 ++++--- awesome_owl/static/src/playground.js | 6 +++--- awesome_owl/static/src/todolist/todo_item.js | 6 ++++-- awesome_owl/static/src/todolist/todo_list.js | 9 ++++---- 11 files changed, 63 insertions(+), 18 deletions(-) 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..2bf7407411c 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -2,9 +2,31 @@ 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"; + static components = {Layout}; + + setup(){ + this.action = useService("action"); + console.log(this.action) + } + + openCustomers(){ + console.log("open customer called") + this.action.doAction("base.action_partner_form"); + } + + openLeads() { + this.action.doAction({ + type: "ir.actions.act_window", + res_model: "crm.lead", + views: [[false, 'form'], [false, 'list']] + }) + } } 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..fd9b4ebd540 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard.scss @@ -0,0 +1,4 @@ +.o_dashboard { + background-color: #d3d3d3; + padding: 20px; +} diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 1a2ac9a2fed..41870784170 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -2,7 +2,14 @@ - hello dashboard + +
+ + +
+
+

Awesome dashboard!

+
+
-
diff --git a/awesome_owl/controllers/__init__.py b/awesome_owl/controllers/__init__.py index 457bae27e11..dd15b5c32e5 100644 --- a/awesome_owl/controllers/__init__.py +++ b/awesome_owl/controllers/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import controllers \ No newline at end of file +from . import controllers diff --git a/awesome_owl/controllers/controllers.py b/awesome_owl/controllers/controllers.py index bccfd6fe283..57d0d0ddae5 100644 --- a/awesome_owl/controllers/controllers.py +++ b/awesome_owl/controllers/controllers.py @@ -1,6 +1,10 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + from odoo import http from odoo.http import request, route + class OwlPlayground(http.Controller): @http.route(['/awesome_owl'], type='http', auth='public') def show_playground(self): diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index 5740c3e253c..861bc7ca40d 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -1,10 +1,14 @@ +/** @odoo-module */ + import { Component, useState } from "@odoo/owl"; export class Card extends Component { + static template = "awesome_owl.card"; static props = { title: { type: String, optional: false }, slots: { type: Object, optional: true }, }; + setup() { this.state = useState({ visibility: true }); } @@ -12,6 +16,4 @@ export class Card extends Component { toggleState() { this.state.visibility = !this.state.visibility; } -} - -Card.template = "awesome_owl.card"; +} \ No newline at end of file diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index c80de7e9c92..13e92509af0 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -1,3 +1,4 @@ +
diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js index 5b7c012dc5e..684c42b96ba 100644 --- a/awesome_owl/static/src/counter/counter.js +++ b/awesome_owl/static/src/counter/counter.js @@ -1,6 +1,9 @@ +/** @odoo-module */ + import {Component, useState} from "@odoo/owl"; export class Counter extends Component{ + static template = "awesome_owl.counter"; static props ={ onChange: {type: Function, optional: true}, }; @@ -14,6 +17,4 @@ export class Counter extends Component{ this.props.onChange(this.state.value); } } -} - -Counter.template = "awesome_owl.counter"; \ No newline at end of file +} \ No newline at end of file diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 7fd6121b5e4..c830d201201 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -6,22 +6,22 @@ import { Card } from "./card/card"; import { TodoList } from "./todolist/todo_list"; export class Playground extends Component { + static template = "awesome_owl.playground"; static components = { Card, Counter, TodoList }; + setup() { this.plainText = "
Plain text content
"; this.htmlContent = markup("
Markup content
"); - this.state = useState({ counter1: 0, counter2: 0, }); - this.incrementSum = (counterNumber, newValue) => { this.state[counterNumber] = newValue; }; } + get sum() { return this.state.counter1 + this.state.counter2; } } -Playground.template = "awesome_owl.playground"; diff --git a/awesome_owl/static/src/todolist/todo_item.js b/awesome_owl/static/src/todolist/todo_item.js index 6f9bcd68809..a792a446bef 100644 --- a/awesome_owl/static/src/todolist/todo_item.js +++ b/awesome_owl/static/src/todolist/todo_item.js @@ -1,6 +1,9 @@ +/** @odoo-module */ + import { Component } from "@odoo/owl"; export class TodoItem extends Component { + static template = "awesome_owl.todo_item"; static props = { todo: { id: Number, description: String, isCompleted: Boolean }, toggleState: { type: Function }, @@ -14,5 +17,4 @@ export class TodoItem extends Component { deleteTodo() { this.props.removeTodo(this.props.todo.id); } - static template = "awesome_owl.todo_item"; -} +} \ No newline at end of file diff --git a/awesome_owl/static/src/todolist/todo_list.js b/awesome_owl/static/src/todolist/todo_list.js index 715b175e445..56bb5ad6d58 100644 --- a/awesome_owl/static/src/todolist/todo_list.js +++ b/awesome_owl/static/src/todolist/todo_list.js @@ -1,14 +1,17 @@ +/** @odoo-module */ + import { Component, useState, useRef, onMounted } from "@odoo/owl"; import { TodoItem } from "./todo_item"; import { useAutofocus } from "../utils"; export class TodoList extends Component { + static template = "awesome_owl.todo_list"; static components = { TodoItem }; setup() { this.todos = useState([]); this.todoCounter = 1; - // this.inputRef = useRef("taskInput"); + this.inputRef = useRef("taskInput"); useAutofocus(this.inputRef); } @@ -39,6 +42,4 @@ export class TodoList extends Component { this.todos.splice(index, 1); } }; -} - -TodoList.template = "awesome_owl.todo_list"; +} \ No newline at end of file From e9f1e7dd8778d1c947f3816c033add500af037b8 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Tue, 25 Feb 2025 18:50:59 +0530 Subject: [PATCH 18/27] [IMP] awesome_dashboard: added dashboard item, api call, pie chart, cached api calls. --- awesome_dashboard/controllers/controllers.py | 4 +- awesome_dashboard/static/src/dashboard.js | 20 +++++++-- awesome_dashboard/static/src/dashboard.scss | 4 ++ awesome_dashboard/static/src/dashboard.xml | 40 +++++++++++++++-- .../static/src/dashboard_item.js | 15 +++++++ .../static/src/dashboard_item.xml | 11 +++++ .../static/src/pie_chart/pie_chart.js | 43 +++++++++++++++++++ .../static/src/pie_chart/pie_chart.xml | 10 +++++ .../static/src/statistics_service.js | 30 +++++++++++++ awesome_owl/static/src/card/card.xml | 8 ++-- estate/models/estate_property.py | 6 --- 11 files changed, 174 insertions(+), 17 deletions(-) create mode 100644 awesome_dashboard/static/src/dashboard_item.js create mode 100644 awesome_dashboard/static/src/dashboard_item.xml create mode 100644 awesome_dashboard/static/src/pie_chart/pie_chart.js create mode 100644 awesome_dashboard/static/src/pie_chart/pie_chart.xml create mode 100644 awesome_dashboard/static/src/statistics_service.js diff --git a/awesome_dashboard/controllers/controllers.py b/awesome_dashboard/controllers/controllers.py index 56d4a051287..9a00d99ad5b 100644 --- a/awesome_dashboard/controllers/controllers.py +++ b/awesome_dashboard/controllers/controllers.py @@ -8,7 +8,10 @@ logger = logging.getLogger(__name__) + class AwesomeDashboard(http.Controller): + _name = "awesome.dashboard" + @http.route('/awesome_dashboard/statistics', type='json', auth='user') def get_statistics(self): """ @@ -33,4 +36,3 @@ def get_statistics(self): }, 'total_amount': random.randint(100, 1000) } - diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 2bf7407411c..4d5a4693af7 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,22 +1,34 @@ /** @odoo-module **/ -import { Component } from "@odoo/owl"; +import { Component, onWillStart, useState, useEffect } 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"; +import { PieChart } from "./pie_chart/pie_chart"; +import { reactive } from "@odoo/owl"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; - static components = {Layout}; + static components = {Layout, DashboardItem, PieChart}; setup(){ this.action = useService("action"); - console.log(this.action) + this.statisticsService = useState(useService("awesome_dashboard.statistics")); + this.state = reactive({ statistics: {} }); + + onWillStart(async () => { + this.state.statistics = await this.statisticsService.loadStatistics(); + }); + + useEffect(() => { + this.state.statistics = this.statisticsService.statistics.data; + }); } openCustomers(){ - console.log("open customer called") this.action.doAction("base.action_partner_form"); } diff --git a/awesome_dashboard/static/src/dashboard.scss b/awesome_dashboard/static/src/dashboard.scss index fd9b4ebd540..2f097fbf098 100644 --- a/awesome_dashboard/static/src/dashboard.scss +++ b/awesome_dashboard/static/src/dashboard.scss @@ -2,3 +2,7 @@ background-color: #d3d3d3; padding: 20px; } +.dashboard-item { + background-color: white; + border: 1px solid #ddd; +} \ No newline at end of file diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 41870784170..3cc3c42f842 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -3,12 +3,46 @@ -
+
+

Dashboard

-
-

Awesome dashboard!

+
+ + Average amount of t-shirt by order this month +
+ +
+
+ + Average time for an order to go from 'new' to 'sent' or 'cancelled' +
+ +
+
+ + Number of new orders this month +
+ +
+
+ + Number of cancelled orders this month +
+ +
+
+ + Total amount of new orders this month +
+ +
+
+ + Shirt orders by size + +
diff --git a/awesome_dashboard/static/src/dashboard_item.js b/awesome_dashboard/static/src/dashboard_item.js new file mode 100644 index 00000000000..c959240c590 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_item.js @@ -0,0 +1,15 @@ +/** @odoo-module **/ + +import { Component } from "@odoo/owl"; + +export class DashboardItem extends Component { + static template = "awesome_dashboard.DashboardItem"; + static props = { + slot: { type: Object, optional: true }, + size: { type: Number, optional: true }, + }; + + static defaultProps = { + size: 1 + } +} diff --git a/awesome_dashboard/static/src/dashboard_item.xml b/awesome_dashboard/static/src/dashboard_item.xml new file mode 100644 index 00000000000..516de834f9f --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_item.xml @@ -0,0 +1,11 @@ + + + +
+
+ +
+ +
+
+
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..29de2774d35 --- /dev/null +++ b/awesome_dashboard/static/src/pie_chart/pie_chart.js @@ -0,0 +1,43 @@ +/** @odoo-module */ + +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 diff --git a/awesome_dashboard/static/src/statistics_service.js b/awesome_dashboard/static/src/statistics_service.js new file mode 100644 index 00000000000..c739350c785 --- /dev/null +++ b/awesome_dashboard/static/src/statistics_service.js @@ -0,0 +1,30 @@ +import { registry } from "@web/core/registry"; +import { memoize } from "@web/core/utils/functions"; +import { rpc } from "@web/core/network/rpc"; +import { reactive } from "@odoo/owl"; + +class StatisticsService { + constructor() { + this.statistics = reactive({ data: null }); + + this._loadStatistics = async () => { + this.statistics.data = await rpc('/awesome_dashboard/statistics'); + }; + + this._loadStatistics(); + + setInterval(() => { + this._loadStatistics(); + }, 10000); + } + + async loadStatistics() { + return this.statistics.data; + } +} + +registry.category("services").add("awesome_dashboard.statistics", { + start() { + return new StatisticsService(); + }, +}); diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 13e92509af0..03a4ed0f05d 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -3,10 +3,12 @@
-
- +
+
+ +
-
+
diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index ad416bec8f3..3cedc9aef20 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -91,12 +91,6 @@ def _compute_best_price(self): prices = property.offer_ids.mapped('price') property.best_price = max(prices, default=0) - @api.constrains('selling_price') - def _check_selling_price(self): - for record in self: - if record.selling_price < 0: - raise ValidationError('The selling price must be positive.') - @api.constrains('expected_price') def _check_expected_price(self): for record in self: From f776574943796e8c31231507ccb1b03f26fa2db9 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Tue, 25 Feb 2025 19:08:39 +0530 Subject: [PATCH 19/27] [IMP] awesome_dashboard: added dashboard item, api call, pie chart Added a dashboard items. Made api calls for statistics data, cached the api calls. Added pie chart. --- awesome_dashboard/static/src/dashboard.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 3cc3c42f842..04bab574062 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -1,5 +1,6 @@ + From 9e4d05c4eeb5c6f6e5dd439c1000370f995e5460 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Wed, 26 Feb 2025 10:09:06 +0530 Subject: [PATCH 20/27] [IMP] awesome_dashboard: added reactive states From 84165551e56a3496ce850bfbbad25a12ed326670 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Wed, 26 Feb 2025 10:10:20 +0530 Subject: [PATCH 21/27] [IMP] awesome_dashboard: remove unnecessary comment lines --- awesome_dashboard/static/src/dashboard.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 04bab574062..3cc3c42f842 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -1,6 +1,5 @@ - From e1f4cdb413839fe079dcf58d55819d970d695fdc Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Wed, 26 Feb 2025 10:10:20 +0530 Subject: [PATCH 22/27] [IMP] awesome_dashboard: remove unnecessary comment lines --- awesome_dashboard/static/src/dashboard.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 04bab574062..3cc3c42f842 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -1,6 +1,5 @@ - From e83e63d60da41870f2abf57953a241d088f16a10 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Wed, 26 Feb 2025 15:24:04 +0530 Subject: [PATCH 23/27] [IMP] awesome_dashboard: updated dashboard for generic and extensive usage. Also added a gear button to add or remove dashboard items. Also made the required changes for code improvement. --- awesome_dashboard/__manifest__.py | 3 + .../static/src/cards/number_card.js | 14 ++++ .../static/src/cards/pie_chart_card.js | 14 ++++ awesome_dashboard/static/src/dashboard.js | 44 ------------ awesome_dashboard/static/src/dashboard.xml | 49 ------------- .../static/src/dashboard/dailog/Dialog.js | 38 ++++++++++ .../static/src/dashboard/dailog/Dialog.xml | 18 +++++ .../static/src/dashboard/dashboard.js | 63 ++++++++++++++++ .../static/src/{ => dashboard}/dashboard.scss | 0 .../static/src/dashboard/dashboard.xml | 28 ++++++++ .../dashboard_item}/dashboard_item.js | 0 .../dashboard_item}/dashboard_item.xml | 0 .../static/src/dashboard/dashboard_items.js | 72 +++++++++++++++++++ .../{ => dashboard}/pie_chart/pie_chart.js | 0 .../{ => dashboard}/pie_chart/pie_chart.xml | 0 .../src/{ => dashboard}/statistics_service.js | 2 + .../static/src/dashboard_action.js | 14 ++++ estate/data/master_data.xml | 2 +- estate/models/estate_property.py | 2 +- estate/report/estate_property_reports.xml | 2 +- .../report/estate_property_user_reports.xml | 2 +- 21 files changed, 270 insertions(+), 97 deletions(-) create mode 100644 awesome_dashboard/static/src/cards/number_card.js create mode 100644 awesome_dashboard/static/src/cards/pie_chart_card.js delete mode 100644 awesome_dashboard/static/src/dashboard.js delete mode 100644 awesome_dashboard/static/src/dashboard.xml create mode 100644 awesome_dashboard/static/src/dashboard/dailog/Dialog.js create mode 100644 awesome_dashboard/static/src/dashboard/dailog/Dialog.xml create mode 100644 awesome_dashboard/static/src/dashboard/dashboard.js rename awesome_dashboard/static/src/{ => dashboard}/dashboard.scss (100%) create mode 100644 awesome_dashboard/static/src/dashboard/dashboard.xml rename awesome_dashboard/static/src/{ => dashboard/dashboard_item}/dashboard_item.js (100%) rename awesome_dashboard/static/src/{ => dashboard/dashboard_item}/dashboard_item.xml (100%) create mode 100644 awesome_dashboard/static/src/dashboard/dashboard_items.js rename awesome_dashboard/static/src/{ => dashboard}/pie_chart/pie_chart.js (100%) rename awesome_dashboard/static/src/{ => dashboard}/pie_chart/pie_chart.xml (100%) rename awesome_dashboard/static/src/{ => dashboard}/statistics_service.js (97%) create mode 100644 awesome_dashboard/static/src/dashboard_action.js diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py index 31406e8addb..0f8ed5b7edb 100644 --- a/awesome_dashboard/__manifest__.py +++ b/awesome_dashboard/__manifest__.py @@ -25,6 +25,9 @@ 'web.assets_backend': [ 'awesome_dashboard/static/src/**/*', ], + 'awesome_dashboard.dashboard_assets': [ + 'awesome_dashboard/static/src/dashboard/**/*', + ], }, 'license': 'AGPL-3' } diff --git a/awesome_dashboard/static/src/cards/number_card.js b/awesome_dashboard/static/src/cards/number_card.js new file mode 100644 index 00000000000..5d5efd029c5 --- /dev/null +++ b/awesome_dashboard/static/src/cards/number_card.js @@ -0,0 +1,14 @@ +/** @odoo-module **/ + +import { Component, xml } from "@odoo/owl"; + +export class NumberCard extends Component { + static template = xml` +
+
+
+ +
+
+ `; +} diff --git a/awesome_dashboard/static/src/cards/pie_chart_card.js b/awesome_dashboard/static/src/cards/pie_chart_card.js new file mode 100644 index 00000000000..9bb6aed2a8f --- /dev/null +++ b/awesome_dashboard/static/src/cards/pie_chart_card.js @@ -0,0 +1,14 @@ +/** @odoo-module **/ + +import { Component, xml } from "@odoo/owl"; +import { PieChart } from "../dashboard/pie_chart/pie_chart"; + +export class PieChartCard extends Component { + static template = xml` +
+
+ +
+ `; + static components = { PieChart }; +} diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js deleted file mode 100644 index 4d5a4693af7..00000000000 --- a/awesome_dashboard/static/src/dashboard.js +++ /dev/null @@ -1,44 +0,0 @@ -/** @odoo-module **/ - -import { Component, onWillStart, useState, useEffect } 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"; -import { PieChart } from "./pie_chart/pie_chart"; -import { reactive } from "@odoo/owl"; - - -class AwesomeDashboard extends Component { - static template = "awesome_dashboard.AwesomeDashboard"; - static components = {Layout, DashboardItem, PieChart}; - - setup(){ - this.action = useService("action"); - this.statisticsService = useState(useService("awesome_dashboard.statistics")); - this.state = reactive({ statistics: {} }); - - onWillStart(async () => { - this.state.statistics = await this.statisticsService.loadStatistics(); - }); - - useEffect(() => { - this.state.statistics = this.statisticsService.statistics.data; - }); - } - - openCustomers(){ - this.action.doAction("base.action_partner_form"); - } - - openLeads() { - this.action.doAction({ - type: "ir.actions.act_window", - res_model: "crm.lead", - views: [[false, 'form'], [false, 'list']] - }) - } -} - -registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml deleted file mode 100644 index 3cc3c42f842..00000000000 --- a/awesome_dashboard/static/src/dashboard.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - -
- - -

Dashboard

-
-
- - Average amount of t-shirt by order this month -
- -
-
- - Average time for an order to go from 'new' to 'sent' or 'cancelled' -
- -
-
- - Number of new orders this month -
- -
-
- - Number of cancelled orders this month -
- -
-
- - Total amount of new orders this month -
- -
-
- - Shirt orders by size - - -
-
-
-
diff --git a/awesome_dashboard/static/src/dashboard/dailog/Dialog.js b/awesome_dashboard/static/src/dashboard/dailog/Dialog.js new file mode 100644 index 00000000000..92d0d05a480 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/dailog/Dialog.js @@ -0,0 +1,38 @@ +/** @odoo-module **/ + +import { Component, useState } from "@odoo/owl"; +import { Dialog } from "@web/core/dialog/dialog"; + +export class DashboardConfigDialog extends Component { + static template = "awesome_dashboard.DashboardConfigDialog"; + static components = { Dialog }; + static props = ["title", "items", "disabledItems", "close"]; + + setup() { + const savedConfig = JSON.parse(localStorage.getItem("dashboard_config")) || []; + this.state = useState({ + disabledItems: new Set(savedConfig.length ? savedConfig : this.props.disabledItems || []) + }); + } + + toggleItem = (itemId) => { + this.state.disabledItems = new Set(this.state.disabledItems); + if (this.state.disabledItems.has(itemId)) { + this.state.disabledItems.delete(itemId); + } else { + this.state.disabledItems.add(itemId); + } + }; + + saveConfig() { + const disabledItemsArray = [...this.state.disabledItems]; + localStorage.setItem("dashboard_hidden_items", JSON.stringify(disabledItemsArray)); + + if (this.props.onSave) { + this.props.onSave(disabledItemsArray); + } + + this.props.close(); + } +} + diff --git a/awesome_dashboard/static/src/dashboard/dailog/Dialog.xml b/awesome_dashboard/static/src/dashboard/dailog/Dialog.xml new file mode 100644 index 00000000000..286510b77cd --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/dailog/Dialog.xml @@ -0,0 +1,18 @@ + + + +
+ +
+ + +
+
+
+
+ +
+
+
diff --git a/awesome_dashboard/static/src/dashboard/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js new file mode 100644 index 00000000000..ef470dc12ae --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -0,0 +1,63 @@ +/** @odoo-module **/ + +import { Component, onWillStart, useState, useEffect, reactive } 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/dashboard_item"; +import { rpc } from "@web/core/network/rpc"; +import {PieChart} from "./pie_chart/pie_chart" +import { items } from "./dashboard_items"; +import { Dialog } from "@web/core/dialog/dialog"; +import { DashboardConfigDialog } from "./dailog/Dialog"; + +class AwesomeDashboard extends Component { + static template = "awesome_dashboard.AwesomeDashboard"; + static components = {Layout, DashboardItem, PieChart, Dialog}; + + setup(){ + this.action = useService("action"); + this.statisticsService = useState(useService("awesome_dashboard.statistics")); + this.state = reactive({ statistics: {}, disabledItems: [] }); + this.items = registry.category("awesome_dashboard").getAll(); + + onWillStart(async () => { + this.state.statistics = await this.statisticsService.loadStatistics(); + this.loadConfig(); + }); + + useEffect(() => { + this.state.statistics = this.statisticsService.statistics.data; + }); + } + + loadConfig() { + const config = localStorage.getItem("dashboard_hidden_items"); + this.state.disabledItems = config ? JSON.parse(config) : []; + } + + openConfiguration() { + this.env.services.dialog.add(DashboardConfigDialog, { + items: this.items, + disabledItems: [...this.state.disabledItems], + onSave: (hiddenItems) => { + localStorage.setItem("dashboard_hidden_items", JSON.stringify(hiddenItems)); + this.state.disabledItems = hiddenItems; + }, + }); + } + + openCustomers(){ + this.action.doAction("base.action_partner_form"); + } + + openLeads() { + this.action.doAction({ + type: "ir.actions.act_window", + res_model: "crm.lead", + views: [[false, 'form'], [false, 'list']] + }) + } +} + +registry.category("lazy_components").add("awesome_dashboard.dashboard", AwesomeDashboard); \ No newline at end of file diff --git a/awesome_dashboard/static/src/dashboard.scss b/awesome_dashboard/static/src/dashboard/dashboard.scss similarity index 100% rename from awesome_dashboard/static/src/dashboard.scss rename to awesome_dashboard/static/src/dashboard/dashboard.scss diff --git a/awesome_dashboard/static/src/dashboard/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml new file mode 100644 index 00000000000..8a6b27fcf48 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/dashboard.xml @@ -0,0 +1,28 @@ + + + + +
+ + +

Dashboard

+ + + + +
+
+ + + + + + +
+
+
+
diff --git a/awesome_dashboard/static/src/dashboard_item.js b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js similarity index 100% rename from awesome_dashboard/static/src/dashboard_item.js rename to awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js diff --git a/awesome_dashboard/static/src/dashboard_item.xml b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml similarity index 100% rename from awesome_dashboard/static/src/dashboard_item.xml rename to awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml diff --git a/awesome_dashboard/static/src/dashboard/dashboard_items.js b/awesome_dashboard/static/src/dashboard/dashboard_items.js new file mode 100644 index 00000000000..9e7cede258b --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/dashboard_items.js @@ -0,0 +1,72 @@ +/** @odoo-module **/ + +import { PieChartCard } from "../cards/pie_chart_card"; +import { NumberCard } from "../cards/number_card"; +import { registry } from "@web/core/registry"; + +const items = [ + { + id: "average_quantity", + description: "Average amount of t-shirts per order this month", + Component: NumberCard, + size: 1, + props: (data) => ({ + title: "Average amount of t-shirts per order this month", + value: data.average_quantity, + }), + }, + { + id: "average_time", + description: "Average time for an order to go from 'new' to 'sent' or 'cancelled'", + Component: NumberCard, + size: 1, + props: (data) => ({ + title: "Avg. time from 'new' to 'sent/cancelled'", + value: data.average_time, + }), + }, + { + id: "nb_new_orders", + description: "Number of new orders this month", + Component: NumberCard, + size: 1, + props: (data) => ({ + title: "New orders this month", + value: data.nb_new_orders, + }), + }, + { + id: "nb_cancelled_orders", + description: "Number of cancelled orders this month", + Component: NumberCard, + size: 1, + props: (data) => ({ + title: "Cancelled orders this month", + value: data.nb_cancelled_orders, + }), + }, + { + id: "total_amount", + description: "Total amount of new orders this month", + Component: NumberCard, + size: 1, + props: (data) => ({ + title: "Total amount of new orders", + value: data.total_amount, + }), + }, + { + id: "orders_by_size", + description: "Shirt orders by size", + Component: PieChartCard, + size: 2, + props: (data) => ({ + title: "Shirt orders by size", + data: data.orders_by_size, + }), + }, +]; + +items.forEach(item => { + registry.category("awesome_dashboard").add(item.id, item); +}); \ No newline at end of file diff --git a/awesome_dashboard/static/src/pie_chart/pie_chart.js b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js similarity index 100% rename from awesome_dashboard/static/src/pie_chart/pie_chart.js rename to awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js diff --git a/awesome_dashboard/static/src/pie_chart/pie_chart.xml b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml similarity index 100% rename from awesome_dashboard/static/src/pie_chart/pie_chart.xml rename to awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml diff --git a/awesome_dashboard/static/src/statistics_service.js b/awesome_dashboard/static/src/dashboard/statistics_service.js similarity index 97% rename from awesome_dashboard/static/src/statistics_service.js rename to awesome_dashboard/static/src/dashboard/statistics_service.js index c739350c785..093791bef37 100644 --- a/awesome_dashboard/static/src/statistics_service.js +++ b/awesome_dashboard/static/src/dashboard/statistics_service.js @@ -1,3 +1,5 @@ +/** @odoo-module **/ + import { registry } from "@web/core/registry"; import { memoize } from "@web/core/utils/functions"; import { rpc } from "@web/core/network/rpc"; diff --git a/awesome_dashboard/static/src/dashboard_action.js b/awesome_dashboard/static/src/dashboard_action.js new file mode 100644 index 00000000000..954963f0b63 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_action.js @@ -0,0 +1,14 @@ +/** @odoo-module **/ + +import { Component, xml } from "@odoo/owl"; +import { LazyComponent } from "@web/core/assets"; +import { registry } from "@web/core/registry"; + +export class AwesomeDashboardLoader extends Component { + static components = { LazyComponent }; + static template = xml` + + `; +} + +registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboardLoader); diff --git a/estate/data/master_data.xml b/estate/data/master_data.xml index 74ba2b1e395..57fa1b1740d 100644 --- a/estate/data/master_data.xml +++ b/estate/data/master_data.xml @@ -1,6 +1,6 @@ - + Residential diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 3cedc9aef20..68691806e9b 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -78,7 +78,7 @@ def _compute_offer_received(self): @api.depends('salesperson_id.name') def _compute_desc(self): for record in self: - record.description = 'Test for salesperson %s' % record.salesperson_id.name + record.description = 'For property information contact salesperson %s' % record.salesperson_id.name @api.depends('living_area', 'garden_area') def _compute_total_area(self): diff --git a/estate/report/estate_property_reports.xml b/estate/report/estate_property_reports.xml index 2019c5d2273..efc956d4e24 100644 --- a/estate/report/estate_property_reports.xml +++ b/estate/report/estate_property_reports.xml @@ -3,7 +3,7 @@ Offer Report estate.property - qweb-html + qweb-pdf estate.report_property_offer 'Property_Offers_%s' % (object.name) diff --git a/estate/report/estate_property_user_reports.xml b/estate/report/estate_property_user_reports.xml index dab8e0e71cc..d84fc4ebbbd 100644 --- a/estate/report/estate_property_user_reports.xml +++ b/estate/report/estate_property_user_reports.xml @@ -2,7 +2,7 @@ User Report res.users - qweb-html + qweb-pdf estate.report_user_properties action From 38d4865de01b064cd9c6c50f5f95c586844c9a51 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Mon, 14 Apr 2025 10:52:28 +0530 Subject: [PATCH 24/27] [ADD] owl_tutorials: added owl_tutorials module for owl practice. --- owl_tutorials/__init__.py | 4 ++ owl_tutorials/__manifest__.py | 40 +++++++++++++++ owl_tutorials/controllers/__init__.py | 3 ++ owl_tutorials/controllers/controllers.py | 22 +++++++++ owl_tutorials/demo/demo.xml | 30 ++++++++++++ owl_tutorials/models/__init__.py | 3 ++ owl_tutorials/models/todo_list.py | 12 +++++ owl_tutorials/security/ir.model.access.csv | 2 + .../src/components/todo_list/todo_list.js | 14 ++++++ .../src/components/todo_list/todo_list.scss | 0 .../src/components/todo_list/todo_list.xml | 9 ++++ owl_tutorials/views/views.xml | 49 +++++++++++++++++++ 12 files changed, 188 insertions(+) create mode 100644 owl_tutorials/__init__.py create mode 100644 owl_tutorials/__manifest__.py create mode 100644 owl_tutorials/controllers/__init__.py create mode 100644 owl_tutorials/controllers/controllers.py create mode 100644 owl_tutorials/demo/demo.xml create mode 100644 owl_tutorials/models/__init__.py create mode 100644 owl_tutorials/models/todo_list.py create mode 100644 owl_tutorials/security/ir.model.access.csv create mode 100644 owl_tutorials/static/src/components/todo_list/todo_list.js create mode 100644 owl_tutorials/static/src/components/todo_list/todo_list.scss create mode 100644 owl_tutorials/static/src/components/todo_list/todo_list.xml create mode 100644 owl_tutorials/views/views.xml diff --git a/owl_tutorials/__init__.py b/owl_tutorials/__init__.py new file mode 100644 index 00000000000..c3d410ea160 --- /dev/null +++ b/owl_tutorials/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +from . import models +from . import controllers diff --git a/owl_tutorials/__manifest__.py b/owl_tutorials/__manifest__.py new file mode 100644 index 00000000000..d732148718d --- /dev/null +++ b/owl_tutorials/__manifest__.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +{ + 'name': "owl_tutorials", + + 'summary': "Short (1 phrase/line) summary of the module's purpose", + + 'description': """ +Long description of module's purpose + """, + + 'author': "My Company", + 'website': "https://www.yourcompany.com", + + # Categories can be used to filter modules in modules listing + # Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml + # for the full list + 'category': 'Uncategorized', + 'version': '0.1', + + # any module necessary for this one to work correctly + 'depends': ['base', 'web'], + + # always loaded + 'data': [ + 'security/ir.model.access.csv', + 'views/views.xml', + ], + # only loaded in demonstration mode + 'demo': [ + 'demo/demo.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'owl_tutorials/static/src/components/**/*', + ], + }, + 'installable': True, + 'application': True, +} + diff --git a/owl_tutorials/controllers/__init__.py b/owl_tutorials/controllers/__init__.py new file mode 100644 index 00000000000..b0f26a9a602 --- /dev/null +++ b/owl_tutorials/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers diff --git a/owl_tutorials/controllers/controllers.py b/owl_tutorials/controllers/controllers.py new file mode 100644 index 00000000000..b7a54f0fc94 --- /dev/null +++ b/owl_tutorials/controllers/controllers.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# from odoo import http + + +# class OwlTutorials(http.Controller): +# @http.route('/owl_tutorials/owl_tutorials', auth='public') +# def index(self, **kw): +# return "Hello, world" + +# @http.route('/owl_tutorials/owl_tutorials/objects', auth='public') +# def list(self, **kw): +# return http.request.render('owl_tutorials.listing', { +# 'root': '/owl_tutorials/owl_tutorials', +# 'objects': http.request.env['owl_tutorials.owl_tutorials'].search([]), +# }) + +# @http.route('/owl_tutorials/owl_tutorials/objects/', auth='public') +# def object(self, obj, **kw): +# return http.request.render('owl_tutorials.object', { +# 'object': obj +# }) + diff --git a/owl_tutorials/demo/demo.xml b/owl_tutorials/demo/demo.xml new file mode 100644 index 00000000000..d87373b0c2e --- /dev/null +++ b/owl_tutorials/demo/demo.xml @@ -0,0 +1,30 @@ + + + + + diff --git a/owl_tutorials/models/__init__.py b/owl_tutorials/models/__init__.py new file mode 100644 index 00000000000..d23b3312bab --- /dev/null +++ b/owl_tutorials/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import todo_list diff --git a/owl_tutorials/models/todo_list.py b/owl_tutorials/models/todo_list.py new file mode 100644 index 00000000000..6d0faa5ea66 --- /dev/null +++ b/owl_tutorials/models/todo_list.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +from odoo import models, fields, api + + +class todo_list(models.Model): + _name = 'todo.list' + _description = 'todo list' + + name = fields.Char() + color = fields.Char() + completed = fields.Boolean() \ No newline at end of file diff --git a/owl_tutorials/security/ir.model.access.csv b/owl_tutorials/security/ir.model.access.csv new file mode 100644 index 00000000000..77e6ca26ce9 --- /dev/null +++ b/owl_tutorials/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_todo_list,access_todo_list,model_todo_list,base.group_user,1,1,1,1 diff --git a/owl_tutorials/static/src/components/todo_list/todo_list.js b/owl_tutorials/static/src/components/todo_list/todo_list.js new file mode 100644 index 00000000000..e17f0d86efe --- /dev/null +++ b/owl_tutorials/static/src/components/todo_list/todo_list.js @@ -0,0 +1,14 @@ +/** @odoo-module **/ + +import { Component } from '@odoo/owl'; +import {registry} from '@web/core/registry'; +import {useState} from '@odoo/owl'; + +class OwlTodoList extends Component { + static template= 'owl.TodoList'; + setup() { + this.state = useState({value:45}); + + } +} +registry.category('actions').add('owl.action_todo_list_js', OwlTodoList) \ No newline at end of file diff --git a/owl_tutorials/static/src/components/todo_list/todo_list.scss b/owl_tutorials/static/src/components/todo_list/todo_list.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/owl_tutorials/static/src/components/todo_list/todo_list.xml b/owl_tutorials/static/src/components/todo_list/todo_list.xml new file mode 100644 index 00000000000..1ade5a119a3 --- /dev/null +++ b/owl_tutorials/static/src/components/todo_list/todo_list.xml @@ -0,0 +1,9 @@ + + +
+

Todo List

+

+
+
+ +
\ No newline at end of file diff --git a/owl_tutorials/views/views.xml b/owl_tutorials/views/views.xml new file mode 100644 index 00000000000..a25bee89c94 --- /dev/null +++ b/owl_tutorials/views/views.xml @@ -0,0 +1,49 @@ + + + + + todo.list.tree + todo.list + + + + + + + + + + + + todo.list.form + todo.list + +
+ + + + + + + +
+
+
+ + + + Todo List + todo.list + list,form + + + + Todo List OWL + owl.action_todo_list_js + + + + + + +
From e89447436a9829240ce9e6888f4bdb7794e2da72 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Mon, 14 Apr 2025 19:50:47 +0530 Subject: [PATCH 25/27] [IMP] owl_tutorials: added lifecycle methods for the fucntioning of code. --- owl_tutorials/__init__.py | 2 +- owl_tutorials/__manifest__.py | 29 ++----- owl_tutorials/controllers/__init__.py | 3 - owl_tutorials/controllers/controllers.py | 22 ----- owl_tutorials/demo/demo.xml | 30 ------- owl_tutorials/models/__init__.py | 1 + owl_tutorials/models/todo_list.py | 5 +- .../src/components/todo_list/todo_list.js | 41 +++++++-- .../src/components/todo_list/todo_list.xml | 85 +++++++++++++++++-- owl_tutorials/views/views.xml | 4 - 10 files changed, 128 insertions(+), 94 deletions(-) delete mode 100644 owl_tutorials/controllers/__init__.py delete mode 100644 owl_tutorials/controllers/controllers.py delete mode 100644 owl_tutorials/demo/demo.xml diff --git a/owl_tutorials/__init__.py b/owl_tutorials/__init__.py index c3d410ea160..dc5e6b693d1 100644 --- a/owl_tutorials/__init__.py +++ b/owl_tutorials/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. from . import models -from . import controllers diff --git a/owl_tutorials/__manifest__.py b/owl_tutorials/__manifest__.py index d732148718d..d0697e38f59 100644 --- a/owl_tutorials/__manifest__.py +++ b/owl_tutorials/__manifest__.py @@ -1,34 +1,20 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + { 'name': "owl_tutorials", - - 'summary': "Short (1 phrase/line) summary of the module's purpose", - 'description': """ -Long description of module's purpose + odoo owl tutorials practice """, - - 'author': "My Company", - 'website': "https://www.yourcompany.com", - - # Categories can be used to filter modules in modules listing - # Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml - # for the full list - 'category': 'Uncategorized', - 'version': '0.1', - - # any module necessary for this one to work correctly + 'author': "Odoo", + 'website': "https://www.odoo.com", + 'license': 'LGPL-3', + 'version': '1.0', 'depends': ['base', 'web'], - - # always loaded 'data': [ 'security/ir.model.access.csv', 'views/views.xml', ], - # only loaded in demonstration mode - 'demo': [ - 'demo/demo.xml', - ], 'assets': { 'web.assets_backend': [ 'owl_tutorials/static/src/components/**/*', @@ -37,4 +23,3 @@ 'installable': True, 'application': True, } - diff --git a/owl_tutorials/controllers/__init__.py b/owl_tutorials/controllers/__init__.py deleted file mode 100644 index b0f26a9a602..00000000000 --- a/owl_tutorials/controllers/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -*- coding: utf-8 -*- - -from . import controllers diff --git a/owl_tutorials/controllers/controllers.py b/owl_tutorials/controllers/controllers.py deleted file mode 100644 index b7a54f0fc94..00000000000 --- a/owl_tutorials/controllers/controllers.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# from odoo import http - - -# class OwlTutorials(http.Controller): -# @http.route('/owl_tutorials/owl_tutorials', auth='public') -# def index(self, **kw): -# return "Hello, world" - -# @http.route('/owl_tutorials/owl_tutorials/objects', auth='public') -# def list(self, **kw): -# return http.request.render('owl_tutorials.listing', { -# 'root': '/owl_tutorials/owl_tutorials', -# 'objects': http.request.env['owl_tutorials.owl_tutorials'].search([]), -# }) - -# @http.route('/owl_tutorials/owl_tutorials/objects/', auth='public') -# def object(self, obj, **kw): -# return http.request.render('owl_tutorials.object', { -# 'object': obj -# }) - diff --git a/owl_tutorials/demo/demo.xml b/owl_tutorials/demo/demo.xml deleted file mode 100644 index d87373b0c2e..00000000000 --- a/owl_tutorials/demo/demo.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - diff --git a/owl_tutorials/models/__init__.py b/owl_tutorials/models/__init__.py index d23b3312bab..305b4f62cb0 100644 --- a/owl_tutorials/models/__init__.py +++ b/owl_tutorials/models/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. from . import todo_list diff --git a/owl_tutorials/models/todo_list.py b/owl_tutorials/models/todo_list.py index 6d0faa5ea66..d30a10faea3 100644 --- a/owl_tutorials/models/todo_list.py +++ b/owl_tutorials/models/todo_list.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import models, fields, api +from odoo import fields, models class todo_list(models.Model): @@ -9,4 +10,4 @@ class todo_list(models.Model): name = fields.Char() color = fields.Char() - completed = fields.Boolean() \ No newline at end of file + completed = fields.Boolean() diff --git a/owl_tutorials/static/src/components/todo_list/todo_list.js b/owl_tutorials/static/src/components/todo_list/todo_list.js index e17f0d86efe..c3d9fca2b82 100644 --- a/owl_tutorials/static/src/components/todo_list/todo_list.js +++ b/owl_tutorials/static/src/components/todo_list/todo_list.js @@ -1,14 +1,45 @@ /** @odoo-module **/ -import { Component } from '@odoo/owl'; import {registry} from '@web/core/registry'; -import {useState} from '@odoo/owl'; +import { Component, useState, onWillStart } from '@odoo/owl'; +import { useService } from '@web/core/utils/hooks'; class OwlTodoList extends Component { static template= 'owl.TodoList'; setup() { - this.state = useState({value:45}); - + this.state = useState({ + task:{name:"", color:"#ff0000", completed:false}, + taskList:[], + isEdit: false, + activeId: false + }); + this.orm = useService('orm'); + this.model = "todo.list"; + + onWillStart(async ()=>{ + await this.getAllTasks(); + }) + + } + + async getAllTasks(){ + this.state.taskList = await this.orm.searchRead(this.model, [], ['name', 'color', 'completed']) + } + + addTask(){ + + } + + editTask(){ + + } + + async saveTask(){ + await this.orm.create(this.model, [{ + name: this.state.task.name, + color: this.state.task.color, + completed: this.state.task.completed + }]); } } -registry.category('actions').add('owl.action_todo_list_js', OwlTodoList) \ No newline at end of file +registry.category('actions').add('owl.action_todo_list_js', OwlTodoList) diff --git a/owl_tutorials/static/src/components/todo_list/todo_list.xml b/owl_tutorials/static/src/components/todo_list/todo_list.xml index 1ade5a119a3..8087f5896a2 100644 --- a/owl_tutorials/static/src/components/todo_list/todo_list.xml +++ b/owl_tutorials/static/src/components/todo_list/todo_list.xml @@ -1,9 +1,84 @@ + -
-

Todo List

-

+
+
+
+ +
+
+
+ + +
+
+
+
+
+ + + + + + + + + + + + + + + +
Task DescriptionCompleted
+
+ + +
+
+ + + + +
+
+
+
+ - - \ No newline at end of file + diff --git a/owl_tutorials/views/views.xml b/owl_tutorials/views/views.xml index a25bee89c94..c4a4d7727e7 100644 --- a/owl_tutorials/views/views.xml +++ b/owl_tutorials/views/views.xml @@ -1,6 +1,5 @@ - todo.list.tree todo.list @@ -13,7 +12,6 @@ - todo.list.form todo.list @@ -30,7 +28,6 @@ - Todo List todo.list @@ -42,7 +39,6 @@ owl.action_todo_list_js - From 57b3280c9dbfbdbff1af25c6cb9e56ecb4ef55fb Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Tue, 15 Apr 2025 18:47:00 +0530 Subject: [PATCH 26/27] [IMP] owl_tutorials: added search functionality, on-click event handling and added view inheritance. --- owl_tutorials/__manifest__.py | 1 + .../src/components/todo_list/todo_list.js | 48 +++++++++++++++---- .../src/components/todo_list/todo_list.xml | 16 +++---- .../view_inheritance/res_partner_list_view.js | 19 ++++++++ owl_tutorials/views/res_partner.xml | 13 +++++ 5 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.js create mode 100644 owl_tutorials/views/res_partner.xml diff --git a/owl_tutorials/__manifest__.py b/owl_tutorials/__manifest__.py index d0697e38f59..66e5741a927 100644 --- a/owl_tutorials/__manifest__.py +++ b/owl_tutorials/__manifest__.py @@ -14,6 +14,7 @@ 'data': [ 'security/ir.model.access.csv', 'views/views.xml', + 'views/res_partner.xml', ], 'assets': { 'web.assets_backend': [ diff --git a/owl_tutorials/static/src/components/todo_list/todo_list.js b/owl_tutorials/static/src/components/todo_list/todo_list.js index c3d9fca2b82..47e45181b07 100644 --- a/owl_tutorials/static/src/components/todo_list/todo_list.js +++ b/owl_tutorials/static/src/components/todo_list/todo_list.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import {registry} from '@web/core/registry'; -import { Component, useState, onWillStart } from '@odoo/owl'; +import { Component, useState, onWillStart, useRef } from '@odoo/owl'; import { useService } from '@web/core/utils/hooks'; class OwlTodoList extends Component { @@ -15,6 +15,7 @@ class OwlTodoList extends Component { }); this.orm = useService('orm'); this.model = "todo.list"; + this.searchInput = useRef("search-input") onWillStart(async ()=>{ await this.getAllTasks(); @@ -27,19 +28,50 @@ class OwlTodoList extends Component { } addTask(){ - + this.resetForm(); } - editTask(){ + editTask(task){ + this.state.task = {...task}; + this.state.isEdit = true; + this.state.activeId = task.id; } async saveTask(){ - await this.orm.create(this.model, [{ - name: this.state.task.name, - color: this.state.task.color, - completed: this.state.task.completed - }]); + if(!this.state.isEdit){ + await this.orm.create(this.model, [this.state.task]); + }else{ + await this.orm.write(this.model, [this.state.activeId], this.state.task ); + } + + await this.getAllTasks(); + } + + async deleteTask(task){ + await this.orm.unlink(this.model,[task.id]); + await this.getAllTasks() + } + + async searchTask(){ + const text = this.searchInput.el.value + this.state.taskList = await this.orm.searchRead(this.model, [['name', 'ilike', text]], ['name', 'color', 'completed']) + } + + async toggleTask(e, task){ + await this.orm.write(this.model, [task.id], {completed: e.target.checked}) + await this.getAllTasks() + } + + async toggleColor(e, task){ + await this.orm.write(this.model, [task.id], {color: e.target.value}) + await this.getAllTasks() + } + + resetForm(){ + this.state.task = {name:"", color:"#ff0000", completed:false}; + this.state.isEdit = false; + this.state.activeId = false; } } registry.category('actions').add('owl.action_todo_list_js', OwlTodoList) diff --git a/owl_tutorials/static/src/components/todo_list/todo_list.xml b/owl_tutorials/static/src/components/todo_list/todo_list.xml index 8087f5896a2..18d136452ef 100644 --- a/owl_tutorials/static/src/components/todo_list/todo_list.xml +++ b/owl_tutorials/static/src/components/todo_list/todo_list.xml @@ -4,12 +4,12 @@
- +
- - + +
@@ -27,18 +27,18 @@
- +
- + - - + + @@ -75,7 +75,7 @@
diff --git a/owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.js b/owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.js new file mode 100644 index 00000000000..a7cdd24cdc9 --- /dev/null +++ b/owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.js @@ -0,0 +1,19 @@ +/** @odoo-module **/ + +import { registry } from "@web/core/registry"; +import { listView } from "@web/views/list/list_view"; +import { ListController } from "@web/views/list/list_controller"; + +class ResPartnerListController extends ListController{ + setup(){ + super.setup() + console.log("This is res parnter controller") + } +} + +export const ResPartnerListView = { + ...listView, + Controller: ResPartnerListController +} + +registry.category("views").add("res_partner_list_view", ResPartnerListView ) \ No newline at end of file diff --git a/owl_tutorials/views/res_partner.xml b/owl_tutorials/views/res_partner.xml new file mode 100644 index 00000000000..add0b7355fe --- /dev/null +++ b/owl_tutorials/views/res_partner.xml @@ -0,0 +1,13 @@ + + + + res.partner.list.view.inherit + res.partner + + + + res_partner_list_view + + + + \ No newline at end of file From 38bf690e88d1d532bb8c05f27091a78f7a60fdb4 Mon Sep 17 00:00:00 2001 From: mebh-odoo Date: Thu, 17 Apr 2025 15:30:13 +0530 Subject: [PATCH 27/27] [IMP] owl_tutorials: added view inheritance for list and kanban view. --- .../res_partner_kanban_view .scss | 3 ++ .../res_partner_kanban_view .xml | 29 ++++++++++++ .../res_partner_kanban_view.js | 45 +++++++++++++++++++ .../view_inheritance/res_partner_list_view.js | 17 ++++++- .../res_partner_list_view.xml | 10 +++++ owl_tutorials/views/res_partner.xml | 16 +++++-- owl_tutorials/views/views.xml | 6 +-- 7 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view .scss create mode 100644 owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view .xml create mode 100644 owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view.js create mode 100644 owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.xml diff --git a/owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view .scss b/owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view .scss new file mode 100644 index 00000000000..66adf24fbbc --- /dev/null +++ b/owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view .scss @@ -0,0 +1,3 @@ +.o_res_partner_kanban_view_sidebar { + flex: 0 0 300px; +} \ No newline at end of file diff --git a/owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view .xml b/owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view .xml new file mode 100644 index 00000000000..501cbf92d0c --- /dev/null +++ b/owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view .xml @@ -0,0 +1,29 @@ + + + + + + + + + + + +
+

Customer Locations

+
+ + + + + + +
+ +
+
+ + model.useSampleModel ? 'o_view_sample_data' : '' + "d-flex" + +
+
\ No newline at end of file diff --git a/owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view.js b/owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view.js new file mode 100644 index 00000000000..7543e3ed9a8 --- /dev/null +++ b/owl_tutorials/static/src/components/view_inheritance/res_partner_kanban_view.js @@ -0,0 +1,45 @@ +/** @odoo-module **/ + +import { registry } from "@web/core/registry"; +import { kanbanView } from "@web/views/kanban/kanban_view"; +import { KanbanController } from "@web/views/kanban/kanban_controller"; +import { useService } from "@web/core/utils/hooks"; +import { onWillStart } from '@odoo/owl'; + +class ResPartnerKanbanController extends KanbanController{ + static template = "owl_tutorials.ResPartnerKanbanView" + setup(){ + super.setup() + console.log("This is res parnter controller") + this.action = useService("action") + this.orm = useService("orm") + + onWillStart(async () => { + this.customerLocation = await this.orm.readGroup("res.partner", [], ['state_id'], ['state_id']) + this.customerLocations = this.customerLocation.slice(0, -1) + console.log(this.customerLocations) + }) + } + + openSalesView(){ + console.log("opened sales view") + this.action.doAction({ + type: "ir.actions.act_window", + name: "Customer Sales", + res_model: "sale.order", + views: [[false, "list"], [false, "form"]] + }) + } + + selectLocations(state){ + this.model.load({ domain: [['state_id', '=', state[0]]] }); + } +} + +export const ResPartnerKanbanView = { + ...kanbanView, + Controller: ResPartnerKanbanController, + buttonTemplate: "owl_tutorials.ResPartnerKanbanView.Buttons" +} + +registry.category("views").add("res_partner_kanban_view", ResPartnerKanbanView ) diff --git a/owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.js b/owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.js index a7cdd24cdc9..2d9fa689765 100644 --- a/owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.js +++ b/owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.js @@ -3,17 +3,30 @@ import { registry } from "@web/core/registry"; import { listView } from "@web/views/list/list_view"; import { ListController } from "@web/views/list/list_controller"; +import { useService } from "@web/core/utils/hooks"; class ResPartnerListController extends ListController{ setup(){ super.setup() console.log("This is res parnter controller") + this.action = useService("action") + } + + openSalesView(){ + console.log("opened sales view") + this.action.doAction({ + type: "ir.actions.act_window", + name: "Customer Sales", + res_model: "sale.order", + views: [[false, "list"], [false, "form"]] + }) } } export const ResPartnerListView = { ...listView, - Controller: ResPartnerListController + Controller: ResPartnerListController, + buttonTemplate: "owl_tutorials.ResPartnerListView.Buttons" } -registry.category("views").add("res_partner_list_view", ResPartnerListView ) \ No newline at end of file +registry.category("views").add("res_partner_list_view", ResPartnerListView ) diff --git a/owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.xml b/owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.xml new file mode 100644 index 00000000000..8fb4b49a077 --- /dev/null +++ b/owl_tutorials/static/src/components/view_inheritance/res_partner_list_view.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/owl_tutorials/views/res_partner.xml b/owl_tutorials/views/res_partner.xml index add0b7355fe..d3956d92ca6 100644 --- a/owl_tutorials/views/res_partner.xml +++ b/owl_tutorials/views/res_partner.xml @@ -1,7 +1,7 @@ - - res.partner.list.view.inherit + + res.partner.list.view.inherit.owl.tutorials res.partner @@ -10,4 +10,14 @@ - \ No newline at end of file + + res.partner.kanban.view.inherit.owl.tutorials + res.partner + + + + res_partner_kanban_view + + + + diff --git a/owl_tutorials/views/views.xml b/owl_tutorials/views/views.xml index c4a4d7727e7..ec122f797bb 100644 --- a/owl_tutorials/views/views.xml +++ b/owl_tutorials/views/views.xml @@ -1,7 +1,7 @@ - - todo.list.tree + + todo.list.view.list todo.list @@ -13,7 +13,7 @@ - todo.list.form + todo.list.view.form todo.list