mirror of https://github.com/OCA/web.git
[ADD] Possibility to display a value base on a field (sum/avg..);
[REF] refactor openerp file description;pull/111/head
parent
c83923b31a
commit
85d3152c71
|
@ -22,6 +22,7 @@
|
|||
##############################################################################
|
||||
{
|
||||
"name": "Dashboard Tile",
|
||||
"summary": "Add Tiles to Dashboard",
|
||||
"version": "1.0",
|
||||
"depends": [
|
||||
'web',
|
||||
|
@ -33,41 +34,59 @@
|
|||
"category": "",
|
||||
'license': 'AGPL-3',
|
||||
"description": """
|
||||
module to give you a dashboard where you can configure tile from any view
|
||||
and add them as short cut.
|
||||
Tile can be:
|
||||
* affected to a user;
|
||||
* be global for all users (In that case, some tiles will be hidden if
|
||||
the current user doesn't have access to the given model);
|
||||
Add Tiles to Dashboard
|
||||
======================
|
||||
Features:
|
||||
---------
|
||||
module to give you a dashboard where you can configure tile from any view
|
||||
and add them as short cut.
|
||||
|
||||
Kown issues/limits:
|
||||
* change color picks wrong color
|
||||
* can not edit tile from dashboard
|
||||
* context are ignored
|
||||
* date filter can not be relative
|
||||
* combine domain of menue and filter so can not restore origin filter
|
||||
* Tile can be:
|
||||
* displayed only for a user;
|
||||
* global for all users (In that case, some tiles will be hidden if
|
||||
the current user doesn't have access to the given model);
|
||||
* The tile displays items count of a given model restricted to a given domain;
|
||||
* Optionnaly, the tile can display the result of a function of a field;
|
||||
* Function is one of sum/avg/min/max;
|
||||
* Field must be integer or float;
|
||||
|
||||
possible future improvments:
|
||||
* support context_today
|
||||
* add icons
|
||||
* support client side action (like inbox)
|
||||
* support select int/float column with min/max/avg/sum to display
|
||||
Screenshot:
|
||||
-----------
|
||||
* Dashboad sample, displaying Sale Orders to invoice:
|
||||
.. image:: web_dashboard_tile/static/src/img/screenshot_dashboard.png
|
||||
* Tree view displayed when user click on the tile:
|
||||
.. image:: web_dashboard_tile/static/src/img/screenshot_action_click.png
|
||||
|
||||
|
||||
Kown issues/limits:
|
||||
-------------------
|
||||
* can not edit tile from dashboard (color, sequence, function, ...);
|
||||
* context are ignored;
|
||||
* date filter can not be relative;
|
||||
* combine domain of menue and filter so can not restore origin filter;
|
||||
|
||||
possible future improvments:
|
||||
----------------------------
|
||||
* support context_today;
|
||||
* add icons;
|
||||
* support client side action (like inbox);
|
||||
""",
|
||||
"summary": "Add tile to dashboard",
|
||||
'data': ['tile.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/rules.xml'],
|
||||
'css': ['static/src/css/tile.css'],
|
||||
|
||||
'data': [
|
||||
'tile.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/rules.xml',
|
||||
],
|
||||
'css': [
|
||||
'static/src/css/tile.css',
|
||||
],
|
||||
'demo': [
|
||||
'demo/res_groups.yml',
|
||||
'demo/tile_tile.yml',
|
||||
],
|
||||
'test': [
|
||||
'js': [
|
||||
'static/src/js/custom_js.js',
|
||||
],
|
||||
'qweb': [
|
||||
'static/src/xml/custom_xml.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'js': ['static/src/js/custom_js.js'],
|
||||
'qweb': ['static/src/xml/custom_xml.xml'],
|
||||
}
|
||||
|
|
|
@ -4,14 +4,41 @@
|
|||
border: 1px solid;
|
||||
border-radius: 0;
|
||||
}
|
||||
.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count{
|
||||
font-size: 48px;
|
||||
|
||||
.openerp .oe_kanban_view .oe_dashbaord_tile .tile_label,
|
||||
.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count_without_computed_value,
|
||||
.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count_with_computed_value,
|
||||
.openerp .oe_kanban_view .oe_dashbaord_tile .tile_computed_value {
|
||||
width: 140px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_view .oe_dashbaord_tile .tile_label{
|
||||
padding: 5px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count_without_computed_value{
|
||||
font-size: 52px;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
left: 9px;
|
||||
bottom: 9px;
|
||||
left: 5px;
|
||||
bottom: 5px;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count_with_computed_value{
|
||||
font-size: 38px;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
bottom: 30px;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_view .oe_dashbaord_tile .tile_computed_value{
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 5px;
|
||||
font-style: italic;
|
||||
}
|
||||
.openerp .oe_kanban_view .oe_dashbaord_tile .tile_label{
|
||||
padding: 9px;
|
||||
font-size: 15px;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 287 B |
Binary file not shown.
After Width: | Height: | Size: 264 B |
Binary file not shown.
After Width: | Height: | Size: 283 B |
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
After Width: | Height: | Size: 305 B |
|
@ -24,7 +24,7 @@
|
|||
##############################################################################
|
||||
|
||||
from openerp.osv import orm, fields
|
||||
import random
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class tile(orm.Model):
|
||||
|
@ -36,16 +36,46 @@ class tile(orm.Model):
|
|||
res = {}
|
||||
records = self.browse(cr, uid, ids, context=context)
|
||||
for r in records:
|
||||
res[r.id] = {
|
||||
'active': False,
|
||||
'count': 0,
|
||||
'computed_value': 0,
|
||||
'helper': '',
|
||||
}
|
||||
if ima_obj.check(
|
||||
cr, uid, r.model_id.model, 'read', False, context):
|
||||
# Compute count item
|
||||
model = self.pool.get(r.model_id.model)
|
||||
res[r.id] = {
|
||||
count = model.search_count(
|
||||
cr, uid, eval(r.domain), context=context)
|
||||
res[r.id].update({
|
||||
'active': True,
|
||||
'count': model.search_count(
|
||||
cr, uid, eval(r.domain), context),
|
||||
}
|
||||
else:
|
||||
res[r.id] = {'active': False, 'count': 0}
|
||||
'count': count,
|
||||
})
|
||||
|
||||
# Compute datas for field_id depending of field_function
|
||||
if r.field_function and r.field_id and count != 0:
|
||||
ids = model.search(
|
||||
cr, uid, eval(r.domain), context=context)
|
||||
vals = [x[r.field_id.name] for x in model.read(
|
||||
cr, uid, ids, [r.field_id.name], context=context)]
|
||||
desc = r.field_id.field_description
|
||||
if r.field_function == 'min':
|
||||
value = min(vals)
|
||||
helper = _("'Minimum value of %s'" % desc)
|
||||
elif r.field_function == 'max':
|
||||
value = max(vals)
|
||||
helper = _("'Maximum value of %s'" % desc)
|
||||
elif r.field_function == 'sum':
|
||||
value = sum(vals)
|
||||
helper = _("'Total value of %s'" % desc)
|
||||
elif r.field_function == 'avg':
|
||||
value = sum(vals) / len(vals)
|
||||
helper = _("'Average value of %s'" % desc)
|
||||
res[r.id].update({
|
||||
'computed_value': value,
|
||||
'helper': helper,
|
||||
})
|
||||
return res
|
||||
|
||||
def _search_active(self, cr, uid, obj, name, arg, context=None):
|
||||
|
@ -64,13 +94,28 @@ class tile(orm.Model):
|
|||
|
||||
_columns = {
|
||||
'name': fields.char('Tile Name'),
|
||||
'model_id': fields.many2one('ir.model', 'Model'),
|
||||
'model_id': fields.many2one('ir.model', 'Model', required=True),
|
||||
'user_id': fields.many2one('res.users', 'User'),
|
||||
'domain': fields.text('Domain'),
|
||||
'action_id': fields.many2one('ir.actions.act_window', 'Action'),
|
||||
'count': fields.function(
|
||||
_get_tile_info, type='int', string='Count',
|
||||
multi='tile_info', readonly=True),
|
||||
'computed_value': fields.function(
|
||||
_get_tile_info, type='float', string='Computed Value',
|
||||
multi='tile_info', readonly=True),
|
||||
'helper': fields.function(
|
||||
_get_tile_info, type='char', string='Helper',
|
||||
multi='tile_info', readonly=True),
|
||||
'field_function': fields.selection([
|
||||
('min', 'Minimum'),
|
||||
('max', 'Maximum'),
|
||||
('sum', 'Sum'),
|
||||
('avg', 'Average')], 'Function'),
|
||||
'field_id': fields.many2one(
|
||||
'ir.model.fields', 'Field',
|
||||
domain="[('model_id', '=', model_id),"
|
||||
" ('ttype', 'in', ['float', 'int'])]"),
|
||||
'active': fields.function(
|
||||
_get_tile_info, type='boolean', string='Active',
|
||||
multi='tile_info', readonly=True, fnct_search=_search_active),
|
||||
|
@ -80,6 +125,31 @@ class tile(orm.Model):
|
|||
'Sequence', required=True),
|
||||
}
|
||||
|
||||
# Constraint Section
|
||||
def _check_model_id_field_id(self, cr, uid, ids, context=None):
|
||||
for t in self.browse(cr, uid, ids, context=context):
|
||||
if t.field_id and t.field_id.model_id.id != t.model_id.id:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _check_field_id_field_function(self, cr, uid, ids, context=None):
|
||||
for t in self.browse(cr, uid, ids, context=context):
|
||||
if t.field_id and not t.field_function or\
|
||||
t.field_function and not t.field_id:
|
||||
return False
|
||||
return True
|
||||
|
||||
_constraints = [
|
||||
(
|
||||
_check_model_id_field_id,
|
||||
"Error ! Please select a field of the select model.",
|
||||
['model_id', 'field_id']),
|
||||
(
|
||||
_check_field_id_field_function,
|
||||
"Error ! Please set both fields: 'Field' and 'Function'.",
|
||||
['field_id', 'field_function']),
|
||||
]
|
||||
|
||||
_defaults = {
|
||||
'domain': '[]',
|
||||
'color': '#0E6C7E',
|
||||
|
@ -123,6 +193,4 @@ class tile(orm.Model):
|
|||
[('model', '=',
|
||||
vals['model_id'])])
|
||||
vals['model_id'] = model_ids[0]
|
||||
if 'color' not in vals:
|
||||
vals['color'] = random.randint(1, 10)
|
||||
return self.create(cr, uid, vals, context)
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
<field name="model_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="action_id"/>
|
||||
<field name="field_function"/>
|
||||
<field name="field_id"/>
|
||||
<field name="color" widget="color"/>
|
||||
<field name="font_color" widget="color"/>
|
||||
</group>
|
||||
|
@ -47,6 +49,9 @@
|
|||
<field name="count"/>
|
||||
<field name="color"/>
|
||||
<field name="font_color"/>
|
||||
<field name="field_id" />
|
||||
<field name="field_function" />
|
||||
<field name="helper" />
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="oe_dashbaord_tile oe_kanban_global_click" t-attf-style="background-color:#{record.color.raw_value}" >
|
||||
|
@ -67,9 +72,20 @@
|
|||
<div style="padding-left: 0.5em; height: 115px;">
|
||||
|
||||
</div>
|
||||
<div class="tile_count">
|
||||
<span><field name="count"/></span>
|
||||
</div>
|
||||
<t t-if="record.field_id.raw_value != '' and record.field_function.raw_value != ''">
|
||||
<div class="tile_count_with_computed_value">
|
||||
<span><field name="count"/></span>
|
||||
</div>
|
||||
<div class="tile_computed_value" t-att-title="record.helper.raw_value">
|
||||
<img t-att-src="_s + '/web_dashboard_tile/static/src/img/' + record.field_function.raw_value + '.png'"/>
|
||||
<span><field name="computed_value"/></span>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="!(record.field_id.raw_value != '' and record.field_function.raw_value != '')">
|
||||
<div class="tile_count_without_computed_value">
|
||||
<span><field name="count"/></span>
|
||||
</div>
|
||||
</t>
|
||||
</a>
|
||||
</div>
|
||||
<div class="oe_clear"></div>
|
||||
|
|
Loading…
Reference in New Issue