Commit 23b41790 authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

New approach to generate metrics using inline script and Ext.grid.Panel.

parent b5b2d02b
......@@ -6,15 +6,19 @@
- the controller build a store containing all the information
- the content of the report is defined in the events table
"""
import json
from datetime import date, timedelta
from gluon.dal import smart_query
from gluon.storage import Storage
from reporting_tools2 import Report, repr_duration
def list():
"""List of information organised in a Ext.grid.Panel.
The main jog of the controller is to build the configuration
for the Ext.data.Array embeded in the grid
for the Ext.data.Array embedded in the grid
"""
# alias
......@@ -83,5 +87,147 @@ def list():
row.teams.team]
cfg['data'].append(li)
return dict(cfg_store=cfg, view=view)
def metric():
""" build the table showing all metrics per category, code, ...
The group field category, code, ... is defined in the viewport
and send using the baseParams techniques.
"""
report = Report(virtdb.metric_selector, exclude_fields=('category',
'metric',
'period_end',
'period_start',
'year'))
report.append_query(db.events.event == "People")
# alias
groupfield = request.vars.group
tablename, fieldname = groupfield.split('.')
# configure the Ext.data.ArrayStore
cfg = dict()
cfg['data'] = []
cfg['fields'] = [{'name': 'group', 'type': 'string'},
{'name': 'count', 'type': 'float'},
{'name': 'sum_fte', 'type': 'float'},
{'name': 'avg_age', 'type': 'float'}]
cfg['sorters'] = ['group']
# fill the data block
for di in report.get_metric(groupfield, year):
cfg['data'].append([di['group'], di['count'], di['sum_fte'], di['avg_age']])
# customize the standard view (Ext.grid.Panel)
view = Storage(columns=[], features=[])
view.columns = [{'text': T(fieldname.title()), 'dataIndex': 'group', 'flex': 0.8},
{'text': '∑ person',
'dataIndex': 'count',
'align': 'right',
'flex': 0.5,
'summaryType': 'sum' },
{'text': '∑ fte',
'dataIndex': 'sum_fte',
'align': 'right',
'flex': 0.5,
'format': '0.00',
'summaryType': 'sum',
'xtype': 'numbercolumn'},
{'text': '<age>',
'dataIndex': 'avg_age',
'align': 'right',
'flex': 0.5,
'format': '0.00',
'xtype': 'numbercolumn'}]
view.features = [{'ftype': 'summary'}]
view.columns = json.dumps(view.columns)
view.features = json.dumps(view.features)
response.view = 'list2/list.html'
return dict(cfg_store=cfg, view=view)
def metric_per_year():
""" Build the table showing metric per category / quality as
a function of the year.
The metric, count, sum_fte or avg_age is selected via the
selector.
The group field, category, code is defined in the viewport
and send using the baseParams techniques.
"""
report = Report(virtdb.metric_selector, exclude_fields=('category',
'metric',
'period_end',
'period_start',
'year'))
report.append_query(db.events.event == "People")
# alias
groupfield = request.vars.group
tablename, fieldname = groupfield.split('.')
metric = report.metric
years = range(report.period_start.year, report.period_end.year + 1)
# configure the Ext.data.ArrayStore
cfg = dict()
cfg['data'] = []
cfg['fields'] = [{'name': 'group', 'type': 'string'}]
cfg['sorters'] = ['group']
# prepare the intermediate dictionary for each group
# the value is a list containing the group and the metric
# value for each year
data = {}
for year in years:
# add the column to the store
cfg['fields'].append({'name': str(year), 'type': 'float'})
# fill the columns
for di in report.get_metric(groupfield, year):
if di['group'] not in data:
li = [di['group']]
li.extend([""]*len(years))
data[di['group']] = li
i = years.index(year) + 1
data[di['group']][i] = di[metric]
# from the intermediate dictionary
# build the data block of the store
for k in data.iterkeys():
cfg['data'].append(data[k])
#customize the standard view (Ext.grid.Panel)
view = Storage(columns=[], features=[])
view.columns.append({'text': T(fieldname.title()),
'dataIndex': 'group',
'flex': 0.8})
for year in years:
view.columns.append({'text': str(year),
'dataIndex': str(year),
'align': 'right',
'flex': 0.5,
'format': '0.00',
'summaryType': 'sum',
'xtype': 'numbercolumn'})
view.features.append({'ftype': 'summary'})
view.columns = json.dumps(view.columns)
view.features = json.dumps(view.features)
response.view = 'list2/list.html'
return dict(cfg_store=cfg, view=view)
\ No newline at end of file
......@@ -47,6 +47,7 @@
'Configure people': 'Configurer les personnels',
'Configure responsibilities': 'Configurer les responsabilités',
'Configure teams': 'Configurer les équipes',
'Configure views': 'Configure views',
'contains': 'contiens',
'Contract': 'Contrat',
'Controller': 'Controller',
......@@ -92,6 +93,7 @@
'Evènement': 'Evènement',
'Executed': 'Executé',
'Feature not yet implemented ...': 'Feature not yet implemented ...',
'Features': 'Features',
'Field': 'Champ',
'Filter agencies': 'Filtrer les agences',
'Filter budgets': 'Filtrer les budgets',
......@@ -122,8 +124,12 @@
'General': 'Général',
'Grade': 'Grade',
'greater or equal to': 'plus grand ou égual à',
'Grid': 'Grid',
'Grid Columns': 'Grid Columns',
'Grid Features': 'Grid Features',
'Group': 'Group',
'Group by': 'Group by',
'Group Field': 'Group Field',
'Group ID': 'Group ID',
'Group uniquely assigned to user %(id)s': 'Group uniquely assigned to user %(id)s',
'Groupby': 'Groupby',
......@@ -177,15 +183,21 @@
'List of trainee': 'Liste des stagiaires',
'Liste': 'Liste',
'Lists': 'Listes',
'Lists (inline)': 'Lists (inline)',
'Logged in': 'Logged in',
'Login': 'Login',
'Logout': 'Logout',
'Lost Password': 'Lost Password',
'Lost password?': 'Lost password?',
'Max Records': 'Max Records',
'Metric': 'Métrique',
'Metric / year / category': 'Métrique / année / catégorie',
'Metric / year / quality': 'Métrique / année / qualité',
'Metric people per category': 'Nb. de personnes par catégorie',
'Metric people per quality': 'Nb. personnes par qualité',
'Metric people per team': 'Nb. de personnes par équipe',
'Metrics / category': 'Métriques / catégorie',
'Metrics / quality': 'Métriques / qualité',
'Model': 'Modèle',
'Modified By': 'Modified By',
'Modified On': 'Modified On',
......@@ -254,6 +266,7 @@
'Select a teams and/or a project !!!': 'Select a teams and/or a project !!!',
'select...': 'selectionner...',
'since %s': 'depuis %s',
'Sorters': 'Sorters',
'Stage': 'Stage',
'Start': 'Début',
'start': 'début',
......@@ -295,6 +308,8 @@
'value already in database or empty': 'value already in database or empty',
'Verify Password': 'Verify Password',
'versions': 'versions',
'View': 'View',
'views': 'views',
'Welcome': 'Welcome',
'Wizards': 'Assistants',
'Year': 'Année',
......
# -*- coding: utf-8 -*-
""" list_selector
""" metric_selector
"""
virtdb.define_table('list_selector',
virtdb.define_table('metric_selector',
Field('year', 'integer', default=year),
Field('period_start', 'date'),
Field('period_end', 'date'),
Field('id_people', 'reference people', label=T('Person')),
Field('category', 'string'),
Field('id_people_categories', 'reference people_categories', label= T("Quality")),
Field('id_teams', 'reference teams', label=T('Team')),
Field('id_projects', 'reference projects', label=T('Project')),
Field('id_events', 'reference events', label=T('List')),
Field('format', 'string', default='html'))
Field('metric', 'string', default='sum_fte'))
virtdb.list_selector.category.requires = IS_IN_SET(PEOPLE_CATEGORIES)
virtdb.list_selector.id_people_categories.requires = IS_IN_DB(db, 'people_categories.code')
virtdb.metric_selector.category.requires = IS_IN_SET(PEOPLE_CATEGORIES)
virtdb.metric_selector.id_people_categories.requires = IS_IN_DB(db, 'people_categories.code')
virtdb.list_selector.id_events.requires = IS_IN_DB(db, 'events.event')
virtdb.list_selector.id_people.requires = IS_IN_DB(db, 'people.last_name')
virtdb.list_selector.id_projects.requires = IS_IN_DB(db, 'projects.project')
virtdb.list_selector.id_teams.requires = IS_IN_DB(db, 'teams.team')
virtdb.metric_selector.id_projects.requires = IS_IN_DB(db, 'projects.project')
virtdb.metric_selector.id_teams.requires = IS_IN_DB(db, 'teams.team')
virtdb.list_selector.format.requires = IS_IN_SET(FORMATS)
virtdb.metric_selector.metric.requires = IS_IN_SET(('avg_age', 'count', 'sum_fte'))
#-------------------------------------------------------------------------------
#
# FIELDS CONFIGURATiON
#
#-------------------------------------------------------------------------------
fieldsModifier = dbui.FieldsModifier('list_selector')
fieldsModifier = dbui.FieldsModifier('metric_selector')
fieldsModifier.configure_field('period_start', flex=1)
fieldsModifier.configure_field('period_end', flex=1)
fieldsModifier.merge_fields('period_start', 'period_end', fieldLabel=T('Period'))
......@@ -37,11 +33,9 @@ fieldsModifier.merge_fields('period_start', 'period_end', fieldLabel=T('Period')
mytype = 'xcomboboxuserreset'
text = T('select...')
fieldsModifier.configure_field('id_people', emptyText=text, xtype=mytype)
fieldsModifier.configure_field('id_people_categories', emptyText=text, xtype=mytype)
fieldsModifier.configure_field('id_teams', emptyText=text, xtype=mytype)
fieldsModifier.configure_field('id_projects', emptyText=text, xtype=mytype)
fieldsModifier.configure_field('id_events', emptyText=text, xtype=mytype)
#-------------------------------------------------------------------------------
#
......
# -*- coding: utf-8 -*-
""" list_selector
"""
virtdb.define_table('list_selector',
Field('year', 'integer', default=year),
Field('period_start', 'date'),
Field('period_end', 'date'),
Field('id_people', 'reference people', label=T('Person')),
Field('category', 'string'),
Field('id_people_categories', 'reference people_categories', label= T("Quality")),
Field('id_teams', 'reference teams', label=T('Team')),
Field('id_projects', 'reference projects', label=T('Project')),
Field('id_events', 'reference events', label=T('List')),
Field('format', 'string', default='html'))
virtdb.list_selector.category.requires = IS_IN_SET(PEOPLE_CATEGORIES)
virtdb.list_selector.id_people_categories.requires = IS_IN_DB(db, 'people_categories.code')
virtdb.list_selector.id_events.requires = IS_IN_DB(db, 'events.event')
virtdb.list_selector.id_people.requires = IS_IN_DB(db, 'people.last_name')
virtdb.list_selector.id_projects.requires = IS_IN_DB(db, 'projects.project')
virtdb.list_selector.id_teams.requires = IS_IN_DB(db, 'teams.team')
virtdb.list_selector.format.requires = IS_IN_SET(FORMATS)
#-------------------------------------------------------------------------------
#
# FIELDS CONFIGURATiON
#
#-------------------------------------------------------------------------------
fieldsModifier = dbui.FieldsModifier('list_selector')
fieldsModifier.configure_field('period_start', flex=1)
fieldsModifier.configure_field('period_end', flex=1)
fieldsModifier.merge_fields('period_start', 'period_end', fieldLabel=T('Period'))
mytype = 'xcomboboxuserreset'
text = T('select...')
fieldsModifier.configure_field('id_people', emptyText=text, xtype=mytype)
fieldsModifier.configure_field('id_people_categories', emptyText=text, xtype=mytype)
fieldsModifier.configure_field('id_teams', emptyText=text, xtype=mytype)
fieldsModifier.configure_field('id_projects', emptyText=text, xtype=mytype)
fieldsModifier.configure_field('id_events', emptyText=text, xtype=mytype)
#-------------------------------------------------------------------------------
#
# FORM CONFIGURATiON
#
#-------------------------------------------------------------------------------
......@@ -94,7 +94,8 @@ helpNode.sort_children()
#-------------------------------------------------------------------------------
listNode2 = Node(T('Lists (inline)'))
listNode2.add_child(T('Configure views'), to_grid('views'))
# add the lists defined in the database
for row in db(db.views.id > 0).select():
leaf = PanelWithUrlSelector(virtdb.list_selector,
......@@ -103,7 +104,28 @@ for row in db(db.views.id > 0).select():
extField='format')
listNode2.add_child(row.view, leaf)
# add the metric
leaf1 = PanelWithUrlSelector(virtdb.metric_selector,
baseParams={'group': 'people_categories.category'},
baseUrl=URL('list2', 'metric'))
leaf2 = PanelWithUrlSelector(virtdb.metric_selector,
baseParams={'group': 'people_categories.code'},
baseUrl=URL('list2', 'metric'))
leaf3 = PanelWithUrlSelector(virtdb.metric_selector,
baseParams={'group': 'people_categories.category'},
baseUrl=URL('list2', 'metric_per_year'))
leaf4 = PanelWithUrlSelector(virtdb.metric_selector,
baseParams={'group': 'people_categories.code'},
baseUrl=URL('list2', 'metric_per_year'))
listNode2.add_child(T('Metrics / category'), leaf1)
listNode2.add_child(T('Metrics / quality'), leaf2)
listNode2.add_child(T('Metric / year / category'), leaf3)
listNode2.add_child(T('Metric / year / quality'), leaf4)
listNode2.sort_children()
#-------------------------------------------------------------------------------
......
......@@ -242,6 +242,58 @@ class Report(SelectorActiveItems):
return False
def get_metric(self, groupby, year=None):
"""Compute the metric:
- history records follow the selector criteria.
- history record belong to a given year
- history record are grouped by
The metric is:
- the number of items in a group
- the sum of fte for the items in the group
- the average age for the items in the group
@type grouby: str
@param groupby: tablename.fieldname
@type year: int
@param year:
@rtype: list of dictionary
@return: the keys of the dictionary are group, count,
fte (sum) and age (average).
"""
if year:
self.period_start = date(year, 1, 1)
self.period_end = date(year, 12, 31)
db = current.globalenv['db']
tablename, fieldname = groupby.split('.')
data, xgroup = [], None
for row in self.select(db.history, orderby=db[tablename][fieldname]):
if row[tablename][fieldname] != xgroup:
xgroup = row[tablename][fieldname]
data.append(dict(group=xgroup, count=0., sum_fte=0., avg_age=[]))
data[-1]['count'] += 1
data[-1]['sum_fte'] += row.history.fte
data[-1]['avg_age'].append(row.people.age)
# average the age
# remove entry equal to 0
for el in data:
if el['count']:
nz = el['avg_age'].count(0)
el['avg_age'] = sum(el['avg_age']) / float(el['count']-nz)
return data
def query(self, table):
"""Supersede the base class method to handle category constraints.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment