diff --git a/commission_plan/README.rst b/commission_plan/README.rst new file mode 100755 index 000000000..b738145b3 --- /dev/null +++ b/commission_plan/README.rst @@ -0,0 +1,46 @@ +.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg + :target: https://www.gnu.org/licenses/lgpl-3.0.en.html + :alt: License: LGPL-3 + +Odoo CRM Commission Plan +======================== + * Additionally, Odoo CRM may include a Commission Plan feature that helps organizations set up and manage commission structures for their sales teams based on predefined rules and criteria. + +Configuration +------------- +- www.odoo.com/documentation/16.0/setup/install.html +- Install our custom addon + +License +------- +Lesser General Public License, Version 3 (LGPL v3). +(https://www.gnu.org/licenses/lgpl-3.0.en.html) + +Company +------- +* `Cybrosys Techno Solutions `__ + +Credits +------- +Developer : (V16) Abhin K, Contact: odoo@cybrosys.com + +Contacts +-------- +* Mail Contact : odoo@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/commission_plan/__init__.py b/commission_plan/__init__.py new file mode 100644 index 000000000..9bd6eafc1 --- /dev/null +++ b/commission_plan/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import controllers +from . import models +from . import wizard diff --git a/commission_plan/__manifest__.py b/commission_plan/__manifest__.py new file mode 100644 index 000000000..e9c568453 --- /dev/null +++ b/commission_plan/__manifest__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +{ + "name": "Odoo CRM Commission Plan", + "version": '16.0.1.0.0', + "category": 'Sales', + 'summary': """CRM Commission Plan for odoo16""", + 'description': """Odoo 16's CRM module features professional commission + plans that drive sales performance effectively.""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + "depends": ['base', 'sale_management', 'crm'], + "data": [ + 'security/ir.model.access.csv', + 'views/crm_commission_views.xml', + 'views/crm_team_views.xml', + 'views/res_users_views.xml', + 'wizard/commission_wizard_views.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'commission_plan/static/src/js/action_manager.js', + ], + }, + 'images': ['static/description/banner.png'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/commission_plan/controllers/__init__.py b/commission_plan/controllers/__init__.py new file mode 100644 index 000000000..479b42798 --- /dev/null +++ b/commission_plan/controllers/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import commission_plan diff --git a/commission_plan/controllers/commission_plan.py b/commission_plan/controllers/commission_plan.py new file mode 100644 index 000000000..90edee647 --- /dev/null +++ b/commission_plan/controllers/commission_plan.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +import json +from odoo import http +from odoo.http import content_disposition, request +from odoo.tools import html_escape + + +class XLSXReportController(http.Controller): + """Xlsx report function is defined here""" + + @http.route('/xlsx_reports', type='http', auth='user', methods=['POST'], csrf=False) + def get_report_xlsx(self, model, options, output_format, report_name, **kw): + """Function is called to print xlsx report""" + uid = request.session.uid + report_obj = request.env[model].with_user(uid) + options = json.loads(options) + token = 'dummy-because-api-expects-one' + try: + if output_format == 'xlsx': + response = request.make_response( + None, + headers=[ + ('Content-Type', 'application/vnd.ms-excel'), + ('Content-Disposition', content_disposition(report_name + '.xlsx')) + ] + ) + report_obj.get_xlsx_report(options, response) + response.set_cookie('fileToken', token) + return response + except Exception as error: + serialize_exception = http.serialize_exception(error) + error = { + 'code': 200, + 'message': 'Odoo Server Error', + 'data': serialize_exception + } + return request.make_response(html_escape(json.dumps(error))) diff --git a/commission_plan/doc/RELEASE_NOTES.md b/commission_plan/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..6df465489 --- /dev/null +++ b/commission_plan/doc/RELEASE_NOTES.md @@ -0,0 +1,6 @@ +## Module + +#### 07.11.2023 +#### Version 16.0.1.0.0 +#### ADD +- Initial commit for Odoo CRM Commission Plan diff --git a/commission_plan/models/__init__.py b/commission_plan/models/__init__.py new file mode 100644 index 000000000..65c5fe512 --- /dev/null +++ b/commission_plan/models/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import commission_graduated +from . import commission_product +from . import crm_commission +from . import crm_team +from . import res_users diff --git a/commission_plan/models/commission_graduated.py b/commission_plan/models/commission_graduated.py new file mode 100644 index 000000000..cd2677946 --- /dev/null +++ b/commission_plan/models/commission_graduated.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from odoo import api, exceptions, fields, models, _ + + +class CommissionGraduated(models.Model): + """commission.graduated model is defined here""" + _name = 'commission.graduated' + _description = 'Commission Revenue Graduated Wise' + + currency_id = fields.Many2one("res.currency", string="Currency", + default=lambda self: + self.env.user.company_id.currency_id.id, + help='Currency of the company') + graduated_amount_type = fields.Selection( + [('percentage', 'Percentage'), ('fixed', 'Fixed Amount')], + string="Amount Type", default='percentage', + help='Graduated Amount Type') + graduated_fixed_amount = fields.Monetary('Commission Amount', default=0.0, + help='Graduated Fixed Amount') + graduated_commission_rate = fields.Float(string='Commission rate (%)', + help='Graduated Commission Rate') + amount_from = fields.Float(string="From Amount", help='The Minimum Amount') + amount_to = fields.Float(string="To Amount", help='The Maximum Amount') + commission_id = fields.Many2one("crm.commission", string='Commission', + help='Crm Commission') + sequence = fields.Integer(string='Sequence', compute='_compute_sequence', + store=True, help='Sequence Generator') + + @api.depends('commission_id') + def _compute_sequence(self): + """sequence is computed in the one2many table""" + number = 1 + seq = self.mapped('commission_id') + for rule in seq.revenue_grd_comm_ids: + rule.sequence = number + number += 1 + + @api.constrains("amount_from", "amount_to") + def _check_amounts(self): + """Amount constraints to check the + amount to is greater than amount from""" + for rec in self: + if rec.amount_to < rec.amount_from: + raise exceptions.ValidationError( + _("The From Amount limit cannot " + "be greater than To Amount.")) diff --git a/commission_plan/models/commission_product.py b/commission_plan/models/commission_product.py new file mode 100644 index 000000000..03039f445 --- /dev/null +++ b/commission_plan/models/commission_product.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from odoo import api, fields, models + + +class CommissionProduct(models.Model): + """commission.product model is defined here""" + _name = 'commission.product' + _description = 'Commission Product Wise' + + user_id = fields.Many2one('res.users', string='User', + help='Select the User') + category_id = fields.Many2one('product.category', + string='Product Category', + help='Select the Product Category') + category_ids = fields.Many2many('product.category', + string='Product Category Reference', + help="To set the domain for the " + "category_id", + compute="_onchange_category_id") + product_id = fields.Many2one('product.product', string='Product', + help='Select the product') + commission_amount_type = fields.Selection([('percentage', 'Percentage'), + ('fixed', 'Fixed Amount')], + string="Amount Type", + default='percentage', + help='Commission amount type') + fixed_amount = fields.Monetary('Commission Amount', default=0.0, + help='Fixed Commission Amount') + percentage = fields.Float(string='Rate in Percentage (%)', + help='Rate in percentage') + amount = fields.Monetary('Maximum Commission Amount', default=0.0, + help='Maximum Commission Amount') + currency_id = fields.Many2one("res.currency", string="Currency", + default=lambda self: + self.env.user.company_id.currency_id.id, + help='Currency of the company') + commission_id = fields.Many2one("crm.commission", string='Commission', + help='Select The Crm Commission') + + @api.depends('category_id') + def _onchange_category_id(self): + """Function Sets the domain for selected category and removes + the product if the product is not in the selected category""" + for rec in self: + rec.category_ids = rec.category_id.search( + [('id', 'child_of', rec.category_id.ids)]).ids + rec.product_id = None if rec.product_id.id not in self.env[ + 'product.product'].search( + [('categ_id', 'in', + rec.category_ids.ids)]).ids else rec.product_id.id diff --git a/commission_plan/models/crm_commission.py b/commission_plan/models/crm_commission.py new file mode 100644 index 000000000..8e17e2c83 --- /dev/null +++ b/commission_plan/models/crm_commission.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from odoo import api, Command, exceptions, fields, models, _ + + +class CommissionPlan(models.Model): + """crm.commission plan model is defined here""" + _name = 'crm.commission' + _description = 'Commission Plan' + _inherit = ['mail.thread', 'mail.activity.mixin'] + + name = fields.Char('Name', required=True, help='Name of the Commission') + active = fields.Boolean('Active', default=True, help='Active or not') + date_from = fields.Date(string="From Date", required=True, + help='Start date of the commission plan') + date_to = fields.Date(string="To Date", required=True, + help='End date of the commission plan') + type = fields.Selection( + [('product', 'Product wise'), + ('revenue', 'Revenue wise')], string="Type", + default="product", help='Type of the Plan') + team_id = fields.Many2one('crm.team', string='Sales Team', + help='Select the Sales team') + user_id = fields.Many2one('res.users', string='Salesperson', + help='Select the Sales Person') + product_comm_ids = fields.One2many('commission.product', 'commission_id', + string="Product Wise", + help='Relational field of commission' + ' product') + currency_id = fields.Many2one("res.currency", string="Currency", + default=lambda self: + self.env.user.company_id.currency_id.id, + help='Currency of the company') + straight_commission_type = fields.Selection([('percentage', 'Percentage'), + ('fixed', 'Fixed Amount')], + string="Amount Type", + default='percentage', + help='Straight commission Type') + straight_commission_fixed = fields.Monetary('Commission Amount', + default=0.0, + help='Straight commission' + ' fixed amount') + straight_commission_rate = fields.Float(string='Commission rate (%)', + help='Straight Commission Rate') + revenue_grd_comm_ids = fields.One2many( + 'commission.graduated', + 'commission_id', + string="Revenue Graduated Wise", + help='Relational Commission Graduated') + + revenue_type = fields.Selection( + [('straight', 'Straight Commission'), + ('graduated', 'Graduated Commission')], + string="Revenue Type", + help='Select the Revenue Type') + + @api.constrains("date_from", "date_to") + def _check_date(self): + """Date constraints""" + for rec in self: + if rec.date_to < rec.date_from: + raise exceptions.ValidationError( + _("The From date cannot be earlier than To date.")) + + @api.onchange('type') + def _onchange_type(self): + """onchange type the corresponding table + is shown and the other table set to hide""" + if self.type == 'revenue': + self.product_comm_ids = [Command.clear()] + elif self.type == 'product': + self.revenue_type = False + self.straight_commission_rate = False + self.revenue_grd_comm_ids = [Command.clear()] diff --git a/commission_plan/models/crm_team.py b/commission_plan/models/crm_team.py new file mode 100644 index 000000000..997f4c5d0 --- /dev/null +++ b/commission_plan/models/crm_team.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from odoo import fields, models + + +class CrmTeam(models.Model): + """model crm.team is inherited to add commission plan""" + _inherit = 'crm.team' + + commission_id = fields.Many2one('crm.commission', string='Commission Plan', + help='Select the Commission Plan') diff --git a/commission_plan/models/res_users.py b/commission_plan/models/res_users.py new file mode 100644 index 000000000..a8103d4d5 --- /dev/null +++ b/commission_plan/models/res_users.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from odoo import fields, models + + +class ResUsers(models.Model): + """res.users is inherited to add commission plan""" + _inherit = 'res.users' + + commission_id = fields.Many2one('crm.commission', string='Commission Plan', + help='Select the Commission Plan') diff --git a/commission_plan/security/ir.model.access.csv b/commission_plan/security/ir.model.access.csv new file mode 100644 index 000000000..9af8081b3 --- /dev/null +++ b/commission_plan/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_commission_plan,access.crm.commission,model_crm_commission,base.group_user,1,1,1,1 +access_commission_product,access.commission.product,model_commission_product,base.group_user,1,1,1,1 +access_commission_wizard,access.commission.wizard,model_commission_wizard,base.group_user,1,1,1,1 +access_commission_graduated,access.commission.graduated,model_commission_graduated,base.group_user,1,1,1,1 diff --git a/commission_plan/static/description/assets/icons/check.png b/commission_plan/static/description/assets/icons/check.png new file mode 100644 index 000000000..ea0da5029 Binary files /dev/null and b/commission_plan/static/description/assets/icons/check.png differ diff --git a/commission_plan/static/description/assets/icons/chevron.png b/commission_plan/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..f49dd8541 Binary files /dev/null and b/commission_plan/static/description/assets/icons/chevron.png differ diff --git a/commission_plan/static/description/assets/icons/cogs.png b/commission_plan/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/commission_plan/static/description/assets/icons/cogs.png differ diff --git a/commission_plan/static/description/assets/icons/consultation.png b/commission_plan/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/commission_plan/static/description/assets/icons/consultation.png differ diff --git a/commission_plan/static/description/assets/icons/ecom-black.png b/commission_plan/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/commission_plan/static/description/assets/icons/ecom-black.png differ diff --git a/commission_plan/static/description/assets/icons/education-black.png b/commission_plan/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/commission_plan/static/description/assets/icons/education-black.png differ diff --git a/commission_plan/static/description/assets/icons/hotel-black.png b/commission_plan/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/commission_plan/static/description/assets/icons/hotel-black.png differ diff --git a/commission_plan/static/description/assets/icons/icon.png b/commission_plan/static/description/assets/icons/icon.png new file mode 100644 index 000000000..61b0eb171 Binary files /dev/null and b/commission_plan/static/description/assets/icons/icon.png differ diff --git a/commission_plan/static/description/assets/icons/license.png b/commission_plan/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/commission_plan/static/description/assets/icons/license.png differ diff --git a/commission_plan/static/description/assets/icons/lifebuoy.png b/commission_plan/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/commission_plan/static/description/assets/icons/lifebuoy.png differ diff --git a/commission_plan/static/description/assets/icons/logo.png b/commission_plan/static/description/assets/icons/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/commission_plan/static/description/assets/icons/logo.png differ diff --git a/commission_plan/static/description/assets/icons/manufacturing-black.png b/commission_plan/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/commission_plan/static/description/assets/icons/manufacturing-black.png differ diff --git a/commission_plan/static/description/assets/icons/pos-black.png b/commission_plan/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/commission_plan/static/description/assets/icons/pos-black.png differ diff --git a/commission_plan/static/description/assets/icons/puzzle.png b/commission_plan/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/commission_plan/static/description/assets/icons/puzzle.png differ diff --git a/commission_plan/static/description/assets/icons/restaurant-black.png b/commission_plan/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/commission_plan/static/description/assets/icons/restaurant-black.png differ diff --git a/commission_plan/static/description/assets/icons/service-black.png b/commission_plan/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/commission_plan/static/description/assets/icons/service-black.png differ diff --git a/commission_plan/static/description/assets/icons/trading-black.png b/commission_plan/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/commission_plan/static/description/assets/icons/trading-black.png differ diff --git a/commission_plan/static/description/assets/icons/training.png b/commission_plan/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/commission_plan/static/description/assets/icons/training.png differ diff --git a/commission_plan/static/description/assets/icons/update.png b/commission_plan/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/commission_plan/static/description/assets/icons/update.png differ diff --git a/commission_plan/static/description/assets/icons/user.png b/commission_plan/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/commission_plan/static/description/assets/icons/user.png differ diff --git a/commission_plan/static/description/assets/icons/wrench.png b/commission_plan/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/commission_plan/static/description/assets/icons/wrench.png differ diff --git a/commission_plan/static/description/assets/misc/categories.png b/commission_plan/static/description/assets/misc/categories.png new file mode 100755 index 000000000..bedf1e0b1 Binary files /dev/null and b/commission_plan/static/description/assets/misc/categories.png differ diff --git a/commission_plan/static/description/assets/misc/check-box.png b/commission_plan/static/description/assets/misc/check-box.png new file mode 100755 index 000000000..42caf24b9 Binary files /dev/null and b/commission_plan/static/description/assets/misc/check-box.png differ diff --git a/commission_plan/static/description/assets/misc/compass.png b/commission_plan/static/description/assets/misc/compass.png new file mode 100755 index 000000000..d5fed8faa Binary files /dev/null and b/commission_plan/static/description/assets/misc/compass.png differ diff --git a/commission_plan/static/description/assets/misc/config.png b/commission_plan/static/description/assets/misc/config.png new file mode 100755 index 000000000..71915e76c Binary files /dev/null and b/commission_plan/static/description/assets/misc/config.png differ diff --git a/commission_plan/static/description/assets/misc/corporate.png b/commission_plan/static/description/assets/misc/corporate.png new file mode 100755 index 000000000..2eb13edbf Binary files /dev/null and b/commission_plan/static/description/assets/misc/corporate.png differ diff --git a/commission_plan/static/description/assets/misc/customer-support.png b/commission_plan/static/description/assets/misc/customer-support.png new file mode 100755 index 000000000..79efc72ed Binary files /dev/null and b/commission_plan/static/description/assets/misc/customer-support.png differ diff --git a/commission_plan/static/description/assets/misc/cybrosys-logo.png b/commission_plan/static/description/assets/misc/cybrosys-logo.png new file mode 100644 index 000000000..cc3cc0ccf Binary files /dev/null and b/commission_plan/static/description/assets/misc/cybrosys-logo.png differ diff --git a/commission_plan/static/description/assets/misc/features.png b/commission_plan/static/description/assets/misc/features.png new file mode 100755 index 000000000..b41769f77 Binary files /dev/null and b/commission_plan/static/description/assets/misc/features.png differ diff --git a/commission_plan/static/description/assets/misc/logo.png b/commission_plan/static/description/assets/misc/logo.png new file mode 100755 index 000000000..478462d3e Binary files /dev/null and b/commission_plan/static/description/assets/misc/logo.png differ diff --git a/commission_plan/static/description/assets/misc/pictures.png b/commission_plan/static/description/assets/misc/pictures.png new file mode 100755 index 000000000..56d255fe9 Binary files /dev/null and b/commission_plan/static/description/assets/misc/pictures.png differ diff --git a/commission_plan/static/description/assets/misc/pie-chart.png b/commission_plan/static/description/assets/misc/pie-chart.png new file mode 100755 index 000000000..426e05244 Binary files /dev/null and b/commission_plan/static/description/assets/misc/pie-chart.png differ diff --git a/commission_plan/static/description/assets/misc/right-arrow.png b/commission_plan/static/description/assets/misc/right-arrow.png new file mode 100755 index 000000000..730984a06 Binary files /dev/null and b/commission_plan/static/description/assets/misc/right-arrow.png differ diff --git a/commission_plan/static/description/assets/misc/star.png b/commission_plan/static/description/assets/misc/star.png new file mode 100755 index 000000000..2eb9ab29f Binary files /dev/null and b/commission_plan/static/description/assets/misc/star.png differ diff --git a/commission_plan/static/description/assets/misc/support.png b/commission_plan/static/description/assets/misc/support.png new file mode 100755 index 000000000..4f18b8b82 Binary files /dev/null and b/commission_plan/static/description/assets/misc/support.png differ diff --git a/commission_plan/static/description/assets/misc/whatsapp.png b/commission_plan/static/description/assets/misc/whatsapp.png new file mode 100755 index 000000000..d513a5356 Binary files /dev/null and b/commission_plan/static/description/assets/misc/whatsapp.png differ diff --git a/commission_plan/static/description/assets/modules/budget_image.png b/commission_plan/static/description/assets/modules/budget_image.png new file mode 100644 index 000000000..bd7643387 Binary files /dev/null and b/commission_plan/static/description/assets/modules/budget_image.png differ diff --git a/commission_plan/static/description/assets/modules/deadline_image.png b/commission_plan/static/description/assets/modules/deadline_image.png new file mode 100644 index 000000000..caff8e754 Binary files /dev/null and b/commission_plan/static/description/assets/modules/deadline_image.png differ diff --git a/commission_plan/static/description/assets/modules/dynamic_financial.png b/commission_plan/static/description/assets/modules/dynamic_financial.png new file mode 100644 index 000000000..0105aa462 Binary files /dev/null and b/commission_plan/static/description/assets/modules/dynamic_financial.png differ diff --git a/commission_plan/static/description/assets/modules/export_image.png b/commission_plan/static/description/assets/modules/export_image.png new file mode 100644 index 000000000..0598e286d Binary files /dev/null and b/commission_plan/static/description/assets/modules/export_image.png differ diff --git a/commission_plan/static/description/assets/modules/gantt_image.png b/commission_plan/static/description/assets/modules/gantt_image.png new file mode 100644 index 000000000..62c3de659 Binary files /dev/null and b/commission_plan/static/description/assets/modules/gantt_image.png differ diff --git a/commission_plan/static/description/assets/modules/pos_image.png b/commission_plan/static/description/assets/modules/pos_image.png new file mode 100644 index 000000000..3fb6154f9 Binary files /dev/null and b/commission_plan/static/description/assets/modules/pos_image.png differ diff --git a/commission_plan/static/description/assets/screenshots/1.png b/commission_plan/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..77889c3de Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/1.png differ diff --git a/commission_plan/static/description/assets/screenshots/2.png b/commission_plan/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..d0b163d6a Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/2.png differ diff --git a/commission_plan/static/description/assets/screenshots/3.png b/commission_plan/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..49255b58c Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/3.png differ diff --git a/commission_plan/static/description/assets/screenshots/4.png b/commission_plan/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..cf1c2db22 Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/4.png differ diff --git a/commission_plan/static/description/assets/screenshots/5.png b/commission_plan/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..f7643974a Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/5.png differ diff --git a/commission_plan/static/description/assets/screenshots/6.png b/commission_plan/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..60bd02e69 Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/6.png differ diff --git a/commission_plan/static/description/assets/screenshots/7.png b/commission_plan/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..13178831b Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/7.png differ diff --git a/commission_plan/static/description/assets/screenshots/8.png b/commission_plan/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..8f790838f Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/8.png differ diff --git a/commission_plan/static/description/assets/screenshots/CRM-Dashboard-user.png b/commission_plan/static/description/assets/screenshots/CRM-Dashboard-user.png new file mode 100644 index 000000000..794115f30 Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/CRM-Dashboard-user.png differ diff --git a/commission_plan/static/description/assets/screenshots/dash_screenshot-1.png b/commission_plan/static/description/assets/screenshots/dash_screenshot-1.png new file mode 100644 index 000000000..1d13a5425 Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/dash_screenshot-1.png differ diff --git a/commission_plan/static/description/assets/screenshots/dash_screenshot-2.png b/commission_plan/static/description/assets/screenshots/dash_screenshot-2.png new file mode 100644 index 000000000..5cf05a3c5 Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/dash_screenshot-2.png differ diff --git a/commission_plan/static/description/assets/screenshots/dash_screenshot-22.png b/commission_plan/static/description/assets/screenshots/dash_screenshot-22.png new file mode 100644 index 000000000..ad247eb9d Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/dash_screenshot-22.png differ diff --git a/commission_plan/static/description/assets/screenshots/dash_screenshot-3.png b/commission_plan/static/description/assets/screenshots/dash_screenshot-3.png new file mode 100644 index 000000000..11799ce0a Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/dash_screenshot-3.png differ diff --git a/commission_plan/static/description/assets/screenshots/dash_screenshot-4.png b/commission_plan/static/description/assets/screenshots/dash_screenshot-4.png new file mode 100644 index 000000000..944bdfaf5 Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/dash_screenshot-4.png differ diff --git a/commission_plan/static/description/assets/screenshots/dash_screenshot-5.png b/commission_plan/static/description/assets/screenshots/dash_screenshot-5.png new file mode 100644 index 000000000..d157c91e0 Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/dash_screenshot-5.png differ diff --git a/commission_plan/static/description/assets/screenshots/dash_screenshot-6.png b/commission_plan/static/description/assets/screenshots/dash_screenshot-6.png new file mode 100644 index 000000000..65e5c42cf Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/dash_screenshot-6.png differ diff --git a/commission_plan/static/description/assets/screenshots/hero.gif b/commission_plan/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..50c7a1d67 Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/hero.gif differ diff --git a/commission_plan/static/description/assets/screenshots/hero_kit.gif b/commission_plan/static/description/assets/screenshots/hero_kit.gif new file mode 100644 index 000000000..8286c472c Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/hero_kit.gif differ diff --git a/commission_plan/static/description/assets/screenshots/output.gif b/commission_plan/static/description/assets/screenshots/output.gif new file mode 100644 index 000000000..bae45f11a Binary files /dev/null and b/commission_plan/static/description/assets/screenshots/output.gif differ diff --git a/commission_plan/static/description/banner.png b/commission_plan/static/description/banner.png new file mode 100644 index 000000000..9b679c69c Binary files /dev/null and b/commission_plan/static/description/banner.png differ diff --git a/commission_plan/static/description/icon.png b/commission_plan/static/description/icon.png new file mode 100644 index 000000000..b8ff73729 Binary files /dev/null and b/commission_plan/static/description/icon.png differ diff --git a/commission_plan/static/description/index.html b/commission_plan/static/description/index.html new file mode 100644 index 000000000..664827ba2 --- /dev/null +++ b/commission_plan/static/description/index.html @@ -0,0 +1,755 @@ +
+ +
+ +
+
+ Community +
+
+ Enterprise +
+
+ Odoo.sh +
+
+
+
+
+
+ +

