Browse Source

[FIX] group_mgmtsystem_manager XML ID

[IMP] mgmtsystem_kpi
pull/510/head^2
Maxime Chambreuil 12 years ago
parent
commit
515db13c76
  1. 2
      mgmtsystem_kpi/__openerp__.py
  2. 156
      mgmtsystem_kpi/mgmtsystem_kpi.py
  3. 38
      mgmtsystem_kpi/mgmtsystem_kpi_view.xml
  4. 11
      mgmtsystem_kpi/security/ir.model.access.csv

2
mgmtsystem_kpi/__openerp__.py

@ -49,6 +49,7 @@
], ],
"data" : [ "data" : [
'mgmtsystem_kpi_view.xml', 'mgmtsystem_kpi_view.xml',
'security/ir.model.access.csv',
], ],
"images" : [ "images" : [
"images/kpi_definition.png", "images/kpi_definition.png",
@ -59,7 +60,6 @@
"demo" : [], "demo" : [],
"test" : [], "test" : [],
"installable" : True, "installable" : True,
"complexity": "normal",
} }
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

156
mgmtsystem_kpi/mgmtsystem_kpi.py

@ -22,7 +22,28 @@
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from datetime import datetime from datetime import datetime
from osv import fields, osv from osv import fields, osv
from openerp.tools.translate import _
import openerp.tools as tools
import time 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():
return True
elif type(result) is list and 'value' in result[0]:
return True
else:
return False
def is_select_query(query):
# check if sql query is a SELECT statement
for statement in ('INSERT', 'UPDATE', 'DELETE', 'CREATE', 'ALTER', 'DROP', 'GRANT', 'REVOKE', 'INDEX'):
if statement in query:
return False
return True
class mgmtsystem_kpi_category(osv.osv): class mgmtsystem_kpi_category(osv.osv):
""" """
@ -44,67 +65,94 @@ class mgmtsystem_kpi_threshold_range(osv.osv):
_name = "mgmtsystem.kpi.threshold.range" _name = "mgmtsystem.kpi.threshold.range"
_description = "KPI Threshold Range" _description = "KPI Threshold Range"
def _compute_min_value(self, cr, uid, ids, field_name, arg, context=None):
def compute_min_value(self, cr, uid, ids, field_name, arg, context=None):
if context is None: if context is None:
context = {} context = {}
result = {} result = {}
for obj in self.browse(cr, uid, ids): for obj in self.browse(cr, uid, ids):
value = 0
if obj.min_type == 'local':
value = None
if obj.min_type == 'local' and is_select_query(obj.min_code):
cr.execute(obj.min_code) cr.execute(obj.min_code)
value = cr.dictfetchone()['value']
elif obj.max_type == 'external':
if not dbsource_id:
dbsrc_obj = self.pool.get('base.external.dbsource').browse(cr, uid, min_dbsource_id, context)
dic = cr.dictfetchall()
if is_one_value(dic):
value = dic[0]['value']
elif obj.min_type == 'external' and obj.min_dbsource_id.id and is_select_query(obj.min_code):
dbsrc_obj = self.pool.get('base.external.dbsource').browse(cr, uid, obj.min_dbsource_id.id, context)
res = dbsrc_obj.execute(obj.min_code) res = dbsrc_obj.execute(obj.min_code)
if is_one_value(res):
value = res[0]['value'] value = res[0]['value']
elif obj.min_type == 'python': elif obj.min_type == 'python':
value = eval(obj.min_code) value = eval(obj.min_code)
else: else:
value = obj.min_fixed_value value = obj.min_fixed_value
result[obj.id] = value result[obj.id] = value
return result return result
def _compute_max_value(self, cr, uid, ids, field_name, arg, context=None):
def compute_max_value(self, cr, uid, ids, field_name, arg, context=None):
if context is None: if context is None:
context = {} context = {}
result = {} result = {}
for obj in self.browse(cr, uid, ids):
value = 0
if obj.max_type == 'local':
for obj in self.browse(cr, uid, ids, context):
value = None
if obj.max_type == 'local' and is_select_query(obj.max_code):
cr.execute(obj.max_code) cr.execute(obj.max_code)
value = cr.dictfetchone()['value']
dic = cr.dictfetchall()
if is_one_value(dic):
value = dic[0]['value']
elif obj.max_type == 'python': elif obj.max_type == 'python':
value = eval(obj.max_code) value = eval(obj.max_code)
elif obj.max_type == 'external':
if not dbsource_id:
dbsrc_obj = self.pool.get('base.external.dbsource').browse(cr, uid, max_dbsource_id, context)
elif obj.max_type == 'external' and obj.max_dbsource_id.id and is_select_query(obj.max_code):
dbsrc_obj = self.pool.get('base.external.dbsource').browse(cr, uid, obj.max_dbsource_id.id, context)
res = dbsrc_obj.execute(obj.max_code) res = dbsrc_obj.execute(obj.max_code)
if is_one_value(res):
value = res[0]['value'] value = res[0]['value']
else: else:
value = obj.max_fixed_value value = obj.max_fixed_value
result[obj.id] = value result[obj.id] = value
return result
def _is_valid_range(self, cr, uid, ids, field_name, arg, context=None):
if context is None:
context = {}
result = {}
for obj in self.browse(cr, uid, ids, context):
if obj.max_value < obj.min_value:
result[obj.id] = False
else:
result[obj.id] = True
return result
def _generate_invalid_message(self, cr, uid, ids, field_name, arg, context=None):
if context is None:
context = {}
result = {}
for obj in self.browse(cr, uid, ids, context):
if obj.valid:
result[obj.id] = ""
else:
result[obj.id] = "Minimum value is greater than the maximum value! Please adjust them."
return result return result
_columns = { _columns = {
'name': fields.char('Name', size=50, required=True), '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_value': fields.function(compute_min_value, string='Minimum', type='float'),
'min_fixed_value': fields.float('Minimum'), 'min_fixed_value': fields.float('Minimum'),
'min_code': fields.text('Minimum Computation Code'), 'min_code': fields.text('Minimum Computation Code'),
'min_dbsource_id': fields.many2one('base.external.dbsource','External DB Source'), '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_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_value': fields.function(compute_max_value, string='Maximum', type='float'),
'max_fixed_value': fields.float('Maximum'), 'max_fixed_value': fields.float('Maximum'),
'max_code': fields.text('Maximum Computation Code'), '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), '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'),
}
_defaults = {
'valid': True,
} }
mgmtsystem_kpi_threshold_range() mgmtsystem_kpi_threshold_range()
@ -116,18 +164,61 @@ class mgmtsystem_kpi_threshold(osv.osv):
_name = "mgmtsystem.kpi.threshold" _name = "mgmtsystem.kpi.threshold"
_description = "KPI Threshold" _description = "KPI Threshold"
def _is_valid_threshold(self, cr, uid, ids, field_name, arg, context=None):
if context is None:
context = {}
result = {}
for obj in self.browse(cr, uid, ids, context):
# check if ranges overlap
for range_obj1 in obj.range_ids:
for range_obj2 in obj.range_ids:
if range_obj1.valid and range_obj2.valid and range_obj1.min_value < range_obj2.min_value:
if range_obj1.max_value <= range_obj2.min_value:
result[obj.id] = True
else:
result[obj.id] = False
return result
def _generate_invalid_message(self, cr, uid, ids, field_name, arg, context=None):
if context is None:
context = {}
result = {}
for obj in self.browse(cr, uid, ids, context):
if obj.valid:
result[obj.id] = ""
else:
result[obj.id] = "2 of your ranges are overlapping! Please make sure your ranges do not overlap."
return result
_columns = { _columns = {
'name': fields.char('Name', size=50, required=True), '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', 'Range', required=True),
'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'),
} }
def write(self, cr, uid, ids, vals, context=None):
_defaults = {
'valid': True,
}
def create(self, cr, uid, data, context=None):
if context is None: if context is None:
context = {} context = {}
# TODO: check if ranges overlap
return super(mgmtsystem_kpi_threshold, self).write(cr, uid, ids, vals, context=context)
# check if ranges overlap
range_obj1 = self.pool.get('mgmtsystem.kpi.threshold.range')
range_obj2 = self.pool.get('mgmtsystem.kpi.threshold.range')
for range1 in data['range_ids'][0][2]:
range_obj1 = range_obj1.browse(cr, uid, range1, context)
for range2 in data['range_ids'][0][2]:
range_obj2 = range_obj2.browse(cr, uid, range2, context)
if range_obj1.valid and range_obj2.valid and range_obj1.min_value < range_obj2.min_value:
if range_obj1.max_value > range_obj2.min_value:
raise osv.except_osv(_("2 of your ranges are overlapping!"), _("Please make sure your ranges do not overlap!"))
range_obj2 = self.pool.get('mgmtsystem.kpi.threshold.range')
range_obj1 = self.pool.get('mgmtsystem.kpi.threshold.range')
return super(mgmtsystem_kpi_threshold, self).create(cr, uid, data, context)
def get_color(self, cr, uid, ids, kpi_value, context=None): def get_color(self, cr, uid, ids, kpi_value, context=None):
if context is None: if context is None:
@ -137,7 +228,7 @@ class mgmtsystem_kpi_threshold(osv.osv):
for obj in self.browse(cr, uid, ids, context): for obj in self.browse(cr, uid, ids, context):
for range_id in obj.range_ids: for range_id in obj.range_ids:
range_obj = self.pool.get('mgmtsystem.kpi.threshold.range').browse(cr, uid, range_id.id, context) 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:
if range_obj.min_value <= kpi_value <= range_obj.max_value and range_obj.valid:
color = range_obj.color color = range_obj.color
return color return color
@ -191,17 +282,16 @@ class mgmtsystem_kpi(osv.osv):
def compute_kpi_value(self, cr, uid, ids, context=None): def compute_kpi_value(self, cr, uid, ids, context=None):
if context is None: if context is None:
context = {} context = {}
kpi_value = 0
for obj in self.browse(cr, uid, ids): for obj in self.browse(cr, uid, ids):
kpi_value = 0 kpi_value = 0
if obj.kpi_type == 'local':
if obj.kpi_type == 'local' and is_select_query(obj.kpi_code):
cr.execute(obj.kpi_code) cr.execute(obj.kpi_code)
if is_one_value(cr.dictfetchall()):
kpi_value = cr.dictfetchone()['value'] kpi_value = cr.dictfetchone()['value']
elif obj.kpi_type == 'external':
if obj.dbsource_id.id:
elif obj.kpi_type == 'external' and obj.dbsource_id.id and is_select_query(obj.kpi_code):
dbsrc_obj = self.pool.get('base.external.dbsource').browse(cr, uid, obj.dbsource_id.id, context) dbsrc_obj = self.pool.get('base.external.dbsource').browse(cr, uid, obj.dbsource_id.id, context)
res = dbsrc_obj.execute(obj.kpi_code) res = dbsrc_obj.execute(obj.kpi_code)
if is_one_value(res):
kpi_value = res[0]['value'] kpi_value = res[0]['value']
elif obj.kpi_type == 'python': elif obj.kpi_type == 'python':
kpi_value = eval(obj.kpi_code) kpi_value = eval(obj.kpi_code)

38
mgmtsystem_kpi/mgmtsystem_kpi_view.xml

@ -116,7 +116,7 @@
<menuitem id="menu_mgmtsystem_configuration_kpi" <menuitem id="menu_mgmtsystem_configuration_kpi"
name="KPI" name="KPI"
parent="mgmtsystem.menu_mgmtsystem_configuration" parent="mgmtsystem.menu_mgmtsystem_configuration"
groups="base.group_mgmtsystem_manager"
groups="mgmtsystem.group_mgmtsystem_manager"
sequence="20"/> sequence="20"/>
<!-- Categories --> <!-- Categories -->
@ -157,7 +157,7 @@
name="Categories" name="Categories"
action="open_mgmtsystem_category_list" action="open_mgmtsystem_category_list"
parent="menu_mgmtsystem_configuration_kpi" parent="menu_mgmtsystem_configuration_kpi"
groups="base.group_mgmtsystem_manager"
groups="mgmtsystem.group_mgmtsystem_manager"
sequence="10"/> sequence="10"/>
<!-- Thresholds --> <!-- Thresholds -->
@ -169,6 +169,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Thresholds"> <tree string="Thresholds">
<field name="name"/> <field name="name"/>
<field name="invalid_message"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -181,14 +182,15 @@
<form string="Threshold"> <form string="Threshold">
<field name="name"/> <field name="name"/>
<newline/> <newline/>
<field name="range_ids" nolabel="1" colspan="2">
<tree string="Ranges">
<field name="name"/>
<field name="min_value"/>
<field name="max_value"/>
<field name="color"/>
</tree>
</field>
<separator string="Ranges" colspan="2"/>
<newline/>
<field name="range_ids" nolabel="1" colspan="2"/>
<newline/>
<separator string="KPIs" colspan="2"/>
<newline/>
<field name="kpi_ids" nolabel="1" colspan="2"/>
<newline/>
<field name="invalid_message" nolabel="1" attrs="{'invisible' : [('invalid_message', '=', '')]}" colspan="2"/>
</form> </form>
</field> </field>
</record> </record>
@ -205,7 +207,7 @@
name="Thresholds" name="Thresholds"
action="open_mgmtsystem_threshold_list" action="open_mgmtsystem_threshold_list"
parent="menu_mgmtsystem_configuration_kpi" parent="menu_mgmtsystem_configuration_kpi"
groups="base.group_mgmtsystem_manager"
groups="mgmtsystem.group_mgmtsystem_manager"
sequence="10"/> sequence="10"/>
<!-- Ranges --> <!-- Ranges -->
@ -220,6 +222,7 @@
<field name="min_value"/> <field name="min_value"/>
<field name="max_value"/> <field name="max_value"/>
<field name="color"/> <field name="color"/>
<field name="invalid_message"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -248,6 +251,10 @@
<field name="max_dbsource_id" attrs="{'invisible' : [('max_type', '!=', 'external')]}"/> <field name="max_dbsource_id" attrs="{'invisible' : [('max_type', '!=', 'external')]}"/>
<newline/> <newline/>
<field name="max_code" colspan="4" attrs="{'invisible' : [('max_type', 'NOT IN', ('local','external','python'))]}"/> <field name="max_code" colspan="4" attrs="{'invisible' : [('max_type', 'NOT IN', ('local','external','python'))]}"/>
<newline/>
<separator string="Thresholds" colspan="4"/>
<field name="threshold_ids" nolabel="1" colspan="4"/>
<field name="invalid_message" nolabel="1" attrs="{'invisible' : [('invalid_message', '=', '')]}" colspan="4"/>
</form> </form>
</field> </field>
</record> </record>
@ -264,7 +271,14 @@
name="Ranges" name="Ranges"
action="open_mgmtsystem_threshold_range_list" action="open_mgmtsystem_threshold_range_list"
parent="menu_mgmtsystem_configuration_kpi" parent="menu_mgmtsystem_configuration_kpi"
groups="base.group_mgmtsystem_manager"
groups="mgmtsystem.group_mgmtsystem_manager"
sequence="20"/>
<menuitem id="menu_mgmtsystem_configuration_kpi_dbsource"
name="Data Sources"
action="base_external_dbsource.action_dbsource"
parent="menu_mgmtsystem_configuration_kpi"
groups="mgmtsystem.group_mgmtsystem_manager"
sequence="20"/> sequence="20"/>
</data> </data>

