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.
 
 
 
 
 

485 lines
24 KiB

# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Arjun S(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 <http://www.gnu.org/licenses/>.
#
#############################################################################
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 CommissionReport(models.TransientModel):
"""The commission.report model is created and shown as the wizard window"""
_name = 'commission.report'
_description = 'Commission Report'
date_from = fields.Date(string="From Date",
help="The date from report is needed")
date_to = fields.Date(string="To Date", help="The date to report is needed")
salesperson_ids = fields.Many2many('res.users', string='Salesperson',
domain="[('share','=',False)]",
help="Salespersons of the corresponding "
"reports")
sales_team_ids = fields.Many2many('crm.team', string='Sales Team',
help="Sales teams of the corresponding "
"reports")
date = fields.Date(string='Date', default=fields.Date.context_today,
help="Current date")
is_sales_person = fields.Boolean(default=False, string="Is sales person",
help="Whether the report is for sales "
"person")
is_sales_team = fields.Boolean(default=False, string="Is sales team",
help="Whether the report is for 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.report',
'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