You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							179 lines
						
					
					
						
							7.3 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							179 lines
						
					
					
						
							7.3 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| ################################################################################ | |
| # | |
| #    Cybrosys Technologies Pvt. Ltd. | |
| # | |
| #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |
| #    Author: ASWIN A K (odoo@cybrosys.com) | |
| # | |
| #    This program is under the terms of the Odoo Proprietary License v1.0 | |
| #    (OPL-1) It is forbidden to publish, distribute, sublicense, or sell | |
| #    copies of the Software or modified copies of the Software. | |
| # | |
| #    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| #    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| #    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
| #    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | |
| #    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
| #    OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR | |
| #    THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| # | |
| ################################################################################ | |
| from odoo import api, fields, models, _ | |
| from odoo.exceptions import UserError | |
| 
 | |
| 
 | |
| class SalesIncentive(models.Model): | |
|     """ | |
|     This class represents the Sales Incentive model, which is used to configure | |
|     incentive schemes for sales personnel. It allows defining various parameters | |
|     such as the calculation method, incentive tiers, and activation status. | |
|     """ | |
|     _name = 'sales.incentive' | |
|     _description = 'Sales Incentive' | |
| 
 | |
|     name = fields.Char( | |
|         string='Name', | |
|         help='Enter the name for your record. This field is required.', | |
|         required=True) | |
|     calculation_method = fields.Selection( | |
|         [('linear', 'Linear'), ('step', 'Tiered Commission Plan')], | |
|         help='Tired : the amount of Incentive ' | |
|              'increases as the sales person achieves more.', | |
|         string='Based On', default='linear') | |
|     select_incentive_ids = fields.One2many( | |
|         'select.incentive', 'sales_incentive_id') | |
|     active_calculation = fields.Boolean( | |
|         string='Active', | |
|         copy=False, | |
|         help='This field controls whether the scheme is active or not.') | |
| 
 | |
|     @api.onchange('active_calculation') | |
|     def _onchange_active_calculation(self): | |
|         """ | |
|             Checks for any active_calculation, if any returns a user error. | |
|         """ | |
|         if self.search([('active_calculation', '=', True)]): | |
|             if self.active_calculation: | |
|                 raise UserError( | |
|                     _('Another scheme already active for incentive calculation') | |
|                 ) | |
| 
 | |
|     def action_incentive_compute(self): | |
|         """ | |
|             Computes calculate_incentive and returns it. | |
|         """ | |
|         calc = self.env['calculate.incentive'].search([]) | |
|         challenge = self.env['gamification.challenge'].search( | |
|             [('incentive_calculation', '=', True)]) | |
|         docs = self.env['gamification.goal'].search( | |
|             [('challenge_id', 'in', challenge.ids)]) | |
|         self.send_warnings(challenge, docs) | |
|         unlink_date_list = self.filter_expired_calc_records(calc, docs) | |
|         self.unlink_expired_calc_records(unlink_date_list) | |
|         for goal in docs: | |
|             incentive = 0.0 | |
|             if self.calculation_method == 'linear': | |
|                 incentive = self.calculate_linear_incentive(goal, incentive) | |
|             else: | |
|                 incentive = self.calculate_tiered_incentive(goal) | |
|             data = { | |
|                 'salesperson_id': goal.user_id.id, | |
|                 'goal': goal.target_goal, | |
|                 'achieved': goal.current, | |
|                 'achievement_percentage': goal.target_achievement_percentage, | |
|                 'incentive': incentive, | |
|                 'start_date': goal.start_date, | |
|                 'end_date': goal.end_date, | |
|                 'status': 'unpaid', | |
|             } | |
|             self.env['calculate.incentive'].create(data) | |
|         return { | |
|             'name': 'Incentive', | |
|             'type': 'ir.actions.act_window', | |
|             'view_mode': 'tree', | |
|             'res_model': 'calculate.incentive', | |
|             'target': 'current', | |
|         } | |
| 
 | |
|     def calculate_linear_incentive(self, goal, incentive, highest=0): | |
|         """Find the incentive by using linear method""" | |
|         for select_line in self.select_incentive_ids: | |
|             if ((goal.target_achievement_percentage >= | |
|                  select_line.upto_percent) | |
|                     and (select_line.upto_percent > highest)): | |
|                 highest = select_line.upto_percent | |
|                 if select_line.incentive_type == 'percent': | |
|                     incentive = goal.current * ( | |
|                             select_line.reward / 100) | |
|                 else: | |
|                     incentive = select_line.reward | |
|         goal.incentive = incentive | |
|         return incentive | |
| 
 | |
|     def send_warnings(self, challenge, docs): | |
|         """It is a method to raise warnings | |
|         :param1 challenge | |
|         :param2 docs that is goals of the challenge | |
|         """ | |
|         if not (challenge and docs): | |
|             raise UserError( | |
|                 _('There is on active challenge and goal for calculation')) | |
|         if docs.filtered(lambda goal: not goal.end_date): | |
|             error_users = "'s,  ".join(docs.mapped('user_id.name')) | |
|             raise UserError( | |
|                 _(f"The goal {error_users}'s " | |
|                   f"{docs[0].display_name} has no end date.")) | |
| 
 | |
|     def filter_expired_calc_records(self, calc, docs): | |
|         """ | |
|         Filter calculate_incentive records based on expiration date. | |
|         """ | |
|         unlink_date_list = [] | |
|         for record in calc: | |
|             if record.end_date >= (fields.Date.today()): | |
|                 record.unlink() | |
|             elif docs[0].end_date == record.end_date: | |
|                 unlink_date_list.append(record.id) | |
|         return unlink_date_list | |
| 
 | |
|     def unlink_expired_calc_records(self, unlink_date_list): | |
|         """ | |
|         Unlink expired calculate_incentive records. | |
|         """ | |
|         self.env['calculate.incentive'].search( | |
|             [('id', 'in', unlink_date_list)]).unlink() | |
| 
 | |
|     def calculate_tiered_incentive(self, goal): | |
|         """ | |
|         Calculate incentive for tiered commission plan. | |
|         """ | |
|         incentive = 0.0 | |
|         sum_value = 0.0 | |
|         old = 0.0 | |
|         final_incentive = 0.0 | |
| 
 | |
|         for select_line in self.select_incentive_ids.sorted( | |
|                 lambda x: x.upto_percent): | |
|             if (goal.target_achievement_percentage | |
|                     >= select_line.upto_percent): | |
|                 new = (goal.target_goal * ( | |
|                         select_line.upto_percent / 100)) - old | |
|                 sum_value += new | |
|                 if select_line.incentive_type == 'percent': | |
|                     incentive += new * (select_line.reward / 100) | |
|                 else: | |
|                     incentive += select_line.reward | |
|                 old = goal.target_goal * ( | |
|                         select_line.upto_percent / 100) | |
|             elif sum_value < goal.current and sum_value != 0.0: | |
|                 last_incentive = goal.current - sum_value | |
|                 if select_line.incentive_type == 'percent': | |
|                     final_incentive = last_incentive * ( | |
|                             select_line.reward / 100) | |
|                 else: | |
|                     final_incentive = select_line.reward | |
|                 sum_value += goal.current - sum_value | |
|         incentive += final_incentive | |
|         goal.incentive = incentive | |
|         return incentive
 | |
| 
 |