+ Odoo CRM Commission Plan

+

CRM Commission Plan for odoo16.

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

+ Overview

+
+

+ Motivating your sales representatives is one of the key factors for successful sales. The + commission-based + plan helps to motivate your Sales Teams and Salespersons to achieve the goals and earnings. + A Commission Plan module is a monetary incentive for motivating Salespeople to meet their Sales + quota + and the CRM Commission Plan has embraced the functionality. In the CRM Commission Plan, we have 2 types of Commission Plans + which are being defined product-wise and revenue-wise further under revenue-wise we have two types: + the straight commission and graduated commission. The CRM Commission Plan also includes the CRM Dashboard which + helps you to see the Overview of the CRM module. Here, you can view all details related to CRM + modules + such as Leads, Opportunities, Expected, and Total Revenue, also we can see the different reports on + the + various CRM activities.
+ Moreover, the Salesperson and the sales team + are + rewarded based on the business Opportunities they bring into the company with a well-structured plan + which + can be crafted in the beginning. +

+
+
+ +
+
+

+ Features

+
+
+
+
+ +

Craft custom Commission to Salesperson and Sales + Team

+
+ +
+ +

Draft Commissions based on Revenue and respective + Product

+
+
+
+
+ +

Define Commission based on Product Category

+
+
+ +

