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.
132 lines
5.7 KiB
132 lines
5.7 KiB
# -*- coding: utf-8 -*-
|
|
# © 2015 Therp BV <http://therp.nl>
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|
import collections
|
|
try:
|
|
import sqlparse
|
|
except ImportError as err:
|
|
import logging
|
|
logging.debug(err)
|
|
import datetime
|
|
from psycopg2.extensions import AsIs
|
|
from dateutil.relativedelta import relativedelta
|
|
from openerp import api, models, fields
|
|
|
|
|
|
class AnalyticEntriesReport(models.Model):
|
|
_inherit = 'analytic.entries.report'
|
|
|
|
fiscalyear_id = fields.Many2one('account.fiscalyear', 'Fiscal year')
|
|
period_id = fields.Many2one('account.period', 'Fiscal period')
|
|
|
|
def init(self, cr):
|
|
"""Here, we try to be less invasive than the usual blunt overwrite of
|
|
the sql view"""
|
|
# added joins to account_period & account_move_line
|
|
# added appropriate fields to select list and group by
|
|
super(AnalyticEntriesReport, self).init(cr)
|
|
cr.execute("select pg_get_viewdef(%s::regclass)", (self._table,))
|
|
for statement in sqlparse.parse(cr.fetchone()[0]):
|
|
current_keyword = None
|
|
for token in statement:
|
|
if token.is_keyword:
|
|
current_keyword = token
|
|
if isinstance(token, sqlparse.sql.IdentifierList) and\
|
|
current_keyword.value == 'SELECT':
|
|
last = None
|
|
for last in token:
|
|
pass
|
|
token.insert_after(last, sqlparse.sql.Token(
|
|
sqlparse.tokens.Generic,
|
|
',coalesce(ml.period_id, p.id) as period_id,'
|
|
'coalesce(p_from_move.fiscalyear_id, p.fiscalyear_id) '
|
|
'as fiscalyear_id'
|
|
))
|
|
if isinstance(
|
|
token,
|
|
(sqlparse.sql.IdentifierList, sqlparse.sql.Parenthesis)
|
|
) and current_keyword.value == 'FROM':
|
|
def find_table(token):
|
|
if isinstance(token, sqlparse.sql.Identifier) and\
|
|
token.get_real_name() == 'account_analytic_line':
|
|
return token
|
|
if not isinstance(token, collections.Iterable):
|
|
return
|
|
for child_token in token:
|
|
result = find_table(child_token)
|
|
if result:
|
|
return result
|
|
|
|
table = find_table(token)
|
|
assert table
|
|
|
|
table.parent.insert_after(table, sqlparse.sql.Token(
|
|
sqlparse.tokens.Generic,
|
|
' left outer join account_period p '
|
|
'on p.special = False and p.date_start <= a.date '
|
|
'and p.date_stop >= a.date '
|
|
'left outer join account_move_line ml '
|
|
'on a.move_id = ml.id '
|
|
'left outer join account_period p_from_move '
|
|
'on ml.period_id = p_from_move.id '))
|
|
if isinstance(token, sqlparse.sql.IdentifierList) and\
|
|
current_keyword.value == 'GROUP BY':
|
|
last = None
|
|
for last in token:
|
|
pass
|
|
token.insert_after(last, sqlparse.sql.Token(
|
|
sqlparse.tokens.Generic,
|
|
', coalesce(p_from_move.fiscalyear_id,'
|
|
'p.fiscalyear_id),'
|
|
'coalesce(ml.period_id, p.id)'))
|
|
cr.execute("create or replace view %s as (%s)",
|
|
(AsIs(self._table), AsIs(str(statement)[:-1])))
|
|
|
|
@api.model
|
|
def _apply_custom_operators(self, domain):
|
|
adjusted_domain = []
|
|
|
|
for proposition in domain:
|
|
if not isinstance(proposition, tuple) and\
|
|
not isinstance(proposition, list) or\
|
|
len(proposition) != 3:
|
|
# we can't use expression.is_leaf here because of our custom
|
|
# operator
|
|
adjusted_domain.append(proposition)
|
|
continue
|
|
field, operator, value = proposition
|
|
if field.endswith('fiscalyear_id') and operator == 'offset':
|
|
date = datetime.date.today() + relativedelta(years=value)
|
|
fiscalyear_id = self.env['account.fiscalyear'].find(dt=date)
|
|
adjusted_domain.append((field, '=', fiscalyear_id))
|
|
elif field.endswith('period_id') and operator == 'offset':
|
|
current_period = self.env['account.period'].with_context(
|
|
account_period_prefer_normal=True).find()
|
|
|
|
direction = '>='
|
|
if value < 0:
|
|
direction = '<='
|
|
|
|
periods = current_period.search(
|
|
[
|
|
('date_start', direction, current_period.date_start),
|
|
('special', '=', False),
|
|
], limit=(abs(value) + 1) or 1, order='date_start ' +
|
|
('asc' if direction == '>=' else 'desc')
|
|
)
|
|
|
|
adjusted_domain.append((field, '=', periods[value].id))
|
|
else:
|
|
adjusted_domain.append(proposition)
|
|
|
|
return adjusted_domain
|
|
|
|
@api.model
|
|
def read_group(self, domain, fields, groupby, offset=0, limit=None,
|
|
orderby=False, lazy=True):
|
|
'''Override read_group to respect filters whose domain can't be
|
|
computed on the client side'''
|
|
adjusted_domain = self._apply_custom_operators(domain)
|
|
return super(AnalyticEntriesReport, self).read_group(
|
|
adjusted_domain, fields, groupby,
|
|
offset=offset, limit=limit, orderby=orderby, lazy=lazy)
|