Browse Source

[WIP] mis_builder refactoring: restore drilldown with support for account details

pull/189/head
Stéphane Bidoul 9 years ago
parent
commit
d2bc009961
  1. 11
      mis_builder/models/aep.py
  2. 58
      mis_builder/models/mis_report.py
  3. 60
      mis_builder/models/mis_report_instance.py
  4. 10
      mis_builder/static/src/js/mis_builder.js
  5. 8
      mis_builder/static/src/xml/mis_widget.xml
  6. 1
      mis_builder/tests/test_fetch_query.py

11
mis_builder/models/aep.py

@ -165,7 +165,8 @@ class AccountingExpressionProcessor(object):
def get_aml_domain_for_expr(self, expr, def get_aml_domain_for_expr(self, expr,
date_from, date_to, date_from, date_to,
target_move, company):
target_move, company,
account_id=None):
""" Get a domain on account.move.line for an expression. """ Get a domain on account.move.line for an expression.
Prerequisite: done_parsing() must have been invoked. Prerequisite: done_parsing() must have been invoked.
@ -180,7 +181,14 @@ class AccountingExpressionProcessor(object):
account_ids = set() account_ids = set()
for account_code in account_codes: for account_code in account_codes:
account_ids.update(self._account_ids_by_code[account_code]) account_ids.update(self._account_ids_by_code[account_code])
if not account_id:
aml_domain.append(('account_id', 'in', tuple(account_ids))) aml_domain.append(('account_id', 'in', tuple(account_ids)))
else:
# filter on account_id
if account_id in account_ids:
aml_domain.append(('account_id', '=', account_id))
else:
continue
if field == 'crd': if field == 'crd':
aml_domain.append(('credit', '>', 0)) aml_domain.append(('credit', '>', 0))
elif field == 'deb': elif field == 'deb':
@ -191,6 +199,7 @@ class AccountingExpressionProcessor(object):
self.get_aml_domain_for_dates(date_from, date_to, self.get_aml_domain_for_dates(date_from, date_to,
mode, target_move, mode, target_move,
company) company)
assert aml_domains
return expression.OR(aml_domains) + \ return expression.OR(aml_domains) + \
expression.OR(date_domain_by_mode.values()) expression.OR(date_domain_by_mode.values())

58
mis_builder/models/mis_report.py