Informative Commission Plan report

+
+
+
+
+
+ +
+
+

+ Configuration

+
+

+ For creating new commission plans:
+

    +
  1. + Creating new commissions:
    +

    Initially Create a new commission and Choose a name to distinguish + that type

    +
  2. +
  3. + Select the type of the Commission:
    +

    Product-based: Commissions are calculated as the percentage of + the price based on the selected product in the form.

    +

    Revenue-based: A certain percentage of revenue is given as + Commission to the Salesperson

    +

    + Straight revenue: Commissions are calculated using a fixed + percentage of the revenue sold. You can fill the percentage in the field "Commission + rate".
    +

    +

    + Graduated revenue: Commissions are calculated as a percentage + of the revenue generated at amount intervals.
    +

    +

    + You can fill in the amount intervals and the percentages in the + "Graduated Revenue Commission" field.
    +

    +
  4. +
+ +

+ For adding Commission in Salesperson & Sales team:
+

+ Go to CRM -> Configuration -> Salesperson or Sales team +
    +
  • Edit the Salesperson or Sales team
  • +
  • Choose a commission type
  • +
  • Save it
  • +
+ +

+ For printing Commission in XLSX report:
+

+ Go to CRM -> Configuration -> Salesperson or Sales team +
    +
  • CRM -> Reporting -> Commission Report
  • +
