[IMP] Refactor improvements using AEP
parent
f6a073f71f
commit
dcf873acd9
|
@ -23,3 +23,4 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from . import mis_builder
|
from . import mis_builder
|
||||||
|
from . import aep
|
||||||
|
|
|
@ -33,22 +33,18 @@ from openerp.tools.safe_eval import safe_eval
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
from openerp import tools
|
from openerp import tools
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from aep import AccountingExpressionProcessor
|
||||||
|
from openerp.api import Environment
|
||||||
|
|
||||||
|
|
||||||
FUNCTION = [('credit', 'cred'),
|
FUNCTION = [('credit', 'crd'),
|
||||||
('debit', 'deb'),
|
('debit', 'deb'),
|
||||||
('balance', 'bal')
|
('balance', 'bal')
|
||||||
]
|
]
|
||||||
|
|
||||||
FUNCTION_LIST = [x[1] for x in FUNCTION]
|
FUNCTION_LIST = [x[1] for x in FUNCTION]
|
||||||
|
|
||||||
PARAMETERS = ['s', 'i', '']
|
PARAMETERS = ['s', 'i', 'e', 'p', '']
|
||||||
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):
|
||||||
|
@ -90,39 +86,7 @@ def _get_sufix(is_solde=False, is_initial=False):
|
||||||
|
|
||||||
|
|
||||||
def _get_prefix(function, is_solde=False, is_initial=False):
|
def _get_prefix(function, is_solde=False, is_initial=False):
|
||||||
return function + _get_sufix(is_solde=is_solde, is_initial=is_initial) \
|
return function + _get_sufix(is_solde=is_solde, is_initial=is_initial)
|
||||||
+ SEPARATOR
|
|
||||||
|
|
||||||
|
|
||||||
def _python_account_var(function, account_code, is_solde=False,
|
|
||||||
is_initial=False):
|
|
||||||
prefix = _get_prefix(function, is_solde=is_solde, is_initial=is_initial)
|
|
||||||
return prefix + re.sub(r'\W', '_', account_code)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO : To review
|
|
||||||
def _get_account_code(account_var):
|
|
||||||
res = re.findall(r'_(\d+)', account_var)
|
|
||||||
assert len(res) == 1
|
|
||||||
return res[0]
|
|
||||||
|
|
||||||
|
|
||||||
# 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:
|
|
||||||
domain_list.extend(re.findall(r'\b%s[%s]?_\w+(\[.+?\])' %
|
|
||||||
(function, PARAMETERS_STR), expr))
|
|
||||||
for domain in domain_list:
|
|
||||||
expr = expr.replace(domain, domain_mapping[domain])
|
|
||||||
return expr
|
|
||||||
|
|
||||||
|
|
||||||
# TODO : To review
|
# TODO : To review
|
||||||
|
@ -131,9 +95,11 @@ def _get_account_vars_in_expr(expr, res_vars, domain_mapping, is_solde=False,
|
||||||
for function in FUNCTION_LIST:
|
for function in FUNCTION_LIST:
|
||||||
prefix = _get_prefix(function, is_solde=is_solde,
|
prefix = _get_prefix(function, is_solde=is_solde,
|
||||||
is_initial=is_initial)
|
is_initial=is_initial)
|
||||||
find_res = re.findall(r'\b%s\w+(?:\[.+?\])?' % prefix, expr)
|
find_res = re.findall(r'\b%s(?:_[0-9]+|\[.*?\])(?:\[.+?\])?' % prefix,
|
||||||
|
expr)
|
||||||
for item in find_res:
|
for item in find_res:
|
||||||
match = re.match(r'\b(%s)(\w+)(\[.+?\])?' % prefix, item)
|
match = re.match(r'\b(%s)(_[0-9]+|\[.*?\])(\[.+?\])?' % prefix,
|
||||||
|
item)
|
||||||
var_tuple = match.groups()
|
var_tuple = match.groups()
|
||||||
domain = "" if var_tuple[2] is None else var_tuple[2]
|
domain = "" if var_tuple[2] is None else var_tuple[2]
|
||||||
key = ""
|
key = ""
|
||||||
|
@ -146,22 +112,19 @@ def _get_account_vars_in_expr(expr, res_vars, domain_mapping, is_solde=False,
|
||||||
key_domain = (key, domain)
|
key_domain = (key, domain)
|
||||||
if not res_vars.get(key_domain, False):
|
if not res_vars.get(key_domain, False):
|
||||||
res_vars[key_domain] = set()
|
res_vars[key_domain] = set()
|
||||||
res_vars[key_domain].add(var_tuple[1])
|
if var_tuple[1].startswith('_'):
|
||||||
|
account_codes = var_tuple[1][1:]
|
||||||
|
else:
|
||||||
def _get_account_vars_in_report(report, domain_mapping, is_solde=False,
|
account_codes = var_tuple[1][1:-1]
|
||||||
is_initial=False):
|
account_codes = [a.strip() for a in account_codes.split(',')]
|
||||||
res_vars = {}
|
account_codes_set = set(account_codes)
|
||||||
for kpi in report.kpi_ids:
|
res_vars[key_domain] |= account_codes_set
|
||||||
_get_account_vars_in_expr(kpi.expression, res_vars, domain_mapping,
|
|
||||||
is_solde, is_initial)
|
|
||||||
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 + SEPARATOR):
|
if name.startswith(item + param):
|
||||||
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)
|
||||||
|
|
||||||
|
@ -624,64 +587,25 @@ class mis_report_instance_period(orm.Model):
|
||||||
('date', '<=', c.date_to)])
|
('date', '<=', c.date_to)])
|
||||||
return domain_list
|
return domain_list
|
||||||
|
|
||||||
def _fetch_account(self, cr, uid, company_id, account_vars, context=None,
|
def compute_period_domain(self, cr, uid, period_report, is_solde,
|
||||||
is_solde=False, is_initial=False):
|
is_initial, context=None):
|
||||||
account_obj = self.pool['account.account']
|
|
||||||
account_move_line_obj = self.pool['account.move.line']
|
|
||||||
# TODO: use child of company_id?
|
|
||||||
# first fetch all codes and filter the one we need+
|
|
||||||
balances = {}
|
|
||||||
for key_domain, account_code in account_vars.iteritems():
|
|
||||||
key, domain = key_domain
|
|
||||||
account_ids = account_obj.search(
|
|
||||||
cr, uid,
|
|
||||||
['|', ('company_id', '=', False),
|
|
||||||
('company_id', '=', company_id),
|
|
||||||
('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)
|
|
||||||
context.update({'query': where_clause,
|
|
||||||
'query_params': where_clause_params})
|
|
||||||
account_datas = account_obj\
|
|
||||||
.read(cr, uid, account_ids,
|
|
||||||
['code', 'balance', 'credit', 'debit'], context=context)
|
|
||||||
for account_data in account_datas:
|
|
||||||
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] = account_data[item[0]]
|
|
||||||
|
|
||||||
return balances
|
|
||||||
|
|
||||||
def _get_context_period(self, cr, uid, report_period, is_solde=False,
|
|
||||||
is_initial=False, context=None):
|
|
||||||
context_period = {}
|
|
||||||
move_obj = self.pool['account.move']
|
|
||||||
period_obj = self.pool['account.period']
|
period_obj = self.pool['account.period']
|
||||||
|
move_obj = self.pool['account.move']
|
||||||
|
domain_list = []
|
||||||
|
target_move = period_report.report_instance_id.target_move
|
||||||
|
if target_move == 'posted':
|
||||||
|
domain_list.append(('move_id.state', '=', target_move))
|
||||||
if not is_solde and not is_initial:
|
if not is_solde and not is_initial:
|
||||||
if report_period.period_from:
|
if period_report.period_from:
|
||||||
context_period.\
|
compute_period_ids = period_obj.build_ctx_periods(
|
||||||
update({'period_from': report_period.period_from.id,
|
cr, uid, period_report.period_from.id,
|
||||||
'period_to': report_period.period_to.id})
|
period_report.period_to.id)
|
||||||
|
domain_list.extend([('period_id', 'in', compute_period_ids)])
|
||||||
else:
|
else:
|
||||||
context_period.update({'date_from': report_period.date_from,
|
domain_list.extend([('date', '>=', period_report.date_from),
|
||||||
'date_to': report_period.date_to})
|
('date', '<=', period_report.date_to)])
|
||||||
else:
|
elif period_report.period_from and period_report.period_to:
|
||||||
period_to = report_period.period_to
|
period_to = period_report.period_to
|
||||||
if is_initial:
|
if is_initial:
|
||||||
move_id = move_obj.search(
|
move_id = move_obj.search(
|
||||||
cr, uid, [('period_id.special', '=', False),
|
cr, uid, [('period_id.special', '=', False),
|
||||||
|
@ -694,7 +618,7 @@ class mis_report_instance_period(orm.Model):
|
||||||
else:
|
else:
|
||||||
computed_period_to = self.pool['account.period'].search(
|
computed_period_to = self.pool['account.period'].search(
|
||||||
cr, uid, [('company_id', '=',
|
cr, uid, [('company_id', '=',
|
||||||
report_period.company_id.id)],
|
period_report.company_id.id)],
|
||||||
order='date_start desc', limit=1)[0]
|
order='date_start desc', limit=1)[0]
|
||||||
# Change start period to search correctly period from
|
# Change start period to search correctly period from
|
||||||
period_to = period_obj.browse(cr, uid, [computed_period_to],
|
period_to = period_obj.browse(cr, uid, [computed_period_to],
|
||||||
|
@ -710,80 +634,15 @@ class mis_report_instance_period(orm.Model):
|
||||||
else:
|
else:
|
||||||
computed_period_from = self.pool['account.period'].search(
|
computed_period_from = self.pool['account.period'].search(
|
||||||
cr, uid, [('company_id', '=',
|
cr, uid, [('company_id', '=',
|
||||||
report_period.company_id.id)],
|
period_report.company_id.id)],
|
||||||
order='date_start', limit=1)[0]
|
order='date_start', limit=1)[0]
|
||||||
context_period.update({'period_from': computed_period_from,
|
compute_period_ids = period_obj.build_ctx_periods(
|
||||||
'period_to': period_to.id})
|
cr, uid, computed_period_from, period_to.id)
|
||||||
return context_period
|
domain_list.extend([('period_id', 'in', compute_period_ids)])
|
||||||
|
return domain_list
|
||||||
def _fetch_balances(self, cr, uid, c, account_vars, context=None):
|
|
||||||
""" fetch the general account balances for the given period
|
|
||||||
|
|
||||||
returns a dictionary {bal_<account.code>: account.balance}
|
|
||||||
"""
|
|
||||||
if not account_vars:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
if context is None:
|
|
||||||
context = {}
|
|
||||||
|
|
||||||
search_ctx = dict(context)
|
|
||||||
search_ctx.update(self._get_context_period(cr, uid, c,
|
|
||||||
context=context))
|
|
||||||
# fetch balances
|
|
||||||
return self._fetch_account(cr, uid, c.company_id.id, account_vars,
|
|
||||||
search_ctx)
|
|
||||||
|
|
||||||
def _fetch_balances_solde(self, cr, uid, c, account_vars, context=None):
|
|
||||||
""" fetch the general account balances solde at the end of
|
|
||||||
the given period
|
|
||||||
|
|
||||||
the period from is computed by searching the last special period
|
|
||||||
with journal entries.
|
|
||||||
If nothing is found, the first period is used.
|
|
||||||
|
|
||||||
returns a dictionary {bals_<account.code>: account.balance.solde}
|
|
||||||
"""
|
|
||||||
if context is None:
|
|
||||||
context = {}
|
|
||||||
balances = {}
|
|
||||||
if not account_vars:
|
|
||||||
return balances
|
|
||||||
|
|
||||||
search_ctx = dict(context)
|
|
||||||
if c.period_to:
|
|
||||||
search_ctx.update(self._get_context_period(cr, uid, c,
|
|
||||||
is_solde=True,
|
|
||||||
context=context))
|
|
||||||
else:
|
|
||||||
return balances
|
|
||||||
|
|
||||||
# fetch balances
|
|
||||||
return self._fetch_account(cr, uid, c.company_id.id, account_vars,
|
|
||||||
search_ctx, is_solde=True)
|
|
||||||
|
|
||||||
def _fetch_balances_initial(self, cr, uid, c, account_vars, context=None):
|
|
||||||
if context is None:
|
|
||||||
context = {}
|
|
||||||
balances = {}
|
|
||||||
if not account_vars:
|
|
||||||
return balances
|
|
||||||
|
|
||||||
search_ctx = dict(context)
|
|
||||||
if c.period_to:
|
|
||||||
search_ctx.update(self._get_context_period(cr, uid, c,
|
|
||||||
is_initial=True,
|
|
||||||
context=context))
|
|
||||||
else:
|
|
||||||
return balances
|
|
||||||
|
|
||||||
# fetch balances
|
|
||||||
return self._fetch_account(cr, uid, c.company_id.id, account_vars,
|
|
||||||
search_ctx, is_initial=True)
|
|
||||||
|
|
||||||
def _fetch_queries(self, cr, uid, c, context):
|
def _fetch_queries(self, cr, uid, c, context):
|
||||||
res = {}
|
res = {}
|
||||||
|
|
||||||
report = c.report_instance_id.report_id
|
report = c.report_instance_id.report_id
|
||||||
for query in report.query_ids:
|
for query in report.query_ids:
|
||||||
obj = self.pool[query.model_id.model]
|
obj = self.pool[query.model_id.model]
|
||||||
|
@ -806,11 +665,9 @@ class mis_report_instance_period(orm.Model):
|
||||||
obj_datas = obj.read(
|
obj_datas = obj.read(
|
||||||
cr, uid, obj_ids, field_names, context=context)
|
cr, uid, obj_ids, field_names, context=context)
|
||||||
res[query.name] = [AutoStruct(**d) for d in obj_datas]
|
res[query.name] = [AutoStruct(**d) for d in obj_datas]
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _compute(self, cr, uid, lang_id, c, account_vars, accounts_vars,
|
def _compute(self, cr, uid, lang_id, c, aep, context=None):
|
||||||
accounti_vars, domain_mapping, context=None):
|
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
|
@ -826,21 +683,20 @@ class mis_report_instance_period(orm.Model):
|
||||||
'len': len,
|
'len': len,
|
||||||
'avg': lambda l: sum(l) / float(len(l)),
|
'avg': lambda l: sum(l) / float(len(l)),
|
||||||
}
|
}
|
||||||
localdict.update(self._fetch_balances(cr, uid, c, account_vars,
|
domain_p = self.compute_period_domain(cr, uid, c, False, False,
|
||||||
context=context))
|
context=context)
|
||||||
localdict.update(self._fetch_balances_solde(cr, uid, c, accounts_vars,
|
domain_s = self.compute_period_domain(cr, uid, c, True, False,
|
||||||
context=context))
|
context=context)
|
||||||
localdict.update(self._fetch_balances_initial(cr, uid, c,
|
domain_i = self.compute_period_domain(cr, uid, c, False, True,
|
||||||
accounti_vars,
|
context=context)
|
||||||
context=context))
|
aep.do_queries(domain_p, domain_i, domain_s)
|
||||||
localdict.update(self._fetch_queries(cr, uid, c,
|
localdict.update(self._fetch_queries(cr, uid, c,
|
||||||
context=context))
|
context=context))
|
||||||
|
|
||||||
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_eval_expression = aep.replace_expr(kpi.expression)
|
||||||
kpi_val = safe_eval(kpi_eval_expression, localdict)
|
kpi_val = safe_eval(kpi_eval_expression, localdict)
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
kpi_val = None
|
kpi_val = None
|
||||||
|
@ -978,28 +834,20 @@ class mis_report_instance(orm.Model):
|
||||||
# empty line name for header
|
# empty line name for header
|
||||||
header = OrderedDict()
|
header = OrderedDict()
|
||||||
header[''] = {'kpi_name': '', 'cols': [], 'default_style': ''}
|
header[''] = {'kpi_name': '', 'cols': [], 'default_style': ''}
|
||||||
|
env = Environment(cr, uid, {})
|
||||||
|
aep = AccountingExpressionProcessor(env)
|
||||||
# initialize lines with kpi
|
# initialize lines with kpi
|
||||||
for kpi in r.report_id.kpi_ids:
|
for kpi in r.report_id.kpi_ids:
|
||||||
|
aep.parse_expr(kpi.expression)
|
||||||
content[kpi.name] = {'kpi_name': kpi.description,
|
content[kpi.name] = {'kpi_name': kpi.description,
|
||||||
'cols': [],
|
'cols': [],
|
||||||
'default_style': ''}
|
'default_style': ''}
|
||||||
|
aep.done_parsing([('company_id', '=', r.company_id.id)])
|
||||||
report_instance_period_obj = self.pool.get(
|
report_instance_period_obj = self.pool.get(
|
||||||
'mis.report.instance.period')
|
'mis.report.instance.period')
|
||||||
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,
|
|
||||||
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,
|
|
||||||
domain_mapping,
|
|
||||||
is_initial=True)
|
|
||||||
|
|
||||||
lang = self.pool['res.users'].read(
|
lang = self.pool['res.users'].read(
|
||||||
cr, uid, uid, ['lang'], context=context)['lang']
|
cr, uid, uid, ['lang'], context=context)['lang']
|
||||||
lang_id = self.pool['res.lang'].search(
|
lang_id = self.pool['res.lang'].search(
|
||||||
|
@ -1021,8 +869,7 @@ class mis_report_instance(orm.Model):
|
||||||
period.date_from))
|
period.date_from))
|
||||||
# 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, aep, 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']
|
||||||
|
|
|
@ -29,7 +29,7 @@ openerp.mis_builder = function(instance) {
|
||||||
var period_id = JSON.parse($(event.target).data("period-id"));
|
var period_id = JSON.parse($(event.target).data("period-id"));
|
||||||
var period_name = JSON.parse($(event.target).data("period-name"));
|
var period_name = JSON.parse($(event.target).data("period-name"));
|
||||||
var self = this;
|
var self = this;
|
||||||
if (!(val === null) && (val_c.indexOf('bal_') >=0)){
|
if (!(val === null) && (val_c.indexOf('bal') >=0)){
|
||||||
new instance.web.Model("mis.report.instance.period").call(
|
new instance.web.Model("mis.report.instance.period").call(
|
||||||
"compute_domain",
|
"compute_domain",
|
||||||
[period_id, val_c],
|
[period_id, val_c],
|
||||||
|
|
Loading…
Reference in New Issue