diff --git a/web_dashboard_tile/__openerp__.py b/web_dashboard_tile/__openerp__.py index 935fbb29..3c294ba5 100644 --- a/web_dashboard_tile/__openerp__.py +++ b/web_dashboard_tile/__openerp__.py @@ -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 - """, - "summary": "Add tile to dashboard", - 'data': ['tile.xml', - 'security/ir.model.access.csv', - 'security/rules.xml'], - 'css': ['static/src/css/tile.css'], +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); + """, + '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'], } diff --git a/web_dashboard_tile/static/src/css/tile.css b/web_dashboard_tile/static/src/css/tile.css index 9158f5bd..c31f87f6 100644 --- a/web_dashboard_tile/static/src/css/tile.css +++ b/web_dashboard_tile/static/src/css/tile.css @@ -4,14 +4,41 @@ border: 1px solid; border-radius: 0; } -.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count{ - font-size: 48px; - font-weight: bold; - position: absolute; - left: 9px; - bottom: 9px; + +.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: 9px; + padding: 5px; font-size: 15px; -} \ No newline at end of file +} + +.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count_without_computed_value{ + font-size: 52px; + font-weight: bold; + position: absolute; + 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; +} diff --git a/web_dashboard_tile/static/src/img/avg.png b/web_dashboard_tile/static/src/img/avg.png new file mode 100644 index 00000000..61d5dd7c Binary files /dev/null and b/web_dashboard_tile/static/src/img/avg.png differ diff --git a/web_dashboard_tile/static/src/img/max.png b/web_dashboard_tile/static/src/img/max.png new file mode 100644 index 00000000..ff33ee43 Binary files /dev/null and b/web_dashboard_tile/static/src/img/max.png differ diff --git a/web_dashboard_tile/static/src/img/min.png b/web_dashboard_tile/static/src/img/min.png new file mode 100644 index 00000000..de7c3fd0 Binary files /dev/null and b/web_dashboard_tile/static/src/img/min.png differ diff --git a/web_dashboard_tile/static/src/img/screenshot_action_click.png b/web_dashboard_tile/static/src/img/screenshot_action_click.png new file mode 100644 index 00000000..3fd41f99 Binary files /dev/null and b/web_dashboard_tile/static/src/img/screenshot_action_click.png differ diff --git a/web_dashboard_tile/static/src/img/screenshot_dashboard.png b/web_dashboard_tile/static/src/img/screenshot_dashboard.png new file mode 100644 index 00000000..8d033563 Binary files /dev/null and b/web_dashboard_tile/static/src/img/screenshot_dashboard.png differ diff --git a/web_dashboard_tile/static/src/img/sum.png b/web_dashboard_tile/static/src/img/sum.png new file mode 100644 index 00000000..90908e8b Binary files /dev/null and b/web_dashboard_tile/static/src/img/sum.png differ diff --git a/web_dashboard_tile/tile.py b/web_dashboard_tile/tile.py index 22825c6a..28778097 100644 --- a/web_dashboard_tile/tile.py +++ b/web_dashboard_tile/tile.py @@ -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) diff --git a/web_dashboard_tile/tile.xml b/web_dashboard_tile/tile.xml index 8872391c..f0e1597a 100644 --- a/web_dashboard_tile/tile.xml +++ b/web_dashboard_tile/tile.xml @@ -27,6 +27,8 @@ + + @@ -47,6 +49,9 @@ + + +
@@ -67,9 +72,20 @@
-
- -
+ +
+ +
+
+ + +
+
+ +
+ +
+