11
mgmtsystem_kpi/security/ir.model.access.csv

@ -0,0 +1,11 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_mgmtsystem_kpi_user","mgmtsystem.kpi.user","model_mgmtsystem_kpi","base.group_user",1,0,0,0
"access_mgmtsystem_kpi_history_user","mgmtsystem.kpi.history.user","model_mgmtsystem_kpi_history","base.group_user",1,0,0,0
"access_mgmtsystem_kpi_category_user","mgmtsystem.kpi.category.user","model_mgmtsystem_kpi_category","base.group_user",1,0,0,0
"access_mgmtsystem_kpi_threshold_user","mgmtsystem.kpi.threshold.user","model_mgmtsystem_kpi_threshold","base.group_user",1,0,0,0
"access_mgmtsystem_kpi_threshold_range_user","mgmtsystem.kpi.threshold.range.user","model_mgmtsystem_kpi_threshold_range","base.group_user",1,0,0,0
"access_mgmtsystem_kpi_manager","mgmtsystem.kpi.manager","model_mgmtsystem_kpi","mgmtsystem.group_mgmtsystem_manager",1,1,1,1
"access_mgmtsystem_kpi_category_manager","mgmtsystem.kpi.category.manager","model_mgmtsystem_kpi_category","mgmtsystem.group_mgmtsystem_manager",1,1,1,1
"access_mgmtsystem_kpi_threshold_manager","mgmtsystem.kpi.threshold.manager","model_mgmtsystem_kpi_threshold","mgmtsystem.group_mgmtsystem_manager",1,1,1,1
"access_mgmtsystem_kpi_threshold_range_manager","mgmtsystem.kpi.threshold.range.manager","model_mgmtsystem_kpi_threshold_range","mgmtsystem.group_mgmtsystem_manager",1,1,1,1
"access_base_external_dbsource_mgmtsystem_manager","base.external.dbsource.manager","base_external_dbsource.model_base_external_dbsource","mgmtsystem.group_mgmtsystem_manager",1,1,1,1
Loading…
Cancel
Save