Add module commission_simple and commission_simple_sale
Improve view inheritance in account_usability
This commit is contained in:
7
commission_simple/models/__init__.py
Normal file
7
commission_simple/models/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import commission
|
||||
from . import res_users
|
||||
from . import res_company
|
||||
from . import account_config_settings
|
||||
from . import account_invoice_line
|
||||
13
commission_simple/models/account_config_settings.py
Normal file
13
commission_simple/models/account_config_settings.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AccountConfigSettings(models.TransientModel):
|
||||
_inherit = 'account.config.settings'
|
||||
|
||||
commission_date_range_type_id = fields.Many2one(
|
||||
related='company_id.commission_date_range_type_id', readonly=False)
|
||||
108
commission_simple/models/account_invoice_line.py
Normal file
108
commission_simple/models/account_invoice_line.py
Normal file
@@ -0,0 +1,108 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 Akretion France (http://www.akretion.com/)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
from odoo import api, fields, models
|
||||
import odoo.addons.decimal_precision as dp
|
||||
|
||||
|
||||
class AccountInvoiceLine(models.Model):
|
||||
_inherit = 'account.invoice.line'
|
||||
|
||||
user_id = fields.Many2one(
|
||||
related='invoice_id.user_id', store=True, readonly=True)
|
||||
product_categ_id = fields.Many2one(
|
||||
related='product_id.categ_id', store=True, readonly=True)
|
||||
commission_result_id = fields.Many2one(
|
||||
'commission.result', string='Commission Result')
|
||||
commission_rule_id = fields.Many2one(
|
||||
'commission.rule', 'Matched Commission Rule', ondelete='restrict')
|
||||
commission_base = fields.Monetary('Commission Base', currency_field='company_currency_id')
|
||||
commission_rate = fields.Float('Commission Rate', digits=dp.get_precision('Commission Rate'))
|
||||
commission_amount = fields.Monetary(
|
||||
string='Commission Amount', currency_field='company_currency_id',
|
||||
readonly=True, compute='_compute_commission_amount', store=True)
|
||||
|
||||
@api.depends('commission_rate', 'commission_base')
|
||||
def _compute_amount(self):
|
||||
for line in self:
|
||||
line.commission_amount = line.commission_rate * line.commission_base / 100.0
|
||||
|
||||
def compute_commission_for_one_user(self, user, date_range, rules):
|
||||
profile = user.commission_profile_id
|
||||
assert profile
|
||||
domain = [
|
||||
('invoice_type', 'in', ('out_invoice', 'out_refund')),
|
||||
('date_invoice', '<=', date_range.date_end),
|
||||
('company_id', '=', self.env.user.company_id.id),
|
||||
('user_id', '=', user.id),
|
||||
('commission_result_id', '=', False),
|
||||
]
|
||||
if profile.trigger_type == 'invoice':
|
||||
domain.append(('state', 'in', ('open', 'paid')))
|
||||
elif profile.trigger_type == 'payment':
|
||||
# TODO : for this trigger, we would need to filter
|
||||
# out the invoices paid after the end date of the period compute
|
||||
domain.append(('state', '=', 'paid'))
|
||||
else:
|
||||
raise
|
||||
ilines = self.search(domain, order='date_invoice, invoice_id, sequence')
|
||||
com_result = self.env['commission.result'].create({
|
||||
'user_id': user.id,
|
||||
'profile_id': profile.id,
|
||||
'date_range_id': date_range.id,
|
||||
})
|
||||
total = 0.0
|
||||
for iline in ilines:
|
||||
rule = iline._match_commission_rule(rules[profile.id])
|
||||
if rule:
|
||||
lvals = iline._prepare_commission_data(rule, com_result)
|
||||
if lvals:
|
||||
iline.write(lvals)
|
||||
total += lvals['commission_amount']
|
||||
com_result.amount_total = total
|
||||
return com_result
|
||||
|
||||
def _match_commission_rule(self, rules):
|
||||
# commission rules are already in the right order
|
||||
self.ensure_one()
|
||||
for rule in rules:
|
||||
if rule['date_start'] and rule['date_start'] > self.date_invoice:
|
||||
continue
|
||||
if rule['date_end'] and rule['date_end'] < self.date_invoice:
|
||||
continue
|
||||
if rule['applied_on'] == '0_customer_product':
|
||||
if (
|
||||
self.commercial_partner_id.id in
|
||||
rule['partner_ids'] and
|
||||
self.product_id.id in rule['product_ids']):
|
||||
return rule
|
||||
elif rule['applied_on'] == '1_customer_product_category':
|
||||
if (
|
||||
self.commercial_partner_id.id in
|
||||
rule['partner_ids'] and
|
||||
self.product_categ_id.id in rule['product_categ_ids']):
|
||||
return rule
|
||||
elif rule['applied_on'] == '2_product':
|
||||
if self.product_id.id in rule['product_ids']:
|
||||
return rule
|
||||
elif rule['applied_on'] == '3_product_category':
|
||||
if self.product_categ_id.id in rule['product_categ_ids']:
|
||||
return rule
|
||||
elif rule['applied_on'] == '4_global':
|
||||
return rule
|
||||
return False
|
||||
|
||||
def _prepare_commission_data(self, rule, commission_result):
|
||||
self.ensure_one()
|
||||
lvals = {
|
||||
'commission_result_id': commission_result.id,
|
||||
'commission_rule_id': rule['id'],
|
||||
# company currency
|
||||
'commission_base': self.price_subtotal_signed,
|
||||
'commission_rate': rule['rate'],
|
||||
'commission_amount': rule['rate'] * self.price_subtotal_signed,
|
||||
}
|
||||
return lvals
|
||||
120
commission_simple/models/commission.py
Normal file
120
commission_simple/models/commission.py
Normal file
@@ -0,0 +1,120 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright Akretion France (http://www.akretion.com/)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
from odoo import fields, models, api
|
||||
import odoo.addons.decimal_precision as dp
|
||||
|
||||
|
||||
class CommissionProfile(models.Model):
|
||||
_name = 'commission.profile'
|
||||
_description = 'Commission Profile'
|
||||
|
||||
name = fields.Char(string='Name of the Profile', required=True)
|
||||
active = fields.Boolean(string='Active', default=True)
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Company',
|
||||
required=True,
|
||||
default=lambda self: self.env['res.company']._company_default_get())
|
||||
line_ids = fields.One2many(
|
||||
'commission.rule', 'profile_id', string='Commission Rules')
|
||||
trigger_type = fields.Selection([
|
||||
('invoice', 'Invoicing'),
|
||||
('payment', 'Payment'),
|
||||
], default='invoice', string='Trigger', required=True)
|
||||
|
||||
|
||||
class CommissionRule(models.Model):
|
||||
_name = 'commission.rule'
|
||||
_description = 'Commission Rule'
|
||||
_order = 'profile_id, applied_on'
|
||||
|
||||
partner_ids = fields.Many2many(
|
||||
'res.partner', string='Customers',
|
||||
domain=[('parent_id', '=', False), ('customer', '=', True)])
|
||||
product_categ_ids = fields.Many2many(
|
||||
'product.category', string="Product Categories",
|
||||
domain=[('type', '=', 'normal')])
|
||||
product_ids = fields.Many2many('product.product', string='Products')
|
||||
date_start = fields.Date('Start Date')
|
||||
date_end = fields.Date('End Date')
|
||||
profile_id = fields.Many2one(
|
||||
'commission.profile', string='Profile', ondelete='cascade')
|
||||
company_id = fields.Many2one(
|
||||
related='profile_id.company_id', store=True, readonly=True)
|
||||
rate = fields.Float(
|
||||
'Commission Rate', digits=dp.get_precision('Commission Rate'),
|
||||
copy=False)
|
||||
applied_on = fields.Selection([
|
||||
('0_customer_product', 'Products and Customers'),
|
||||
('1_customer_product_category', "Product Categories and Customers"),
|
||||
('2_product', "Products"),
|
||||
('3_product_category', "Product Categories"),
|
||||
('4_global', u'Global')],
|
||||
string='Apply On', default='4_global', required=True)
|
||||
active = fields.Boolean(string='Active', default=True)
|
||||
|
||||
@api.model
|
||||
def load_all_rules(self):
|
||||
rules = self.search_read()
|
||||
res = {} # key = profile, value = [rule1 recordset, rule2]
|
||||
for rule in rules:
|
||||
if rule['profile_id']:
|
||||
if rule['profile_id'][0] not in res:
|
||||
res[rule['profile_id'][0]] = [rule]
|
||||
else:
|
||||
res[rule['profile_id'][0]].append(rule)
|
||||
return res
|
||||
|
||||
_sql_constraints = [(
|
||||
'rate_positive',
|
||||
'CHECK(rate >= 0)',
|
||||
'Rate must be positive !')]
|
||||
|
||||
|
||||
class CommissionResult(models.Model):
|
||||
_name = 'commission.result'
|
||||
_description = "Commission Result"
|
||||
_order = 'date_start desc'
|
||||
|
||||
user_id = fields.Many2one(
|
||||
'res.users', 'Salesman', required=True, ondelete='restrict',
|
||||
readonly=True)
|
||||
profile_id = fields.Many2one(
|
||||
'commission.profile', string='Commission Profile',
|
||||
readonly=True)
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Company',
|
||||
required=True, readonly=True,
|
||||
default=lambda self: self.env['res.company']._company_default_get())
|
||||
company_currency_id = fields.Many2one(
|
||||
related='company_id.currency_id', string='Company Currency',
|
||||
readonly=True, store=True)
|
||||
date_range_id = fields.Many2one(
|
||||
'date.range', required=True, string='Period', readonly=True)
|
||||
date_start = fields.Date(
|
||||
related='date_range_id.date_start', readonly=True, store=True)
|
||||
date_end = fields.Date(
|
||||
related='date_range_id.date_end', readonly=True, store=True)
|
||||
line_ids = fields.One2many(
|
||||
'account.invoice.line', 'commission_result_id', 'Commission Lines',
|
||||
readonly=True)
|
||||
amount_total = fields.Monetary(
|
||||
string='Commission Total', currency_field='company_currency_id',
|
||||
help='This is the total amount at the date of the computation of the commission',
|
||||
readonly=True)
|
||||
|
||||
def name_get(self):
|
||||
res = []
|
||||
for result in self:
|
||||
name = '%s (%s)' % (result.user_id.name, result.date_range_id.name)
|
||||
res.append((result.id, name))
|
||||
return res
|
||||
|
||||
_sql_constraints = [(
|
||||
'salesman_period_company_unique',
|
||||
'unique(company_id, commission_partner_id, date_range_id)',
|
||||
'A commission result already exists for this salesman for '
|
||||
'the same period')]
|
||||
14
commission_simple/models/res_company.py
Normal file
14
commission_simple/models/res_company.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 Akretion France (http://www.akretion.com/)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = 'res.company'
|
||||
|
||||
commission_date_range_type_id = fields.Many2one(
|
||||
'date.range.type', string='Commission Periodicity')
|
||||
15
commission_simple/models/res_users.py
Normal file
15
commission_simple/models/res_users.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 Akretion France (http://www.akretion.com/)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
commission_profile_id = fields.Many2one(
|
||||
'commission.profile', string='Commission Profile',
|
||||
company_dependant=True)
|
||||
Reference in New Issue
Block a user