+
+
+ + +
+
+

+ Screenshots

+
+
+
+ +

Commission Plan

+
+

The Commission Plan window can be accessed from the Configuration menu of the module and + select + the Commission Plan menu. Here all the Commission Plan details of the operation in respect + to + the + functioning of the Odoo CRM will be depicted.

+ +
+ +
+
+ +

Commission Plan based on Product Category

+
+

The Commission Plan Creation window can be accessed from the Commission Plan menu from the configuration menu and while + selecting the Type the Product Wise options can be selected. Further, the Product Categories + with + respect to the respective Product Category based Commission Plan can be defined.

+

You can also choose the commission amount type as fixed or percentage for each product.

+ +
+
+
+ +

Revenue-based Commission Plan: Straight Revenue Commission Plan

+
+

The second form of Commission Plan in the Odoo CRM Commission Plan where the Sales Revenue and its + percentage + calculation will be provided as Commission to the Salesperson.
+ While Creating a Straight Revenue Commission plan the Revenue type can be selected as + Straight + Commission. Further, the commission rate can be defined under the Straight Revenue + Commission + tab.

+

The commission amount type can be chosen as fixed or percentage. You need to enter the percentage rate if you choose percentage type.

+ + +

You need to enter the fixed amount if you choose the fixed type.

+ +
+ +
+
+ +

