|
|
@ -1025,109 +1025,6 @@ class MisReportInstancePeriod(models.Model): |
|
|
|
else: |
|
|
|
return False |
|
|
|
|
|
|
|
@api.multi |
|
|
|
def _render_period(self, kpi_matrix, lang_id, aep): |
|
|
|
""" Compute and render a mis report instance period |
|
|
|
|
|
|
|
It returns a dictionary keyed on kpi.name with a list of dictionaries |
|
|
|
with the following values (one item in the list for each subkpi): |
|
|
|
* val: the evaluated kpi, or None if there is no data or an error |
|
|
|
* val_r: the rendered kpi as a string, or #ERR, #DIV |
|
|
|
* val_c: a comment (explaining the error, typically) |
|
|
|
* style: the css style of the kpi |
|
|
|
(may change in the future!) |
|
|
|
* prefix: a prefix to display in front of the rendered value |
|
|
|
* suffix: a prefix to display after rendered value |
|
|
|
* dp: the decimal precision of the kpi |
|
|
|
* is_percentage: true if the kpi is of percentage type |
|
|
|
(may change in the future!) |
|
|
|
* expr: the kpi expression |
|
|
|
* drilldown: true if the drilldown method of |
|
|
|
mis.report.instance.period is going to do something |
|
|
|
useful in this kpi |
|
|
|
""" |
|
|
|
# TODO FIXME remove this method |
|
|
|
self.ensure_one() |
|
|
|
# first invoke the compute method on the mis report template |
|
|
|
# passing it all the information regarding period and filters |
|
|
|
self.report_instance_id.report_id._compute_period( |
|
|
|
kpi_matrix, self, |
|
|
|
aep, |
|
|
|
self.date_from, self.date_to, |
|
|
|
self.report_instance_id.target_move, |
|
|
|
self.report_instance_id.company_id, |
|
|
|
self.subkpi_ids, |
|
|
|
self._get_additional_move_line_filter, |
|
|
|
self._get_additional_query_filter, |
|
|
|
) |
|
|
|
# second, render it to something that can be used by the widget |
|
|
|
res = {} |
|
|
|
mis_report_kpi_style = self.env['mis.report.kpi.style'] |
|
|
|
for kpi_name, kpi, vals in kpi_matrix.iter_kpi_vals(self): |
|
|
|
res[kpi_name] = [] |
|
|
|
try: |
|
|
|
# TODO FIXME check style_expression evaluation wrt subkpis |
|
|
|
kpi_style = None |
|
|
|
if kpi.style_expression: |
|
|
|
style_name = safe_eval(kpi.style_expression, |
|
|
|
kpi_matrix.get_locals_dict(self)) |
|
|
|
styles = mis_report_kpi_style.search( |
|
|
|
[('name', '=', style_name)]) |
|
|
|
kpi_style = styles and styles[0] |
|
|
|
except: |
|
|
|
_logger.warning("error evaluating css stype expression %s", |
|
|
|
kpi.style, exc_info=True) |
|
|
|
|
|
|
|
default_vals = { |
|
|
|
'prefix': kpi.prefix, |
|
|
|
'suffix': kpi.suffix, |
|
|
|
'dp': kpi.dp, |
|
|
|
'is_percentage': kpi.type == 'pct', |
|
|
|
'period_id': self.id, |
|
|
|
'style': '', |
|
|
|
'xlsx_style': {}, |
|
|
|
} |
|
|
|
if kpi_style: |
|
|
|
default_vals.update({ |
|
|
|
'style': kpi_style.to_css_style(), |
|
|
|
'xlsx_style': kpi_style.to_xlsx_forma_properties(), |
|
|
|
}) |
|
|
|
|
|
|
|
for idx, subkpi_val in enumerate(vals): |
|
|
|
vals = default_vals.copy() |
|
|
|
if isinstance(subkpi_val, DataError): |
|
|
|
vals.update({ |
|
|
|
'val': subkpi_val.name, |
|
|
|
'val_r': subkpi_val.name, |
|
|
|
'val_c': subkpi_val.msg, |
|
|
|
'drilldown': False, |
|
|
|
}) |
|
|
|
else: |
|
|
|
if kpi.multi: |
|
|
|
expression = kpi.expression_ids[idx].name |
|
|
|
comment = '{}.{} = {}'.format( |
|
|
|
kpi.name, |
|
|
|
kpi.expression_ids[idx].subkpi_id.name, |
|
|
|
expression) |
|
|
|
else: |
|
|
|
expression = kpi.expression |
|
|
|
comment = '{} = {}'.format( |
|
|
|
kpi.name, |
|
|
|
expression) |
|
|
|
drilldown = (subkpi_val is not AccountingNone and |
|
|
|
AEP.has_account_var(expression)) |
|
|
|
vals.update({ |
|
|
|
'val': (None |
|
|
|
if subkpi_val is AccountingNone |
|
|
|
else subkpi_val), |
|
|
|
'val_r': kpi.render(lang_id, subkpi_val), |
|
|
|
'val_c': comment, |
|
|
|
'expr': expression, |
|
|
|
'drilldown': drilldown, |
|
|
|
}) |
|
|
|
res[kpi_name].append(vals) |
|
|
|
return res |
|
|
|
|
|
|
|
|
|
|
|
class MisReportInstance(models.Model): |
|
|
|
"""The MIS report instance combines everything to compute |
|
|
@ -1380,112 +1277,3 @@ class MisReportInstance(models.Model): |
|
|
|
'header': header, |
|
|
|
'content': content, |
|
|
|
} |
|
|
|
|
|
|
|
@api.multi |
|
|
|
def old_compute(self): |
|
|
|
self.ensure_one() |
|
|
|
aep = self.report_id._prepare_aep(self.company_id) |
|
|
|
|
|
|
|
# fetch user language only once |
|
|
|
# TODO: is this necessary? |
|
|
|
lang = self.env.user.lang |
|
|
|
if not lang: |
|
|
|
lang = 'en_US' |
|
|
|
lang_id = self.env['res.lang'].search([('code', '=', lang)]).id |
|
|
|
|
|
|
|
# compute kpi values for each period |
|
|
|
kpi_values_by_period_ids = {} |
|
|
|
kpi_matrix = KpiMatrix(lang_id) |
|
|
|
for period in self.period_ids: |
|
|
|
if not period.valid: |
|
|
|
continue |
|
|
|
kpi_values = period._render_period(kpi_matrix, lang_id, aep) |
|
|
|
kpi_values_by_period_ids[period.id] = kpi_values |
|
|
|
kpi_matrix.load_account_names(self.env['account.account']) |
|
|
|
|
|
|
|
# prepare header and content |
|
|
|
header = [{ |
|
|
|
'kpi_name': '', |
|
|
|
'cols': [] |
|
|
|
}, { |
|
|
|
'kpi_name': '', |
|
|
|
'cols': [] |
|
|
|
}] |
|
|
|
content = [] |
|
|
|
rows_by_kpi_name = {} |
|
|
|
for kpi_name, kpi_description, kpi in kpi_matrix.iter_kpis(): |
|
|
|
props = { |
|
|
|
'kpi_name': kpi_description, |
|
|
|
'cols': [], |
|
|
|
'default_style': '', |
|
|
|
'default_xlsx_style': {}, |
|
|
|
} |
|
|
|
rows_by_kpi_name[kpi_name] = props |
|
|
|
if kpi.style: |
|
|
|
props.update({ |
|
|
|
'default_style': kpi.style.to_css_style(), |
|
|
|
'default_xlsx_style': kpi.style.to_xlsx_format_properties() |
|
|
|
}) |
|
|
|
|
|
|
|
content.append(rows_by_kpi_name[kpi_name]) |
|
|
|
|
|
|
|
# populate header and content |
|
|
|
for period in self.period_ids: |
|
|
|
if not period.valid: |
|
|
|
continue |
|
|
|
# add the column header |
|
|
|
if period.duration > 1 or period.type in ('w', 'date_range'): |
|
|
|
# from, to |
|
|
|
date_from = self._format_date(lang_id, period.date_from) |
|
|
|
date_to = self._format_date(lang_id, period.date_to) |
|
|
|
header_date = _('from %s to %s') % (date_from, date_to) |
|
|
|
else: |
|
|
|
header_date = self._format_date(lang_id, period.date_from) |
|
|
|
subkpis = period.subkpi_ids or \ |
|
|
|
period.report_instance_id.report_id.subkpi_ids |
|
|
|
header[0]['cols'].append(dict( |
|
|
|
name=period.name, |
|
|
|
date=header_date, |
|
|
|
colspan=len(subkpis) or 1, |
|
|
|
)) |
|
|
|
if subkpis: |
|
|
|
for subkpi in subkpis: |
|
|
|
header[1]['cols'].append(dict( |
|
|
|
name=subkpi.description, |
|
|
|
colspan=1, |
|
|
|
)) |
|
|
|
else: |
|
|
|
header[1]['cols'].append(dict( |
|
|
|
name="", |
|
|
|
colspan=1, |
|
|
|
)) |
|
|
|
# add kpi values |
|
|
|
kpi_values = kpi_values_by_period_ids[period.id] |
|
|
|
for kpi_name in kpi_values: |
|
|
|
rows_by_kpi_name[kpi_name]['cols'] += kpi_values[kpi_name] |
|
|
|
|
|
|
|
# add comparison columns |
|
|
|
for compare_col in period.comparison_column_ids: |
|
|
|
compare_kpi_values = \ |
|
|
|
kpi_values_by_period_ids.get(compare_col.id) |
|
|
|
if compare_kpi_values: |
|
|
|
# add the comparison column header |
|
|
|
header[0]['cols'].append( |
|
|
|
dict(name=_('%s vs %s') % (period.name, |
|
|
|
compare_col.name), |
|
|
|
date='')) |
|
|
|
# add comparison values |
|
|
|
for kpi in self.report_id.kpi_ids: |
|
|
|
rows_by_kpi_name[kpi.name]['cols'].append({ |
|
|
|
'val_r': kpi.render_comparison( |
|
|
|
lang_id, |
|
|
|
kpi_values[kpi.name]['val'], |
|
|
|
compare_kpi_values[kpi.name]['val'], |
|
|
|
period.normalize_factor, |
|
|
|
compare_col.normalize_factor) |
|
|
|
}) |
|
|
|
return { |
|
|
|
'report_name': self.name, |
|
|
|
'header': header, |
|
|
|
'content': content, |
|
|
|
} |