diff --git a/mis_builder/__init__.py b/mis_builder/__init__.py index 033bfb38..11c59f64 100644 --- a/mis_builder/__init__.py +++ b/mis_builder/__init__.py @@ -21,6 +21,6 @@ # = #============================================================================== -import models +from . import models from . import wizard from . import report diff --git a/mis_builder/__openerp__.py b/mis_builder/__openerp__.py index 8b91ac49..8efdaad3 100644 --- a/mis_builder/__openerp__.py +++ b/mis_builder/__openerp__.py @@ -42,7 +42,7 @@ 'tests/mis.report.csv', 'tests/mis.report.instance.period.csv', 'tests/mis.report.instance.csv', - ], + ], 'js': [ 'static/src/js/*.js' ], diff --git a/mis_builder/models/__init__.py b/mis_builder/models/__init__.py index 4d7f1bd5..4d576aa8 100644 --- a/mis_builder/models/__init__.py +++ b/mis_builder/models/__init__.py @@ -21,4 +21,4 @@ # = #============================================================================== -import mis_builder +from . import mis_builder diff --git a/mis_builder/models/mis_builder.py b/mis_builder/models/mis_builder.py index 989c079d..cd81235e 100644 --- a/mis_builder/models/mis_builder.py +++ b/mis_builder/models/mis_builder.py @@ -56,7 +56,8 @@ def _utc_midnight(d, tz_name, add_day=0): utc_tz = pytz.timezone('UTC') context_tz = pytz.timezone(tz_name) local_timestamp = context_tz.localize(d, is_dst=False) - return datetime.strftime(local_timestamp.astimezone(utc_tz), tools.DEFAULT_SERVER_DATETIME_FORMAT) + return datetime.strftime(local_timestamp.astimezone(utc_tz), + tools.DEFAULT_SERVER_DATETIME_FORMAT) def _clean(varStr): @@ -64,6 +65,7 @@ def _clean(varStr): class mis_report_kpi(orm.Model): + """ A KPI is an element of a MIS report. In addition to a name and description, it has an expression @@ -132,10 +134,13 @@ class mis_report_kpi(orm.Model): # check it is a valid python identifier res = {} if name and not re.match("[_A-Za-z][_a-zA-Z0-9]*$", name): - res['warning'] = {'title': 'Invalid name', 'message': 'The name must be a valid python identifier'} + res['warning'] = { + 'title': 'Invalid name', + 'message': 'The name must be a valid python identifier'} return res - def onchange_description(self, cr, uid, ids, description, name, context=None): + def onchange_description(self, cr, uid, ids, description, name, + context=None): # construct name from description res = {} if description and not name: @@ -155,47 +160,60 @@ class mis_report_kpi(orm.Model): def _render(self, cr, uid, kpi, value, context=None): """ render a KPI value as a unicode string, ready for display """ if kpi.type == 'num': - return self._render_num(cr, uid, value, kpi.divider, kpi.dp, kpi.suffix, context=context) + return self._render_num(cr, uid, value, kpi.divider, kpi.dp, + kpi.suffix, context=context) elif kpi.type == 'pct': - return self._render_num(cr, uid, value, 0.01, kpi.dp, '%', context=context) + return self._render_num(cr, uid, value, 0.01, kpi.dp, '%', + context=context) else: return unicode(value) - def _render_comparison(self, cr, uid, kpi, value, base_value, average_value, average_base_value, context=None): + def _render_comparison(self, cr, uid, kpi, value, base_value, + average_value, average_base_value, context=None): """ render the comparison of two KPI values, ready for display """ if value is None or base_value is None: return '' if kpi.type == 'pct': - return self._render_num(cr, uid, value - base_value, 0.01, kpi.dp, _('pp'), sign='+', context=context) + return self._render_num(cr, uid, value - base_value, 0.01, kpi.dp, + _('pp'), sign='+', context=context) elif kpi.type == 'num': if average_value: value = value / float(average_value) if average_base_value: base_value = base_value / float(average_base_value) if kpi.compare_method == 'diff': - return self._render_num(cr, uid, value - base_value, kpi.divider, - kpi.dp, kpi.suffix, sign='+', context=context) + return self._render_num(cr, uid, value - base_value, + kpi.divider, + kpi.dp, kpi.suffix, sign='+', + context=context) elif kpi.compare_method == 'pct' and base_value != 0: return self._render_num(cr, uid, value / base_value - 1, 0.01, kpi.dp, '%', sign='+', context=context) return '' - def _render_num(self, cr, uid, value, divider, dp, suffix, sign='-', context=None): - divider_label = _get_selection_label(self._columns['divider'].selection, divider) + def _render_num(self, cr, uid, value, divider, dp, suffix, sign='-', + context=None): + divider_label = _get_selection_label( + self._columns['divider'].selection, divider) if divider_label == '1': divider_label = '' # format number following user language - lang = self.pool['res.users'].read(cr, uid, uid, ['lang'], context=context)['lang'] - language_id = self.pool['res.lang'].search(cr, uid, [('code', '=', lang)], context=context) + lang = self.pool['res.users'].read( + cr, uid, uid, ['lang'], context=context)['lang'] + language_id = self.pool['res.lang'].search( + cr, uid, [('code', '=', lang)], context=context) value = round(value / float(divider or 1), dp) or 0 return '%s %s%s' % (self.pool['res.lang'].format(cr, uid, language_id, - '%%%s.%df' % (sign, dp), - value, context=context), + '%%%s.%df' % ( + sign, dp), + value, + context=context), divider_label, suffix or '') class mis_report_query(orm.Model): + """ A query to fetch data for a MIS report. A query works on a model and has a domain and list of fields to fetch. @@ -216,7 +234,10 @@ class mis_report_query(orm.Model): def onchange_field_ids(self, cr, uid, ids, field_ids, context=None): # compute field_names field_name = [] - for field in self.pool.get('ir.model.fields').read(cr, uid, field_ids[0][2], ['name'], context=context): + for field in self.pool.get('ir.model.fields').read(cr, uid, + field_ids[0][2], + ['name'], + context=context): field_name.append(field['name']) return {'value': {'field_name': ', '.join(field_name)}} @@ -227,12 +248,15 @@ class mis_report_query(orm.Model): string='Model'), 'field_ids': fields.many2many('ir.model.fields', required=True, string='Fields to fetch'), - 'field_name': fields.function(_get_field_names, type='char', string='Fetched fields name', + 'field_name': fields.function(_get_field_names, type='char', + string='Fetched fields name', store={'mis.report.query': - (lambda self, cr, uid, ids, c={}: ids, ['field_ids'], 20), }), + (lambda self, cr, uid, ids, c={}: + ids, ['field_ids'], 20), }), 'date_field': fields.many2one('ir.model.fields', required=True, string='Date field', - domain=[('ttype', 'in', ('date', 'datetime'))]), + domain=[('ttype', 'in', ('date', + 'datetime'))]), 'domain': fields.char(string='Domain'), 'report_id': fields.many2one('mis.report', string='Report'), } @@ -251,6 +275,7 @@ class mis_report_query(orm.Model): class mis_report(orm.Model): + """ A MIS report template (without period information) The MIS report holds: @@ -284,19 +309,24 @@ class mis_report(orm.Model): if line[0] == 0: line[2]['sequence'] = idx + 1 else: - mis_report_kpi_obj.write(cr, uid, [line[1]], {'sequence': idx + 1}, context=context) + mis_report_kpi_obj.write( + cr, uid, [line[1]], {'sequence': idx + 1}, + context=context) return super(mis_report, self).create(cr, uid, vals, context=context) def write(self, cr, uid, ids, vals, context=None): - res = super(mis_report, self).write(cr, uid, ids, vals, context=context) + res = super(mis_report, self).write( + cr, uid, ids, vals, context=context) mis_report_kpi_obj = self.pool.get('mis.report.kpi') for report in self.browse(cr, uid, ids, context): for idx, kpi in enumerate(report.kpi_ids): - mis_report_kpi_obj.write(cr, uid, [kpi.id], {'sequence': idx + 1}, context=context) + mis_report_kpi_obj.write( + cr, uid, [kpi.id], {'sequence': idx + 1}, context=context) return res class mis_report_instance_period(orm.Model): + """ A MIS report instance has the logic to compute a report template for a give date period. @@ -313,34 +343,45 @@ class mis_report_instance_period(orm.Model): if c.type == 'd': date_from = d + timedelta(days=c.offset) date_to = date_from + timedelta(days=c.duration - 1) - date_from = date_from.strftime(tools.DEFAULT_SERVER_DATE_FORMAT) + date_from = date_from.strftime( + tools.DEFAULT_SERVER_DATE_FORMAT) date_to = date_to.strftime(tools.DEFAULT_SERVER_DATE_FORMAT) period_ids = None elif c.type == 'w': date_from = d - timedelta(d.weekday()) date_from = date_from + timedelta(days=c.offset * 7) date_to = date_from + timedelta(days=(7 * c.duration) - 1) - date_from = date_from.strftime(tools.DEFAULT_SERVER_DATE_FORMAT) + date_from = date_from.strftime( + tools.DEFAULT_SERVER_DATE_FORMAT) date_to = date_to.strftime(tools.DEFAULT_SERVER_DATE_FORMAT) period_ids = None elif c.type == 'fp': period_obj = self.pool['account.period'] - all_period_ids = period_obj.search(cr, uid, - [('special', '=', False), - '|', ('company_id', '=', False), - ('company_id', '=', c.company_id.id)], - order='date_start', - context=context) - current_period_ids = period_obj.search(cr, uid, - [('special', '=', False), - ('date_start', '<=', d), - ('date_stop', '>=', d), - '|', ('company_id', '=', False), - ('company_id', '=', c.company_id.id)], - context=context) + all_period_ids = period_obj.search( + cr, uid, + [('special', '=', False), + '|', ( + 'company_id', '=', + False), + ('company_id', '=', + c.company_id.id)], + order='date_start', + context=context) + current_period_ids = period_obj.search( + cr, uid, + [('special', '=', False), + ('date_start', '<=', d), + ('date_stop', + '>=', d), + '|', + ('company_id', + '=', False), + ('company_id', '=', c.company_id.id)], + context=context) if not current_period_ids: raise orm.except_orm(_("Error!"), - _("No current fiscal period for %s") % d) + _("No current fiscal period for %s") + % d) p = all_period_ids.index(current_period_ids[0]) + c.offset if p < 0 or p >= len(all_period_ids): raise orm.except_orm(_("Error!"), @@ -396,11 +437,16 @@ class mis_report_instance_period(orm.Model): 'sequence': fields.integer(string='Sequence'), 'report_instance_id': fields.many2one('mis.report.instance', string='Report Instance'), - 'comparison_column_ids': fields.many2many('mis.report.instance.period', 'mis_report_instance_period_rel', - 'period_id', 'compare_period_id', string='Compare with'), + 'comparison_column_ids': fields.many2many( + 'mis.report.instance.period', + 'mis_report_instance_period_rel', + 'period_id', + 'compare_period_id', + string='Compare with'), 'company_id': fields.many2one('res.company', 'Company', required=True), - 'normalize_factor': fields.integer(string='Factor', - help='Factor to use to normalize the period (used in comparison'), + 'normalize_factor': fields.integer( + string='Factor', + help='Factor to use to normalize the period (used in comparison'), } _defaults = { @@ -408,17 +454,22 @@ class mis_report_instance_period(orm.Model): 'duration': 1, 'sequence': 100, 'normalize_factor': 1, - 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, - 'mis.report.instance.period', - context=c) + 'company_id': lambda s, cr, uid, c: + s.pool.get('res.company')._company_default_get( + cr, uid, + 'mis.report.instance.period', + context=c) } _order = 'sequence' _sql_constraints = [ - ('duration', 'CHECK (duration>0)', 'Wrong duration, it must be positive!'), - ('normalize_factor', 'CHECK (normalize_factor>0)', 'Wrong normalize factor, it must be positive!'), - ('name_unique', 'unique(name, report_instance_id)', 'Period name should be unique by report'), + ('duration', 'CHECK (duration>0)', + 'Wrong duration, it must be positive!'), + ('normalize_factor', 'CHECK (normalize_factor>0)', + 'Wrong normalize factor, it must be positive!'), + ('name_unique', 'unique(name, report_instance_id)', + 'Period name should be unique by report'), ] def _fetch_balances(self, cr, uid, c, context=None): @@ -439,8 +490,11 @@ class mis_report_instance_period(orm.Model): 'date_to': c.date_to}) # TODO: initial balance? - account_ids = account_obj.search(cr, uid, ['|', ('company_id', '=', False), ('company_id', '=', c.company_id.id)], context=context) - account_datas = account_obj.read(cr, uid, account_ids, ['code', 'balance'], context=search_ctx) + account_ids = account_obj.search(cr, uid, ['|', ('company_id', '=', + False), ( + 'company_id', '=', c.company_id.id)], context=context) + account_datas = account_obj.read( + cr, uid, account_ids, ['code', 'balance'], context=search_ctx) balances = {} for account_data in account_datas: key = 'bal' + _clean(account_data['code']) @@ -460,15 +514,20 @@ class mis_report_instance_period(orm.Model): domain.extend([(query.date_field.name, '>=', c.date_from), (query.date_field.name, '<=', c.date_to)]) else: - datetime_from = _utc_midnight(c.date_from, context.get('tz', 'UTC')) - datetime_to = _utc_midnight(c.date_to, context.get('tz', 'UTC'), add_day=1) + datetime_from = _utc_midnight( + c.date_from, context.get('tz', 'UTC')) + datetime_to = _utc_midnight( + c.date_to, context.get('tz', 'UTC'), add_day=1) domain.extend([(query.date_field.name, '>=', datetime_from), (query.date_field.name, '<', datetime_to)]) if obj._columns.get('company_id', False): - domain.extend(['|', ('company_id', '=', False), ('company_id', '=', c.company_id.id)]) + domain.extend( + ['|', ('company_id', '=', False), ('company_id', '=', + c.company_id.id)]) field_names = [field.name for field in query.field_ids] obj_ids = obj.search(cr, uid, domain, context=context) - obj_datas = obj.read(cr, uid, obj_ids, field_names, context=context) + obj_datas = obj.read( + cr, uid, obj_ids, field_names, context=context) res[query.name] = [AutoStruct(**d) for d in obj_datas] return res @@ -504,7 +563,8 @@ class mis_report_instance_period(orm.Model): kpi_val_rendered = '#ERR' kpi_val_comment = traceback.format_exc() else: - kpi_val_rendered = kpi_obj._render(cr, uid, kpi, kpi_val, context=context) + kpi_val_rendered = kpi_obj._render( + cr, uid, kpi, kpi_val, context=context) kpi_val_comment = None localdict[kpi.name] = kpi_val @@ -529,6 +589,7 @@ class mis_report_instance_period(orm.Model): class mis_report_instance(orm.Model): + """ The MIS report instance combines compute and display a MIS report template for a set of periods """ @@ -564,37 +625,51 @@ class mis_report_instance(orm.Model): string='Periods'), 'target_move': fields.selection([('posted', 'All Posted Entries'), ('all', 'All Entries'), - ], 'Target Moves', required=True), + ], 'Target Moves', required=True), } _defaults = { - 'target_move': 'posted', + 'target_move': 'posted', } def create(self, cr, uid, vals, context=None): if 'period_ids' in vals: - mis_report_instance_period_obj = self.pool.get('mis.report.instance.period') + mis_report_instance_period_obj = self.pool.get( + 'mis.report.instance.period') for idx, line in enumerate(vals['period_ids']): if line[0] == 0: line[2]['sequence'] = idx + 1 else: - mis_report_instance_period_obj.write(cr, uid, [line[1]], {'sequence': idx + 1}, context=context) - return super(mis_report_instance, self).create(cr, uid, vals, context=context) + mis_report_instance_period_obj.write( + cr, uid, [line[1]], {'sequence': idx + 1}, + context=context) + return super(mis_report_instance, self).create(cr, uid, vals, + context=context) def write(self, cr, uid, ids, vals, context=None): - res = super(mis_report_instance, self).write(cr, uid, ids, vals, context=context) - mis_report_instance_period_obj = self.pool.get('mis.report.instance.period') + res = super(mis_report_instance, self).write( + cr, uid, ids, vals, context=context) + mis_report_instance_period_obj = self.pool.get( + 'mis.report.instance.period') for instance in self.browse(cr, uid, ids, context): for idx, period in enumerate(instance.period_ids): - mis_report_instance_period_obj.write(cr, uid, [period.id], {'sequence': idx + 1}, context=context) + mis_report_instance_period_obj.write( + cr, uid, [period.id], {'sequence': idx + 1}, + context=context) return res def _format_date(self, cr, uid, date, context=None): # format date following user language - lang = self.pool['res.users'].read(cr, uid, uid, ['lang'], context=context)['lang'] - language_id = self.pool['res.lang'].search(cr, uid, [('code', '=', lang)], context=context)[0] - tformat = self.pool['res.lang'].read(cr, uid, language_id, ['date_format'])['date_format'] - return datetime.strftime(datetime.strptime(date, tools.DEFAULT_SERVER_DATE_FORMAT), tformat) + lang = self.pool['res.users'].read( + cr, uid, uid, ['lang'], context=context)['lang'] + language_id = self.pool['res.lang'].search( + cr, uid, [('code', '=', lang)], context=context)[0] + tformat = self.pool['res.lang'].read( + cr, uid, language_id, ['date_format'])['date_format'] + return datetime.strftime(datetime.strptime( + date, + tools.DEFAULT_SERVER_DATE_FORMAT), + tformat) def compute(self, cr, uid, _ids, context=None): assert isinstance(_ids, (int, long)) @@ -604,31 +679,37 @@ class mis_report_instance(orm.Model): context['state'] = r.target_move content = OrderedDict() - #empty line name for header + # empty line name for header header = OrderedDict() header[''] = {'kpi_name': '', 'cols': []} - #initialize lines with kpi + # initialize lines with kpi for kpi in r.report_id.kpi_ids: content[kpi.name] = {'kpi_name': kpi.description, 'cols': []} - report_instance_period_obj = self.pool.get('mis.report.instance.period') + report_instance_period_obj = self.pool.get( + 'mis.report.instance.period') kpi_obj = self.pool.get('mis.report.kpi') period_values = {} for period in r.period_ids: # add the column header - header['']['cols'].append(dict(name=period.name, - date=(period.duration > 1 or period.type == 'w') and - _('from %s to %s' % - (period.period_from and period.period_from.name - or self._format_date(cr, uid, period.date_from, context=context), - period.period_to and period.period_to.name - or self._format_date(cr, uid, period.date_to, context=context))) - or period.period_from and period.period_from.name or period.date_from)) + header['']['cols'].append(dict( + name=period.name, + date=(period.duration > 1 or period.type == 'w') and + _('from %s to %s' % + (period.period_from and period.period_from.name + or self._format_date(cr, uid, period.date_from, + context=context), + period.period_to and period.period_to.name + or self._format_date(cr, uid, period.date_to, + context=context))) + or period.period_from and period.period_from.name or + period.date_from)) # compute kpi values - values = report_instance_period_obj._compute(cr, uid, period, context=context) + values = report_instance_period_obj._compute( + cr, uid, period, context=context) period_values[period.name] = values for key in values: content[key]['cols'].append(values[key]) @@ -637,14 +718,22 @@ class mis_report_instance(orm.Model): for period in r.period_ids: for compare_col in period.comparison_column_ids: # add the column header - header['']['cols'].append(dict(name='%s - %s' % (period.name, compare_col.name), date='')) + header['']['cols'].append( + dict(name='%s - %s' % (period.name, compare_col.name), + date='')) column1_values = period_values[period.name] column2_values = period_values[compare_col.name] for kpi in r.report_id.kpi_ids: - content[kpi.name]['cols'].append({'val_r': kpi_obj._render_comparison(cr, uid, kpi, - column1_values[kpi.name]['val'], - column2_values[kpi.name]['val'], - period.normalize_factor, compare_col.normalize_factor, context=context)}) + content[kpi.name]['cols'].append( + {'val_r': kpi_obj._render_comparison( + cr, + uid, + kpi, + column1_values[kpi.name]['val'], + column2_values[kpi.name]['val'], + period.normalize_factor, + compare_col.normalize_factor, + context=context)}) return {'header': header, 'content': content} diff --git a/mis_builder/report/mis_builder_xls.py b/mis_builder/report/mis_builder_xls.py index 08615cb5..2882ad07 100644 --- a/mis_builder/report/mis_builder_xls.py +++ b/mis_builder/report/mis_builder_xls.py @@ -31,23 +31,29 @@ _logger = logging.getLogger(__name__) class mis_builder_xls_parser(report_sxw.rml_parse): def __init__(self, cr, uid, name, context): - super(mis_builder_xls_parser, self).__init__(cr, uid, name, context=context) + super(mis_builder_xls_parser, self).__init__( + cr, uid, name, context=context) self.context = context class mis_builder_xls(report_xls): - def __init__(self, name, table, rml=False, parser=False, header=True, store=False): - super(mis_builder_xls, self).__init__(name, table, rml, parser, header, store) + def __init__(self, name, table, rml=False, parser=False, header=True, + store=False): + super(mis_builder_xls, self).__init__( + name, table, rml, parser, header, store) # Cell Styles _xs = self.xls_styles # header - rh_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all'] + _xs['right'] + rh_cell_format = _xs['bold'] + _xs['fill'] + \ + _xs['borders_all'] + _xs['right'] self.rh_cell_style = xlwt.easyxf(rh_cell_format) - self.rh_cell_style_date = xlwt.easyxf(rh_cell_format, num_format_str=report_xls.date_format) + self.rh_cell_style_date = xlwt.easyxf( + rh_cell_format, num_format_str=report_xls.date_format) # lines - self.mis_rh_cell_style = xlwt.easyxf(_xs['borders_all'] + _xs['bold'] + _xs['fill']) + self.mis_rh_cell_style = xlwt.easyxf( + _xs['borders_all'] + _xs['bold'] + _xs['fill']) def generate_xls_report(self, _p, _xs, data, objects, wb): @@ -68,26 +74,36 @@ class mis_builder_xls(report_xls): ('report_name', 1, 0, 'text', report_name), ] row_data = self.xls_row_template(c_specs, ['report_name']) - row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=xlwt.easyxf(_xs['xls_title'])) + row_pos = self.xls_write_row( + ws, row_pos, row_data, row_style=xlwt.easyxf(_xs['xls_title'])) row_pos += 1 # get the computed result of the report - data = self.pool.get('mis.report.instance').compute(self.cr, self.uid, objects[0].id) + data = self.pool.get('mis.report.instance').compute( + self.cr, self.uid, objects[0].id) # Column headers header_name_list = [''] col_specs_template = {'': {'header': [1, 30, 'text', ''], 'header_date': [1, 1, 'text', '']}} for col in data['header']['']['cols']: - col_specs_template[col['name']] = {'header': [1, 30, 'text', col['name']], - 'header_date': [1, 1, 'text', col['date']]} + col_specs_template[col['name']] = {'header': [1, 30, 'text', + col['name']], + 'header_date': [1, 1, 'text', + col['date']]} header_name_list.append(col['name']) - c_specs = map(lambda x: self.render(x, col_specs_template, 'header'), header_name_list) + c_specs = map( + lambda x: self.render(x, col_specs_template, 'header'), + header_name_list) row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs]) - row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=self.rh_cell_style, set_column_size=True) - c_specs = map(lambda x: self.render(x, col_specs_template, 'header_date'), header_name_list) + row_pos = self.xls_write_row( + ws, row_pos, row_data, row_style=self.rh_cell_style, + set_column_size=True) + c_specs = map(lambda x: self.render( + x, col_specs_template, 'header_date'), header_name_list) row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs]) - row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=self.rh_cell_style_date) + row_pos = self.xls_write_row( + ws, row_pos, row_data, row_style=self.rh_cell_style_date) ws.set_horz_split_pos(row_pos) ws.set_vert_split_pos(1) @@ -104,7 +120,9 @@ class mis_builder_xls(report_xls): num_format_str += '0' * int(value['dp']) if value.get('suffix'): num_format_str = num_format_str + ' "%s"' % value['suffix'] - kpi_cell_style = xlwt.easyxf(_xs['borders_all'] + _xs['right'], num_format_str=num_format_str) + kpi_cell_style = xlwt.easyxf( + _xs['borders_all'] + _xs['right'], + num_format_str=num_format_str) if value.get('val'): val = value['val'] if value.get('is_percentage'): @@ -116,7 +134,7 @@ class mis_builder_xls(report_xls): mis_builder_xls('report.mis.report.instance.xls', - 'mis.report.instance', - parser=mis_builder_xls_parser) + 'mis.report.instance', + parser=mis_builder_xls_parser) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/mis_builder/tests/mis_builder_test.py b/mis_builder/tests/mis_builder_test.py index e067cc93..ec6238f3 100644 --- a/mis_builder/tests/mis_builder_test.py +++ b/mis_builder/tests/mis_builder_test.py @@ -37,29 +37,42 @@ class mis_builder_test(common.TransactionCase): def test_datetime_conversion(self): date_to_convert = '2014-07-05' - date_time_convert = models.mis_builder._utc_midnight(date_to_convert, 'Europe/Brussels') - self.assertEqual(date_time_convert, '2014-07-04 22:00:00', 'The converted date time convert must contains hour') - date_time_convert = models.mis_builder._utc_midnight(date_to_convert, 'Europe/Brussels', add_day=1) - self.assertEqual(date_time_convert, '2014-07-05 22:00:00', 'The converted date time convert must contains hour') - date_time_convert = models.mis_builder._utc_midnight(date_to_convert, 'US/Pacific') - self.assertEqual(date_time_convert, '2014-07-05 07:00:00', 'The converted date time convert must contains hour') - date_time_convert = models.mis_builder._utc_midnight(date_to_convert, 'US/Pacific', add_day=1) - self.assertEqual(date_time_convert, '2014-07-06 07:00:00', 'The converted date time convert must contains hour') + date_time_convert = models.mis_builder._utc_midnight( + date_to_convert, 'Europe/Brussels') + self.assertEqual(date_time_convert, '2014-07-04 22:00:00', + 'The converted date time convert must contains hour') + date_time_convert = models.mis_builder._utc_midnight( + date_to_convert, 'Europe/Brussels', add_day=1) + self.assertEqual(date_time_convert, '2014-07-05 22:00:00', + 'The converted date time convert must contains hour') + date_time_convert = models.mis_builder._utc_midnight( + date_to_convert, 'US/Pacific') + self.assertEqual(date_time_convert, '2014-07-05 07:00:00', + 'The converted date time convert must contains hour') + date_time_convert = models.mis_builder._utc_midnight( + date_to_convert, 'US/Pacific', add_day=1) + self.assertEqual(date_time_convert, '2014-07-06 07:00:00', + 'The converted date time convert must contains hour') def test_fetch_query(self): - # create a report on a model without company_id field : account.analytic.balance - data = self.registry('mis.report.instance').compute(self.cr, self.uid, self.ref('mis_builder.mis_report_instance_test')) - self.assertDictContainsSubset({'content': OrderedDict([(u'total_test', - {'kpi_name': u'total test', - 'cols': [{'style': None, - 'val_c': None, - 'val': 0, - 'val_r': '0 '}]})]), - 'header': OrderedDict([('', - {'kpi_name': '', - 'cols': [{'date': '2014-07-31', - 'name': u'today'}] - })]) - }, data) + # create a report on a model without company_id field : + # account.analytic.balance + data = self.registry('mis.report.instance').compute( + self.cr, self.uid, + self.ref('mis_builder.mis_report_instance_test')) + self.assertDictContainsSubset( + {'content': + OrderedDict([(u'total_test', + {'kpi_name': u'total test', + 'cols': [{'style': None, + 'val_c': None, + 'val': 0, + 'val_r': '0 '}]})]), + 'header': OrderedDict([('', + {'kpi_name': '', + 'cols': [{'date': '2014-07-31', + 'name': u'today'}] + })]) + }, data) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/mis_builder/wizard/__init__.pyc b/mis_builder/wizard/__init__.pyc index ada309ee..09780526 100644 Binary files a/mis_builder/wizard/__init__.pyc and b/mis_builder/wizard/__init__.pyc differ diff --git a/mis_builder/wizard/mis_builder_dashboard.py b/mis_builder/wizard/mis_builder_dashboard.py index f47b4092..0fcf2274 100644 --- a/mis_builder/wizard/mis_builder_dashboard.py +++ b/mis_builder/wizard/mis_builder_dashboard.py @@ -29,17 +29,21 @@ class add_mis_report_instance_dashboard(orm.TransientModel): _name = "add.mis.report.instance.dashboard.wizard" _columns = {'name': fields.char('Name', size=32, required=True), - 'dashboard_id': fields.many2one('ir.actions.act_window', string="Dashboard", required=True, - domain="[('res_model', '=', 'board.board')]"), + 'dashboard_id': fields.many2one( + 'ir.actions.act_window', + string="Dashboard", required=True, + domain="[('res_model', '=', 'board.board')]"), } def default_get(self, cr, uid, fields, context=None): if context is None: context = {} if context.get('active_id'): - res = super(add_mis_report_instance_dashboard, self).default_get(cr, uid, fields, context=context) + res = super(add_mis_report_instance_dashboard, self).default_get( + cr, uid, fields, context=context) # get report instance name - res['name'] = self.pool['mis.report.instance'].read(cr, uid, context['active_id'], ['name'])['name'] + res['name'] = self.pool['mis.report.instance'].read( + cr, uid, context['active_id'], ['name'])['name'] return res def action_add_to_dashboard(self, cr, uid, ids, context=None): @@ -48,28 +52,36 @@ class add_mis_report_instance_dashboard(orm.TransientModel): assert 'active_id' in context, "active_id missing in context" wizard_data = self.browse(cr, uid, ids, context=context)[0] # create the act_window corresponding to this report - view_id = self.pool['ir.model.data'].get_object_reference(cr, uid, 'mis_builder', 'mis_report_instance_result_view_form')[1] - report_result = self.pool['ir.actions.act_window'].create(cr, uid, {'name': 'mis.report.instance.result.view.action.%d' % context['active_id'], - 'res_model': 'mis.report.instance', - 'res_id': context['active_id'], - 'target': 'current', - 'view_mode': 'form', - 'view_id': view_id}) + view_id = self.pool['ir.model.data'].get_object_reference( + cr, uid, 'mis_builder', 'mis_report_instance_result_view_form')[1] + report_result = self.pool['ir.actions.act_window'].create( + cr, uid, + {'name': 'mis.report.instance.result.view.action.%d' + % context['active_id'], + 'res_model': 'mis.report.instance', + 'res_id': context['active_id'], + 'target': 'current', + 'view_mode': 'form', + 'view_id': view_id}) # add this result in the selected dashboard - last_customization = self.pool['ir.ui.view.custom'].search(cr, uid, [('user_id', '=', uid), - ('ref_id', '=', wizard_data.dashboard_id.view_id.id)], limit=1) + last_customization = self.pool['ir.ui.view.custom'].search( + cr, uid, + [('user_id', '=', uid), + ('ref_id', '=', wizard_data.dashboard_id.view_id.id)], limit=1) arch = wizard_data.dashboard_id.view_id.arch if last_customization: - arch = self.pool['ir.ui.view.custom'].read(cr, uid, last_customization[0], ['arch'])['arch'] + arch = self.pool['ir.ui.view.custom'].read( + cr, uid, last_customization[0], ['arch'])['arch'] new_arch = etree.fromstring(arch) column = new_arch.xpath("//column")[0] column.append(etree.Element('action', {'context': str(context), - 'name': str(report_result), - 'string': wizard_data.name, - 'view_mode': 'form'})) - self.pool['ir.ui.view.custom'].create(cr, uid, {'user_id': uid, - 'ref_id': wizard_data.dashboard_id.view_id.id, - 'arch': etree.tostring(new_arch, pretty_print=True)}) + 'name': str(report_result), + 'string': wizard_data.name, + 'view_mode': 'form'})) + self.pool['ir.ui.view.custom'].create( + cr, uid, {'user_id': uid, + 'ref_id': wizard_data.dashboard_id.view_id.id, + 'arch': etree.tostring(new_arch, pretty_print=True)}) return {'type': 'ir.actions.act_window_close', } diff --git a/mis_builder_demo/__openerp__.py b/mis_builder_demo/__openerp__.py index 452d8fbf..312322cb 100644 --- a/mis_builder_demo/__openerp__.py +++ b/mis_builder_demo/__openerp__.py @@ -39,7 +39,7 @@ 'mis.report.csv', 'mis.report.instance.period.csv', 'mis.report.instance.csv', - ], + ], 'installable': True, 'application': True, 'auto_install': False,