Revenue-based Commission Plan: Graduated Revenue Commission Plan

+
+

While Creating a Graduated Revenue Commission Plan the Commission type can be selected as + Graduated Commission. Further, the commission rate/ commission amount can be defined under the Graduated + Revenue + Commission tab.

+ +
+ +
+
+ +

Assigning Commission Plan for Salesperson

+
+

In the CRM Commission Plan under the respective Salesperson description tab, there will be a dedicated + tab + the + Commission Plan where the respective Commission Plan with respect to the operation can be + defined.

+ +
+ +
+
+ +

Assigning Commission Plan for Sales Team

+
+

In the CRM Commission Plan under the respective sales team description tab, there will be a dedicated tab + the + Commission Plan where the respective Commission Plan with respect to the operation can be + defined.

+ +
+ +
+
+ +

Print the Commission Plan Report in XLSX Format

+
+

The CRM Commission Plan also holds an advanced operations feature where the Admins, as well as every + User, + can take the Print out of the Commission Plan Reports based on their need and for the period + of + operations that are required. The Reports can be generated in XLSX formats and can be saved + based + on the need. To take the printout of the Commission Plan Report you should go to the + Reporting + tab + of the CRM Commission Plan and further select the Commission Plan menu and select the Required entries + and + Click to Print XLS.

+ +
+
+
+ + +
+
+

+ Suggested Products

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

+ Our Services

+
+
+ +
+
+ +
+
+ Odoo + Customization
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Support
+
+ + +
+
+ +
+
+ Hire + Odoo + Developer
+
+ +
+
+ +
+
+ Odoo + Integration
+
+ +
+
+ +
+
+ Odoo + Migration
+
+ + +
+
+ +
+
+ Odoo + Consultancy
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ 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

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

Need Help?

+
+
+
+ + + +
+
+ +
+

+ Support +

+
+
+
+
+
+
+ +
+
+

Need Help?

+

Got questions or need help? + Get in touch.

+ +

+ odoo@cybrosys.com

+
+
+
+
+
+
+
+ +
+
+

WhatsApp

+

Say hi to us on WhatsApp!

+ +

+ +91 86068 + 27707

