From d6f69f08867695191ad582e19d5a53d10e320e5e Mon Sep 17 00:00:00 2001 From: "Adrien Peiffer (ACSONE)" Date: Thu, 23 Apr 2015 14:38:51 +0200 Subject: [PATCH] [IMP] Refactor improvements using AEP --- mis_builder/models/__init__.py | 1 + mis_builder/models/mis_builder.py | 259 +++++------------------ mis_builder/static/src/js/mis_builder.js | 2 +- 3 files changed, 55 insertions(+), 207 deletions(-) diff --git a/mis_builder/models/__init__.py b/mis_builder/models/__init__.py index 7882034f..85b6d02f 100644 --- a/mis_builder/models/__init__.py +++ b/mis_builder/models/__init__.py @@ -23,3 +23,4 @@ ############################################################################## from . import mis_builder +from . import aep diff --git a/mis_builder/models/mis_builder.py b/mis_builder/models/mis_builder.py index ee54c7df..9c34950e 100644 --- a/mis_builder/models/mis_builder.py +++ b/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.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.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'] diff --git a/mis_builder/static/src/js/mis_builder.js b/mis_builder/static/src/js/mis_builder.js index 0d1244c3..48e71efb 100644 --- a/mis_builder/static/src/js/mis_builder.js +++ b/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],