diff --git a/mgmtsystem_kpi/__openerp__.py b/mgmtsystem_kpi/__openerp__.py index 648e526a1..25eb63f4f 100755 --- a/mgmtsystem_kpi/__openerp__.py +++ b/mgmtsystem_kpi/__openerp__.py @@ -1,6 +1,6 @@ # -*- encoding: utf-8 -*- ############################################################################## -# +# # OpenERP, Open Source Management Solution # Copyright (C) 2012 Savoir-faire Linux (). # @@ -15,57 +15,56 @@ # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . +# along with this program. If not, see . # ############################################################################## { - "name" : "Key Performance Indicator", - "version" : "1.1", - "author" : "Savoir-faire Linux", - "website" : "http://www.savoirfairelinux.com", - "license" : "AGPL-3", - "category" : "Management System", - "complexity" : "normal", + "name": "Key Performance Indicator", + "version": "1.1", + "author": "Savoir-faire Linux", + "website": "http://www.savoirfairelinux.com", + "license": "AGPL-3", + "category": "Management System", + "complexity": "normal", "description": """\ This module provides the basis for creating key performance indicators, -including static and dynamic thresholds (SQL query or Python code), +including static and dynamic thresholds (SQL query or Python code), on local and remote data sources. -The module also provides the mecanism to update KPIs automatically. -A scheduler is executed every hour and updates the KPI values, based -on the periodicity of each KPI. KPI computation can also be done +The module also provides the mecanism to update KPIs automatically. +A scheduler is executed every hour and updates the KPI values, based +on the periodicity of each KPI. KPI computation can also be done manually. A threshold is a list of ranges and a range is: * a name (like Good, Warning, Bad) * a minimum value (fixed, sql query or python code) * a maximum value (fixed, sql query or python code) - * color (RGB code like #00FF00 for green, #FFA500 for orange, + * color (RGB code like #00FF00 for green, #FFA500 for orange, #FF0000 for red) This module depends on: * base_external_dbsource (available in lp:openobject-extension) * web_color (available in lp:web-addons) """, - "depends" : [ + "depends": [ 'mgmtsystem', 'base_external_dbsource', 'web_color', ], - "data" : [ + "data": [ 'security/ir.model.access.csv', 'security/mgmtsystem_kpi_security.xml', 'mgmtsystem_kpi_view.xml', ], - "images" : [ + "images": [ "images/kpi_definition.png", "images/kpi_computation.png", "images/kpi_threshold.png", "images/kpi_range.png", ], - "demo" : [], - "test" : [], - "installable" : True, + "demo": [], + "test": [], + "installable": True, } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - diff --git a/mgmtsystem_kpi/mgmtsystem_kpi.py b/mgmtsystem_kpi/mgmtsystem_kpi.py index 002aa3424..7e9b8d9ef 100755 --- a/mgmtsystem_kpi/mgmtsystem_kpi.py +++ b/mgmtsystem_kpi/mgmtsystem_kpi.py @@ -1,6 +1,6 @@ # -*- encoding: utf-8 -*- ############################################################################## -# +# # OpenERP, Open Source Management Solution # Copyright (C) 2012 Savoir-faire Linux (). # @@ -15,19 +15,19 @@ # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . +# along with this program. If not, see . # ############################################################################## from dateutil.relativedelta import relativedelta from datetime import datetime -from osv import fields, osv +from osv import fields, orm, osv from openerp.tools.translate import _ -import openerp.tools as tools import time import logging _logger = logging.getLogger(__name__) + def is_one_value(result): # check if sql query returns only one value if type(result) is dict and 'value' in result.dictfetchone(): @@ -37,6 +37,7 @@ def is_one_value(result): else: return False + def is_select_query(query): # check if sql query is a SELECT statement @@ -45,7 +46,8 @@ def is_select_query(query): return False return True -class mgmtsystem_kpi_category(osv.osv): + +class mgmtsystem_kpi_category(orm.Model): """ KPI Category """ @@ -56,9 +58,8 @@ class mgmtsystem_kpi_category(osv.osv): 'description': fields.text('Description') } -mgmtsystem_kpi_category() -class mgmtsystem_kpi_threshold_range(osv.osv): +class mgmtsystem_kpi_threshold_range(orm.Model): """ KPI Threshold Range """ @@ -70,7 +71,7 @@ class mgmtsystem_kpi_threshold_range(osv.osv): context = {} result = {} for obj in self.browse(cr, uid, ids): - value = None + value = None if obj.min_type == 'local' and is_select_query(obj.min_code): cr.execute(obj.min_code) dic = cr.dictfetchall() @@ -119,7 +120,7 @@ class mgmtsystem_kpi_threshold_range(osv.osv): if obj.max_value < obj.min_value: result[obj.id] = False else: - result[obj.id] = True + result[obj.id] = True return result def _generate_invalid_message(self, cr, uid, ids, field_name, arg, context=None): @@ -137,18 +138,18 @@ class mgmtsystem_kpi_threshold_range(osv.osv): 'name': fields.char('Name', size=50, required=True), 'valid': fields.function(_is_valid_range, string='Valid', type='boolean', required=True), 'invalid_message': fields.function(_generate_invalid_message, string='Message', type='char', size=100), - 'min_type': fields.selection((('static','Fixed value'), ('python','Python Code'), ('local', 'SQL - Local DB'), ('external', 'SQL - Externa DB')), 'Min Type', required=True), + 'min_type': fields.selection((('static', 'Fixed value'), ('python', 'Python Code'), ('local', 'SQL - Local DB'), ('external', 'SQL - Externa DB')), 'Min Type', required=True), 'min_value': fields.function(compute_min_value, string='Minimum', type='float'), 'min_fixed_value': fields.float('Minimum'), 'min_code': fields.text('Minimum Computation Code'), - 'min_dbsource_id': fields.many2one('base.external.dbsource','External DB Source'), - 'max_type': fields.selection((('static','Fixed value'), ('python','Python Code'), ('local', 'SQL - Local DB'), ('external', 'SQL - External DB')), 'Max Type', required=True), + 'min_dbsource_id': fields.many2one('base.external.dbsource', 'External DB Source'), + 'max_type': fields.selection((('static', 'Fixed value'), ('python', 'Python Code'), ('local', 'SQL - Local DB'), ('external', 'SQL - External DB')), 'Max Type', required=True), 'max_value': fields.function(compute_max_value, string='Maximum', type='float'), 'max_fixed_value': fields.float('Maximum'), 'max_code': fields.text('Maximum Computation Code'), - 'max_dbsource_id': fields.many2one('base.external.dbsource','External DB Source'), + 'max_dbsource_id': fields.many2one('base.external.dbsource', 'External DB Source'), 'color': fields.char('Color', help='RGB code with #', size=7, required=True), - 'threshold_ids': fields.many2many('mgmtsystem.kpi.threshold','mgmtsystem_kpi_threshold_range_rel', 'range_id', 'threshold_id', 'Thresholds'), + 'threshold_ids': fields.many2many('mgmtsystem.kpi.threshold', 'mgmtsystem_kpi_threshold_range_rel', 'range_id', 'threshold_id', 'Thresholds'), 'company_id': fields.many2one('res.company', 'Company') } @@ -157,9 +158,8 @@ class mgmtsystem_kpi_threshold_range(osv.osv): 'valid': True, } -mgmtsystem_kpi_threshold_range() -class mgmtsystem_kpi_threshold(osv.osv): +class mgmtsystem_kpi_threshold(orm.Model): """ KPI Threshold """ @@ -194,7 +194,7 @@ class mgmtsystem_kpi_threshold(osv.osv): _columns = { 'name': fields.char('Name', size=50, required=True), - 'range_ids': fields.many2many('mgmtsystem.kpi.threshold.range','mgmtsystem_kpi_threshold_range_rel', 'threshold_id', 'range_id', 'Ranges'), + 'range_ids': fields.many2many('mgmtsystem.kpi.threshold.range', 'mgmtsystem_kpi_threshold_range_rel', 'threshold_id', 'range_id', 'Ranges'), 'valid': fields.function(_is_valid_threshold, string='Valid', type='boolean', required=True), 'invalid_message': fields.function(_generate_invalid_message, string='Message', type='char', size=100), 'kpi_ids': fields.one2many('mgmtsystem.kpi', 'threshold_id', 'KPIs'), @@ -231,14 +231,13 @@ class mgmtsystem_kpi_threshold(osv.osv): color = '#FFFFFF' for obj in self.browse(cr, uid, ids, context): for range_id in obj.range_ids: - range_obj = self.pool.get('mgmtsystem.kpi.threshold.range').browse(cr, uid, range_id.id, context) - if range_obj.min_value <= kpi_value <= range_obj.max_value and range_obj.valid: - color = range_obj.color + range_obj = self.pool.get('mgmtsystem.kpi.threshold.range').browse(cr, uid, range_id.id, context) + if range_obj.min_value <= kpi_value <= range_obj.max_value and range_obj.valid: + color = range_obj.color return color -mgmtsystem_kpi_threshold() -class mgmtsystem_kpi_history(osv.osv): +class mgmtsystem_kpi_history(orm.Model): """ History of the KPI """ @@ -261,11 +260,10 @@ class mgmtsystem_kpi_history(osv.osv): 'color': '#FFFFFF', } - _order = "date desc" + _order = "date desc" -mgmtsystem_kpi_threshold() -class mgmtsystem_kpi(osv.osv): +class mgmtsystem_kpi(orm.Model): """ Key Performance Indicators """ @@ -275,7 +273,7 @@ class mgmtsystem_kpi(osv.osv): def _display_last_kpi_value(self, cr, uid, ids, field_name, arg, context=None): if context is None: context = {} - + result = {} for obj in self.browse(cr, uid, ids): if obj.history_ids: @@ -288,8 +286,8 @@ class mgmtsystem_kpi(osv.osv): def compute_kpi_value(self, cr, uid, ids, context=None): if context is None: context = {} - for obj in self.browse(cr, uid, ids): - kpi_value = 0 + for obj in self.browse(cr, uid, ids): + kpi_value = 0 if obj.kpi_type == 'local' and is_select_query(obj.kpi_code): cr.execute(obj.kpi_code) dic = cr.dictfetchall() @@ -305,10 +303,10 @@ class mgmtsystem_kpi(osv.osv): threshold_obj = self.pool.get('mgmtsystem.kpi.threshold').browse(cr, uid, obj.threshold_id.id, context) values = { - 'kpi_id': obj.id, + 'kpi_id': obj.id, 'value': kpi_value, 'color': threshold_obj.get_color(kpi_value), - } + } history_obj = self.pool.get('mgmtsystem.kpi.history') history_id = history_obj.create(cr, uid, values, context=context) @@ -322,13 +320,13 @@ class mgmtsystem_kpi(osv.osv): for obj in self.browse(cr, uid, ids): if obj.periodicity_uom == 'hour': - new_date = datetime.now() + relativedelta( hours = +obj.periodicity ) - elif obj.periodicity_uom == 'day': - new_date = datetime.now() + relativedelta( days = +obj.periodicity ) - elif obj.periodicity_uom == 'week': - new_date = datetime.now() + relativedelta( weeks = +obj.periodicity ) - elif obj.periodicity_uom == 'month': - new_date = datetime.now() + relativedelta( months = +obj.periodicity ) + new_date = datetime.now()+relativedelta(hours=+obj.periodicity) + elif obj.periodicity_uom == 'day': + new_date = datetime.now()+relativedelta(days=+obj.periodicity) + elif obj.periodicity_uom == 'week': + new_date = datetime.now()+relativedelta(weeks=+obj.periodicity) + elif obj.periodicity_uom == 'month': + new_date = datetime.now()+relativedelta(months=+obj.periodicity) values = { 'next_execution_date': new_date.strftime('%Y-%m-%d %H:%M:%S'), @@ -354,20 +352,20 @@ class mgmtsystem_kpi(osv.osv): self.update_next_execution_date(cr, uid, ids, context=context) except Exception: _logger.exception("Failed updating KPI values") - + return res _columns = { 'name': fields.char('Name', size=50, required=True), 'description': fields.text('Description'), - 'category_id': fields.many2one('mgmtsystem.kpi.category','Category', required=True), - 'threshold_id': fields.many2one('mgmtsystem.kpi.threshold','Threshold', required=True), + 'category_id': fields.many2one('mgmtsystem.kpi.category', 'Category', required=True), + 'threshold_id': fields.many2one('mgmtsystem.kpi.threshold', 'Threshold', required=True), 'periodicity': fields.integer('Periodicity'), - 'periodicity_uom': fields.selection((('hour','Hour'), ('day','Day'), ('week','Week'), ('month','Month')), 'Periodicity UoM', required=True), + 'periodicity_uom': fields.selection((('hour', 'Hour'), ('day', 'Day'), ('week', 'Week'), ('month', 'Month')), 'Periodicity UoM', required=True), 'next_execution_date': fields.datetime('Next execution date', readonly=True), 'value': fields.function(_display_last_kpi_value, string='Value', type='float'), - 'kpi_type': fields.selection((('python','Python'), ('local','SQL - Local DB'), ('external','SQL - External DB')),'KPI Computation Type'), - 'dbsource_id': fields.many2one('base.external.dbsource','External DB Source'), + 'kpi_type': fields.selection((('python', 'Python'), ('local', 'SQL - Local DB'), ('external', 'SQL - External DB')), 'KPI Computation Type'), + 'dbsource_id': fields.many2one('base.external.dbsource', 'External DB Source'), 'kpi_code': fields.text('KPI Code', help='SQL code must return the result as \'value\' (i.e. \'SELECT 5 AS value\').'), 'history_ids': fields.one2many('mgmtsystem.kpi.history', 'kpi_id', 'History'), 'active': fields.boolean('Active', help="Only active KPIs will be updated by the scheduler based on the periodicity configuration."), @@ -381,6 +379,4 @@ class mgmtsystem_kpi(osv.osv): 'periodicity_uom': 'day', } -mgmtsystem_kpi() - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: