Files
tryton/modules/commission/invoice.py
T

254 lines
8.9 KiB
Python
Raw Normal View History

2014-12-19 12:14:20 +01:00
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from collections import defaultdict
from itertools import groupby
2014-12-19 12:14:20 +01:00
2021-12-11 17:58:42 +01:00
from trytond.model import ModelView, Workflow, fields
2020-04-23 21:44:00 +02:00
from trytond.modules.product import round_price
2021-12-11 17:58:42 +01:00
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval, If
from trytond.tools import grouped_slice
from trytond.transaction import Transaction
2020-04-23 21:44:00 +02:00
2014-12-19 12:14:20 +01:00
2018-06-26 19:11:46 +02:00
class Invoice(metaclass=PoolMeta):
2014-12-19 12:14:20 +01:00
__name__ = 'account.invoice'
agent = fields.Many2One('commission.agent', 'Commission Agent',
domain=[
('type_', '=', 'agent'),
2014-12-19 12:14:20 +01:00
('company', '=', Eval('company', -1)),
],
states={
'invisible': Eval('type') == 'in',
2014-12-19 12:14:20 +01:00
'readonly': Eval('state', '') != 'draft',
},
2020-04-13 17:35:36 +02:00
help="The agent who receives a commission for the invoice.")
2014-12-19 12:14:20 +01:00
2020-10-12 13:02:30 +02:00
@classmethod
def _journal_types(cls, invoice_type):
return super()._journal_types(invoice_type) + ['commission']
2014-12-19 12:14:20 +01:00
@classmethod
2021-02-27 15:23:46 +01:00
def _post(cls, invoices):
# Create commission only the first time the invoice is posted
to_commission = [i for i in invoices
if i.state not in ['posted', 'paid']]
2021-02-27 15:23:46 +01:00
super()._post(invoices)
cls.create_commissions(to_commission)
2014-12-19 12:14:20 +01:00
@classmethod
def create_commissions(cls, invoices):
pool = Pool()
Commission = pool.get('commission')
all_commissions = []
for invoice in invoices:
for line in invoice.lines:
commissions = line.get_commissions()
if commissions:
all_commissions.extend(commissions)
Commission.save(all_commissions)
return all_commissions
@classmethod
def set_commissions_date(cls, invoices):
2014-12-19 12:14:20 +01:00
pool = Pool()
Date = pool.get('ir.date')
Commission = pool.get('commission')
date2commissions = defaultdict(list)
for company, c_invoices in groupby(invoices, key=lambda i: i.company):
with Transaction().set_context(company=company.id):
today = Date.today()
for sub_invoices in grouped_slice(list(c_invoices)):
ids = [i.id for i in sub_invoices]
for commission in Commission.search([
('date', '=', None),
('origin.invoice', 'in', ids,
'account.invoice.line'),
]):
date = commission.origin.invoice.reconciled or today
date2commissions[date].append(commission)
to_write = []
for date, commissions in date2commissions.items():
to_write.append(commissions)
to_write.append({
'date': date,
})
if to_write:
Commission.write(*to_write)
2014-12-19 12:14:20 +01:00
@classmethod
@Workflow.transition('paid')
def paid(cls, invoices):
super().paid(invoices)
cls.set_commissions_date(invoices)
2014-12-19 12:14:20 +01:00
@classmethod
@ModelView.button
@Workflow.transition('cancelled')
2014-12-19 12:14:20 +01:00
def cancel(cls, invoices):
pool = Pool()
Commission = pool.get('commission')
invoices_to_revert_commission = []
invoices_to_set_date = []
for invoice in invoices:
if invoice.move:
invoices_to_set_date.append(invoice)
else:
invoices_to_revert_commission.append(invoice)
super().cancel(invoices)
cls.set_commissions_date(invoices_to_set_date)
2014-12-19 12:14:20 +01:00
to_delete = []
to_save = []
for sub_invoices in grouped_slice(invoices_to_revert_commission):
2014-12-19 12:14:20 +01:00
ids = [i.id for i in sub_invoices]
to_delete += Commission.search([
('invoice_line', '=', None),
('origin.invoice', 'in', ids, 'account.invoice.line'),
])
to_cancel = Commission.search([
('invoice_line', '!=', None),
('origin.invoice', 'in', ids, 'account.invoice.line'),
])
for commission in Commission.copy(to_cancel):
commission.amount *= -1
to_save.append(commission)
Commission.delete(to_delete)
Commission.save(to_save)
def _credit(self, **values):
values.setdefault('agent', self.agent)
return super()._credit(**values)
2014-12-19 12:14:20 +01:00
2018-06-26 19:11:46 +02:00
class InvoiceLine(metaclass=PoolMeta):
2014-12-19 12:14:20 +01:00
__name__ = 'account.invoice.line'
principal = fields.Many2One('commission.agent', 'Commission Principal',
domain=[
('type_', '=', 'principal'),
('company', '=', Eval('_parent_invoice', {}).get('company',
Eval('company', -1))),
],
states={
'invisible': If(Bool(Eval('_parent_invoice')),
2016-03-20 22:58:54 +01:00
Eval('_parent_invoice', {}).get('type') == 'in',
Eval('invoice_type') == 'in'),
2022-10-09 18:48:58 +02:00
'readonly': Eval('invoice_state') != 'draft',
},
2020-04-13 17:35:36 +02:00
help="The principal who pays a commission for the invoice line.")
2014-12-19 12:14:20 +01:00
commissions = fields.One2Many('commission', 'origin', 'Commissions',
readonly=True,
states={
'invisible': ~Eval('commissions'),
})
from_commissions = fields.One2Many('commission', 'invoice_line',
'From Commissions', readonly=True,
states={
'invisible': ~Eval('from_commissions'),
})
@property
def agent_plans_used(self):
"List of agent, plan tuple"
used = []
if self.invoice.agent:
used.append((self.invoice.agent, self.invoice.agent.plan))
if self.principal:
used.append((self.principal, self.principal.plan))
return used
def get_commissions(self):
pool = Pool()
Commission = pool.get('commission')
Currency = pool.get('currency.currency')
Date = pool.get('ir.date')
if self.type != 'line':
return []
with Transaction().set_context(company=self.invoice.company.id):
today = Date.today()
2014-12-19 12:14:20 +01:00
commissions = []
for agent, plan in self.agent_plans_used:
if not plan:
continue
with Transaction().set_context(date=self.invoice.currency_date):
2021-06-11 00:17:19 +02:00
base_amount = Currency.compute(self.invoice.currency,
2014-12-19 12:14:20 +01:00
self.amount, agent.currency, round=False)
base_amount = round_price(base_amount)
2021-06-11 00:17:19 +02:00
amount = self._get_commission_amount(base_amount, plan)
2014-12-19 12:14:20 +01:00
if amount:
2020-04-23 21:44:00 +02:00
amount = round_price(amount)
2014-12-19 12:14:20 +01:00
if not amount:
continue
commission = Commission()
commission.origin = self
if plan.commission_method == 'posting':
commission.date = self.invoice.invoice_date or today
elif (plan.commission_method == 'payment'
and self.invoice.state == 'paid'):
commission.date = self.invoice.reconciled or today
2014-12-19 12:14:20 +01:00
commission.agent = agent
commission.product = plan.commission_product
2021-06-11 00:17:19 +02:00
commission.base_amount = base_amount
2014-12-19 12:14:20 +01:00
commission.amount = amount
commissions.append(commission)
return commissions
def _get_commission_amount(self, amount, plan, pattern=None):
return plan.compute(amount, self.product, pattern=pattern)
@fields.depends('product', 'principal')
def on_change_product(self):
super(InvoiceLine, self).on_change_product()
if self.product:
if self.product.principals:
if self.principal not in self.product.principals:
self.principal = self.product.principal
2014-12-19 12:14:20 +01:00
elif self.principal:
self.principal = None
2015-03-09 19:41:36 +01:00
@classmethod
def view_attributes(cls):
return super(InvoiceLine, cls).view_attributes() + [
('//page[@id="commissions"]', 'states', {
2015-03-09 19:41:36 +01:00
'invisible': Eval('type') != 'line',
})]
2014-12-19 12:14:20 +01:00
@classmethod
def copy(cls, lines, default=None):
if default is None:
default = {}
2018-09-01 01:02:03 +02:00
else:
default = default.copy()
2014-12-19 12:14:20 +01:00
default.setdefault('commissions', None)
default.setdefault('from_commissions', None)
return super(InvoiceLine, cls).copy(lines, default=default)
2020-06-24 23:00:48 +02:00
class CreditInvoiceStart(metaclass=PoolMeta):
__name__ = 'account.invoice.credit.start'
with_agent = fields.Boolean(
"With Agent",
help="Check to keep the original invoice's agent.")
@classmethod
def default_with_agent(cls):
return True
class CreditInvoice(metaclass=PoolMeta):
__name__ = 'account.invoice.credit'
@property
def _credit_options(self):
options = super()._credit_options
if not self.start.with_agent:
options['agent'] = None
return options