Browse Source

[IMP] Refactor improvements using AEP

pull/86/head
Adrien Peiffer (ACSONE) 9 years ago
committed by Stéphane Bidoul
parent
commit
dcf873acd9
  1. 1
      mis_builder/models/__init__.py
  2. 259
      mis_builder/models/mis_builder.py
  3. 2
      mis_builder/static/src/js/mis_builder.js

1
mis_builder/models/__init__.py

@ -23,3 +23,4 @@
##############################################################################
from . import mis_builder
from . import aep

259
mis_builder/models/mis_builder.py

@ -33,22 +33,18 @@ from openerp.tools.safe_eval import safe_eval
from openerp.tools.translate import _
from openerp import tools
from collections import OrderedDict
from aep import AccountingExpressionProcessor
from openerp.api import Environment
FUNCTION = [('credit', 'cred'),
FUNCTION = [('credit', 'crd'),
('debit', 'deb'),
('balance', 'bal')
]
FUNCTION_LIST = [x[1] for x in FUNCTION]
PARAMETERS = ['s', 'i', '']
PARAMETERS_WITHOUT_BLANK = [x for x in PARAMETERS if x != '']
SEPARATOR = '_'
PARAMETERS_STR = ''.join(PARAMETERS)
FUNCTION_CONDITION = '|'.join(PARAMETERS_WITHOUT_BLANK)
PARAMETERS = ['s', 'i', 'e', 'p', '']
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):
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
return function + _get_sufix(is_solde=is_solde, is_initial=is_initial)
# 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:
prefix = _get_prefix(function, is_solde=is_solde,
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:
match = re.match(r'\b(%s)(\w+)(\[.+?\])?' % prefix, item)
match = re.match(r'\b(%s)(_[0-9]+|\[.*?\])(\[.+?\])?' % prefix,
item)
var_tuple = match.groups()
domain = "" if var_tuple[2] is None else var_tuple[2]
key = ""
@ -146,22 +112,19 @@ def _get_account_vars_in_expr(expr, res_vars, domain_mapping, is_solde=False,
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])
def _get_account_vars_in_report(report, domain_mapping, is_solde=False,
is_initial=False):
res_vars = {}
for kpi in report.kpi_ids:
_get_account_vars_in_expr(kpi.expression, res_vars, domain_mapping,
is_solde, is_initial)
return res_vars
if var_tuple[1].startswith('_'):
account_codes = var_tuple[1][1:]
else:
account_codes = var_tuple[1][1:-1]
account_codes = [a.strip() for a in account_codes.split(',')]
account_codes_set = set(account_codes)
res_vars[key_domain] |= account_codes_set
def _is_valid_python_var(name):
for item in FUNCTION_LIST:
for param in PARAMETERS:
if name.startswith(item + param + SEPARATOR):
if name.startswith(item + param):
return False
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)])
return domain_list
def _fetch_account(self, cr, uid, company_id, account_vars, context=None,
is_solde=False, is_initial=False):
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']
def compute_period_domain(self, cr, uid, period_report, is_solde,
is_initial, context=None):
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 report_period.period_from:
context_period.\
update({'period_from': report_period.period_from.id,
'period_to': report_period.period_to.id})
if period_report.period_from:
compute_period_ids = period_obj.build_ctx_periods(
cr, uid, period_report.period_from.id,
period_report.period_to.id)
domain_list.extend([('period_id', 'in', compute_period_ids)])
else:
context_period.update({'date_from': report_period.date_from,
'date_to': report_period.date_to})
else:
period_to = report_period.period_to
domain_list.extend([('date', '>=', period_report.date_from),
('date', '<=', period_report.date_to)])
elif period_report.period_from and period_report.period_to:
period_to = period_report.period_to
if is_initial:
move_id = move_obj.search(
cr, uid, [('period_id.special', '=', False),
@ -694,7 +618,7 @@ class mis_report_instance_period(orm.Model):
else:
computed_period_to = self.pool['account.period'].search(
cr, uid, [('company_id', '=',
report_period.company_id.id)],
period_report.company_id.id)],
order='date_start desc', limit=1)[0]
# Change start period to search correctly period from
period_to = period_obj.browse(cr, uid, [computed_period_to],
@ -710,80 +634,15 @@ class mis_report_instance_period(orm.Model):
else:
computed_period_from = self.pool['account.period'].search(
cr, uid, [('company_id', '=',
report_period.company_id.id)],
period_report.company_id.id)],
order='date_start', limit=1)[0]
context_period.update({'period_from': computed_period_from,
'period_to': period_to.id})
return context_period
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)
compute_period_ids = period_obj.build_ctx_periods(
cr, uid, computed_period_from, period_to.id)
domain_list.extend([('period_id', 'in', compute_period_ids)])
return domain_list
def _fetch_queries(self, cr, uid, c, context):
res = {}
report = c.report_instance_id.report_id
for query in report.query_ids:
obj = self.pool[query.model_id.model]
@ -806,11 +665,9 @@ class mis_report_instance_period(orm.Model):
obj_datas = obj.read(
cr, uid, obj_ids, field_names, context=context)
res[query.name] = [AutoStruct(**d) for d in obj_datas]
return res
def _compute(self, cr, uid, lang_id, c, account_vars, accounts_vars,
accounti_vars, domain_mapping, context=None):
def _compute(self, cr, uid, lang_id, c, aep, context=None):
if context is None:
context = {}
@ -826,21 +683,20 @@ class mis_report_instance_period(orm.Model):
'len': len,
'avg': lambda l: sum(l) / float(len(l)),
}
localdict.update(self._fetch_balances(cr, uid, c, account_vars,
context=context))
localdict.update(self._fetch_balances_solde(cr, uid, c, accounts_vars,
context=context))
localdict.update(self._fetch_balances_initial(cr, uid, c,
accounti_vars,
context=context))
domain_p = self.compute_period_domain(cr, uid, c, False, False,
context=context)
domain_s = self.compute_period_domain(cr, uid, c, True, False,
context=context)
domain_i = self.compute_period_domain(cr, uid, c, False, True,
context=context)
aep.do_queries(domain_p, domain_i, domain_s)
localdict.update(self._fetch_queries(cr, uid, c,
context=context))
for kpi in c.report_instance_id.report_id.kpi_ids:
try:
kpi_eval_expression = _get_eval_expression(kpi.expression,
domain_mapping)
kpi_val_comment = kpi.expression
kpi_eval_expression = aep.replace_expr(kpi.expression)
kpi_val = safe_eval(kpi_eval_expression, localdict)
except ZeroDivisionError:
kpi_val = None
@ -978,28 +834,20 @@ class mis_report_instance(orm.Model):
# empty line name for header
header = OrderedDict()
header[''] = {'kpi_name': '', 'cols': [], 'default_style': ''}
env = Environment(cr, uid, {})
aep = AccountingExpressionProcessor(env)
# initialize lines with kpi
for kpi in r.report_id.kpi_ids:
aep.parse_expr(kpi.expression)
content[kpi.name] = {'kpi_name': kpi.description,
'cols': [],
'default_style': ''}
aep.done_parsing([('company_id', '=', r.company_id.id)])
report_instance_period_obj = self.pool.get(
'mis.report.instance.period')
kpi_obj = self.pool.get('mis.report.kpi')
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(
cr, uid, uid, ['lang'], context=context)['lang']
lang_id = self.pool['res.lang'].search(
@ -1021,8 +869,7 @@ class mis_report_instance(orm.Model):
period.date_from))
# compute kpi values
values = report_instance_period_obj._compute(
cr, uid, lang_id, period, account_vars, accounts_vars,
accounti_vars, domain_mapping, context=context)
cr, uid, lang_id, period, aep, context=context)
period_values[period.name] = values
for key in values:
content[key]['default_style'] = values[key]['default_style']

2
mis_builder/static/src/js/mis_builder.js

@ -29,7 +29,7 @@ openerp.mis_builder = function(instance) {
var period_id = JSON.parse($(event.target).data("period-id"));
var period_name = JSON.parse($(event.target).data("period-name"));
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(
"compute_domain",
[period_id, val_c],

Loading…
Cancel
Save