236 lines
7.4 KiB
Python
236 lines
7.4 KiB
Python
# 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 dateutil.relativedelta import relativedelta
|
|
from sql import Null
|
|
from sql.aggregate import Count, Min, Sum
|
|
from sql.conditionals import Coalesce
|
|
from sql.functions import DateTrunc, Round
|
|
|
|
from trytond.model import ModelSQL, ModelView, fields
|
|
from trytond.modules.currency.fields import Monetary
|
|
from trytond.modules.product import price_digits
|
|
from trytond.pool import Pool
|
|
from trytond.pyson import Eval, If
|
|
from trytond.tools import pairwise_longest
|
|
from trytond.tools.chart import sparkline
|
|
from trytond.transaction import Transaction
|
|
|
|
|
|
class Agent(ModelView, ModelSQL):
|
|
__name__ = 'commission.reporting.agent'
|
|
|
|
agent = fields.Many2One('commission.agent', 'Agent')
|
|
number = fields.Integer("Number")
|
|
|
|
base_amount = Monetary(
|
|
"Base Amount", currency='currency', digits='currency')
|
|
base_amount_trend = fields.Function(
|
|
fields.Char("Base Amount Trend"), 'get_trend')
|
|
amount = Monetary("Amount", currency='currency', digits=price_digits)
|
|
|
|
time_series = fields.One2Many(
|
|
'commission.reporting.agent.time_series', 'agent', "Time Series")
|
|
|
|
currency = fields.Many2One('currency.currency', "Currency")
|
|
|
|
@classmethod
|
|
def table_query(cls):
|
|
from_item, tables, withs = cls._joins()
|
|
return from_item.select(
|
|
*cls._columns(tables, withs),
|
|
where=cls._where(tables, withs),
|
|
group_by=cls._group_by(tables, withs),
|
|
with_=withs.values())
|
|
|
|
@classmethod
|
|
def _joins(cls):
|
|
pool = Pool()
|
|
Commission = pool.get('commission')
|
|
Agent = pool.get('commission.agent')
|
|
Currency = pool.get('currency.currency')
|
|
|
|
tables = {}
|
|
tables['commission'] = commission = Commission.__table__()
|
|
tables['commission.agent'] = agent = Agent.__table__()
|
|
tables['commission.agent.currency'] = currency = Currency.__table__()
|
|
withs = {}
|
|
|
|
from_item = (commission
|
|
.join(agent, condition=commission.agent == agent.id)
|
|
.join(currency, condition=agent.currency == currency.id))
|
|
return from_item, tables, withs
|
|
|
|
@classmethod
|
|
def _columns(cls, tables, withs):
|
|
commission = tables['commission']
|
|
agent = tables['commission.agent']
|
|
currency = tables['commission.agent.currency']
|
|
return [
|
|
cls._column_id(tables, withs).as_('id'),
|
|
commission.agent.as_('agent'),
|
|
agent.currency.as_('currency'),
|
|
Count(commission.id, distinct=True).as_('number'),
|
|
Round(
|
|
Sum(Coalesce(commission.base_amount, 0)),
|
|
currency.digits).as_('base_amount'),
|
|
Round(Sum(commission.amount), price_digits[1]).as_('amount'),
|
|
]
|
|
|
|
@classmethod
|
|
def _column_id(cls, tables, withs):
|
|
commission = tables['commission']
|
|
return commission.agent
|
|
|
|
@classmethod
|
|
def _group_by(cls, tables, withs):
|
|
commission = tables['commission']
|
|
agent = tables['commission.agent']
|
|
currency = tables['commission.agent.currency']
|
|
return [commission.agent, agent.currency, currency.digits]
|
|
|
|
@classmethod
|
|
def _where(cls, tables, withs):
|
|
context = Transaction().context
|
|
commission = tables['commission']
|
|
agent = tables['commission.agent']
|
|
where = agent.type_ == cls._get_agent_type(context.get('type', 'out'))
|
|
from_date = context.get('from_date')
|
|
if from_date:
|
|
where &= commission.date >= from_date
|
|
to_date = context.get('to_date')
|
|
if to_date:
|
|
where &= commission.date <= to_date
|
|
if context.get('invoiced'):
|
|
where &= commission.invoice_line != Null
|
|
return where
|
|
|
|
@classmethod
|
|
def _get_agent_type(cls, type):
|
|
return {
|
|
'out': 'agent',
|
|
'in': 'principal',
|
|
}.get(type)
|
|
|
|
@property
|
|
def time_series_all(self):
|
|
delta = self._period_delta()
|
|
for ts, next_ts in pairwise_longest(self.time_series or []):
|
|
yield ts
|
|
if delta and next_ts:
|
|
date = ts.date + delta
|
|
while date < next_ts.date:
|
|
yield None
|
|
date += delta
|
|
|
|
@classmethod
|
|
def _period_delta(cls):
|
|
context = Transaction().context
|
|
return {
|
|
'year': relativedelta(years=1),
|
|
'month': relativedelta(months=1),
|
|
'day': relativedelta(days=1),
|
|
}.get(context.get('period'))
|
|
|
|
def get_trend(self, name):
|
|
name = name[:-len('_trend')]
|
|
return sparkline([
|
|
getattr(ts, name, 0) or 0 for ts in self.time_series_all])
|
|
|
|
def get_rec_name(self, name):
|
|
return self.agent.rec_name
|
|
|
|
@classmethod
|
|
def search_rec_name(cls, name, clause):
|
|
return [('agent.rec_name', *clause[1:])]
|
|
|
|
|
|
class AgentTimeseries(Agent):
|
|
__name__ = 'commission.reporting.agent.time_series'
|
|
|
|
date = fields.Date("Date")
|
|
time_series = None
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super().__setup__()
|
|
cls._order.insert(0, ('date', 'ASC'))
|
|
|
|
@classmethod
|
|
def _columns(cls, tables, withs):
|
|
return super()._columns(tables, withs) + [
|
|
cls._column_date(tables, withs).as_('date')]
|
|
|
|
@classmethod
|
|
def _column_id(cls, tables, withs):
|
|
commission = tables['commission']
|
|
return Min(commission.id)
|
|
|
|
@classmethod
|
|
def _column_date(cls, tables, withs):
|
|
context = Transaction().context
|
|
commission = tables['commission']
|
|
date = DateTrunc(context.get('period'), commission.date)
|
|
date = cls.date.sql_cast(date)
|
|
return date
|
|
|
|
@classmethod
|
|
def _group_by(cls, tables, withs):
|
|
return super()._group_by(tables, withs) + [
|
|
cls._column_date(tables, withs)]
|
|
|
|
|
|
class Context(ModelView):
|
|
__name__ = 'commission.reporting.context'
|
|
|
|
type = fields.Selection([
|
|
('in', "Incoming"),
|
|
('out', "Outgoing"),
|
|
], "Type", required=True)
|
|
from_date = fields.Date("From Date",
|
|
domain=[
|
|
If(Eval('to_date') & Eval('from_date'),
|
|
('from_date', '<=', Eval('to_date')),
|
|
()),
|
|
])
|
|
to_date = fields.Date("To Date",
|
|
domain=[
|
|
If(Eval('from_date') & Eval('to_date'),
|
|
('to_date', '>=', Eval('from_date')),
|
|
()),
|
|
])
|
|
period = fields.Selection([
|
|
('year', "Year"),
|
|
('month', "Month"),
|
|
('day', "Day"),
|
|
], "Period", required=True)
|
|
invoiced = fields.Boolean(
|
|
"Invoiced",
|
|
help="Only include invoiced commissions.")
|
|
|
|
@classmethod
|
|
def default_type(cls):
|
|
return Transaction().context.get('type', 'out')
|
|
|
|
@classmethod
|
|
def default_from_date(cls):
|
|
pool = Pool()
|
|
Date = pool.get('ir.date')
|
|
context = Transaction().context
|
|
if 'from_date' in context:
|
|
return context['from_date']
|
|
return Date.today() - relativedelta(years=1)
|
|
|
|
@classmethod
|
|
def default_to_date(cls):
|
|
pool = Pool()
|
|
Date = pool.get('ir.date')
|
|
context = Transaction().context
|
|
if 'to_date' in context:
|
|
return context['to_date']
|
|
return Date.today()
|
|
|
|
@classmethod
|
|
def default_period(cls):
|
|
return Transaction().context.get('period', 'month')
|