@ -134,14 +134,14 @@ class KpiMatrixCell(object):
def __init__(self, row, subcol, def __init__(self, row, subcol,
val, val_rendered, val_comment, val, val_rendered, val_comment,
style=None, drilldown_key=None):
style=None, drilldown_arg=None):
self.row = row self.row = row
self.subcol = subcol self.subcol = subcol
self.val = val self.val = val
self.val_rendered = val_rendered self.val_rendered = val_rendered
self.val_comment = val_comment self.val_comment = val_comment
self.style = style self.style = style
self.drilldown_key = None
self.drilldown_arg = drilldown_arg
class KpiMatrix(object): class KpiMatrix(object):
@ -191,14 +191,17 @@ class KpiMatrix(object):
self._comparison_todo[last_period_key].append( self._comparison_todo[last_period_key].append(
(period_key, base_period_key)) (period_key, base_period_key))
def set_values(self, kpi, period_key, vals):
def set_values(self, kpi, period_key, vals,
drilldown_args):
""" Set values for a kpi and a period. """ Set values for a kpi and a period.
Invoke this after declaring the kpi and the period. Invoke this after declaring the kpi and the period.
""" """
self.set_values_detail_account(kpi, period_key, None, vals)
self.set_values_detail_account(kpi, period_key, None, vals,
drilldown_args)
def set_values_detail_account(self, kpi, period_key, account_id, vals):
def set_values_detail_account(self, kpi, period_key, account_id, vals,
drilldown_args):
""" Set values for a kpi and a period and a detail account. """ Set values for a kpi and a period and a detail account.
Invoke this after declaring the kpi and the period. Invoke this after declaring the kpi and the period.
@ -215,7 +218,8 @@ class KpiMatrix(object):
col = self._cols[period_key] col = self._cols[period_key]
cell_tuple = [] cell_tuple = []
assert len(vals) == col.colspan assert len(vals) == col.colspan
for val, subcol in izip(vals, col.iter_subcols()):
for val, drilldown_arg, subcol in \
izip(vals, drilldown_args, col.iter_subcols()):
if isinstance(val, DataError): if isinstance(val, DataError):
val_rendered = val.name val_rendered = val.name
val_comment = val.msg val_comment = val.msg
@ -231,8 +235,8 @@ class KpiMatrix(object):
row.kpi.name, row.kpi.name,
row.kpi.expression) row.kpi.expression)
# TODO style # TODO style
# TODO drilldown_key
cell = KpiMatrixCell(row, subcol, val, val_rendered, val_comment)
cell = KpiMatrixCell(row, subcol, val, val_rendered, val_comment,
None, drilldown_arg)
cell_tuple.append(cell) cell_tuple.append(cell)
col._set_cell_tuple(row, cell_tuple) col._set_cell_tuple(row, cell_tuple)
@ -358,14 +362,16 @@ class KpiMatrix(object):
if cell is None: if cell is None:
row_data['cols'].append({}) row_data['cols'].append({})
else: else:
row_data['cols'].append({
col_data = {
'val': (cell.val 'val': (cell.val
if cell.val is not AccountingNone else None), if cell.val is not AccountingNone else None),
'val_r': cell.val_rendered, 'val_r': cell.val_rendered,
'val_c': cell.val_comment, 'val_c': cell.val_comment,
# TODO FIXME style # TODO FIXME style
# TODO FIXME drilldown
})
}
if cell.drilldown_arg:
col_data['drilldown_arg'] = cell.drilldown_arg
row_data['cols'].append(col_data)
content.append(row_data) content.append(row_data)
return { return {
@ -975,11 +981,19 @@ class MisReport(models.Model):
expressions.append(expression.name) expressions.append(expression.name)
vals = [] vals = []
drilldown_args = []
try: try:
for expression in expressions: for expression in expressions:
replaced_expr = aep.replace_expr(expression) replaced_expr = aep.replace_expr(expression)
vals.append( vals.append(
mis_safe_eval(replaced_expr, locals_dict)) mis_safe_eval(replaced_expr, locals_dict))
if replaced_expr != expression:
drilldown_args.append({
'period_id': period_key,
'expr': expression,
})
else:
drilldown_args.append(None)
except NameError: except NameError:
recompute_queue.append(kpi) recompute_queue.append(kpi)
break break
@ -991,19 +1005,29 @@ class MisReport(models.Model):
else: else:
locals_dict[kpi.name] = SimpleArray(vals) locals_dict[kpi.name] = SimpleArray(vals)
kpi_matrix.set_values(kpi, period_key, vals)
kpi_matrix.set_values(
kpi, period_key, vals, drilldown_args)
if not kpi.auto_expand_accounts: if not kpi.auto_expand_accounts:
continue continue
for account_id, replaced_exprs in \ for account_id, replaced_exprs in \
aep.replace_exprs_by_account_id(expressions): aep.replace_exprs_by_account_id(expressions):
account_id_vals = []
for replaced_expr in replaced_exprs:
account_id_vals.append(
mis_safe_eval(replaced_expr, locals_dict))
vals = []
drilldown_args = []
for expression, replaced_expr in \
izip(expressions, replaced_exprs):
vals.append(mis_safe_eval(replaced_expr, locals_dict))
if replaced_expr != expression:
drilldown_args.append({
'period_id': period_key,
'expr': expression,
'account_id': account_id
})
else:
drilldown_args.append(None)
kpi_matrix.set_values_detail_account( kpi_matrix.set_values_detail_account(
kpi, period_key, account_id, account_id_vals)
kpi, period_key, account_id, vals, drilldown_args)
if len(recompute_queue) == 0: if len(recompute_queue) == 0:
# nothing to recompute, we are done # nothing to recompute, we are done

60
mis_builder/models/mis_report_instance.py

@ -169,33 +169,6 @@ class MisReportInstancePeriod(models.Model):
self.ensure_one() self.ensure_one()
return [] return []
@api.multi
def drilldown(self, expr):
self.ensure_one()
# TODO FIXME: drilldown by account
if AEP.has_account_var(expr):
aep = AEP(self.env)
aep.parse_expr(expr)
aep.done_parsing(self.report_instance_id.company_id)
domain = aep.get_aml_domain_for_expr(
expr,
self.date_from, self.date_to,
self.report_instance_id.target_move,
self.report_instance_id.company_id)
domain.extend(self._get_additional_move_line_filter())
return {
'name': expr + ' - ' + self.name,
'domain': domain,
'type': 'ir.actions.act_window',
'res_model': 'account.move.line',
'views': [[False, 'list'], [False, 'form']],
'view_type': 'list',
'view_mode': 'list',
'target': 'current',
}
else:
return False
class MisReportInstance(models.Model): class MisReportInstance(models.Model):
"""The MIS report instance combines everything to compute """The MIS report instance combines everything to compute
@ -383,11 +356,9 @@ class MisReportInstance(models.Model):
aep = self.report_id._prepare_aep(self.company_id) aep = self.report_id._prepare_aep(self.company_id)
kpi_matrix = self.report_id._prepare_kpi_matrix() kpi_matrix = self.report_id._prepare_kpi_matrix()
for period in self.period_ids: for period in self.period_ids:
# add the column header
if period.date_from == period.date_to: if period.date_from == period.date_to:
comment = self._format_date(period.date_from) comment = self._format_date(period.date_from)
else: else:
# from, to
date_from = self._format_date(period.date_from) date_from = self._format_date(period.date_from)
date_to = self._format_date(period.date_to) date_to = self._format_date(period.date_to)
comment = _('from %s to %s') % (date_from, date_to) comment = _('from %s to %s') % (date_from, date_to)
@ -414,3 +385,34 @@ class MisReportInstance(models.Model):
self.ensure_one() self.ensure_one()
kpi_matrix = self._compute_matrix() kpi_matrix = self._compute_matrix()
return kpi_matrix.as_dict() return kpi_matrix.as_dict()
@api.multi
def drilldown(self, arg):
self.ensure_one()
period_id = arg.get('period_id')
expr = arg.get('expr')
account_id = arg.get('account_id')
if period_id and expr and AEP.has_account_var(expr):
period = self.env['mis.report.instance.period'].browse(period_id)
aep = AEP(self.env)
aep.parse_expr(expr)
aep.done_parsing(self.company_id)
domain = aep.get_aml_domain_for_expr(
expr,
period.date_from, period.date_to,
self.target_move,
self.company_id,
account_id)
domain.extend(period._get_additional_move_line_filter())
return {
'name': u'{} - {}'.format(expr, period.name),
'domain': domain,
'type': 'ir.actions.act_window',
'res_model': 'account.move.line',
'views': [[False, 'list'], [False, 'form']],
'view_type': 'list',
'view_mode': 'list',
'target': 'current',
}
else:
return False

10
mis_builder/static/src/js/mis_builder.js

@ -116,15 +116,11 @@ var MisReport = form_common.FormWidget.extend({
drilldown: function(event) { drilldown: function(event) {
var self = this; var self = this;
var drilldown = JSON.parse($(event.target).data("drilldown"));
var drilldown = $(event.target).data("drilldown");
if (drilldown) { if (drilldown) {
var period_id = JSON.parse($(event.target).data("period-id"));
var val_c = JSON.parse($(event.target).data("expr"));
var context = new data.CompoundContext(self.build_context(), self.get_context()|| {})
new Model("mis.report.instance.period").call(
new Model("mis.report.instance").call(
"drilldown", "drilldown",
[period_id, val_c],
{'context': context}
[self.mis_report_instance_id, drilldown]
).then(function(result) { ).then(function(result) {
if (result) { if (result) {
self.do_action(result); self.do_action(result);

8
mis_builder/static/src/xml/mis_widget.xml

@ -32,17 +32,15 @@
<t t-foreach="c_value.cols" t-as="value"> <t t-foreach="c_value.cols" t-as="value">
<td t-att="{'style': c_value.style}" class="mis_builder_amount"> <td t-att="{'style': c_value.style}" class="mis_builder_amount">
<div t-att="{'style': value_value.style, 'title': value_value.val_c}"> <div t-att="{'style': value_value.style, 'title': value_value.val_c}">
<t t-if="value_value.drilldown">
<t t-if="value_value.drilldown_arg">
<a href="javascript:void(0)" <a href="javascript:void(0)"
class="mis_builder_drilldown" class="mis_builder_drilldown"
t-att-data-drilldown="JSON.stringify(value_value.drilldown)"
t-att-data-period-id="JSON.stringify(value_value.period_id)"
t-att-data-expr="JSON.stringify(value_value.expr)"
t-att-data-drilldown="JSON.stringify(value_value.drilldown_arg)"
> >
<t t-esc="value_value.val_r"/> <t t-esc="value_value.val_r"/>
</a> </a>
</t> </t>
<t t-if="!value_value.drilldown">
<t t-if="!value_value.drilldown_arg">
<t t-esc="value_value.val_r"/> <t t-esc="value_value.val_r"/>
</t> </t>
</div> </div>

1
mis_builder/tests/test_fetch_query.py

@ -12,6 +12,7 @@ class TestFetchQuery(common.TransactionCase):
data = self.registry('mis.report.instance').compute( data = self.registry('mis.report.instance').compute(
self.cr, self.uid, self.cr, self.uid,
self.ref('mis_builder.mis_report_instance_test')) self.ref('mis_builder.mis_report_instance_test'))
self.maxDiff = None
self.assertEquals( self.assertEquals(
{'content': {'content':
[{'description': u'total test', [{'description': u'total test',

Loading…
Cancel
Save