+
+
+
+
+
+
+
+ +
+
+
+
+ + +
\ No newline at end of file diff --git a/commission_plan/static/src/js/action_manager.js b/commission_plan/static/src/js/action_manager.js new file mode 100644 index 000000000..c61fa821d --- /dev/null +++ b/commission_plan/static/src/js/action_manager.js @@ -0,0 +1,21 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; +import { download } from "@web/core/network/download"; +import framework from 'web.framework'; +import session from 'web.session'; + +registry.category("ir.actions.report handlers").add("xlsx", async (action) => { + if (action.report_type === 'xlsx') { + framework.blockUI(); + var def = $.Deferred(); + session.get_file({ + url: '/xlsx_reports', + data: action.data, + success: def.resolve.bind(def), + error: (error) => this.call('crash_manager', 'rpc_error', error), + complete: framework.unblockUI, + }); + return def; + } +}); \ No newline at end of file diff --git a/commission_plan/views/crm_commission_views.xml b/commission_plan/views/crm_commission_views.xml new file mode 100644 index 000000000..324c4295e --- /dev/null +++ b/commission_plan/views/crm_commission_views.xml @@ -0,0 +1,123 @@ + + + + + crm.commission.tree + crm.commission + + + + + + + + + + crm.commission.form + crm.commission + +
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + + CRM Commission Plan + ir.actions.act_window + crm.commission + tree,form + +

+ Create New Commission Plan! +

