[ADD] Add possibility to define domain on function
parent
0d57782890
commit
b34f094a23
|
@ -23,3 +23,4 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from . import mis_builder
|
from . import mis_builder
|
||||||
|
from . import account_account
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Authors: Adrien Peiffer
|
||||||
|
# Copyright (c) 2015 Acsone SA/NV (http://www.acsone.eu)
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
from openerp.osv import orm
|
||||||
|
|
||||||
|
|
||||||
|
class account_account(orm.Model):
|
||||||
|
_inherit = 'account.account'
|
||||||
|
|
||||||
|
def _compute(self, cr, uid, ids, field_names, arg=None, context=None,
|
||||||
|
query='', query_params=()):
|
||||||
|
return self.__compute(cr, uid, ids, field_names, arg=arg,
|
||||||
|
context=context, query=query,
|
||||||
|
query_params=query_params)
|
|
@ -42,7 +42,13 @@ FUNCTION = [('credit', 'cred'),
|
||||||
|
|
||||||
FUNCTION_LIST = [x[1] for x in FUNCTION]
|
FUNCTION_LIST = [x[1] for x in FUNCTION]
|
||||||
|
|
||||||
PARAMETERS = ['s_', 'i_', '_']
|
PARAMETERS = ['s', 'i', '']
|
||||||
|
PARAMETERS_WITHOUT_BLANK = [x for x in PARAMETERS if x != '']
|
||||||
|
SEPARATOR = '_'
|
||||||
|
|
||||||
|
PARAMETERS_STR = ''.join(PARAMETERS)
|
||||||
|
|
||||||
|
FUNCTION_CONDITION = '|'.join(PARAMETERS_WITHOUT_BLANK)
|
||||||
|
|
||||||
|
|
||||||
class AutoStruct(object):
|
class AutoStruct(object):
|
||||||
|
@ -76,54 +82,84 @@ def _python_var(var_str):
|
||||||
|
|
||||||
def _get_sufix(is_solde=False, is_initial=False):
|
def _get_sufix(is_solde=False, is_initial=False):
|
||||||
if is_solde:
|
if is_solde:
|
||||||
return 's_'
|
return 's'
|
||||||
elif is_initial:
|
elif is_initial:
|
||||||
return 'i_'
|
return 'i'
|
||||||
else:
|
else:
|
||||||
return '_'
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
def _get_prefix(function, is_solde=False, is_initial=False):
|
||||||
|
return function + _get_sufix(is_solde=is_solde, is_initial=is_initial) \
|
||||||
|
+ SEPARATOR
|
||||||
|
|
||||||
|
|
||||||
def _python_account_var(function, account_code, is_solde=False,
|
def _python_account_var(function, account_code, is_solde=False,
|
||||||
is_initial=False):
|
is_initial=False):
|
||||||
prefix = function + _get_sufix(is_solde=is_solde, is_initial=is_initial)
|
prefix = _get_prefix(function, is_solde=is_solde, is_initial=is_initial)
|
||||||
return prefix + re.sub(r'\W', '_', account_code)
|
return prefix + re.sub(r'\W', '_', account_code)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO : To review
|
||||||
def _get_account_code(account_var):
|
def _get_account_code(account_var):
|
||||||
res = re.findall(r'_(\d+)', account_var)
|
res = re.findall(r'_(\d+)', account_var)
|
||||||
assert len(res) == 1
|
assert len(res) == 1
|
||||||
return res[0]
|
return res[0]
|
||||||
|
|
||||||
|
|
||||||
def _get_account_vars_in_expr(expr, is_solde=False, is_initial=False):
|
# TODO : To review
|
||||||
res = []
|
def _get_account_vars_in_expr(expr, res_vars, is_solde=False, is_initial=False):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# TODO : Not use here, Check in upstream
|
||||||
|
# def _get_vars_in_expr(expr, varnames=None):
|
||||||
|
# if not varnames:
|
||||||
|
# return []
|
||||||
|
# varnames_re = r'\b' + r'\b|\b'.join(varnames) + r'\b'
|
||||||
|
# return re.findall(varnames_re, expr)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_eval_expression(expr, domain_mapping):
|
||||||
|
domain_list = []
|
||||||
for function in FUNCTION_LIST:
|
for function in FUNCTION_LIST:
|
||||||
prefix = function + _get_sufix(is_solde=is_solde,
|
domain_list.extend(re.findall(r'\b%s[%s]?_\w+(\[.+?\])' % (function, PARAMETERS_STR), expr))
|
||||||
is_initial=is_initial)
|
for domain in domain_list:
|
||||||
res.extend(re.findall(r'\b%s\w+' % prefix, expr))
|
expr = expr.replace(domain, domain_mapping[domain])
|
||||||
return res
|
return expr
|
||||||
|
|
||||||
|
|
||||||
def _get_vars_in_expr(expr, varnames=None):
|
def _get_account_vars_in_report(report, domain_mapping, is_solde=False,
|
||||||
if not varnames:
|
is_initial=False):
|
||||||
return []
|
res_vars = {}
|
||||||
varnames_re = r'\b' + r'\b|\b'.join(varnames) + r'\b'
|
domain_count = 0
|
||||||
return re.findall(varnames_re, expr)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_account_vars_in_report(report, is_solde=False, is_initial=False):
|
|
||||||
res = set()
|
|
||||||
for kpi in report.kpi_ids:
|
for kpi in report.kpi_ids:
|
||||||
for account_var in _get_account_vars_in_expr(kpi.expression, is_solde,
|
for function in FUNCTION_LIST:
|
||||||
is_initial):
|
prefix = _get_prefix(function, is_solde=is_solde, is_initial=is_initial)
|
||||||
res.add(account_var)
|
find_res = re.findall(r'\b%s\w+(?:\[.+?\])?' % prefix, kpi.expression)
|
||||||
return res
|
for item in find_res:
|
||||||
|
match = re.match(r'\b(%s)(\w+)(\[.+?\])?' % prefix, item)
|
||||||
|
var_tuple = match.groups()
|
||||||
|
domain = "" if var_tuple[2] is None else var_tuple[2]
|
||||||
|
key = ""
|
||||||
|
if domain != "":
|
||||||
|
if domain not in domain_mapping:
|
||||||
|
key = 'd' + str(domain_count)
|
||||||
|
domain_count += 1
|
||||||
|
domain_mapping[domain] = key
|
||||||
|
else:
|
||||||
|
key = domain_mapping[domain]
|
||||||
|
key_domain = (key, domain)
|
||||||
|
if not res_vars.get(key_domain, False):
|
||||||
|
res_vars[key_domain] = set()
|
||||||
|
res_vars[key_domain].add(var_tuple[1])
|
||||||
|
return res_vars
|
||||||
|
|
||||||
|
|
||||||
def _is_valid_python_var(name):
|
def _is_valid_python_var(name):
|
||||||
for item in FUNCTION_LIST:
|
for item in FUNCTION_LIST:
|
||||||
for param in PARAMETERS:
|
for param in PARAMETERS:
|
||||||
if name.startswith(item + param):
|
if name.startswith(item + param + SEPARATOR):
|
||||||
return False
|
return False
|
||||||
return re.match("[_A-Za-z][_a-zA-Z0-9]*$", name)
|
return re.match("[_A-Za-z][_a-zA-Z0-9]*$", name)
|
||||||
|
|
||||||
|
@ -534,6 +570,7 @@ class mis_report_instance_period(orm.Model):
|
||||||
'Period name should be unique by report'),
|
'Period name should be unique by report'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# TODO : To review
|
||||||
def compute_domain(self, cr, uid, ids, account_, context=None):
|
def compute_domain(self, cr, uid, ids, account_, context=None):
|
||||||
if isinstance(ids, (int, long)):
|
if isinstance(ids, (int, long)):
|
||||||
ids = [ids]
|
ids = [ids]
|
||||||
|
@ -583,32 +620,39 @@ class mis_report_instance_period(orm.Model):
|
||||||
def _fetch_account(self, cr, uid, company_id, account_vars, context=None,
|
def _fetch_account(self, cr, uid, company_id, account_vars, context=None,
|
||||||
is_solde=False, is_initial=False):
|
is_solde=False, is_initial=False):
|
||||||
account_obj = self.pool['account.account']
|
account_obj = self.pool['account.account']
|
||||||
|
account_move_line_obj = self.pool['account.move.line']
|
||||||
# TODO: use child of company_id?
|
# TODO: use child of company_id?
|
||||||
# first fetch all codes and filter the one we need+
|
# first fetch all codes and filter the one we need+
|
||||||
account_code = []
|
|
||||||
for account_var in account_vars:
|
|
||||||
account = _get_account_code(account_var)
|
|
||||||
if account not in account_code:
|
|
||||||
account_code.append(account)
|
|
||||||
account_ids = account_obj.search(
|
|
||||||
cr, uid,
|
|
||||||
['|', ('company_id', '=', False),
|
|
||||||
('company_id', '=', company_id),
|
|
||||||
('code', 'in', account_code)],
|
|
||||||
context=context)
|
|
||||||
|
|
||||||
# fetch balances
|
|
||||||
account_datas = account_obj.read(
|
|
||||||
cr, uid, account_ids, ['code', 'balance', 'credit', 'debit'],
|
|
||||||
context=context)
|
|
||||||
balances = {}
|
balances = {}
|
||||||
for account_data in account_datas:
|
for key_domain, account_code in account_vars.iteritems():
|
||||||
for item in FUNCTION:
|
key, domain = key_domain
|
||||||
key = _python_account_var(item[1], account_data['code'],
|
account_ids = account_obj.search(
|
||||||
is_solde=is_solde,
|
cr, uid,
|
||||||
is_initial=is_initial)
|
['|', ('company_id', '=', False),
|
||||||
assert key not in balances
|
('company_id', '=', company_id),
|
||||||
balances[key] = account_data[item[0]]
|
('code', 'in', list(account_code))],
|
||||||
|
context=context)
|
||||||
|
# fetch balances
|
||||||
|
where_clause = ''
|
||||||
|
where_clause_params = ()
|
||||||
|
if domain != '':
|
||||||
|
domain_eval = safe_eval(domain)
|
||||||
|
query = account_move_line_obj._where_calc(cr, uid, domain_eval, context=context)
|
||||||
|
from_clause, where_clause, where_clause_params = query.get_sql()
|
||||||
|
assert from_clause == '"account_move_line"'
|
||||||
|
where_clause = where_clause.replace("account_move_line", "l")
|
||||||
|
where_clause_params = tuple(where_clause_params)
|
||||||
|
account_datas = self.pool['account.account']._compute(cr, uid, account_ids,['balance', 'credit', 'debit'], arg=None, context=context, query=where_clause, query_params=where_clause_params)
|
||||||
|
for id, fields in account_datas.iteritems():
|
||||||
|
account_data = account_obj.read(cr, uid, [id], ['code'],
|
||||||
|
context=context)[0]
|
||||||
|
for item in FUNCTION:
|
||||||
|
var = _python_account_var(item[1], account_data['code'],
|
||||||
|
is_solde=is_solde,
|
||||||
|
is_initial=is_initial)
|
||||||
|
var = var + key
|
||||||
|
assert key not in balances
|
||||||
|
balances[var] = fields[item[0]]
|
||||||
|
|
||||||
return balances
|
return balances
|
||||||
|
|
||||||
|
@ -755,7 +799,7 @@ class mis_report_instance_period(orm.Model):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _compute(self, cr, uid, lang_id, c, account_vars, accounts_vars,
|
def _compute(self, cr, uid, lang_id, c, account_vars, accounts_vars,
|
||||||
accounti_vars, context=None):
|
accounti_vars, domain_mapping, context=None):
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
|
@ -783,8 +827,10 @@ class mis_report_instance_period(orm.Model):
|
||||||
|
|
||||||
for kpi in c.report_instance_id.report_id.kpi_ids:
|
for kpi in c.report_instance_id.report_id.kpi_ids:
|
||||||
try:
|
try:
|
||||||
|
kpi_eval_expression = _get_eval_expression(kpi.expression,
|
||||||
|
domain_mapping)
|
||||||
kpi_val_comment = kpi.expression
|
kpi_val_comment = kpi.expression
|
||||||
kpi_val = safe_eval(kpi.expression, localdict)
|
kpi_val = safe_eval(kpi_eval_expression, localdict)
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
kpi_val = None
|
kpi_val = None
|
||||||
kpi_val_rendered = '#DIV/0'
|
kpi_val_rendered = '#DIV/0'
|
||||||
|
@ -933,10 +979,14 @@ class mis_report_instance(orm.Model):
|
||||||
kpi_obj = self.pool.get('mis.report.kpi')
|
kpi_obj = self.pool.get('mis.report.kpi')
|
||||||
|
|
||||||
period_values = {}
|
period_values = {}
|
||||||
|
domain_mapping = {}
|
||||||
account_vars = _get_account_vars_in_report(r.report_id)
|
account_vars = _get_account_vars_in_report(r.report_id,
|
||||||
accounts_vars = _get_account_vars_in_report(r.report_id, is_solde=True)
|
domain_mapping)
|
||||||
|
accounts_vars = _get_account_vars_in_report(r.report_id,
|
||||||
|
domain_mapping,
|
||||||
|
is_solde=True)
|
||||||
accounti_vars = _get_account_vars_in_report(r.report_id,
|
accounti_vars = _get_account_vars_in_report(r.report_id,
|
||||||
|
domain_mapping,
|
||||||
is_initial=True)
|
is_initial=True)
|
||||||
|
|
||||||
lang = self.pool['res.users'].read(
|
lang = self.pool['res.users'].read(
|
||||||
|
@ -961,7 +1011,7 @@ class mis_report_instance(orm.Model):
|
||||||
# compute kpi values
|
# compute kpi values
|
||||||
values = report_instance_period_obj._compute(
|
values = report_instance_period_obj._compute(
|
||||||
cr, uid, lang_id, period, account_vars, accounts_vars,
|
cr, uid, lang_id, period, account_vars, accounts_vars,
|
||||||
accounti_vars, context=context)
|
accounti_vars, domain_mapping, context=context)
|
||||||
period_values[period.name] = values
|
period_values[period.name] = values
|
||||||
for key in values:
|
for key in values:
|
||||||
content[key]['default_style'] = values[key]['default_style']
|
content[key]['default_style'] = values[key]['default_style']
|
||||||
|
|
Loading…
Reference in New Issue