91 lines
4.0 KiB
Python
91 lines
4.0 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import io
|
|
|
|
from odoo import _
|
|
from odoo.http import Controller, request, route, content_disposition
|
|
|
|
|
|
class SaleCommissionTargetExportController(Controller):
|
|
@route('/sale_commission/export/targets/<int:plan_id>', type='http', auth='user', readonly=True)
|
|
def export_targets(self, plan_id):
|
|
plan = request.env['sale.commission.plan'].browse(plan_id)
|
|
target_ids = plan.target_commission_ids
|
|
headers = [_("Performance"), _("Commission"), _("Currency")]
|
|
return self._generate_xlsx(filename=plan.name, target_ids=target_ids, headers=headers)
|
|
|
|
def _interpolate_target(self, target_rate, sorted_rates, values_by_rate):
|
|
"""Linear interpolation of the target value according to existing targets
|
|
For two known targets values t1 and t2 having respontively x1 and x2 rate and
|
|
y1 and y2 commission amounts, an intermediate t3 target at 'target_rate'
|
|
position (x) will have the following amount (y)
|
|
y = a * target_rate + y1 where a is the slope.
|
|
a = (y2-y1)/(x2-x1)
|
|
"""
|
|
for rate in sorted_rates:
|
|
if rate > target_rate:
|
|
x2 = rate
|
|
# all rate have a defined row
|
|
y2 = values_by_rate[rate][1]
|
|
break
|
|
# previous values
|
|
x1 = rate
|
|
# all rate have a defined row
|
|
y1 = values_by_rate[rate][1]
|
|
if x1 is None or x2 is None or x2 == x1:
|
|
return 0
|
|
# y = b + ax
|
|
amount = y1 + (y2 - y1) / (x2 - x1) * (target_rate - x1)
|
|
return amount
|
|
|
|
def _generate_rows(self, target_ids):
|
|
""" Generate a xls file containing a table with a line for every 10% of target completion
|
|
and the commission amount. Starting at 0% and ending with the last target level
|
|
"""
|
|
if not target_ids:
|
|
return []
|
|
rows = []
|
|
values_by_rate = {}
|
|
sorted_rates = []
|
|
currency_name = target_ids[0].currency_id.name
|
|
for target in target_ids.sorted('target_rate'):
|
|
row = [target.target_rate * 100, target.amount, currency_name]
|
|
values_by_rate[target.target_rate] = row
|
|
sorted_rates.append(target.target_rate)
|
|
rows.append(row)
|
|
target_max = target.target_rate + 0.1
|
|
all_rate = [x / 100 for x in range(0, int(target_max * 100), 10) if x / 100 <= target.target_rate] + sorted_rates
|
|
all_rate = set(all_rate)
|
|
all_rate = sorted(all_rate)
|
|
all_rows = []
|
|
for target_val in all_rate:
|
|
row_val = values_by_rate.get(target_val)
|
|
if not row_val:
|
|
amount = self._interpolate_target(target_val, sorted_rates, values_by_rate)
|
|
row_val = [target_val * 100, amount, currency_name]
|
|
all_rows.append(row_val)
|
|
return all_rows
|
|
|
|
def _generate_xlsx(self, filename="", target_ids=None, headers=None):
|
|
buffer = io.BytesIO()
|
|
import xlsxwriter # noqa: PLC0415
|
|
workbook = xlsxwriter.Workbook(buffer, {'in_memory': True})
|
|
worksheet = workbook.add_worksheet()
|
|
worksheet.write_row(0, 0, headers)
|
|
rows = self._generate_rows(target_ids)
|
|
column_widths = [len(header) for header in headers]
|
|
for row_idx, row in enumerate(rows, start=1):
|
|
worksheet.write_row(row_idx, 0, row)
|
|
for col_idx, cell_value in enumerate(row):
|
|
column_widths[col_idx] = max(column_widths[col_idx], len(str(cell_value)))
|
|
for col_idx, width in enumerate(column_widths):
|
|
worksheet.set_column(col_idx, col_idx, width)
|
|
workbook.close()
|
|
content = buffer.getvalue()
|
|
buffer.close()
|
|
headers = [
|
|
('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'),
|
|
('Content-Disposition', content_disposition(f'Targets - {filename}.xlsx'))
|
|
]
|
|
return request.make_response(content, headers)
|