+
+
+ +
diff --git a/commission_plan/views/crm_team_views.xml b/commission_plan/views/crm_team_views.xml new file mode 100644 index 000000000..ce4d0516b --- /dev/null +++ b/commission_plan/views/crm_team_views.xml @@ -0,0 +1,14 @@ + + + + + crm.team.inherit.commission.plan + crm.team + + + + + + + + diff --git a/commission_plan/views/res_users_views.xml b/commission_plan/views/res_users_views.xml new file mode 100644 index 000000000..93e3531b1 --- /dev/null +++ b/commission_plan/views/res_users_views.xml @@ -0,0 +1,26 @@ + + + + + res.users.inherit.commission.plan + res.users + + + + + + + + + Sales Persons + ir.actions.act_window + res.users + [('share','=',False)] + tree,kanban,form + + + diff --git a/commission_plan/wizard/__init__.py b/commission_plan/wizard/__init__.py new file mode 100644 index 000000000..26249dbb7 --- /dev/null +++ b/commission_plan/wizard/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import commission_report diff --git a/commission_plan/wizard/commission_report.py b/commission_plan/wizard/commission_report.py new file mode 100644 index 000000000..214798cd3 --- /dev/null +++ b/commission_plan/wizard/commission_report.py @@ -0,0 +1,476 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Abhin K(odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################# +import io +import json + +from odoo import api, fields, models +from odoo.exceptions import ValidationError +from odoo.tools import date_utils + +try: + from odoo.tools.misc import xlsxwriter +except ImportError: + import xlsxwriter + + +class CommissionReportWizard(models.TransientModel): + """commission.wizard model is created and shown as the wizard window""" + _name = 'commission.wizard' + _description = 'Commission Wizard' + + date_from = fields.Date(string="From Date") + date_to = fields.Date(string="To Date") + salesperson_ids = fields.Many2many('res.users', string='Salesperson', + domain="[('share','=',False)]") + sales_team_ids = fields.Many2many('crm.team', string='Sales Team') + date = fields.Date(string='Date', default=fields.Date.context_today) + is_sales_person = fields.Boolean(default=False, string="Is sales person") + is_sales_team = fields.Boolean(default=False, string="Is sales team") + + @api.onchange('salesperson_ids') + def _onchange_salesperson_ids(self): + """Function for hide a field base on values""" + self.is_sales_person = bool(self.salesperson_ids) + + @api.onchange('sales_team_ids') + def _onchange_sales_team_ids(self): + """Function for hide a field base on values""" + self.is_sales_team = bool(self.sales_team_ids) + + @api.constrains('sales_team_ids', 'salesperson_ids') + def sales_team_constrains(self): + """Function for showing validation error""" + for rec in self: + if self.sales_team_ids: + if not rec.sales_team_ids.member_ids: + raise ValidationError( + "Selected Sales Team haven't any Salespersons") + if not self.sales_team_ids.member_ids.commission_id and \ + not self.sales_team_ids.commission_id: + raise ValidationError( + "Selected Sales Team haven't any Commission Plan") + elif self.salesperson_ids and not \ + rec.salesperson_ids.commission_id: + raise ValidationError( + "Selected Salesperson haven't any Commission Plan") + + def action_print_xlsx_report(self): + """Function for printing xlsx report""" + # sales person's condition starts here # + user_sale_orders = self.env['sale.order'].search([ + ('user_id', 'in', self.salesperson_ids.ids)]) + total_list = [] + commission_list = [] + user_commission_name = [] + user_commission_salesperson = [] + user_obj = user_sale_orders.mapped('user_id'). \ + sorted(key=lambda d: d.id) + user_sale_orders_dict = { + user: user_sale_orders.filtered(lambda rec: rec.user_id == user) + for user in user_obj} + for user, user_sale_orders in user_sale_orders_dict.items(): + commission_id = user.commission_id + if not commission_id: + continue + if self.date_to and self.date_from: + filtered_order_lines = user_sale_orders.filtered( + lambda rec: self.date_from <= rec.date_order.date() + <= self.date_to and rec.date_order.date() + >= commission_id.date_from + ).mapped('order_line') + elif not self.date_to and self.date_from: + filtered_order_lines = user_sale_orders \ + .filtered(lambda rec: rec.date_order.date() >= + self.date_from >= + commission_id.date_from)\ + .mapped('order_line') + elif self.date_to and not self.date_from: + filtered_order_lines = user_sale_orders \ + .filtered(lambda rec: rec.date_order.date() <= + self.date_to <= + commission_id.date_to)\ + .mapped('order_line') + else: + filtered_order_lines = user_sale_orders.mapped( + 'order_line') + filtered_order_lines_commission_total = sum( + filtered_order_lines.mapped('price_subtotal')) + if commission_id.type == 'product': + self._calculate_product_commission( + filtered_order_lines, + total_list, commission_list, + user_commission_salesperson, user, commission_id, + user_commission_name + ) + elif commission_id.type == 'revenue' and \ + commission_id.revenue_type == 'graduated': + for rule in commission_id.revenue_grd_comm_ids: + self._calculate_graduated_commission( + commission_list, + user_commission_salesperson, + total_list, user, commission_id, rule, + filtered_order_lines_commission_total, + user_commission_name + ) + elif commission_id.type == 'revenue' and \ + commission_id.revenue_type == 'straight': + self._calculate_straight_commission( + commission_id, + filtered_order_lines_commission_total, + commission_list, + user_commission_name, + user_commission_salesperson, + total_list, user + ) + # sales person's condition ends here # + if not self.sales_team_ids and not self.salesperson_ids: + self.sales_team_ids = self.env['crm.team'].search([]) + # sales team's condition starts here # + team_sale_orders = self.env['sale.order'].search( + [('team_id', 'in', self.sales_team_ids.ids)]) + team_obj = team_sale_orders.mapped('user_id'). \ + sorted(key=lambda d: d.id) + team_sale_orders_dict = { + team_user: self._filter_sale_orders_by_user(team_sale_orders, + team_user) for + team_user in team_obj} + commission_total, commission, commission_name, commission_salesperson, \ + commission_sales_team = self._calculate_commissions( + team_sale_orders_dict + ) + # sales team's condition ends here # + data = { + 'model_id': self.id, + 'date': self.date, + 'date_from': self.date_from, + 'date_to': self.date_to, + 'sales_team_ids': self.sales_team_ids.ids, + 'salesperson_ids': self.salesperson_ids.ids, + 'commission_list': commission_list, + 'total_list': total_list, + 'commission': commission, + 'commission_total': commission_total, + 'commission_name': commission_name, + 'commission_salesperson': commission_salesperson, + 'commission_sales_team': commission_sales_team, + 'user_commission_name': user_commission_name, + 'user_commission_salesperson': user_commission_salesperson, + } + return { + 'type': 'ir.actions.report', + 'data': { + 'model': 'commission.wizard', + 'options': json.dumps(data, default=date_utils.json_default), + 'output_format': 'xlsx', + 'report_name': 'Commission Plan xlsx report'}, + 'report_type': 'xlsx' + } + + def get_xlsx_report(self, data, response): + """get_xlsx_report function""" + date = data['date'] + team = data['sales_team_ids'] + user = data['salesperson_ids'] + commission_list = data['commission_list'] + total_list = data['total_list'] + commission = data['commission'] + commission_total = data['commission_total'] + commission_name = data['commission_name'] + commission_salesperson = data['commission_salesperson'] + commission_sales_team = data['commission_sales_team'] + user_commission_name = data['user_commission_name'] + user_commission_salesperson = data['user_commission_salesperson'] + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + sheet = workbook.add_worksheet() + head = workbook.add_format({'align': 'center', 'bold': True, + 'font_size': '15px', 'valign': 'vcenter'}) + format1 = workbook.add_format({'align': 'left', 'font_size': '12px'}) + format2 = workbook.add_format({'align': 'right', 'font_size': '12x'}) + format3 = workbook.add_format( + {'align': 'right', 'font_size': '12x', 'bold': True}) + heading = workbook.add_format({'align': 'left', 'bold': True, + 'font_size': '12px', + 'valign': 'vcenter'}) + date_format = workbook.add_format( + {'num_format': 'dd/mm/yy', 'align': 'left', 'font_size': '10px'}) + sheet.merge_range('A2:B2', "Printed Date: " + date, date_format) + sheet.write('A4', 'No.', heading) + sheet.set_column(5, 1, 25) + sheet.set_row(0, 25) + row = 5 + col = 0 + index = 1 + if user: + sheet.merge_range('A1:E1', 'COMMISSION PLAN REPORT', head) + if data.get('date_from'): + sheet.write('D2', 'Date From: ' + data['date_from'], + date_format) + if data.get('date_to'): + sheet.write('E2', 'Date To: ' + data['date_to'], date_format) + sheet.write('B4', 'Sale Persons', heading) + sheet.write('C4', 'Commission Plan Name', heading) + sheet.write('D4', 'Total Revenue', heading) + sheet.write('E4', 'Commission Amount', heading) + for j in user_commission_salesperson: + sheet.write(row, col + 0, index, format2) + sheet.write(row, col + 1, j, format1) + row += 1 + index += 1 + row = 5 + col = 0 + for j in user_commission_name: + sheet.write(row, col + 2, j, format1) + row += 1 + row = 5 + col = 0 + for j in total_list: + sheet.write(row, col + 3, round(j, 2), format2) + row += 1 + row = 5 + col = 0 + for i in commission_list: + sheet.write(row, col + 4, round(i, 2), format2) + row += 1 + sheet.write(row + 1, col + 2, 'Total', format3) + sheet.write(row + 1, col + 3, round(sum(total_list), 2), format2) + sheet.write(row + 1, col + 4, round(sum(commission_list), 2), + format2) + elif team: + sheet.merge_range('A1:F1', 'COMMISSION PLAN REPORT', head) + if data.get('date_from'): + sheet.write('E2', 'Date From: ' + data['date_from'], + date_format) + if data.get('date_to'): + sheet.write('F2', 'Date To: ' + data['date_to'], date_format) + sheet.write('B4', 'Sales Teams', heading) + sheet.write('C4', 'Sales Person', heading) + sheet.write('D4', 'Commission Plan Name', heading) + sheet.write('E4', 'Total Revenue', heading) + sheet.write('F4', 'Commission Amount', heading) + for j in commission_sales_team: + sheet.write(row, col + 0, index, format2) + sheet.write(row, col + 1, j, format1) + row += 1 + index += 1 + row = 5 + col = 0 + for j in commission_salesperson: + sheet.write(row, col + 2, j, format1) + row += 1 + row = 5 + col = 0 + for j in commission_name: + sheet.write(row, col + 3, j, format1) + row += 1 + row = 5 + col = 0 + for j in commission_total: + sheet.write(row, col + 4, round(j, 2), format2) + row += 1 + row = 5 + col = 0 + for i in commission: + sheet.write(row, col + 5, round(i, 2), format2) + row += 1 + sheet.write(row + 1, col + 3, 'Total:', format3) + sheet.write(row + 1, col + 4, round(sum(commission_total), 2), + format2) + sheet.write(row + 1, col + 5, round(sum(commission), 2), format2) + workbook.close() + output.seek(0) + response.stream.write(output.read()) + output.close() + + def _calculate_product_commission(self, filtered_order_lines, + total_list, commission_list, + user_commission_salesperson, *args): + """Returns the calculated product commission""" + user, commission_id, user_commission_name = args + commission_products = commission_id.product_comm_ids.mapped( + 'product_id') + commission_category = commission_id.product_comm_ids.mapped( + 'category_id') + prod_commission = filtered_order_lines.filtered( + lambda + rec: rec.product_id.id in commission_products.ids or + rec.product_id.categ_id.id in commission_category.ids + ) + for rule in commission_id.product_comm_ids: + product_order_line = prod_commission.filtered( + lambda rec: rec.product_id == rule.product_id or + rec.product_id.categ_id.id == rule.category_id.id) + total_price = sum(product_order_line.mapped('price_subtotal')) + product_commission = (total_price * rule.percentage) / 100 if \ + rule.commission_amount_type == 'percentage' else \ + rule.fixed_amount + total_list.append(total_price) + user_commission_name.append(commission_id.name) + user_commission_salesperson.append(user.name) + commission_list.append( + rule.amount if product_commission > rule.amount and + rule.commission_amount_type == 'percentage' + else product_commission + ) + + def _calculate_graduated_commission(self, + commission_list, + user_commission_salesperson, + total_list, *args + ): + """Returns the calculated Graduated commission""" + user, commission_id, rule, filtered_order_lines_commission_total, \ + user_commission_name = args + graduated_commission = ( + filtered_order_lines_commission_total + * rule.graduated_commission_rate + ) / 100 if rule.amount_from \ + <= filtered_order_lines_commission_total < rule.amount_to else \ + rule.graduated_fixed_amount + commission_list.append(graduated_commission) + user_commission_name.append(commission_id.name) + user_commission_salesperson.append(user.name) + total_list.append(filtered_order_lines_commission_total) + + def _calculate_straight_commission(self, commission_id, + filtered_order_lines_commission_total, + commission_list, + *args): + """Returns the calculated Straight commission""" + user_commission_name, \ + user_commission_salesperson, total_list, user = args + straight_commission = ( + filtered_order_lines_commission_total + * commission_id.straight_commission_rate + ) / 100 if \ + commission_id.straight_commission_type == 'percentage' else \ + commission_id.straight_commission_fixed + commission_list.append(straight_commission) + user_commission_name.append(commission_id.name) + user_commission_salesperson.append(user.name) + total_list.append(filtered_order_lines_commission_total) + + def _filter_sale_orders_by_user(self, team_sale_orders, team_user): + """Returns the filtered team_sale_orders using the team_users""" + return team_sale_orders.filtered(lambda rec: rec.user_id == team_user) + + def _calculate_commissions(self, team_sale_orders_dict): + """Returns the calculated commissions""" + commission_total = [] + commission = [] + commission_name = [] + commission_salesperson = [] + commission_sales_team = [] + for team_user, team_sale_orders in team_sale_orders_dict.items(): + commissions_id = team_user.commission_id or \ + team_user.sale_team_id.commission_id + if commissions_id: + if self.date_to and self.date_from: + filtered_order_lines = team_sale_orders.filtered( + lambda rec: self.date_from <= rec.date_order.date() + <= self.date_to and rec.date_order.date() + >= commissions_id.date_from + ).mapped('order_line') + elif not self.date_to and self.date_from: + filtered_order_lines = team_sale_orders \ + .filtered(lambda rec: rec.date_order.date() >= + self.date_from >= + commissions_id.date_from)\ + .mapped('order_line') + elif self.date_to and not self.date_from: + filtered_order_lines = team_sale_orders \ + .filtered(lambda rec: rec.date_order.date() <= + self.date_to <= + commissions_id.date_to)\ + .mapped('order_line') + else: + filtered_order_lines = team_sale_orders.mapped( + 'order_line') + filtered_order_lines_commission_total = sum( + filtered_order_lines.mapped('price_subtotal')) + if commissions_id.type == 'product': + commission_products = commissions_id.product_comm_ids.mapped( + 'product_id').ids + commission_category = commissions_id.product_comm_ids.mapped( + 'category_id').ids + prod_commission = filtered_order_lines.filtered( + lambda rec: rec.product_id.id in commission_products or + rec.product_id.categ_id.id in commission_category + ) + for rules in commissions_id.product_comm_ids: + product_order_line = prod_commission.filtered( + lambda rec: rec.product_id == rules.product_id or + rec.product_id.categ_id.id == rules.category_id.id) + total_price = sum( + product_order_line.mapped('price_subtotal') + ) + product_commission = ( + total_price * rules.percentage + ) / 100 if \ + rules.commission_amount_type == 'percentage' else \ + rules.fixed_amount + commission_total.append(total_price) + commission_name.append(commissions_id.name) + commission_salesperson.append(team_user.name) + commission_sales_team.append( + team_user.sale_team_id.name) + commission.append( + rules.amount if product_commission > rules.amount + and rules.commission_amount_type == 'percentage' + else product_commission + ) + if commissions_id.type == 'revenue' and ( + commissions_id.revenue_type == 'graduated'): + for rules in commissions_id.revenue_grd_comm_ids: + if rules.amount_from <= \ + filtered_order_lines_commission_total \ + < rules.amount_to: + graduated_commission = ( + filtered_order_lines_commission_total + * rules.graduated_commission_rate) / 100 if \ + rules.graduated_amount_type == 'percentage' \ + else rules.graduated_fixed_amount + commission.append(graduated_commission) + commission_name.append(commissions_id.name) + commission_salesperson.append(team_user.name) + commission_sales_team.append( + team_user.sale_team_id.name) + commission_total.append( + filtered_order_lines_commission_total) + if commissions_id.type == 'revenue' and ( + commissions_id.revenue_type == 'straight'): + straight_commission = ( + filtered_order_lines_commission_total + * commissions_id.straight_commission_rate + ) / 100 if \ + commissions_id.straight_commission_type == \ + 'percentage' else \ + commissions_id.straight_commission_fixed + commission.append(straight_commission) + commission_name.append(commissions_id.name) + commission_salesperson.append(team_user.name) + commission_sales_team.append(team_user.sale_team_id.name) + commission_total.append( + filtered_order_lines_commission_total + ) + return commission_total, commission, commission_name, \ + commission_salesperson, commission_sales_team diff --git a/commission_plan/wizard/commission_wizard_views.xml b/commission_plan/wizard/commission_wizard_views.xml new file mode 100644 index 000000000..19c28e3f8 --- /dev/null +++ b/commission_plan/wizard/commission_wizard_views.xml @@ -0,0 +1,47 @@ + + + + + commission.wizard.form + commission.wizard + form + +
+ + + + + + + + + + + + + + +
+
+
+
+
+ + Commission Report + commission.wizard + form + + new + + +