diff --git a/all_in_one_multi_followers/README.rst b/all_in_one_multi_followers/README.rst new file mode 100644 index 000000000..a2d1e0c03 --- /dev/null +++ b/all_in_one_multi_followers/README.rst @@ -0,0 +1,51 @@ +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +All in One Multi Followers +========================== +The module is used to add or remove the multi followers in the whole odoo model +by dynamic actions. If you want to set multiple followers in your model, +it is helpful to select multiple followers when clicking the action. +After adding or removing the followers, it will affect the model. +So in this way, you can add or remove multiple followers +from the whole odoo quickly. + +Configuration +============= +* No additional configurations needed + +Company +------- +* `Cybrosys Techno Solutions `__ + +License +------- +Affero General Public License v3.0 (AGPL v3) +(https://www.gnu.org/licenses/agpl-3.0-standalone.html) + +Credits +------- +* Developer : (V17) Ajith V , + (V16) Junaidul Ansar M , Contact: odoo@cybrosys.com + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com + +This module is maintained by Cybrosys Technologies. +For support and more information, please visit `Our Website `__ + +Further information +=================== +HTML Description: ``__ diff --git a/all_in_one_multi_followers/__init__.py b/all_in_one_multi_followers/__init__.py new file mode 100644 index 000000000..c3f1d71ed --- /dev/null +++ b/all_in_one_multi_followers/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Ajith V (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import models +from . import wizard diff --git a/all_in_one_multi_followers/__manifest__.py b/all_in_one_multi_followers/__manifest__.py new file mode 100644 index 000000000..1ee8cf658 --- /dev/null +++ b/all_in_one_multi_followers/__manifest__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Ajith V (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +{ + 'name': 'All in One Multi Followers', + 'version': '17.0.1.0.0', + 'category': 'Extra Tools', + 'summary': 'The module used to add or remove the multi followers in the ' + 'whole odoo models by dynamic actions.', + 'description': ' The module used to add or remove the multi followers in ' + 'the whole odoo models by dynamic actions.If you want to set' + ' a multi followers in your model this is helpful you to ' + 'select the multi followers when clicking the action. ' + 'After adding or removing the followers it will affect' + ' the model. So in this way you can add or remove multiple' + ' followers in the whole odoo quickly.', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': 'https://www.cybrosys.com', + 'depends': ['base'], + 'data': [ + 'security/ir.model.access.csv', + 'views/multi_follower_views.xml', + 'views/res_config_settings_views.xml', + 'wizard/follower_adding_removing_views.xml', + ], + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'application': False, + 'auto_install': False +} diff --git a/all_in_one_multi_followers/doc/RELEASE_NOTES.md b/all_in_one_multi_followers/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..57178bb05 --- /dev/null +++ b/all_in_one_multi_followers/doc/RELEASE_NOTES.md @@ -0,0 +1,7 @@ +## Module + +#### 15.05.2025 +#### Version 17.0.1.0.0 +#### ADD + +- Initial Commit All in One Multi Followers. diff --git a/all_in_one_multi_followers/models/__init__.py b/all_in_one_multi_followers/models/__init__.py new file mode 100644 index 000000000..5d3082d83 --- /dev/null +++ b/all_in_one_multi_followers/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Ajith V (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import multi_follower diff --git a/all_in_one_multi_followers/models/multi_follower.py b/all_in_one_multi_followers/models/multi_follower.py new file mode 100644 index 000000000..e85aa37c4 --- /dev/null +++ b/all_in_one_multi_followers/models/multi_follower.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Ajith V (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models + + +class MultiFollower(models.Model): + """Creating multi follower creation model""" + _name = 'multi.follower' + _description = 'Multi Follower' + _rec_name = 'action_name' + + action_name = fields.Char(string="Action Name", + help='This is the action name. So this name is ' + 'visible under the the appropriate' + ' model action.', + required=True) + applied_to_ids = fields.Many2many('ir.model', + string='Applied To', + help='Select the model in which you ' + 'want to apply this action.', + required=True) + enabled_value = fields.Boolean(string="Create Action", + help="Enabling and hiding the " + "create action button.", + default=True, + copy=False) + created_action_names = fields.Char(string="Created Action Names", + compute="_compute_created_action_names", + help='If the name is visible to the line' + ' its created the action. If its ' + 'not its deleted the action.') + states = fields.Selection([('draft', 'Draft'), + ('running', 'Running'), ('cancel', 'Cancelled')], + string='State', help='State of the action', + default="draft", copy=False) + window_action_ids = fields.Many2many('ir.actions.act_window', + string="Window Actions", + helps="Related Window Actions") + + @api.depends('action_name') + def _compute_created_action_names(self): + """ + Computes and updates the `created_action_names` field with the names + of the actions that have been created for the current follower. + + This method depends on the `action_name` field and is triggered when + the `action_name` is modified. It retrieves the window actions associated + with the current follower and stores their names as a comma-separated + string in the `created_action_names` field. + + Key Steps: + 1. For each follower record, it searches for window actions (`ir.actions.act_window`) + that match the action IDs in `follower.window_action_ids`. + 2. The names of the found actions are extracted using `mapped('name')` + and joined into a single string, separated by commas. + 3. The resulting string is stored in the `created_action_names` field + for display purposes. + + Returns: + None + """ + for follower in self: + actions = self.env['ir.actions.act_window'].search( + [('id', 'in', follower.window_action_ids.ids)]) + follower.created_action_names = ', '.join(actions.mapped('name')) + + def action_create(self): + """ + Creates a new action in the selected model when the 'Add Action' button + is clicked. + + This method performs the following tasks: + 1. Disables the `enabled_value` field and sets the `states` field to 'running'. + 2. Loops through the `applied_to_ids` (the models to which the action will + be applied) and creates a new window action (`ir.actions.act_window`) + for each model. + 3. The newly created window action is associated with the + 'follower.adding.removing' model and its corresponding form view. + 4. The created window action is linked to the current record by adding it + to the `window_action_ids` field. + 5. Once the actions are created, it reloads the client interface to reflect + the changes. + + Returns: + dict: A dictionary to trigger a client action that reloads the current view + to reflect the newly created actions. + + Key Fields: + - `enabled_value`: Set to `False` to indicate the action creation process is + ongoing. + - `states`: Updated to 'running' to show the action is in progress. + - `action_name`: The name used for the new actions. + - `applied_to_ids`: The models to which the new actions are applied. + - `window_action_ids`: Updated to include the newly created window actions. + + Returns: + A reload action to refresh the view. + """ + self.enabled_value = False + self.states = 'running' + # Check if action_name has changed and update existing actions + for model_id in self.applied_to_ids: + res = self.env['ir.actions.act_window'].create({ + 'name': self.action_name, + 'res_model': 'follower.adding.removing', + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'binding_model_id': model_id.id, + 'target': 'new', + 'view_id': self.env.ref( + 'all_in_one_multi_followers.' + 'follower_adding_removing_view_form').id, + 'binding_view_types': 'list' + }) + self.window_action_ids += res + return { + 'type': 'ir.actions.client', + 'tag': 'reload', + } + + def action_unlink(self): + """ + Removes the contextual actions created for server actions. + + This method performs the following tasks: + 1. Sets the `states` field to 'cancel', indicating that the action removal + process is in progress or has been completed. + 2. Deletes all window actions associated with the current record by unlinking + them through the `window_action_ids` field. + 3. Clears the `window_action_ids` field by setting it to `False`. + 4. Resets the `enabled_value` field to `True`, enabling the functionality for + future use. + 5. Returns an action to reload the client interface to reflect the removal of + the actions. + + Returns: + dict: A dictionary to trigger a client action that reloads the current view + to reflect the removal of the actions. + + Key Fields: + - `states`: Updated to 'cancel' to indicate that the action removal is + completed or in progress. + - `window_action_ids`: Unlinked (deleted) to remove the associated actions. + - `enabled_value`: Set to `True` to re-enable the functionality for adding + actions in the future. + + Returns: + A reload action to refresh the view. + """ + self.states = 'cancel' + self.window_action_ids.unlink() + self.window_action_ids = False + self.enabled_value = True + return { + 'type': 'ir.actions.client', + 'tag': 'reload', + } + + def unlink(self): + """ + Overrides the unlink method to remove associated active actions before + deleting the record. + + This method performs the following tasks: + 1. Iterates over each record in the current recordset (`self`). + 2. For each record, it calls the `action_unlink` method to remove any + active actions associated with that record. + 3. After removing the active actions, it proceeds to call the original + `unlink` method from the parent class to delete the record itself. + + Key Steps: + - Ensures that all associated active actions are properly cleaned up + before the record is deleted. + - Maintains the integrity of related actions by explicitly handling their + removal. + + Returns: + None + + Note: + - This method should be used when you want to ensure that any associated + actions are removed before the record is deleted from the database. + """ + for rec in self: + rec.action_unlink() + super().unlink() diff --git a/all_in_one_multi_followers/security/ir.model.access.csv b/all_in_one_multi_followers/security/ir.model.access.csv new file mode 100644 index 000000000..c9a535714 --- /dev/null +++ b/all_in_one_multi_followers/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink +access_multi_follower_user,access.multi.follower.user,model_multi_follower,base.group_user,1,1,1,1 +access_follower_adding_removing_user,access.follower.adding.removing.user,model_follower_adding_removing,base.group_user,1,1,1,1 diff --git a/all_in_one_multi_followers/static/description/assets/icons/capture (1).png b/all_in_one_multi_followers/static/description/assets/icons/capture (1).png new file mode 100755 index 000000000..8824deafc Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/capture (1).png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/check.png b/all_in_one_multi_followers/static/description/assets/icons/check.png new file mode 100755 index 000000000..c8e85f51d Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/check.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/chevron.png b/all_in_one_multi_followers/static/description/assets/icons/chevron.png new file mode 100755 index 000000000..2089293d6 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/chevron.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/cogs.png b/all_in_one_multi_followers/static/description/assets/icons/cogs.png new file mode 100755 index 000000000..95d0bad62 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/cogs.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/consultation.png b/all_in_one_multi_followers/static/description/assets/icons/consultation.png new file mode 100755 index 000000000..8319d4baa Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/consultation.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/ecom-black.png b/all_in_one_multi_followers/static/description/assets/icons/ecom-black.png new file mode 100755 index 000000000..a9385ff13 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/ecom-black.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/education-black.png b/all_in_one_multi_followers/static/description/assets/icons/education-black.png new file mode 100755 index 000000000..3eb09b27b Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/education-black.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/hotel-black.png b/all_in_one_multi_followers/static/description/assets/icons/hotel-black.png new file mode 100755 index 000000000..130f613be Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/hotel-black.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/img.png b/all_in_one_multi_followers/static/description/assets/icons/img.png new file mode 100755 index 000000000..70197f477 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/img.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/license.png b/all_in_one_multi_followers/static/description/assets/icons/license.png new file mode 100755 index 000000000..a5869797e Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/license.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/lifebuoy.png b/all_in_one_multi_followers/static/description/assets/icons/lifebuoy.png new file mode 100755 index 000000000..658d56ccc Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/lifebuoy.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/manufacturing-black.png b/all_in_one_multi_followers/static/description/assets/icons/manufacturing-black.png new file mode 100755 index 000000000..697eb0e9f Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/manufacturing-black.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/photo-capture.png b/all_in_one_multi_followers/static/description/assets/icons/photo-capture.png new file mode 100755 index 000000000..06c111758 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/photo-capture.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/pos-black.png b/all_in_one_multi_followers/static/description/assets/icons/pos-black.png new file mode 100755 index 000000000..97c0f90c1 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/pos-black.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/puzzle.png b/all_in_one_multi_followers/static/description/assets/icons/puzzle.png new file mode 100755 index 000000000..65cf854e7 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/puzzle.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/restaurant-black.png b/all_in_one_multi_followers/static/description/assets/icons/restaurant-black.png new file mode 100755 index 000000000..4a35eb939 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/restaurant-black.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/service-black.png b/all_in_one_multi_followers/static/description/assets/icons/service-black.png new file mode 100755 index 000000000..301ab51cb Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/service-black.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/trading-black.png b/all_in_one_multi_followers/static/description/assets/icons/trading-black.png new file mode 100755 index 000000000..9398ba2f1 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/trading-black.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/training.png b/all_in_one_multi_followers/static/description/assets/icons/training.png new file mode 100755 index 000000000..884ca024d Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/training.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/update.png b/all_in_one_multi_followers/static/description/assets/icons/update.png new file mode 100755 index 000000000..ecbc5a01a Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/update.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/user.png b/all_in_one_multi_followers/static/description/assets/icons/user.png new file mode 100755 index 000000000..6ffb23d9f Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/user.png differ diff --git a/all_in_one_multi_followers/static/description/assets/icons/wrench.png b/all_in_one_multi_followers/static/description/assets/icons/wrench.png new file mode 100755 index 000000000..6c04dea0f Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/icons/wrench.png differ diff --git a/all_in_one_multi_followers/static/description/assets/misc/Cybrosys R.png b/all_in_one_multi_followers/static/description/assets/misc/Cybrosys R.png new file mode 100755 index 000000000..da4058087 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/misc/Cybrosys R.png differ diff --git a/all_in_one_multi_followers/static/description/assets/misc/email.svg b/all_in_one_multi_followers/static/description/assets/misc/email.svg new file mode 100755 index 000000000..15291cdc3 --- /dev/null +++ b/all_in_one_multi_followers/static/description/assets/misc/email.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/all_in_one_multi_followers/static/description/assets/misc/phone.svg b/all_in_one_multi_followers/static/description/assets/misc/phone.svg new file mode 100755 index 000000000..b7bd7f251 --- /dev/null +++ b/all_in_one_multi_followers/static/description/assets/misc/phone.svg @@ -0,0 +1,3 @@ + + + diff --git a/all_in_one_multi_followers/static/description/assets/misc/star (1) 2.svg b/all_in_one_multi_followers/static/description/assets/misc/star (1) 2.svg new file mode 100755 index 000000000..5ae9f507a --- /dev/null +++ b/all_in_one_multi_followers/static/description/assets/misc/star (1) 2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/all_in_one_multi_followers/static/description/assets/misc/support (1) 1.svg b/all_in_one_multi_followers/static/description/assets/misc/support (1) 1.svg new file mode 100755 index 000000000..7d37a8f30 --- /dev/null +++ b/all_in_one_multi_followers/static/description/assets/misc/support (1) 1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/all_in_one_multi_followers/static/description/assets/misc/support-email.svg b/all_in_one_multi_followers/static/description/assets/misc/support-email.svg new file mode 100755 index 000000000..eb70370d6 --- /dev/null +++ b/all_in_one_multi_followers/static/description/assets/misc/support-email.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/all_in_one_multi_followers/static/description/assets/misc/tick-mark.svg b/all_in_one_multi_followers/static/description/assets/misc/tick-mark.svg new file mode 100755 index 000000000..2dbb40187 --- /dev/null +++ b/all_in_one_multi_followers/static/description/assets/misc/tick-mark.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/all_in_one_multi_followers/static/description/assets/misc/whatsapp 1.svg b/all_in_one_multi_followers/static/description/assets/misc/whatsapp 1.svg new file mode 100755 index 000000000..0bfaf8fc6 --- /dev/null +++ b/all_in_one_multi_followers/static/description/assets/misc/whatsapp 1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/all_in_one_multi_followers/static/description/assets/misc/whatsapp.svg b/all_in_one_multi_followers/static/description/assets/misc/whatsapp.svg new file mode 100755 index 000000000..b618aea1d --- /dev/null +++ b/all_in_one_multi_followers/static/description/assets/misc/whatsapp.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/all_in_one_multi_followers/static/description/assets/modules/l1.png b/all_in_one_multi_followers/static/description/assets/modules/l1.png new file mode 100755 index 000000000..ca9e86ba7 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/modules/l1.png differ diff --git a/all_in_one_multi_followers/static/description/assets/modules/l2.png b/all_in_one_multi_followers/static/description/assets/modules/l2.png new file mode 100755 index 000000000..4774e32ee Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/modules/l2.png differ diff --git a/all_in_one_multi_followers/static/description/assets/modules/l3.png b/all_in_one_multi_followers/static/description/assets/modules/l3.png new file mode 100755 index 000000000..b17a2667d Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/modules/l3.png differ diff --git a/all_in_one_multi_followers/static/description/assets/modules/l4.png b/all_in_one_multi_followers/static/description/assets/modules/l4.png new file mode 100755 index 000000000..968bd03c9 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/modules/l4.png differ diff --git a/all_in_one_multi_followers/static/description/assets/modules/l5.png b/all_in_one_multi_followers/static/description/assets/modules/l5.png new file mode 100755 index 000000000..f68b76095 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/modules/l5.png differ diff --git a/all_in_one_multi_followers/static/description/assets/modules/l6.png b/all_in_one_multi_followers/static/description/assets/modules/l6.png new file mode 100755 index 000000000..eb16e49d0 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/modules/l6.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/1.png b/all_in_one_multi_followers/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..9f76247bb Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/1.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/10.png b/all_in_one_multi_followers/static/description/assets/screenshots/10.png new file mode 100644 index 000000000..6c8f5b30c Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/10.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/11.png b/all_in_one_multi_followers/static/description/assets/screenshots/11.png new file mode 100644 index 000000000..9ebaa2f02 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/11.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/12.png b/all_in_one_multi_followers/static/description/assets/screenshots/12.png new file mode 100644 index 000000000..0d4d573db Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/12.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/13.png b/all_in_one_multi_followers/static/description/assets/screenshots/13.png new file mode 100644 index 000000000..4e29313bc Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/13.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/2.png b/all_in_one_multi_followers/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..8798a8ee5 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/2.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/3.png b/all_in_one_multi_followers/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..aa56ecb42 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/3.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/4.png b/all_in_one_multi_followers/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..35eec9181 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/4.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/5.png b/all_in_one_multi_followers/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..1088f4c91 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/5.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/6.png b/all_in_one_multi_followers/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..f1e42aa03 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/6.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/7.png b/all_in_one_multi_followers/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..db0c4b91f Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/7.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/8.png b/all_in_one_multi_followers/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..a85191a26 Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/8.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/9.png b/all_in_one_multi_followers/static/description/assets/screenshots/9.png new file mode 100644 index 000000000..94725caac Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/9.png differ diff --git a/all_in_one_multi_followers/static/description/assets/screenshots/Gif.gif b/all_in_one_multi_followers/static/description/assets/screenshots/Gif.gif new file mode 100644 index 000000000..e0ce609ec Binary files /dev/null and b/all_in_one_multi_followers/static/description/assets/screenshots/Gif.gif differ diff --git a/all_in_one_multi_followers/static/description/banner.jpg b/all_in_one_multi_followers/static/description/banner.jpg new file mode 100644 index 000000000..a3d364bd9 Binary files /dev/null and b/all_in_one_multi_followers/static/description/banner.jpg differ diff --git a/all_in_one_multi_followers/static/description/icon.png b/all_in_one_multi_followers/static/description/icon.png new file mode 100644 index 000000000..a907369d5 Binary files /dev/null and b/all_in_one_multi_followers/static/description/icon.png differ diff --git a/all_in_one_multi_followers/static/description/index.html b/all_in_one_multi_followers/static/description/index.html new file mode 100755 index 000000000..0e0c00a21 --- /dev/null +++ b/all_in_one_multi_followers/static/description/index.html @@ -0,0 +1,851 @@ + + + + + + + Odoo App 3 Index + + + + + + + + +
+
+
+
+
+ +
+
+
+ Community +
+
+ Enterprise +
+
+ Odoo.sh +
+
+
+
+
+
+

+ All in One Multi Followers

+

+ Setting Multi-Followers in the Whole Odoo Model by Using + Dynamic Actions +

+
+ +
+
+
+
+
+

+ Key Highlights +

+
+
+
+
+
+ +
+
+

+ Community & Enterprise Support.

+
+
+
+
+
+
+ +
+
+

+ You can Add/Remove Multiple Followers using + Dynamic Action.

+
+
+
+
+
+
+ +
+
+

+ You can Add/Remove Multiple Followers in any + odoo model.

+
+
+
+
+
+
+ +
+
+

+ You can apply Dynamic Action in the particular + models.

+
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+

+ Configure the Dynamic Action +

+

Navigate to Settings → General Settings → Dynamic Followers to create a Dynamic + Action +

+
+
+
+ +
+
+
+ +
+
+

+ Action Creation +

+

Enter an Action Name and select the model in + which you want to apply. After that, click + 'CREATE ACTION' to add this Action to the + model. +

+
+
+
+
+
+
+ +
+
+

+ After Creation. +

+

The action is applied to the selected model. To add or remove multiple followers, + select the desired records, go to the “Action” menu, and click on the corresponding + action +

+
+
+
+
+
+
+ +
+
+

+ Action +

+

Action applied in the selected model. Select + the order line in which you want to + Add/Remove Multiple Followers, then go to + Action and click on that Action. +

+
+
+
+
+
+
+ +
+
+

+ Wizard to Add or Remove the Followers. +

+

A wizard will open where you can select the action type and choose the partner(s) or + follower(s) you want to add or remove. Then, click the 'Submit' button. +

+
+
+
+
+
+
+ +
+
+

+ Before Adding Followers. +

+
+
+
+
+
+
+ +
+
+

+ Followers are Added. +

+
+
+
+
+
+
+ +
+
+

+ Followers Removing Popup. +

+
+
+
+
+
+
+ +
+
+

+ Before Removing Followers. +

+
+
+
+
+
+
+ +
+
+

+ Followers are Removed. +

+
+
+
+
+
+
+ +
+
+

+ Remove Action. +

+
+
+
+
+
+
+ +
+
+

+ After Removing. +

+

+ After clicking the button, the state changed + to the 'Cancelled' state and the 'Create + Action' button appeared. +

+
+
+
+
+
+
+
    +
  • + Sale Order + History +
  • +
  • + Directly add + products into Sale order line from History +
  • +
+
+
+
+
+
+
Version + 17.0.1.0.0|Released on:15th May 2025 +
+

+ Initial Commit forAll in One Multi Followers

+
+
+
+
+
+
+
+

+ Related Products

+
+
+ +
+
+

+ Our Services

+
+
+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Customization

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Implementation

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Support

+
+
+
+
+
+
+ service-icon +
+
+

Hire + Odoo Developer

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Integration

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Migration

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Consultancy

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Implementation

+
+
+
+
+
+
+ service-icon +
+
+

Odoo + Licensing Consultancy

+
+
+
+
+
+
+

+ Our Industries

+
+
+
+
+
+
+ +

Trading

+

Easily procure and sell your products

+
+
+
+
+ +

POS

+

Easy configuration and convivial experience

+
+
+
+
+ +

+ Education

+

A platform for educational management

+
+
+
+
+ +

+ Manufacturing

+

Plan, track and schedule your operations

+
+
+
+
+ +

E-commerce & + Website

+

Mobile friendly, awe-inspiring product pages

+
+
+
+
+ +

Service + Management

+

Keep track of services and invoice

+
+
+
+
+ +

+ Restaurant

+

Run your bar or restaurant methodically

+
+
+
+
+ +

Hotel + Management

+

An all-inclusive hotel management application

+
+
+
+
+
+
+

+ Support

+
+
+
+
+
+
+
+ +
+ Need + Help? +

Got + questions or need help? Get in touch.

+
odoo@cybrosys.com +
+
+
+
+
+
+
+
+ +
+ WhatsApp +

Say hi to + us on WhatsApp!

+
+91 + 99456767686 +
+
+
+
+
+
+
+
+
+ + + + + + diff --git a/all_in_one_multi_followers/views/multi_follower_views.xml b/all_in_one_multi_followers/views/multi_follower_views.xml new file mode 100644 index 000000000..6ebe21da5 --- /dev/null +++ b/all_in_one_multi_followers/views/multi_follower_views.xml @@ -0,0 +1,65 @@ + + + + + Multi Follower + ir.actions.act_window + multi.follower + tree,form + +

+ Click to add the followers dynamic action +

+
+
+ + + multi.follower.view.form + multi.follower + +
+
+ +
+ + + + + + + +
+
+
+
\ No newline at end of file diff --git a/all_in_one_multi_followers/views/res_config_settings_views.xml b/all_in_one_multi_followers/views/res_config_settings_views.xml new file mode 100644 index 000000000..750efaa4e --- /dev/null +++ b/all_in_one_multi_followers/views/res_config_settings_views.xml @@ -0,0 +1,83 @@ + + + + + + res.config.settings.view.form.inherit.all.in.one.multi.followers + + res.config.settings + + + + +
+

Dynamic Followers

+ +
+ Create a Dynamic + Action + +
+
+
+
+
+
+
+
+
+ + + Settings + res.config.settings + form + inline + {'module' : 'all_in_one_multi_followers', + 'bin_size': False} + + +
diff --git a/all_in_one_multi_followers/wizard/__init__.py b/all_in_one_multi_followers/wizard/__init__.py new file mode 100644 index 000000000..6943c2152 --- /dev/null +++ b/all_in_one_multi_followers/wizard/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Ajith V (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import follower_adding_removing diff --git a/all_in_one_multi_followers/wizard/follower_adding_removing.py b/all_in_one_multi_followers/wizard/follower_adding_removing.py new file mode 100644 index 000000000..e70faf00d --- /dev/null +++ b/all_in_one_multi_followers/wizard/follower_adding_removing.py @@ -0,0 +1,199 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2025-TODAY Cybrosys Technologies() +# Author: Ajith V (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################### +from lxml import etree +from lxml.html import builder as html +from odoo import api, fields, models, _ + + +class FollowerAddingRemoving(models.TransientModel): + """Creating a popup wizard to adding or removing the followers in to + the model""" + _name = 'follower.adding.removing' + _description = 'Follower Adding Removing' + + res_id = fields.Integer('Related Document ID', + help='Id of the followed resource') + type = fields.Selection( + [('add', 'Add Followers'), ('remove', 'Remove Followers')], + string="Action Type", help='Select the action type', + default='add') + partner_ids = fields.Many2many('res.partner', string='Partners', + help='Select the partners to add or' + ' remove to the followers') + send_mail = fields.Boolean(string='Send Email', default=True, + help="If checked, the partners will receive an " + "email warning they have been added in " + "the document's followers.") + message = fields.Html(string='Message', help='Invite/ Remove mailing ' + 'message.') + + def action_submit(self): + """ + Adds or removes followers from records based on user input when the + submit button is clicked. + + - Retrieves the model information for the current active model (the one + from which the action is triggered). + - Based on the action type (`add` or `remove`), it either subscribes or + unsubscribes the selected followers (partners) to/from the records. + - If the `send_mail` flag is enabled and a message is provided, an email + notification is sent to the new followers. + + Key Steps: + 1. Retrieve the active model and its records using the context's + `active_model` and `active_ids`. + 2. If the action type is 'add', the selected partners (followers) are + subscribed to the record via `message_subscribe`. + 3. If the action type is 'remove', the selected partners are unsubscribed + via `message_unsubscribe`. + 4. If email notifications are enabled (`send_mail` is True) and a message + is provided, an email is composed and sent to the new followers. + + Returns: + None + """ + model_info = self.env['ir.model'].search( + [('model', '=', self.env.context.get('active_model'))], + limit=1) + email_from = self.env.user.email_formatted + title = [active_model.display_name for active_model in + self.env[self.env.context.get('active_model')].browse( + self.env.context.get('active_ids'))] + for record_id in self.env.context.get('active_ids'): + record = self.env[self.env.context.get('active_model')].browse( + record_id) + if self.type == 'add': + record.message_subscribe(partner_ids=self.partner_ids.ids) + elif self.type == 'remove': + record.message_unsubscribe(partner_ids=self.partner_ids.ids) + new_partners = self.partner_ids + model_name = model_info.display_name + if self.send_mail and self.message and not self.message == '
': + self.env['mail.mail'].create( + self._prepare_message_values(title, model_name, email_from, + new_partners) + ).send() + + @api.onchange('type') + def _onchange_type(self): + """ + Updates the 'message' field based on the selected type (add or remove) when + the 'type' field is changed. + + This method is triggered automatically when the 'type' field is updated + by the user. It generates a message to reflect whether the user is adding + or removing followers from a document, and then updates the 'message' + field of the current record with this information. + + Key Steps: + 1. Retrieves the name of the current user (`user_name`) and the active + document's model (`active_model`) from the context. + 2. Fetches the display name of the document (record) and creates a message + informing the user whether they are being invited to follow or are being + removed from following the document. + 3. The message is formatted as HTML using the `html.DIV` and `html.P` elements, + and is then serialized to a string and stored in the 'message' field. + + Example: + - If the 'type' is 'add': + "John Doe has invited you to follow the Sales Order document: SO001". + - If the 'type' is 'remove': + "John Doe has removed you from following the Sales Order document: SO001". + + Returns: + None + """ + user_name = self.env.user.display_name + model = self.env.context.get('active_model') + document = self.env['ir.model']._get(model).display_name + title = [active_model.display_name for active_model in + self.env[model].browse(self.env.context.get('active_ids'))] + if self.type == 'add': + msg_fmt = _( + f'{user_name} has invited you to follow the {document} ' + f'document: {title}') + else: + msg_fmt = _( + f'{user_name} has removed you from following the {document} ' + f'document: {title}') + text = msg_fmt % locals() + message = html.DIV( + html.P(_('Hello,')), + html.P(text) + ) + self.message = etree.tostring(message) + + def _prepare_message_values(self, title, model_name, email_from, + new_partners): + """ + Prepares the necessary email values for sending a notification about + following or unfollowing a document. + + This method is responsible for generating the content of the email that + will be sent when followers are added or removed from a document. The email + contains details such as the document's model and title, the sender's email + address, and the recipients' email addresses. + + Parameters: + - title (str): The display name or title of the document being followed + or unfollowed. + - model_name (str): The display name of the model (e.g., "Sales Order", + "Purchase Order"). + - email_from (str): The formatted email address of the current user (the sender). + - new_partners (recordset): A recordset of partners (followers) to whom + the email will be sent. + + Returns: + dict: A dictionary of email values containing the following keys: + - `subject`: The subject line of the email, including the document model + and title. + - `body_html`: The HTML content of the email, using the message field + defined in the current record. + - `record_name`: The name of the document being followed/unfollowed. + - `email_from`: The sender's email address. + - `email_to`: A comma-separated list of email addresses of the new partners. + - `reply_to`: The sender's email address for reply purposes. + - `reply_to_force_new`: A flag to force new email threads for replies. + - `email_add_signature`: A flag to include the user's email signature in + the message. + + This method is designed to format and structure the email data so that it + can be sent out to notify partners of changes in document followers. + """ + email_values = { + 'subject': _( + 'The Document follow %(document_model)s: %(document_name)s', + document_model=model_name, + document_name=title), + 'body_html': self.message, + 'record_name': title, + 'email_from': email_from, + 'email_to': ','.join(new_partners.mapped('email')), + 'reply_to': email_from, + 'reply_to_force_new': True, + 'email_add_signature': True, + } + return email_values + + + + diff --git a/all_in_one_multi_followers/wizard/follower_adding_removing_views.xml b/all_in_one_multi_followers/wizard/follower_adding_removing_views.xml new file mode 100644 index 000000000..66106a379 --- /dev/null +++ b/all_in_one_multi_followers/wizard/follower_adding_removing_views.xml @@ -0,0 +1,44 @@ + + + + + follower.adding.removing.view.form + follower.adding.removing + +
+ + + + + + + +
+
+
+