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
|
|
|