From 0c452ab97506f557efa3188aca5405a404b4737c Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 16 Jul 2015 17:03:00 +0200 Subject: [PATCH] [WIP] port without changes from 7.0 branch. Instable version. --- web_dashboard_tile/__init__.py | 26 ++ web_dashboard_tile/__openerp__.py | 92 +++++++ web_dashboard_tile/demo/res_groups.yml | 25 ++ web_dashboard_tile/demo/tile_tile.yml | 33 +++ web_dashboard_tile/i18n/fr.po | 220 +++++++++++++++++ .../i18n/web_dashboard_tile.pot | 232 ++++++++++++++++++ .../7.0.1.0/post-migration-color.py | 48 ++++ .../security/ir.model.access.csv | 2 + web_dashboard_tile/security/rules.xml | 13 + web_dashboard_tile/static/src/css/tile.css | 44 ++++ web_dashboard_tile/static/src/img/avg.png | Bin 0 -> 340 bytes web_dashboard_tile/static/src/img/icon.png | Bin 0 -> 1044 bytes web_dashboard_tile/static/src/img/max.png | Bin 0 -> 264 bytes web_dashboard_tile/static/src/img/median.png | Bin 0 -> 287 bytes web_dashboard_tile/static/src/img/min.png | Bin 0 -> 283 bytes .../src/img/screenshot_action_click.png | Bin 0 -> 24751 bytes .../static/src/img/screenshot_dashboard.png | Bin 0 -> 45633 bytes web_dashboard_tile/static/src/img/sum.png | Bin 0 -> 305 bytes web_dashboard_tile/static/src/js/custom_js.js | 105 ++++++++ .../static/src/xml/custom_xml.xml | 12 + web_dashboard_tile/tile.py | 209 ++++++++++++++++ web_dashboard_tile/view/tile.xml | 120 +++++++++ 22 files changed, 1181 insertions(+) create mode 100644 web_dashboard_tile/__init__.py create mode 100644 web_dashboard_tile/__openerp__.py create mode 100644 web_dashboard_tile/demo/res_groups.yml create mode 100644 web_dashboard_tile/demo/tile_tile.yml create mode 100644 web_dashboard_tile/i18n/fr.po create mode 100644 web_dashboard_tile/i18n/web_dashboard_tile.pot create mode 100644 web_dashboard_tile/migrations/7.0.1.0/post-migration-color.py create mode 100644 web_dashboard_tile/security/ir.model.access.csv create mode 100644 web_dashboard_tile/security/rules.xml create mode 100644 web_dashboard_tile/static/src/css/tile.css create mode 100644 web_dashboard_tile/static/src/img/avg.png create mode 100644 web_dashboard_tile/static/src/img/icon.png create mode 100644 web_dashboard_tile/static/src/img/max.png create mode 100644 web_dashboard_tile/static/src/img/median.png create mode 100644 web_dashboard_tile/static/src/img/min.png create mode 100644 web_dashboard_tile/static/src/img/screenshot_action_click.png create mode 100644 web_dashboard_tile/static/src/img/screenshot_dashboard.png create mode 100644 web_dashboard_tile/static/src/img/sum.png create mode 100644 web_dashboard_tile/static/src/js/custom_js.js create mode 100644 web_dashboard_tile/static/src/xml/custom_xml.xml create mode 100644 web_dashboard_tile/tile.py create mode 100644 web_dashboard_tile/view/tile.xml diff --git a/web_dashboard_tile/__init__.py b/web_dashboard_tile/__init__.py new file mode 100644 index 00000000..9ad11b3e --- /dev/null +++ b/web_dashboard_tile/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2013 OpenERP s.a. (). +# Copyright (C) 2014 initOS GmbH & Co. KG (). +# Copyright (C) 2015-Today GRAP +# Author Markus Schneider +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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 . +# +############################################################################## + +from . import tile diff --git a/web_dashboard_tile/__openerp__.py b/web_dashboard_tile/__openerp__.py new file mode 100644 index 00000000..d0f8cf41 --- /dev/null +++ b/web_dashboard_tile/__openerp__.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2013 OpenERP s.a. (). +# Copyright (C) 2014 initOS GmbH & Co. KG (). +# Author Markus Schneider +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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 . +# +############################################################################## +{ + "name": "Dashboard Tile", + "summary": "Add Tiles to Dashboard", + "version": "1.0", + "depends": [ + 'web', + 'board', + 'mail', + 'web_widget_color', + ], + 'author': "initOS GmbH & Co. KG,GRAP,Odoo Community Association (OCA)", + "category": "", + 'license': 'AGPL-3', + "description": """ +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. + +* 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/median; + * Field must be integer or float; + +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); + """, + 'data': [ + 'view/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', + ], + 'js': [ + 'static/src/js/custom_js.js', + ], + 'qweb': [ + 'static/src/xml/custom_xml.xml', + ], +} diff --git a/web_dashboard_tile/demo/res_groups.yml b/web_dashboard_tile/demo/res_groups.yml new file mode 100644 index 00000000..735437c5 --- /dev/null +++ b/web_dashboard_tile/demo/res_groups.yml @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2015-Today GRAP +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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 . +# +############################################################################## + +- !record {model: res.groups, id: base.group_no_one}: + users: + - base.user_root diff --git a/web_dashboard_tile/demo/tile_tile.yml b/web_dashboard_tile/demo/tile_tile.yml new file mode 100644 index 00000000..c40b5903 --- /dev/null +++ b/web_dashboard_tile/demo/tile_tile.yml @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2015-Today GRAP +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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 . +# +############################################################################## + +- !record {model: tile.tile, id: installed_modules}: + name: Installed Modules + model_id: base.model_ir_module_module + domain: [['state', 'in', ['installed', 'to upgrade', 'to remove']]] + action_id: base.open_module_tree + +- !record {model: tile.tile, id: installed_OCA_modules}: + name: Installed OCA Modules + model_id: base.model_ir_module_module + domain: [['state', 'in', ['installed', 'to upgrade', 'to remove']], ['author', 'ilike', 'Odoo Community Association (OCA)']] + action_id: base.open_module_tree diff --git a/web_dashboard_tile/i18n/fr.po b/web_dashboard_tile/i18n/fr.po new file mode 100644 index 00000000..6bb700fa --- /dev/null +++ b/web_dashboard_tile/i18n/fr.po @@ -0,0 +1,220 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * web_dashboard_tile +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-04-10 01:04+0000\n" +"PO-Revision-Date: 2015-04-10 01:04+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_dashboard_tile +#: field:tile.tile,action_id:0 +msgid "Action" +msgstr "Action" + +#. module: web_dashboard_tile +#: field:tile.tile,active:0 +msgid "Active" +msgstr "Actif" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Average" +msgstr "Moyenne" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:82 +#, python-format +msgid "Average value of '%s'" +msgstr "Valeur moyenne du champ '%s'" + +#. module: web_dashboard_tile +#: field:tile.tile,color:0 +msgid "Background color" +msgstr "Couleur de fond" + +#. module: web_dashboard_tile +#: field:tile.tile,computed_value:0 +msgid "Computed Value" +msgstr "Valeur calculée" + +#. module: web_dashboard_tile +#: field:tile.tile,count:0 +msgid "Count" +msgstr "Quantité" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/xml/custom_xml.xml:8 +#, python-format +msgid "Create" +msgstr "Créer" + +#. module: web_dashboard_tile +#: model:ir.actions.act_window,name:web_dashboard_tile.action_kanban_dashboard_tile +#: model:ir.actions.act_window,name:web_dashboard_tile.action_tree_dashboard_tile +#: model:ir.ui.menu,name:web_dashboard_tile.mail_dashboard +msgid "Dashboard" +msgstr "Tableau de bord" + +#. module: web_dashboard_tile +#: model:ir.ui.menu,name:web_dashboard_tile.menue_dashboard_tile +msgid "Dashboard Tile" +msgstr "Indicateur de tableau de bord" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Dashboard tiles" +msgstr "Indicateurs de tableau de bord" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Delete" +msgstr "Supprimer" + +#. module: web_dashboard_tile +#: field:tile.tile,domain:0 +msgid "Domain" +msgstr "Domaine" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Edit..." +msgstr "Editer..." + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:61 +#, python-format +msgid "Error" +msgstr "Erreur" + +#. module: web_dashboard_tile +#: constraint:tile.tile:0 +msgid "Error ! Please select a field of the selected model." +msgstr "Erreur ! Veuillez sélectioner un champ qui correspond au modèle." + +#. module: web_dashboard_tile +#: constraint:tile.tile:0 +msgid "Error ! Please set both fields: 'Field' and 'Function'." +msgstr "Erreur ! Veuillez renseigner les deux champs : 'Champ' et 'Fonction'." + +#. module: web_dashboard_tile +#: field:tile.tile,field_id:0 +msgid "Field" +msgstr "Champ" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:61 +#, python-format +msgid "Filter name is required." +msgstr "Le nom du filtre est requis." + +#. module: web_dashboard_tile +#: field:tile.tile,font_color:0 +msgid "Font Color" +msgstr "Couleur du texte" + +#. module: web_dashboard_tile +#: field:tile.tile,field_function:0 +msgid "Function" +msgstr "Fonction" + +#. module: web_dashboard_tile +#: field:tile.tile,helper:0 +msgid "Helper Text" +msgstr "Texte Descriptif" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Maximum" +msgstr "Maximum" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:76 +#, python-format +msgid "Maximum value of '%s'" +msgstr "Valeur maximale du champ '%s'" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Median" +msgstr "Médiane" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:85 +#, python-format +msgid "Median value of '%s'" +msgstr "Valeur médian du champ '%s'" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Minimum" +msgstr "Minimum" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:73 +#, python-format +msgid "Minimum value of '%s'" +msgstr "Valeur minimale du champ '%s'" + +#. module: web_dashboard_tile +#: field:tile.tile,model_id:0 +msgid "Model" +msgstr "Modèle" + +#. module: web_dashboard_tile +#: field:tile.tile,sequence:0 +msgid "Sequence" +msgstr "Séquence" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:100 +#, python-format +msgid "Success" +msgstr "Succès" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Sum" +msgstr "Somme" + +#. module: web_dashboard_tile +#: field:tile.tile,name:0 +msgid "Tile Name" +msgstr "Nom de l'indicateur" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:100 +#, python-format +msgid "Tile is created" +msgstr "L'indicateur a été créé" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/xml/custom_xml.xml:6 +#, python-format +msgid "Tile:" +msgstr "Indicateur :" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:79 +#, python-format +msgid "Total value of '%s'" +msgstr "Somme du champ '%s'" + +#. module: web_dashboard_tile +#: field:tile.tile,user_id:0 +msgid "User" +msgstr "Utilisateur" diff --git a/web_dashboard_tile/i18n/web_dashboard_tile.pot b/web_dashboard_tile/i18n/web_dashboard_tile.pot new file mode 100644 index 00000000..0e89f8ca --- /dev/null +++ b/web_dashboard_tile/i18n/web_dashboard_tile.pot @@ -0,0 +1,232 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * web_dashboard_tile +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-04-10 01:03+0000\n" +"PO-Revision-Date: 2015-04-10 01:03+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_dashboard_tile +#: field:tile.tile,action_id:0 +msgid "Action" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,active:0 +msgid "Active" +msgstr "" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Average" +msgstr "" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:82 +#, python-format +msgid "Average value of '%s'" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,color:0 +msgid "Background color" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,computed_value:0 +msgid "Computed Value" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,count:0 +msgid "Count" +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/xml/custom_xml.xml:8 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_dashboard_tile +#: model:ir.actions.act_window,name:web_dashboard_tile.action_kanban_dashboard_tile +#: model:ir.actions.act_window,name:web_dashboard_tile.action_tree_dashboard_tile +#: model:ir.ui.menu,name:web_dashboard_tile.mail_dashboard +msgid "Dashboard" +msgstr "" + +#. module: web_dashboard_tile +#: model:ir.ui.menu,name:web_dashboard_tile.menue_dashboard_tile +msgid "Dashboard Tile" +msgstr "" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Dashboard tiles" +msgstr "" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Delete" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,domain:0 +msgid "Domain" +msgstr "" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Edit..." +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:61 +#, python-format +msgid "Error" +msgstr "" + +#. module: web_dashboard_tile +#: constraint:tile.tile:0 +msgid "Error ! Please select a field of the selected model." +msgstr "" + +#. module: web_dashboard_tile +#: constraint:tile.tile:0 +msgid "Error ! Please set both fields: 'Field' and 'Function'." +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,field_id:0 +msgid "Field" +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:61 +#, python-format +msgid "Filter name is required." +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,font_color:0 +msgid "Font Color" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,field_function:0 +msgid "Function" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,helper:0 +msgid "Helper Text" +msgstr "" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Maximum" +msgstr "" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:76 +#, python-format +msgid "Maximum value of '%s'" +msgstr "" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Median" +msgstr "" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:85 +#, python-format +msgid "Median value of '%s'" +msgstr "" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Minimum" +msgstr "" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:73 +#, python-format +msgid "Minimum value of '%s'" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,model_id:0 +msgid "Model" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:100 +#, python-format +msgid "Success" +msgstr "" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Sum" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,name:0 +msgid "Tile Name" +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:100 +#, python-format +msgid "Tile is created" +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/xml/custom_xml.xml:6 +#, python-format +msgid "Tile:" +msgstr "" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:79 +#, python-format +msgid "Total value of '%s'" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,user_id:0 +msgid "User" +msgstr "" + +#. module: web_dashboard_tile +#: code:_description:0 +#: model:ir.model,name:web_dashboard_tile.model_tile_tile +#, python-format +msgid "tile.tile" +msgstr "" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "í" +msgstr "" diff --git a/web_dashboard_tile/migrations/7.0.1.0/post-migration-color.py b/web_dashboard_tile/migrations/7.0.1.0/post-migration-color.py new file mode 100644 index 00000000..f8c33840 --- /dev/null +++ b/web_dashboard_tile/migrations/7.0.1.0/post-migration-color.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2015-Today GRAP +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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 . +# +############################################################################## + + +COLOR_NUMERIC_TO_RVB = { + 0: '#006015', + 1: '#CD2513', + 2: '#CDC713', + 3: '#57158A', + 4: '#0E9B2D', + 5: '#7F0C00', + 6: '#7F7B00', + 7: '#320455', + 8: '#CD6E13', + 9: '#0E6C7E', +} + + +def migrate_color(cr): + for old, new in COLOR_NUMERIC_TO_RVB.iteritems(): + cr.execute(""" + UPDATE tile_tile + SET color='%s', font_color='#FFFFFF' + WHERE color='%s' + """ % (new, old)) + + +def migrate(cr, installed_version): + migrate_color(cr) diff --git a/web_dashboard_tile/security/ir.model.access.csv b/web_dashboard_tile/security/ir.model.access.csv new file mode 100644 index 00000000..3229b4ea --- /dev/null +++ b/web_dashboard_tile/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +tile_user,tile_user,model_tile_tile,base.group_user,1,1,1,1 diff --git a/web_dashboard_tile/security/rules.xml b/web_dashboard_tile/security/rules.xml new file mode 100644 index 00000000..8d653b70 --- /dev/null +++ b/web_dashboard_tile/security/rules.xml @@ -0,0 +1,13 @@ + + + + + + tile.owner + + + [('user_id','in',[False,user.id])] + + + + diff --git a/web_dashboard_tile/static/src/css/tile.css b/web_dashboard_tile/static/src/css/tile.css new file mode 100644 index 00000000..1d057cee --- /dev/null +++ b/web_dashboard_tile/static/src/css/tile.css @@ -0,0 +1,44 @@ +.openerp .oe_kanban_view .oe_dashbaord_tile{ + width: 150px; + height: 150px; + border: 0; + border-radius: 0; +} + +.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: 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 0000000000000000000000000000000000000000..2f534e932c820d634b47bd8f97312d9329204001 GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m=s)o-U3d9-U7^4+=IJ2*gO--_~HV!2e>uS%PF#Guu4HsE%_hVl#Mu zg>hXFI?(RdBEZ!7@!^j3(K|M5ub#~Kqts%Xor~t#Bk6%6mb%eQ3<7P6>mOUNG3+p7 zP5H5_q0nX1nYCODpU$}cxyUywEl-Dmp+z9h_?Xn(%$mtF*>l-d8W(SEmb{zvh+Sga zX`8v1)W84wW4oYZMbRUZ;9|y8vS;))*N6W*y+(V9RuSW=j(4+d&pl@B+Zz)-mpL$A zQ-5~AWyby!7M~|IFG@&c?|!|z@@C-^;kr%Dx2xJOYaCcO+j_}shX+q(GyEd1pPzZs jcP+E$o4=p6KQb(z=J|E&+*QoL5Mc0h^>bP0l+XkKyXJ@& literal 0 HcmV?d00001 diff --git a/web_dashboard_tile/static/src/img/icon.png b/web_dashboard_tile/static/src/img/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fb6b1b2987d393c31aab5be90542687029ca8223 GIT binary patch literal 1044 zcmeAS@N?(olHy`uVBq!ia0vp^eIU%i1|*;VHQ)eJY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP~6Tb+HMO2(&6i`UA#5JPCIX^cyHLrxhxhOTUBsE2$ zJhLQ2!QIn0AiR-JoPmM4#?!?yq~g}wyS^DRr4k1omZxu?oi}Oe#)IugmyDL zRFG+DE^x5mU6zM_0ek>)%)Oa@Fnc)3_$8nBP01 zFo(C~ckK2f7ay-b!rcGP=<$Yao6l@^W>0!?_xYmygzkqkR_}iNZf@b19|3PFpTwOm zytXXhO{cQ_o*h{xQ#XFhFuir?;irS!B$obrs_(nmxcK8!_2rK~_wVa1tG>9j>vUP1 zzul*wOOMA*OEa{p(cAa)&G8lg!n#j9YTNCuJSRJ6lbLLM{V(S^vj0r89t#`V8cIiR z=auM-j9Y!PZ@&NB-uL??`naF}@9N|hPtGe-y!G~|=z9t7<=sm&#h$y>_g_|bd-O-Y z-es+oWW9fEm)qV<%X6n@^@h!{_*SdpsrPT@Kl5k$SCxG)znk&?&(G_EetSiO>(9AN zOPgKvRAo+I?5ay1vopj0y?gf<9M%GSkg!Gy^+Sn|D<)*yy2nmB;+=1|_tojT-)!4l z7Vh|zSNG$-%eemmlBv zcX#-oU;gUu$v>WCToGTlp8Y}Ws%w&dlit74d!sA5_(HV7~}yde<+`pLkw9 zd{0z}MMP*~=us(C>9-Y+AGB|LeC=T09@*%{_j;mAm2RzdeVC(Gy!msWHg z2CB#UBqy#D{Q9%4z-)5ZW?AFOo6}?j_zpRO5>P_{m<9FaAx2<|TDLc5o8*6P@pB;g z3tx@T&8*&5{4nJ z@ErkR#;MwT(m=sgo-U3d9-YYv60aI2MzL)@Y5d1se09}{11Fqxxg~%=>)rq6&DJ6_ zL2QW`D>4u6Ub}>5aS7mj+4!+_N2QL``(Pu9bejH=Gnb^no z;V5GykZOySIZ!#}7^Co-9d1ma{42wsKW1Slo^Q_AzJ0=HpsN`?UHx3vIVCg!0IU#M AU;qFB literal 0 HcmV?d00001 diff --git a/web_dashboard_tile/static/src/img/median.png b/web_dashboard_tile/static/src/img/median.png new file mode 100644 index 0000000000000000000000000000000000000000..61d5dd7c264544941b4de07c7c19da7391b485b9 GIT binary patch literal 287 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEX7WqAsj$Z!;#Vf4nJ z@ErkR#;MwT(m=t3o-U3d9-YYv60aI2MzL+(vgMDv`0AA_6H^vWW90#Yt5>fUlx1gY zGlPJzsqO)`j6BAhjxD-pR%S6WGk-I1XIIwXyY)me;BZYDFEewHKwu6~oZ0#4-}-{G zcBR63>Y5$*bYqVeTs=7H;RL&nw>C7&v9&-crN|A!;5+s)%rtX1_le3eJ-29 zs`9Jhi-OWc_AlMcNvFlS9yQF^lqzwAv6JClyi?%;7Vl*q58|`9;|^zMWvvK%{+NY9 Y4nJ z@ErkR#;MwT(m=tzo-U3d9-UXG8uBqI3b@|S+0*X6VcTb;dj~g6IpCXP(^kIW8{0Rt zZrQ@fNv<1rJu=XNd^C^60O! zL;j>i8&aRu1Tih)nV5w&0^IwjKl-Pe_ss_f z5$PWY?~5mbQRw@3L|Z8h2Pi1i-hZsniS($1?+5W6#nl~EY)l+o4D5}eOs#Ez#*7Yz z_QuB64rVrv=dd6_C@3;0X))m+t{EqpE}lQc7ksl@Ibva?4~X+aasg6GozXB!xE^l| zp*mft&U*BmC+!h`$!LDzib2!*Ph0v6?2otO`Tn5^&;3XH9@PyUo0<6CKzYX3SXfglv_>REl`P1j%`g&^lCB2Ycup3pqh8wDV$HRgxW=^V@+B(;o3tyM=!*X{K;zs` zJNsjgQFV3f(Zsg=L$tI8Gp{c_jb$3mk&)Jty>i0;9*Xd0qsz{qit8-1&$j^^? zE*z^v9GNT5?><&rhVW9ZN+-8`w^=3=JXITqS*ptUUF~XEF6QfsGlO9kp}a>j1it4x zLVl!CY9yT6sH_4=Qkkz zy(h^CnW*25+B9~rZv1pjFmcMob9nxa>*DG_mx6c^%i%z=A&B{`Ii1-#kO#cOpXF)9 z62$=L&akcie0WZFr5;`|F{>a+RU&ZZ93ntxFf>Gqg^NoZD}tR+efnI4cf06nQobHl zD~{VzUoLam4@$Y4&WwcU)4D0$6&c{|VsmtIU&LABNw~$fq}zbg`l(_z>3f)0OnO2^ zc@jr<{tQ*1VgqAEB*2gxp+a2z+wY4tMg+|3e9;<9CJB#k#J5V2ASpybkY~zDc4jwe z>a&!^N>l~oiIv_RA!b%fGS}Pa_BZX8ELyKo>Im-o;3`=WpJOPH|H% zc6B zC(JnZ65Vtpp6oB&$C*E*_RvT#AhT{pXY@U((-}Pq9kC;D1y>H(gl*wCeBRqLXhj## zN5ngP%H~VAuH)^lEIKnp3FQ&qqjwdiA$a{pG(veVItW3j5sM#YN!^*zbY?M%5Ncdd znFR&?Q24$s?E@7UJxDA;Zj~iMgwEWw*yy=7(Qy|Jk?|~?Jlp|+^_6xrKBflF_`|GO z8l&2Y3a9h!+{eQszwWO8c{dH^b07BaMUxVL;f8aKeX=~yLJ@T1As*j8saujwZw<@c zX&~}hipubr^;<((iD_pFL2FGT2XaRKHs%M};yZ+Eu|AX>A1KMN$YIXhC?{aMYdgy< z4dr|I_g~iH>Oa%=wqe#}J34W7h_NPpkAJY1P4L12s5W^8CMWlghp+9UjgwKfa2ygy zYOC!S$`O)$@!72`yZI(EF~VJ|f>AgSFtFV>b)e29n8#Wb@_5~_S^X%YJ#iJ|cHWrD zt)fzO`WR%V;60wp$iz!J6G5c~+I$9LPYYKGu%0DMn*tH(e^)e`0Rq(8gmC5 z%}6OG@XzR2+R+B;8{!@hTSu1-RW*t0KI%L^tDd}q@Sg)9HHqNb(KSD&vA~m`;EQe_ zu!&o_Jkiv!I3)P6?RtqI9Cjy(;rTasO#bG0DKK|b&uzcjMMD!$D|0LA@OJCg{qj2? zQ-L>)w==7tbg|)vJnPYjDIK%bVHm$?s`N}A$LAJsURlvI#D!MWN+`ws+wzPj*<_{r z0MvHjtE!WjCNmY>T*lEg_39~asfJYfeiaOVd-mF9d0&d_HkG3ld!yl)WF%HR2bv0I z^gU?`;C;2CX+J(Ug6vOR9C>n4e^}Bl-TK(}2wr%!6Gvx+L*A_;|GiYB4^R-`_p7I@ zj#|R#3C+${LZu5fAg?xtKZ0)UARchA@#&hlPOhDrNj%PSjjnb}jvL=0?Se!Swj?m24iU#Xhb{<@WQZI*!V zB}98knN~f^o+EtYg@Z*O*|g7(dVO9TJ-7eXfp+W#!;$=#spOQktY+XhCsDA0ave1; zv~pU(Cf2(HI{AePui@NQRY&;~Kc+xXWrf0?vsxli5etmG-1$n|Ca-?OHyzi(aes2Z zT18P{ZN&SN;xyxJ#3y|NGWoFY=&UkdkTB<>V0<@=o#EhzPN8t&-k!s}dK$%T@W4~n z`iv>~WcvjegIX2qm6?A0ke@6>`a43!t==9VCBIqFRGzTf>S=mM_G(eBijDhN?Qcb=xT5jGV+ex;y3b@gYS@3cuH5SGh+>udJ&sb2nz3-gi#XS=P$o*+8p}BQW8Wtff}*W)24)76>~lzVI}+yZeA@Y54HNZk5Ki~QgTkU zuH7MR&v%xttB36Jv?x-9DYd;V3cV7!cCiVnkb*_q1?gT?tdm8_FxpurA#&sALG46w zzdXS)a;f4>JA5t_hs#4Qhm?mWA}W}A&D;H#(iRL?AkEenA4x&|BD?3O#dcj;a=*RP z8G}t#=X3gi;EqE;8mndR(gY1Wt_o4UlR#o=3mRM-*7vgh%ou17lm!rCG zdk6NzqW1u6h5K~!9LKvlesd4gJch zj87TaHN33(L71@dtK#R^y-3%zR&KNk+EyInvi4jyL8{cYGfl@*tId%gXQ;2b(AeDe z+vRVXY9WxC4}3#WzkRJ5%9n-B8~3=!JZn_Xp)sT?w^8xJl_E9B{pAJ@OcMg6@zaZ5 zl0%A4{v7h$+fA6u*%j39{Z%>oeZLaZmerhm`bcT@a$ElQ1wRQ=#x@Szw5nm#nYfjv z8Q1Kqn3fk50=2D9aD|Rdq!)(xSKWc*;61b!J=Ow!|1_4gzj-Z|4H&Nlepks?9PY2o zJ*B3Eyk`VgA7JMB4G-C}KdMgbgPy&q-B&%3olxzOUNFU)>#2eTuI$v~aM2@Y^O~== zz<94`UpqXuO!gYBBn|Hc=PTDGzD!>1pl3`CBN7HU@R@s_4ArH*pc4wZrc@KQD0yr% z?45&2lD|FAM3Z~1H@-k_9SLrvO(#|>Q#w=+?B$r@dYgho#bN`aGdzCkdHYy!LKN4t zmVZ0yZ~Lpc+H2!tG&1f~w!=@;?OMHMNM^6f$0Ur6W~C!JMemPR-13y2bvDh>Qhisu zoYSgg9Z~J>C@WxC`+;!Q!*ict!rgHJQ(y$)O$^ic_;T6qqyGudS=*V+2D{dKrSq^T z@H~FoNo(v&NT|NdX%D68YiD~r=fzTrR%*H(-r*i_}#d$sJ>>DI`cf zs)(f>KK_xrnB9v;1Wa#?#Gq`2;a~GFo>Dx~Y%Oy|Knn)%^}4DzclJXE904I8!TfeK z^L>d1k~Yp5628Os?wFA;r>lv3zn5xNr`su(y_L7**bR#n*l>e4Lpvs541+Z2%@&J| z>%BTgHhiX$bKMu~tu1u!PS&wm*Y?U#@)t^7I=}nb6trFrxm>M!;W}7_Jf*CtR#^d2 z!^)%e2jwO%9*prRly5mBLiKGNzq+it;j9tj*1jz8SjqAvc|-cRpw(6!@V&OlP)FV} z!$`fxPuk15Atmt5yNh)P1o`0=v9qrtkn_R7R}c>Yve84IBVy0wrIX$SZS;M{o?B(po6aKt5f||teEYT$zlM% z$B1II)vn3?l{kZDvVz6HcGF2mNE3G+XY>;+Lw{-}RZ*nT&Y`5D&46~H_Z_|-GhMzh zNT&I^2HAp--pclA_VGmis4w)nVlzJ)(JJE-dj>LCWLN3Xw>*Nw`hV^9?&Uig{6ZmxqjkuBd`bk>8Go!o=#?^WM^yEsK4h)t>x z$-(aZ2K{yDPgJ^%$MAWN#nrbO`eiI$N1in^Wxq-h1m8%l(gVVvrJS7`jB~sFJyk2U zC8X`DjazQqZ_U?BP^?}2jd_K5cz9-uF(DEm26&5BoL121^7r5^HaT#w1s3?8 z&o5|Oh>U;XH={HvF&o@X9(V~o#|O>37*UiOmF|BBl3bloDnko-;73nul^ z@NO^BDpG$Q0K;{iJE2%%`VjkH-e-dJU`dlu=7n&)64NA|yuSTeTRC+eu`@w>0^!08 zh_iFzjW38joh6e_uonLyrPqouu0ZV19=8dYy78h($3p+E*3o^7_7*(#=B?Y(unl>8 zsBG~TY?AjoEZ^%=ygN&_!GqJSbn!`@`fQ%@e7tJ|{`Q!&cl}KO_V&|Bgucjae01xP z-5*25+~Zo?YLWa!x{R@bU$q=Tb#-+I4fC_|vRfAzkpqW4>Un1eK-dF6At^oky^2z8Cm7OK^({D|H6I0puXCyxA|zI{fE8f=Brie zwgCR;WOUfrb`Kedxxl|jAeMO8@7W)X6@&Eu#*T7gux|f3&C zqA3bGMn;3Kw$ziwj?|a7)qev-l76N3r)~S@?UMX|^GKS+Fbm7Ewk07YYRb6UiS}4R zn|AUYyRloY_zmYO_gy_Zl?tQyr~zh&spjJJ*&kettu1(${!y7(!-vk}H4dkraq-7i z^En-7wm(p#c^W9<+2-ZAMrA4mXtPT@%@oGOo9^Se1`KPx)kLh{6MX3SDU{|JLZ?(O zm(#WFwU%)c=ZBx-5*Oe=%1P7ko4m?8H-Ih1F+S_4P=}P-(DWx0xuX1fwsVExx_Ipm zE|le#rY&*8rS$_Rl({!>_IYi4cu(KKLu%76@s6m7^j3V<=M8M7hGF?iPWeJyqPDNO z-If>Yc3llPwi&-n)i`W2+-pyWR;Gts+%8oXYS-mK^YY%Kl^u~jax3tcBer_!*&Nk1 z6QBCf_FE3`YlJnBuky-W>JB4+5jGnAm|!NB(xv>W>Yz+1tA6o29&+l{uuzp5F_Kju zr(^AFu%CnQ=wF=%zm0z^M%WsZ+tRV?Yo&oK$k!*A{O3_9i%8Z7_Z`AI$>6*`kxJTs z4>$e?hpn-DO>3etNxXCj_|&*- zHj4Uq9dA?-gO8}jxfXrGNDyX{+{HGR zN7_jA;3jjsc^LlWIn!~jAUM+Bmew@^(im=Pb?-@LYQGhr)V92yS65qLBD?nW{HE+M zyu@I3G5PRAjK>TwSZN&_zOp@2F7SCE&C&U-*2{uB5D7$Q{QC5DzViNJlT3;5r^NgyTHx;?PYh+?ZcGTsR|F%f@QW+le9szCL zaylnR8f4k7t+ddeJ_8JeUh%HIUg7<#R#by7Hta%UIL8TTwgJmhFL-|}YWy?3!4eLX z)uhT;A_-4k79B}7AU`%G=shA?rN7kD5YLkG^u*68@6*yT_aLA{bGHZ9lM(G3p+}i!;`=1{z-NF;m@+OaK za$#MV?b_Opr4!6V$(uWKMVU9i<3e3aTynuG)?07fwX{}g;NI3UB3yy5X;GAaU3I5FkLh5}u%u)#r)T7jn!5IIrl*7I*uQWL?U!9AFE?*efJ-!b#+j^%_3ZZT z29WvoNly!POVXoZGurOpvFV3@Rh?nNQyV=T&7EuNy$9(1S7Ol}N39Mg+ow(IX@Vwh zhy;8kij%_;ML^9}gPyLg>SBxdQt+kzf+Hblmc#ANJl@1-Ikknd^Www2=aIf*aQdvf z^^^9|MhuZ2n=2RZmW9Ky4E;1CGa?vHBDG7#l-JEAqDv+qL;F76&$K-gvX<$2*Aedx z)ZuUXFz+hQqg|Ie;q!O@Yt4IO>}DA>dD53k#ky`1XL&l*E7Q9|D#HPf z=11;$tfE*=1*r;@+uvn-UyePy)W?>Blt%ZbFyu~x1FMHVck~VKpBAxmYM~bXs$hj8 ze`#Xie0cc5r6c+53=QSVwZv0V9Z{sFm3)YJ<)RAVE#Za#{FCgwO0qstaIa2vaXN^t z1+UFHF%uqKTWyuT!J4zwOd{yEnqOg1b*#o0L6{mTC|Z^3ui@?5F0!Shdv<1gF@_bO zbBuh)$$1#7oz-tVUCC(mg87~Gz&#*jLHF9;GG>@}M`G}wo@xx2(h6Mlitn1_YP+e_ z;<1^+Af)$5t5c|otsVR$uhv!H-QP>;KY(@jYQEhL(m%$~!}qhdxWBqOc4S_|90rn+ znlSsB2>hu_dp%!+x4b79Z3hc4^kg{l%y+e8=8&mQ6!vC*0$HBCv3vUHdaq-}%9~keoe0@))<4Njk=?+Lr4DehVms}l#SnAEZ(=fd&=i^nt9(~nJJUANMF>CKmOR`K+jEY)`m zFGlkw$5IQ7e2EDt>(a%sqB9(y>0Z^!T;*Emj5prDk~zr-?-~3o3`v$}b3K5e1|{oh zOJ#LATnBPNXbfK+nTz#!T-|e&UU}i0Ko^I9tTHnrDypWA1ksM?-I_twQSjb*(|xH1 z4^(fqP9u*zPn`Upk!Lnm7Od);rguV-Wy7JYywu1 z>G1x32ILi-_pY7cB?jNDn>cN|vGSqobjlasJg&>7p{l@wZzf&u)Sm*U)_GEl=_%-#h<#0LaG4xH137P!msrKrM+>E^ZIEk_8xIEMs7bHBCz^7>@YRj?UPYY%yPP2eits8dV@0d zK+zrxTaa2XA4b5Z4K`cOIf-0^HP@dNv;WXUJI zw);5Y;vgnx+{N!GoIq$BuXsx#X2W$As(Qwk5UB&u{mahAF|Te`v$UD6q?yp{$YL#W zp=T;5-kGr5Q{^f> z1+~>ThJ2PDsr;@Dij@^Zhq%iO^&k=c>RVEGRY8T3qRD090x0=e#$ z{TZvsc0ZNP==H@(GgVZ4;IgzxE{Zemk1@gyW-n(Fnnor6_0&4RYQ{}Bwn^eQ-CmdK zGqYo3U1xk5>hwW2RO?6D7kPepMT5{dnH!iL!GO$@-5LU_@dd{bmtp_`T3?ljC8JJfK1iX^c2-AST-h2g19| z3y+~gM%qK?!C+qgIYyC;>XrGL9wQB4ABd-#x1J^2I)q+vk zmBb)rjwtOU{3)ku6(IgcpSeld6J-Mgh0w1*Z?8ZZ#cpV`8X0Z9+G+knjUcwMJ{Xu=1JWrK#u>iZ{jHyc~T;a zRy7AwynO`8b;syY*OlwpxlE{f8&}z|HKijJbApM5R05MugI*W{YCccDv{0a3u-tx( zmz!8Q`~eoveyhEl>8Bea|Akj&LylEZ@6c@^uUTh1)z%z;UGz=5p=EO7*m)U;3W;pT~$LXq^2y#h$ta7dgv!HWlk8zxUI(ZSsw;<3=zU543c<JOxL=Lf1^SB!z<6QY zW>xPm56w&JR!f+2iQSPhc^yN$lK8Ta;Xh`znK8A2mT;+yDHdpmn>>mek$FW{B?Aav!;psbzVXl`#|^iRCmo{ zySlOqGXbO@7d5c=Ni;Z>om*CF&7g{E!X+9bB^!}3`bLK_B7v{-YR>b`G+bOzjp#@{ z9<8)Nl7@(9rG7q1jyuz4%5nQ3AA$WKTZeL3Av8=8`2Z&V+p)VQdwYV>=9 z^YV=2;TNqV_i}G7i()ic-^J5Md5KE4MC~9L4&Q^PeXGjZvsfj>#1~D?s9Fr zlI6=At*Wp4&l`%|FC;BTJe@{w;Ry+yEo-~cZT#6OiMuH#-`1g;{RBUEelC{M%Brwd zp;@GS^?ezoMazm2>v|v+SW< zUPX$(dt?=*z{vP9`X?y)a!f@xjT8H7UNoyw`yQ~l76N=}>$#a5`OHFpw2P^WuGp(< z`iAG*GA2?aV_~ffdKaKnh%ndUsh(andWjSF%mJ5GsMcjm7J{o6HNv_=NbznwhkK?e zjTv;c`=@tF`tR5uUWfx=0_&1Q?rMBFnSu+nMhK_DdUiEDhzEo-kw%h<#?Q|y%ntj> z&P=Y@5}rT$UwDi?AvMWoVTsS3_aT9&Bd=a0WcS&3C~r^XqZvkNCW&=g)V$o+CWNi+ zTj`ekBHmxPF%7_^oBLl%Jt1zRKI&ujw<{7^pjSIGgC0c~xA$EMypgAO2*x0!O&tQKgsLGA6OiO>ec#8ANJ(VaEZaj&ke~n%iG(1$Gu#{Tctv{kk zDAabiGyBDvKiRc;+ZH^0#B<0=;?dP#ff0b6&F$(DGc*VLQ7c795};UGIsgFYMEqPq z7Lv!i(8Q-#O{jkNmWVfo?RC`H%c>9_QiK(1!W+^P7u0$C)x++yA=ER^0sR%{2hX}p z^C7CnEGQ(Q(pcEo`}BBfHG~);qiGiSuWSad?u%`bQdK7d7bD-t0faHyXFDAeR#vOP zDvPv$)())kj$w++a|^4W-<|!-91Ci63EY5;RMc_qk@4PLMMa8^Qw(R@AKTILubAyb$;O5| z^l*fCoh77J8DMbNb!pD48`UY!qMKQ+u(MxR+rqm{r?WFt{gqEr)v4kkTcr2v+GcV} zU7F?o<`A5R1By4k>3)R3)B}8W(Y1K zZYDiNP=?j-B0X*7~?biRAtjY1hoF0XOt z3lBc#c)_dbVd%nd3tA%&mf_OF%%~OoQ*sM=I;&4v!f&R-54#%ij_G8GRQKM8n+F=G z(Pl>`7xcCxxFnDnnhiRp55LK99#K!9!&QOX-#N@z7xSet;|t};=1>q1MKBw?aJ4+2 z9q#p@LgE}$MZ2Up+@5rp?~-*Kk52Y3<*3df8wOCEf-Aqyk`3{yc3lEabU2yLxAQ$* za3zU0w?fHRiTL{EbBu+8D-G?1(7^4#YPRgC1(ut6E=dTz2HaeC@V-cZ3xD7;%L-12 zAJ1Da*Ig2qw>GQCnq2itZMM>D*Bu>fna2zXw4=%wh5EJ^CpY$cY%)^oXtwa|Dh1T8 zU)egCcCC*RD&xYMIeX*Bpj6rIvofVM*s*SDZTg|LJ1T_gz~^-&CkwI`3#@l3mFwIP z8x#$-lVovA*fw0VK#1cRV_M8sR>zvRH!INEZxAoV_QDx1a@iyVNL!GuyB3H8vySB5G)u{fHWd znU3bCCI>2TZ*D6+jQAMdBuDUwI_(D6N){JG#PVmENAx`w6&!1G5pg2uawjI{@j=jN z!I}?2bneZ$jk~bvogc}^cEUTVrf9X7MttDEJY5>@RvMPnf-<3o#!>BPNjta1LDK~* zoA1>dn^bFuc{t88Jq3wIK~_##gucit7mwgY7ChJ1>13*lD0FNW$^4fFDH;uk10?uz zq&SvTGi2i(9ZoewjhQ6e%k`Z@I>IQZSwJAYR}lO#E3#gTzE*J+^j#5Rk>vrT(n<^a zaZ>u!rW0KBj7uDFG5{9x)7fl9>tVUOuLcK;c%jJ>W-u#uAQ%91L>4An9*z}rK=o*d zL}-3m1}~gMx*>{B(vJ^_I+aKBOG4JKjV?WhKWnD?lj-#j%tdmcCE{$*+}Do_+MFYy z=D)u1_Adule_pK6wV4$E-i-1z^2r(v#I*Z+%fvyjIdLY)5|*WEh5m$6-Gl~wkbG|A z;MTLWx~FedCdwtEU@8;Bn&XuQ^t=so+g7N8@b#bv;p6{G6@mx;jmA>*Ad;K9_SqeKz+)Tjx%}IK-YJ7uiPx-je9)81biCrnqNEvB*HlHF~1z{g$bN z-~LMjNrlfV=iY*lqRB@0kG|$lUa;2^EBoObaeEZQ$Q|hn8Qx*%(enAtg}nR70dx*& zw;9CQ>eOkAjEV!{{E7J|3oFCSKbW}QY0J3QCM?}T-qqvqZRuqFmNtbD&U$iSv`5*^ z9p+s4KSjH};bSc7chT|aF-z*1@J=gf+HVOV$Il4C6-RU-G}xuJIRRecVM*`ToZz4Q z9zNt^W#(o)$=(dJN$$H+iA?7_K|R$w&8O`6VTF&-ey^j1`qL4a<`N)y9{%GU*(ZEH zxPyM*1PtW7@H+kn`&a)jwT1u2{{Jl{hSfh`2fo#j{990*+v^J*+Cd=uA5Af8u))DR z!GDa0{a+gYFP(B2T`V&#?dHIF;pMtk~zfoa}Ni zJ-#iBo4{qq zrkx^3=sR{6ulE}9Tde7n^vV$ryyN?f+5n1|^1PlidOS_ersSd?_`0S5_94Ia$;MXF z{ecy}x+a|8l?o6l#~E6puCYoR{Not6KJlKXQ$HUg#w~{;6EI%&kOC}|LuK71D0(QT zO_~N#V?wb)SC^G{sw~BlfY^__c5ypcaWRdW*&}Z{`A&>+ghIGWiS#umY;jEH0Oqm? z1#C-pRp8M8)*~<RJgP?!8$6P;f-&fdJ#2j)!Ap<4!P?AgK1@ow~-g#-@Tmm&76{6XaiPLWISp)Nj4{x50+zvlgeg z;0b2VD{5@O?m5)EXZxJ??dM{oq^FaUg6{A9jwk_u^)Y}XkGKS!({MkUcCU=iPl0!~<@#h2-GojCpo2N@D9=>x`^F`}70s!oBSRDe}9Sgsf`)sU8EI^!0uT4GQi#+bo4MHk* zc1~u$t{@1S%u5}tjR`fH#jGw0*M12e>|GJpq>6~8upfHvc$YgCNbNhuo!gIGbKpL1 z5XTv6hUteow#pjGRab@rg~Bt|HG0FO)*1kfa#*xq%bnuB#xb9NHjh7P{R3Rq+ld&9 zD~0s1#3dL2nuS683>c4~Jg*4c3MxPk7=4J#Yrnyp`D;^NC~=&GWGMfA>qN)MSMipj zP<{dVd{Y&@_7>fvQnmLmz`qnMLk+003m>#A7e_7{R8kA&=Th8Bxdik<18p=KEgB4* z7VoO1?CIl{ki>W?LL*0zxy{4N9=_$qnw(7+22CB<1%`N3h6FIY+8GSzh$Ac|i4 zXt^K}Ck>9+Nd;s9;>K#l+!xUCUyGP^79Z(DkNSnHnaJKFaTtC-Rr^n`h{TB%g-|=P zU#H1*=vadx#K|84Hl*a!TdHy0S7pY>;_eio{57jBqrb^~aL4r|b@uIZQFp+ew?U!i zCGqpWf5i>Bhc@wsuU;1pZk7K;vAEU(RNw%70&BD@2Ups?f-@g0LR&Kjr+sC*XsN^5 zn}v-s`*azb65L$#;B?=++WwoxmI z2KOg0@Nayj>^|_sEek0|bLkna^@o>wvFYt}A;&SrL|BFXDb21_C_h0E&;STz00y$D zrd#}^O3B5o-zZ*umA6KrKU}S$4>jo+Y55JVQi~CV61jl}$35c?^Tf5w#c*(bqLj3( zh-vE3)G$aI4G_ga!T`8(xU?e}JWSF?gV%ucyYQD=KdF%qags@z$2Be`Qkjl%3wvQF z;}~x4f25wo0d7A_e}pOewYfA72BC<-LDY;y8wSIr0r=K&mZsqeCgC?SIL$X+aX>z? z!gcE3i{FeSvMP1gKAXGx4TfvSWjcsIQHN>Y$=n_jaW82W&}&fI8v*0!1u>SYC3jk< z0EnSCNS}7fkCJr8I3w|629Lcw1@r2D>>Qo}GD%C-fz0Y;_9-emHTPl-rV*pAvJ~iX zOuK%bZ9pcL%mU(%<9XZEe*S>!I)5 zz~#70vxWadbsFdelvsgv7|E=DY6p_Cp5({k_j#{CE@<`%2mKV+z!X2(TO(Mff_--( zy}w^k2J}aMBA^e35GHG_V@g|{YJI~(A0ndu?HV}PQiIUJVzwG`y}&xB;pyl3!()fo zS#tK-@qKbe7~xq4;*3Q1S>=Whe(Wq392g38dPBLC{82*GZ0A!P7_J;G!0VXIh7_;< z3+tZ-=|ja9v`>uV1t@-(3q5&~zH4yhmHwQWT?|a154?f24Q5<3u-Q6DGE716&p*6A z8*aKDa3Qav?}%BvedB2mGn;|Y{x*)$R4l}=OSp~)U6@#b5RVmAiC3DJ1i728@wVZlD9nh%5IkV;ePeQE#~F{+aEi`osdN+I@G2;!GjDKlxTkg zpn(>X)f0?Kqu+jIfQeJiiulD2>qS4`yaydnzA8~n2gk74*yPmlro~emit_3#fqe;7bJ&0Z^WO&ncSlfYD!{4;kwO4f}mX z}N*)2X zZhuz$5$DW|C@EC0lZD#soPCXrV;>m@Fo_HqXF(Lo0W9BLpXrD7w`p!}i|fru|+I+w_IdZ`j5WrQGToYZWT3SPyPt&B0~ zB0;#7_Sj_jB_xACNEn17o)#Jo(p6@Sa_3z@t&N^mQCap!7H`IkIl&sDkvp{Cuw)-E zh8S%ZtE-;*)nDmvDll`9OL?6`mMk}KHz(@_h`3;Mc`yZiK7J}$vL5crn+`M#XsP$~ zA>gcPCR=)!u3Ldx|A_X4S339HH*+CjXo?8D@diPc^NOqoPonWYIZ5+Cd%F{JMhER7 zPQHpfc#D>CT*tMOd{PqyOT;Ga@r`F7P_`O8Yf4$84MD;wJ10lT$eXowxavyva#}&U zmw#)2wv=0v6$nr~-r9>6`PSqXYn^g8UjLsA>>_!5CB#rBILxT1d2H_ibh8I?I$sz93pcX>YRawc0pc zN_*~0mkNBH;K#FLG`5cL(=ORkx5=-l;q@d+z1CC9`H6a=H>*}bSH*o;HlW+S6oyDXf?*BO@$O6%KY09N(cQ{D6{==hJljTkv+8}QN%V|-bif} zmHDm*zCWpa_W0Hjye1PNT%fWO2Ftl%*EL6F)X!{WuFQTMty|>tIDpviK-4}$gBWo9 zC!=!ze4LHCNlGrvPc5CTwK*)f{mvnl6TTnglHx@a8}TV_eJNYX_*Pu3G?CeKefP$` z*ywbow}fwud2EId?}AY*P4&uoCF3fDkp?v||EM9Bt>SB~QA7jrl76}F1G%5v)Uy$f z=Y{v+@LbpZAN4M7wQP-) z53JCi`5yp^VQ4tl3wxKg)3%GJE-WyQK^x!w)myqPNb14^%Jv2o-vhX~W&C>`fXAO? z>WP_NBwB_rgPX|N^OKMdoK{RwJVCFji4KyFPA0G9yT178c3*v3Gj0_rIHCJ7xm)ep z;M!T84-MkMw{zzwXue^EQYnNC)n)K}@FcCNA#)%u(?UUW z@~=?n)XVOgSJ-@DqqoM@9ICc>dn8p$sy#P#HKXOf|G+-(H!2H`t0%P3NHE}lBKpX( zr`@zozF0-5D(e@g*ZH_0oZ_a)gOIS(wcd_B&_NVS@i!4A+Z(M}{9>e*h4FdgaPo!W zpcd8I4ZC5l^LNZNV}j61zh6p%5OP$x{on2l7Zy(uT8O{E5z5%eSm% zvRvZ#c!78{hH=sKr5zQI@?xg;VvS^wz9NllSx{{&V(w*b57~?#_v{tR`6NI{D3BFt z<0=Ah6NbAd7f9>#h=X532;bKNAeB48nW7r0zC!vkum(07xs49V)0GO509e2+_Qr7K#w${Xw(2xqT2 z^=N4_SBujE<1ArcSfu9G0~T)3rR&1-U2xofIrqWhsqQ;NXzcA}(5(Qc3ZGM(zF5zd zUaHrxcn^!|-UywvDC~p_14_T=C1cjSiVi*=XI)Xx2Sm@xc%k)6&jv<@g-daXUR4^GNsH?UazYA$!}IsUa5(dJn# zB@m);A1oQpFC=s$D&rUEVL6ti0oW&I+7jtq`nK~MSIiz}9o1pWpu_&i8OO~+wNuLy zMo&nC>dJ~MPNh&4G~Q*Cgs{R{IGA<`@JfGJr?Ok6iR0r9M@~_{WklUPQeESW3?gO1 zlE%Zk2rjd4(-M1X6&p_h{7M7R3w=JEnca`!eUsct91(X<5IP~SNk@`3U4kQtL&SX~ z0d#Co>wz7miw|tr)QnE>1;NS7+B><`00lH0yZ6@@jw1VYDK8QlwJ_48>tx!R8(U)%27KtdQMx8b6jl1_2&Z`F6e z@(3<)ZMWfDO%)xvPr~iKB_=x;b@k~KD$jhMK|a>c5_xczmS0d*YwEIt@;AMfbFwN< z5HasvIO-b*AEW(=`3<@daYQIk;gi04vX3U)I|_P3$<>UT7#lN~dTGYO#?~yfoczn0 z$?H;}dg=IePq&~3M@L_ZZvRJd3P%KGZa((kf>!7?&42vG zf3*LXHuitxSO3enP{ASURR7;v*773jCRBz0XaWACYlRl82MF2RDa=Ys@0>U=@APY( zBe-chypB;c5tr#cs;wr_FBxrLj%YhtA5n44$&FMnNwn!37QMr&%-R!ezFu(&Hm+in zwHxlPAy_>;EI93KtjcOOi`WRNV(aA_yQ>o-SerlxEwEi&+EIo3jYHMc$d{O(>1Rcg z8ReM@sgfG4a*4bjj#6)aMF(YNY468YSs) zKppMN+$bxXo0bZnCGm3)lI=U~jw`GkpmG$wY*QLzcdNX&zFJD&| z_Dto?#z zYn@;staG^Z*|s`C!7$SB=9vo%C=soz)}kpn)f5MQS#=DX^oH;Lhn(``l~$wC zROOo;MNz(b;qg){GvPvISi~=hu&(%?j5grAUZOR!TxSB-ueuhofq~ekVA`)Oa?!e*}GRG6p zzwf5r(A$IYc3Bj{DvO?{wei3&Nftc4=7));M^8k@!d=^Av)m6Hc$Sb*p8+b}rAV5U zU~Yb%0;Sg1W_La8{!M!2oeVt-us{Fx-;B5Mz+dU=rhxn41QmCXzrZGa@+)C~9b?`+ z+YWzw3;HQ3XB`7;Hj>Xb>-+fW)L$X?a72z@{!9vD8{OnTd&pleKs_VQ1f)M3p`PuG z)dgJHkiO8c$MRI?zRqnuU7cZM7sp4D1D(#u51NT~AG@yUu-{G`2S3}eyH6D<$sR0_M#$+hw3 z_l(Y2O2DJh20U{e()KKAy0*m{%1l ze;v)`R9MaXdu}u?qCW$c8d*ac{HgE|V#Zl*aq`O3PiDVWu{H1cFbDD6SsA3p(nQMeoH7 zHY)VC7+B#)tiD+sMPs<=^;}0Z9wkxRrgy8ed-2kY&~{4A`_(x)sG}PWtQ~8Mf>;;5 z|Ks`C(oI}~XMifM(+ zuobvcEELgK3PG8W+S`T4zZaIAfUL2*tFnD7L}6E2T-%roTqU?ftPiB4x;-X{n*8KK z=XKu&9#?lXl23JdeyJuRnoAGKiBA!Z9MFf?Ed#V+C`?wEz0DCQ`E7%KZ75wrGxy?Q z=(hwV#M4pLwpFrfVacyFr2t#c_$_S45dC`*7wW?+mh?kXy=9|EPh4g>xo>Dg%S_@$ z67`-Kkh-FS%1}$95L@2m;SjT5#V`kDkCtSte9dwy$?dtahve8-OLr!_H#p3rc1Eq3 z!2q2_@qhmD`i!xM+>T96qa^RBk*tf4)JoLydL%xv)@8%|-M3M7DvpUrvYf`b76lQf zb`p>xyr~Vh?d0-Bm;k`$`}vqXCE)EaPbe(Lmb9y3uw$a($!ixFkZ%9H&fXe?v@vo! zh(6?<=HoB~6tYayjr`b+k@BlOFy{0xF`>T+J45qfA=m*=IoeY-!x(6I z{{v=f*3!h@R1}cj5NSt>Sn!|S?K)xAOl`j5Fnqm&>Sr8t^9}i}c^xK&p!%v#*f^*T zT?FCtq{POuI(OaSILoSs9Ns!pI+2d`3fz)|8*7IiZ>{)xvbLL+1kf&sIwn|O6#xwqP0=>L$03ak< zksbtJboy3J1Fkz&yO^0|Iv?dLq!sx>BhNhrHB?vjPaYkDI{M6py3Y3hyVbbbyvT^0%t$1 zDCm^2u+u;V(5J}B5}&u5n3U@Dd}U4GC+_UMmvysyH;8|7%%c2ihW6x_&h<}NQHNHA zgVpi=Yt@M#D|m~w)UZ@tAS-j#c<}M~WNJ@=u_kz(=`%~BCpx%sFZ{gCr>TgSP=1~| zJ3A77g)E5ggzP3tjtgOKv`ZCngN{$M3@fFvqCMKBmt~A(n=x{G4WO zQgY1zbDGE=0KbuDKcOzo-Vhwy*fQv;Y=AV?+|>BJy+Mjx<8_4Io`1%}Aw^S?gDW)y z8*;CjCV-)aNSncM8&V0|mcoARnU4WFH!%|(G9B>6{=|T#!p1)ZRfF3ysj75a@Eum< zH<_~+H<;~3SQgjzsvlZP1zFm0$;68-KVHxVXZ4^G{739gX;j6u&a)kp@8uB@-=K%If>rNL1+0pprVk2S#d zQ^bPx(6O6-T%A#hz^ex|kl&o8u9$|ZXlf|9F0c|^LT5Qyy&nX7nob|KGF091^qGUW zzukT!WQdOJ=#ZXAn93bMgz&w4*7zAhz2$jfthK)P&1n6jpU0Ccg$t42`Qs|Q{bDV^ zp;)n`buBurv7Mo1n+j6w+g(U}u!FLDYl4$Ny!#qV4W}scEQkK2S`a+Zv#xrWMJn%O zLsDO;$EG>UW-iPS&YMu_E2fd~(>q@Y$t9#B-};jaM|4(>Ufrm=@mj~2eXhMU71p?D z67s#A6Y9?p**yu2@J)H{=rYN_aku@KB&)RruJong#wgdL)QF z>Pm-l-LkK|QtBHB!!UXCX3lSXQhga6d}?!+YUD}}8LCmcR2P2;$M;^R~kn147TKRxM{EE_u+RLIC-e+{)lCJ?@^@4j8tb&LzF%8y9s&x zd#y<5MSq!s{G_VdRo&TQwY=UcL2oVi%1Y!+J?Mj5uVZ_nO%eCw8pX)P)>#(U_G4_w z#DW$Nv)L9;uHX7)iVb*NZEpKyql0+BY`~P$B=s>q!gM^(i?a7&qeae4e_Q3zOlz6q z*(KR0lr?X%4hAYpshpe{guP!_H&QekDzMwt_)}Su<4B%|ETlH#n>OSNkZ34T z3bnQM>G;O6dkrr{?aT#bJL=n}v&l})} z*bAe%r`DvLh1D9V8<_|*lAG1VXxuL?n7|3AO%GS_6y!Cl%`W+_n5{M7^VpAyFee}i znW!W+x2MY1VxBfx1ZzQ>c+G=g9i(F($lvT=-Ok^f8rIEJ-myvQWBtP!J zQ7mQ|czH*6O}`Q;hqb0$Vs>pay2Go$qE>b%m82URpdVc6nRk52_64#3w08>6IL1#YB5D{Jv#mE+g`l) zt0C;Qqko*A_kBq~=*pPLx@8U8L`pZi!|Eo25^dg1il*325A#KMteef46;~;pLvYUQ ze5x%BmPh~_PEPJCo+Gf)NRuRh$(DpXOH-Q2w7?m}AaL`(uotM!?H+TuBYhB4aoxkG zTSun8QMr7VlS_Ck2|B7ISYWfakg$v!cFf4f zM@=T{%(7nmSR`xAm^t?)-rE!C`)we;O$|}3REdhDIV2eX>|pk?G*+F37xVOkd1x4HnQJ@BQ16USlok;VS7$VjW1r1Dt7S zFl=>~GREXy!zn^l#6}UA1{R6PN}mzc{qQSgs^lqx2U42ddXv-Lyk=l~=dH9?VNbIs zYZzo=dneAl{T3*%uCcOLe(xeusR(9Swd*=DNqCo?xW8m20(sYTF2c5UJ1NaZzR=wL z(BoAU98bh^WCy@IH_t1FhRM@&5B3 z*yqlYIVT61hw+I|#;L`Vzbi5a>Y->T_{D^y*i-#t+` zdzBZ{hbI^HE4(PWX*yY}B|co_qLuDYb~B+ntxDw)L=M-@q3R-&27e%N>OM(K;ci7` z4EL=0mq1|60j>8vplDTfG9LInbH`gC?so`Ij4ZhugcpFabS``q4ub%@TE56Ixtpn` z``RUkQHA!l1hT`=#NgA*Pd|SztgEl=X@$;)cQ_wt+8?Z6U5T1g<=wMOSEm;#sqZ!> zw2qtJensTY0o8OAtj}IWN$%H?-7pk_?w@k~cTb?mIp%TI3h`0D{)Q-#7y@8NF1ALCvi+Nqx3~ z+Q7!0`=c&5kmF>3wGrAf**?6aYq{@7SrSw)W`4^_8;^W7QQD0D^detIWjhr40v@zs zyRh9sh;%`!lxTRQ1n9q;)%rPznH-GiZUxZ`o{>byU^7{2qEif|?qg0zVo0asVUyJgGBBaa zCB?V7ld*Ya>WDPqzD3J3E^Bec$qh9Hz|g*3t&w1-{0Il@tZhaW)k%GkDp{`9N!^$# zyoCPONmbbK>6fPP!6_;6iLjoC%yF6hL+#MecthmI*dFj99&G5)Tn`pjr29D|`m?YH zdT|(K8{m;Mn5|0;`Lr=K858H%Wl|nK*dRnrH$H&Q_^MFJd!g&O1~@Ibn=b_z^UIxN z49Z#ZcL`x#Dpc6R@arO~k#8}dieT0FlOCHAVv+A|qtWav^Ifx%3vgxU_8qkO2j=9W zXy@O`)T&f8o#m|n{vLUyN@gCRCTq=-et1HvT(Tu=HT6UD@Ts~dR(Q8>TIMHn%Y1$Q z&QoQahc8(E>}7-K5Ppha$p~-+X$|I-yzK$Tg!3)-A~g7GTSN^Hs-!En-i~Ekt()P4 z8$zLv+b6%Bj!U_O?AGr0F;0xyf#q>;t-z|FNu8i_#6Dz7o@Ab{#I#v}RRsj1B9AHR z)~>GL-C&m75L}ocQtAD#-f5a}iS%xQ>mfiAX3={7< z{_Bq6^EgO8QW2U{&}_v1Mc~KaluRh{c=um9&S_x}x8}0$X98_}zADPat%c1$%y_*@ z5sy3z`+=OAs1|VG@eP zl2L?Z3sIHs?Y|gjJhOugn#BW^-yo3GCSvqk?oo~@{8yNkBGC6^kIpd+{~o)fbiOQP zl$J^>zy7&Svmz|NJhys88F2|Gd_)eg4zfO%p1SHPhUPq_yh@JQ@=tDHNcAJvy?U8$ zz*@;^J@Qo`e|ThK<7Sr5?sLmY^N7Z%s14p$MBZwD;z@0emWXh9(;$D*fXlV3pZO&A z11%4n=XApgU$Jz@m4i_dPjz(eFlqvC36+zU_xIz4{#v>FlUp)>51zih-W?NlZr5*J z+WqSgy7cgG{HUmhG*@T}K{Xq2Y53pMD23NFh37XuT;|*6hcYn9|$kgWKiI}H=ABVNJ60uLpu*pk>)ezylF}XAduUmcXu!s@e z9`rreln9R*zYam$z%%;mL=V18rb}2eh%8wfbT*QMj#qaKtxHq%h!okw*zEM-8gb8l zNO^(jzhBj$9k9%(Kn$sph@P`z5Du}6ZB0J^j?aw${pHb@h58yO%UNdig`sjj;gqXN zBB;zu5{t=76z|8l8MikCSt3YZ4n){KnL+HfMviU(4mne$DDM!n+?}?mGq@t{UvGy- z#Pe&`Xg8aeF5&B~RsQ@uEu@@i&+-O|&JqKlk9tHSri_W)vvo#db14^su3o+RnQr$5 z3MVy&>i#kr@MXa_`9S|9GA2%e6MU;Wmb_J$iMt)j8QjBW`MxFB`jc|m^MsO!VnRCZ zJ-u>UWK5LGJcU0^q`6OYJqr`04DFkD_|;?!eNmWN%hOtv$^WSzO{VUBDfe8X$L?oM zsgC(fe3lxoC+kIiJo&)D&LQ`+6HYUg=;Ko({cey^qJj56!^b2&-gE(Y}SZ#<%kGSIs!9)U~2VWbX@tSC=?mX%!q z#dN3d+G5LSG^_W3Dd}g+Z-wmR6oH(G2*q*q@O>6cyhHJEaM;3o`@V)Vm#EYthLq;57 zIW(;_cyNwWGfW&rJ50V$R@9Jbz3h`VGF#R?zk9XmV_vVu5yN9U{&&HE+JJwx#L01d3{RlwQNM;u z7k7{}7C}mnFTLab`um%yI9r~B!3`+xc6AW*jn|;-_7jKt7X}sEdTKxMe=GFmdfd9G zo3>s0Od5$(%L*bWRjytuEiz#Ire2!ylJNV+zhTK&fp&zdp0nO>XW^WFoI=} z{LTR9ZBT|(!!i|TK7oU;*&MS3%&4RAoZ4bj0hgO>0wYy%GkvtaQx&HLuFr;2BjB&T z`3S%fIGiSu>eP|obRKcj(%DMk3?(Zj7}-}oLUKK5@ZEnMy2 zoZ(!`5on*UR(mry8!VzlwCdboFtsopMX;ANypLChdt1^$hRjSjF3^rwxsRRxUST^& zq_|4l(tLfi^Ry&<&5HWi>q?(2N%LtF?ivYd(L`dFZPXHmj{Z!SiYSEqToX zwtxsxfmG~fb7S0$p_5%^rcz3-=e>;S7Zh|g&FUJzx)}1fx~KTRFhR-eT)At+plg2# zyF2rr7Trzmei!2!+i7{d0~3&Y&*mIV%OT(9t^MzWy8mYuqxnBAd{1lc#@{DsF0P9^ k-$>x{-#r4v@0|%u^BvI8$JbY!`~LZtuCY$>1G_i>1ELkVCjbBd literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9cbdeecd3d601ffbea9c197ed5c71d2480371613 GIT binary patch literal 45633 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 literal 0 HcmV?d00001 diff --git a/web_dashboard_tile/static/src/js/custom_js.js b/web_dashboard_tile/static/src/js/custom_js.js new file mode 100644 index 00000000..53a2bd0e --- /dev/null +++ b/web_dashboard_tile/static/src/js/custom_js.js @@ -0,0 +1,105 @@ +// @@@ web_dashboard_tile custom JS @@@ +//############################################################################# +// +// Copyright (C) 2010-2013 OpenERP s.a. () +// Copyright (C) 2014 initOS GmbH & Co. KG () +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// 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 . +// +//############################################################################# + +openerp.web_dashboard_tile = function (instance) +{ +var QWeb = instance.web.qweb, + _t = instance.web._t, + _lt = instance.web._lt; +_.mixin({ + sum: function (obj) { return _.reduce(obj, function (a, b) { return a + b; }, 0); } +}); + var module = instance.board.AddToDashboard; + + module.include({ + start: function () { + this._super(); + var self = this; + this.$('#add_dashboard_tile').on('click', this, function (){ + self.save_tile(); + }) + }, + render_data: function(dashboard_choices){ + var selection = instance.web.qweb.render( + "SearchView.addtodashboard.selection", { + selections: dashboard_choices}); + this.$("form input").before(selection) + }, + save_tile: function () { + var self = this; + var getParent = this.getParent(); + var view_parent = this.getParent().getParent(); + if (! view_parent.action || ! this.$el.find("select").val()) { + this.do_warn("Can't find dashboard action"); + return; + } + + var $name = this.$('#dashboard_tile_new_name'); + + this.tile = new instance.web.Model('tile.tile'); + + var private_filter = !this.$('#oe_searchview_custom_public').prop('checked'); + if (_.isEmpty($name.val())){ + this.do_warn(_t("Error"), _t("Filter name is required.")); + return false; + } + var search = this.view.build_search_data(); + var context = new instance.web.CompoundContext(getParent.dataset.get_context() || []); + var domain = new instance.web.CompoundDomain(getParent.dataset.get_domain() || []); + _.each(search.contexts, context.add, context); + _.each(search.domains, domain.add, domain); + + var c = instance.web.pyeval.eval('context', context); + for(var k in c) { + if (c.hasOwnProperty(k) && /^search_default_/.test(k)) { + delete c[k]; + } + } + // TODO: replace this 6.1 workaround by attribute on + c.dashboard_merge_domains_contexts = false; + var d = instance.web.pyeval.eval('domain', domain); + + context.add({ + group_by: instance.web.pyeval.eval('groupbys', search.groupbys || []) + }); + // Don't save user_context keys in the custom filter, otherwise end + // up with e.g. wrong uid or lang stored *and used in subsequent + // reqs* + var ctx = context; + _(_.keys(instance.session.user_context)).each(function (key) { + delete ctx[key]; + }); + var filter = { + name: $name.val(), + user_id: private_filter ? instance.session.uid : false, + model_id: self.view.model, + //context: context, + domain: d, + action_id: view_parent.action.id, + }; + // FIXME: current context? + return self.tile.call('add', [filter]).done(function (id) { + self.do_warn(_t("Success"), _t("Tile is created")); + }); + + } + }); +} diff --git a/web_dashboard_tile/static/src/xml/custom_xml.xml b/web_dashboard_tile/static/src/xml/custom_xml.xml new file mode 100644 index 00000000..3e0c2316 --- /dev/null +++ b/web_dashboard_tile/static/src/xml/custom_xml.xml @@ -0,0 +1,12 @@ + + + + +
+ + + +
+
+
+
diff --git a/web_dashboard_tile/tile.py b/web_dashboard_tile/tile.py new file mode 100644 index 00000000..92243875 --- /dev/null +++ b/web_dashboard_tile/tile.py @@ -0,0 +1,209 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2013 OpenERP s.a. (). +# Copyright (C) 2014 initOS GmbH & Co. KG (). +# Copyright (C) 2015-Today GRAP +# Author Markus Schneider +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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 . +# +############################################################################## + +from openerp.osv import orm, fields +from openerp.tools.translate import _ + + +class tile(orm.Model): + _name = 'tile.tile' + _order = 'sequence, name' + + def median(self, aList): + # https://docs.python.org/3/library/statistics.html#statistics.median + # TODO : refactor, using statistics.median when Odoo will be available + # in Python 3.4 + even = (0 if len(aList) % 2 else 1) + 1 + half = (len(aList) - 1) / 2 + return sum(sorted(aList)[half:half + even]) / float(even) + + def _get_tile_info(self, cr, uid, ids, fields, args, context=None): + ima_obj = self.pool['ir.model.access'] + 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) + count = model.search_count( + cr, uid, eval(r.domain), context=context) + res[r.id].update({ + 'active': True, + '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 + elif r.field_function == 'median': + value = self.median(vals) + helper = _("Median 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): + ima_obj = self.pool['ir.model.access'] + ids = [] + cr.execute(""" + SELECT tt.id, im.model + FROM tile_tile tt + INNER JOIN ir_model im + ON tt.model_id = im.id""") + for result in cr.fetchall(): + if (ima_obj.check(cr, uid, result[1], 'read', False) == + arg[0][2]): + ids.append(result[0]) + return [('id', 'in', ids)] + + _columns = { + 'name': fields.char('Tile Name'), + '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 Text', + multi='tile_info', readonly=True), + 'field_function': fields.selection([ + ('min', 'Minimum'), + ('max', 'Maximum'), + ('sum', 'Sum'), + ('avg', 'Average'), + ('median', 'Median'), + ], '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), + 'color': fields.char('Background color'), + 'font_color': fields.char('Font Color'), + 'sequence': fields.integer( + '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 selected 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', + 'font_color': '#FFFFFF', + 'sequence': 0, + } + + def open_link(self, cr, uid, ids, context=None): + + tile_id = ids[0] + tile_object = self.browse(cr, uid, tile_id, context=context) + + if tile_object.action_id: + act_obj = self.pool.get('ir.actions.act_window') + result = act_obj.read(cr, uid, [tile_object.action_id.id], + context=context)[0] + # FIXME: restore original Domain + Filter would be better + result['domain'] = tile_object.domain + return result + + # we have no action_id stored, + # so try to load a default tree view + return { + 'name': tile_object.name, + 'view_type': 'form', + 'view_mode': 'tree', + 'view_id': [False], + 'res_model': tile_object.model_id.model, + 'type': 'ir.actions.act_window', + 'context': context, + 'nodestroy': True, + 'target': 'current', + 'domain': tile_object.domain, + } + + def add(self, cr, uid, vals, context=None): + # TODO: check if string + if 'model_id' in vals: + # need to replace model_name with its id + model_ids = self.pool.get('ir.model').search(cr, uid, + [('model', '=', + vals['model_id'])]) + vals['model_id'] = model_ids[0] + return self.create(cr, uid, vals, context) diff --git a/web_dashboard_tile/view/tile.xml b/web_dashboard_tile/view/tile.xml new file mode 100644 index 00000000..154efd90 --- /dev/null +++ b/web_dashboard_tile/view/tile.xml @@ -0,0 +1,120 @@ + + + + + tile.tile.tree + tile.tile + + + + + + + + + + + + + + + tile.tile.form + tile.tile + +
+ + + + + + + + + + + +
+
+
+ + + + tile.tile.kanban + tile.tile + + + + + + + + + + + + + + +
+ + + + + + + + Dashboard + tile.tile + form + tree,kanban,form + + + + + + + Dashboard + tile.tile + form + kanban + ['|',('user_id','=',False),('user_id','=',uid)] + + + + + Dashboard + + + + + + +