[MIG+IMP] bi_view_editor: Migration to v10 + enhancements

* Add menu items creation feature
* Added selection of fields of a tree view
* Improved usability and strings made translatable
* Avoid display duplicated nodes
* Robustness
* Updated Dutch translation
* Avoid possible sql injection in bi_view_editor
* Removed deprecated RegistryManager
pull/202/head
Andrea 2017-03-06 09:48:49 +01:00 committed by Pedro M. Baeza
parent f7d63ce3f2
commit fca2ec8d52
81 changed files with 656 additions and 462 deletions

View File

@ -28,17 +28,18 @@ Usage
To graphically design your analysis data-set: To graphically design your analysis data-set:
- From the Reporting menu, select "Custom BI Views" - From the Dashboards menu, select "Custom BI Views"
- Browse trough the business objects in the Query tab - Browse trough the business objects in the Query tab
- Pick the interesting fields (Drag & Drop) - Pick the interesting fields (Drag & Drop)
- For each selected field, right-click on the Options column and select whether it's a row, column or measure - For each selected field, right-click on the Options column and select whether it's a row, column or measure; if you want to remove the field from the list view, unflag the checkbox ´List´ in the Options column
- Save and click "Generate BI View" - Save and click "Generate BI View"
- Click "Open BI View" to view the result - Click "Open BI View" to view the result
- If module Dashboard (board) is installed, the standard "Add to My Dashboard" functionality would be available - If module Dashboard (board) is installed, the standard "Add to My Dashboard" functionality would be available
- Click "Create a menu" to create a new menu item directly linked to your new BI view (this feature is available in developer mode); when the BI view is reset back to draft this menu will be removed, and you will need to re-create the menu entry.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot :alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/143/9.0 :target: https://runbot.odoo-community.org/runbot/143/10.0
Known issues / Roadmap Known issues / Roadmap
====================== ======================
@ -47,6 +48,7 @@ Known issues / Roadmap
* Provide graph view for table relations * Provide graph view for table relations
* Extend the capabilities of the tree views (e.g. add sums) * Extend the capabilities of the tree views (e.g. add sums)
* Provide a tutorial (eg. a working example of usage) * Provide a tutorial (eg. a working example of usage)
* Implement a more advanced UI, with possibilities to use LEFT JOIN as default instead of INNER JOIN
Bug Tracker Bug Tracker
=========== ===========

View File

@ -3,4 +3,5 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models from . import models
from . import wizard
from .hooks import uninstall_hook from .hooks import uninstall_hook

View File

@ -10,7 +10,7 @@
'license': 'AGPL-3', 'license': 'AGPL-3',
'website': 'http://www.onestein.eu', 'website': 'http://www.onestein.eu',
'category': 'Reporting', 'category': 'Reporting',
'version': '9.0.1.0.0', 'version': '10.0.1.0.1',
'depends': [ 'depends': [
'base', 'base',
'web' 'web'
@ -24,9 +24,6 @@
'qweb': [ 'qweb': [
'templates/qweb_template.xml', 'templates/qweb_template.xml',
], ],
'js': [ 'installable': True,
'static/src/js/bve.js'
],
'installable': False,
'uninstall_hook': 'uninstall_hook' 'uninstall_hook': 'uninstall_hook'
} }

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr "Estat"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr "Status"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -181,7 +181,7 @@ msgstr "Estado"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "Usa el constructor especial de consultas para definir la consulta del informe de datos. NOTA: para ser editada, la consulta debe estar en estado 'Borrador'" msgstr "Usa el constructor especial de consultas para definir la consulta del informe de datos. NOTA: para ser editada, la consulta debe estar en estado 'Borrador'"
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr "Tila"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr "État"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr "État"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr "Status"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr "Stato"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

66
bi_view_editor/i18n/nl.po 100644 → 100755
View File

@ -1,16 +1,17 @@
# Translation of Odoo Server. # Translation of Odoo Server.
# This file contains the translation of the following modules: # This file contains the translation of the following modules:
# * bi_view_editor # * bi_view_editor
# #
# Translators: # Translators:
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: reporting-engine (8.0)\n" "Project-Id-Version: reporting-engine (8.0)\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-01-07 05:41+0000\n" "POT-Creation-Date: 2017-01-07 05:41+0000\n"
"PO-Revision-Date: 2016-03-21 15:33+0000\n" "PO-Revision-Date: 2017-03-14 19:54+0100\n"
"Last-Translator: <>\n" "Last-Translator: <>\n"
"Language-Team: Dutch (http://www.transifex.com/oca/OCA-reporting-engine-8-0/language/nl/)\n" "Language-Team: Dutch (http://www.transifex.com/oca/OCA-reporting-engine-10-0/"
"language/nl/)\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n" "Content-Transfer-Encoding: \n"
@ -27,21 +28,27 @@ msgid ""
" </p>\n" " </p>\n"
" " " "
msgstr "" msgstr ""
"<p class=\"oe_view_nocontent_create\">\n"
" Klik om een nieuwe custom query object te maken.\n"
" </p><p>\n"
"\n"
" </p>\n"
" "
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,action_id:0 #: field:bve.view,action_id:0
msgid "Action" msgid "Action"
msgstr "" msgstr "Actie"
#. module: bi_view_editor #. module: bi_view_editor
#: model:ir.model,name:bi_view_editor.model_bve_view #: model:ir.model,name:bi_view_editor.model_bve_view
msgid "BI View Editor" msgid "BI View Editor"
msgstr "" msgstr "BI Weergave bewerker"
#. module: bi_view_editor #. module: bi_view_editor
#: selection:bve.view,state:0 #: selection:bve.view,state:0
msgid "Created" msgid "Created"
msgstr "" msgstr "Aangemaakt"
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,create_uid:0 #: field:bve.view,create_uid:0
@ -56,33 +63,33 @@ msgstr "Aangemaakt op"
#. module: bi_view_editor #. module: bi_view_editor
#: view:bve.view:bi_view_editor.view_bi_view_editor_view_tree #: view:bve.view:bi_view_editor.view_bi_view_editor_view_tree
msgid "Custom BI View" msgid "Custom BI View"
msgstr "" msgstr "Aangepaste BI Weergave"
#. module: bi_view_editor #. module: bi_view_editor
#: sql_constraint:bve.view:0 #: sql_constraint:bve.view:0
msgid "Custom BI View names must be unique!" msgid "Custom BI View names must be unique!"
msgstr "" msgstr "Aangepaste BI Weergave moet uniek zijn!"
#. module: bi_view_editor #. module: bi_view_editor
#: model:ir.actions.act_window,name:bi_view_editor.action_bi_view_editor_view_form #: model:ir.actions.act_window,name:bi_view_editor.action_bi_view_editor_view_form
#: model:ir.ui.menu,name:bi_view_editor.menu_bi_view_editor_view #: model:ir.ui.menu,name:bi_view_editor.menu_bi_view_editor_view
msgid "Custom BI Views" msgid "Custom BI Views"
msgstr "" msgstr "Aangepaste BI Weergaves"
#. module: bi_view_editor #. module: bi_view_editor
#: view:bve.view:bi_view_editor.view_bi_view_editor_view_form #: view:bve.view:bi_view_editor.view_bi_view_editor_view_form
msgid "Custom Object" msgid "Custom Object"
msgstr "" msgstr "Aangepast object"
#. module: bi_view_editor #. module: bi_view_editor
#: model:ir.ui.menu,name:bi_view_editor.menu_bi_view_editor_custom_reports #: model:ir.ui.menu,name:bi_view_editor.menu_bi_view_editor_custom_reports
msgid "Custom Reports" msgid "Custom Reports"
msgstr "" msgstr "Aangepaste rapporten"
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,data:0 #: field:bve.view,data:0
msgid "Data" msgid "Data"
msgstr "" msgstr "Data"
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,display_name:0 #: field:bve.view,display_name:0
@ -92,23 +99,23 @@ msgstr "Te tonen naam"
#. module: bi_view_editor #. module: bi_view_editor
#: selection:bve.view,state:0 #: selection:bve.view,state:0
msgid "Draft" msgid "Draft"
msgstr "" msgstr "Concept"
#. module: bi_view_editor #. module: bi_view_editor
#: code:addons/bi_view_editor/models/bve_view.py:72 #: code:addons/bi_view_editor/models/bve_view.py:72
#, python-format #, python-format
msgid "Error" msgid "Error"
msgstr "" msgstr "Fout"
#. module: bi_view_editor #. module: bi_view_editor
#: view:bve.view:bi_view_editor.view_bi_view_editor_view_form #: view:bve.view:bi_view_editor.view_bi_view_editor_view_form
msgid "Generate BI View" msgid "Generate BI View"
msgstr "" msgstr "Genereer BI Weergave"
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,group_ids:0 #: field:bve.view,group_ids:0
msgid "Groups" msgid "Groups"
msgstr "" msgstr "Groepen"
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,id:0 #: field:bve.view,id:0
@ -133,12 +140,12 @@ msgstr "Laatst bijgewerkt op"
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,model_name:0 #: field:bve.view,model_name:0
msgid "Model Name" msgid "Model Name"
msgstr "" msgstr "Model naam"
#. module: bi_view_editor #. module: bi_view_editor
#: model:ir.model,name:bi_view_editor.model_ir_model #: model:ir.model,name:bi_view_editor.model_ir_model
msgid "Models" msgid "Models"
msgstr "" msgstr "Modellen"
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,name:0 #: field:bve.view,name:0
@ -149,39 +156,42 @@ msgstr "Naam"
#: view:bve.view:bi_view_editor.view_bi_view_editor_view_form #: view:bve.view:bi_view_editor.view_bi_view_editor_view_form
#: field:bve.view,note:0 #: field:bve.view,note:0
msgid "Notes" msgid "Notes"
msgstr "" msgstr "Notities"
#. module: bi_view_editor #. module: bi_view_editor
#: view:bve.view:bi_view_editor.view_bi_view_editor_view_form #: view:bve.view:bi_view_editor.view_bi_view_editor_view_form
msgid "Open BI View" msgid "Open BI View"
msgstr "" msgstr "Open BI Weergave"
#. module: bi_view_editor #. module: bi_view_editor
#: view:bve.view:bi_view_editor.view_bi_view_editor_view_form #: view:bve.view:bi_view_editor.view_bi_view_editor_view_form
msgid "Query" msgid "Query"
msgstr "" msgstr "Query"
#. module: bi_view_editor #. module: bi_view_editor
#: view:bve.view:bi_view_editor.view_bi_view_editor_view_form #: view:bve.view:bi_view_editor.view_bi_view_editor_view_form
msgid "Reset to Draft" msgid "Reset to Draft"
msgstr "" msgstr "Terug naar concept"
#. module: bi_view_editor #. module: bi_view_editor
#: view:bve.view:bi_view_editor.view_bi_view_editor_view_form #: view:bve.view:bi_view_editor.view_bi_view_editor_view_form
msgid "Security" msgid "Security"
msgstr "" msgstr "Beveiliging"
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,state:0 #: field:bve.view,state:0
msgid "State" msgid "State"
msgstr "" msgstr "Status"
#. module: bi_view_editor #. module: bi_view_editor
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
"Gebruik de speciale query bouwer om queries te definiëren voor uw "
"rapportage dataset. LET OP: Om te bewerken moet de query in de 'Concept\" "
"status zijn. "
#. module: bi_view_editor #. module: bi_view_editor
#: help:bve.view,group_ids:0 #: help:bve.view,group_ids:0
@ -189,6 +199,8 @@ msgid ""
"User groups allowed to see the generated report; if NO groups are specified " "User groups allowed to see the generated report; if NO groups are specified "
"the report will be public for everyone." "the report will be public for everyone."
msgstr "" msgstr ""
"Gebruikers groepen die de gegenereerde rapporten kunnen zijn; wanneer geen "
"groepen ingesteld zijn is het rapport zichtbaar voor alle gebruikers."
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,user_ids:0 #: field:bve.view,user_ids:0
@ -198,10 +210,12 @@ msgstr "Gebruikers"
#. module: bi_view_editor #. module: bi_view_editor
#: field:bve.view,view_id:0 #: field:bve.view,view_id:0
msgid "View" msgid "View"
msgstr "" msgstr "Weergave"
#. module: bi_view_editor #. module: bi_view_editor
#: code:addons/bi_view_editor/models/bve_view.py:73 #: code:addons/bi_view_editor/models/bve_view.py:73
#, python-format #, python-format
msgid "You cannot delete a created view! Reset the view to draft first." msgid "You cannot delete a created view! Reset the view to draft first."
msgstr "" msgstr ""
"U kunt een aangemaakte weergave niet verwijderen. Reset de weergave eerst "
"naar de concept fase."

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr "Estado"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -181,7 +181,7 @@ msgstr "Stanje"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "Uporabite posebni gradnik poizvedb za določanje poizvedbe, ki bo ustvarila poročilo z vašim naborom podatkov. OPOMBA: Urejate lahko le poizvedbe s statusom 'Osnutek'." msgstr "Uporabite posebni gradnik poizvedb za določanje poizvedbe, ki bo ustvarila poročilo z vašim naborom podatkov. OPOMBA: Urejate lahko le poizvedbe s statusom 'Osnutek'."
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr "Durum"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -181,7 +181,7 @@ msgstr "Hal"
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -180,7 +180,7 @@ msgstr ""
#: help:bve.view,data:0 #: help:bve.view,data:0
msgid "" msgid ""
"Use the special query builder to define the query to generate your report " "Use the special query builder to define the query to generate your report "
"dataset. NOTE: Te be edited, the query should be in 'Draft' status." "dataset. NOTE: To be edited, the query should be in 'Draft' status."
msgstr "" msgstr ""
#. module: bi_view_editor #. module: bi_view_editor

View File

@ -2,5 +2,6 @@
# Copyright 2015-2017 Onestein (<http://www.onestein.eu>) # Copyright 2015-2017 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models
from . import bve_view from . import bve_view
from . import ir_model from . import ir_model

View File

@ -4,9 +4,9 @@
import json import json
from openerp import api, fields, models, tools from odoo import api, fields, models, tools
from openerp.exceptions import Warning as UserError from odoo.exceptions import UserError
from openerp.tools.translate import _ from odoo.tools.translate import _
class BveView(models.Model): class BveView(models.Model):
@ -23,11 +23,17 @@ class BveView(models.Model):
else: else:
bve_view.user_ids = self.env['res.users'].sudo().search([]) bve_view.user_ids = self.env['res.users'].sudo().search([])
@api.depends('name')
@api.multi
def _compute_model_name(self):
for bve_view in self:
name = [x for x in bve_view.name.lower() if x.isalnum()]
model_name = ''.join(name).replace('_', '.').replace(' ', '.')
bve_view.model_name = 'x_bve.' + model_name
name = fields.Char(required=True, copy=False) name = fields.Char(required=True, copy=False)
model_name = fields.Char() model_name = fields.Char(compute='_compute_model_name', store=True)
note = fields.Text(string='Notes') note = fields.Text(string='Notes')
state = fields.Selection( state = fields.Selection(
[('draft', 'Draft'), [('draft', 'Draft'),
('created', 'Created')], ('created', 'Created')],
@ -36,22 +42,19 @@ class BveView(models.Model):
data = fields.Text( data = fields.Text(
help="Use the special query builder to define the query " help="Use the special query builder to define the query "
"to generate your report dataset. " "to generate your report dataset. "
"NOTE: Te be edited, the query should be in 'Draft' status.") "NOTE: To be edited, the query should be in 'Draft' status.")
action_id = fields.Many2one('ir.actions.act_window', string='Action') action_id = fields.Many2one('ir.actions.act_window', string='Action')
view_id = fields.Many2one('ir.ui.view', string='View') view_id = fields.Many2one('ir.ui.view', string='View')
group_ids = fields.Many2many( group_ids = fields.Many2many(
'res.groups', 'res.groups',
string='Groups', string='Groups',
help="User groups allowed to see the generated report; " help="User groups allowed to see the generated report; "
"if NO groups are specified the report will be public " "if NO groups are specified the report will be public "
"for everyone.") "for everyone.")
user_ids = fields.Many2many( user_ids = fields.Many2many(
'res.users', 'res.users',
string='Users', string='Users',
compute=_compute_users, compute='_compute_users',
store=True) store=True)
_sql_constraints = [ _sql_constraints = [
@ -60,40 +63,21 @@ class BveView(models.Model):
_('Custom BI View names must be unique!')), _('Custom BI View names must be unique!')),
] ]
@api.multi @classmethod
def unlink(self): def _get_format_data(cls, data):
for view in self: data = data.replace('\'', '"')
if view.state == 'created': data = data.replace(': u"', ':"')
raise UserError( return data
_('You cannot delete a created view! '
'Reset the view to draft first.'))
return super(BveView, self).unlink()
@api.multi
def action_reset(self):
self.ensure_one()
if self.action_id:
if self.action_id.view_id:
self.action_id.view_id.sudo().unlink()
self.action_id.sudo().unlink()
models = self.env['ir.model'].sudo().search(
[('model', '=', self.model_name)])
for model in models:
model.sudo().unlink()
table_name = self.model_name.replace('.', '_')
tools.drop_view_if_exists(self.env.cr, table_name)
self.state = 'draft'
@api.multi @api.multi
def _create_view_arch(self): def _create_view_arch(self):
self.ensure_one() self.ensure_one()
def _get_field_def(field_name, def_type): def _get_field_def(name, def_type=''):
if not def_type:
return ''
return """<field name="x_{}" type="{}" />""".format( return """<field name="x_{}" type="{}" />""".format(
field_name, def_type name, def_type
) )
def _get_field_type(field_info): def _get_field_type(field_info):
@ -102,28 +86,42 @@ class BveView(models.Model):
measure = field_info['measure'] and 'measure' measure = field_info['measure'] and 'measure'
return row or column or measure return row or column or measure
def _get_field_list(fields_info):
view_fields = []
for field_info in fields_info:
field_name = field_info['name']
def_type = _get_field_type(field_info)
if def_type:
field_def = _get_field_def(field_name, def_type)
view_fields.append(field_def)
return view_fields
fields_info = json.loads(self._get_format_data(self.data)) fields_info = json.loads(self._get_format_data(self.data))
view_fields = [] view_fields = _get_field_list(fields_info)
for field_info in fields_info:
field_name = field_info['name']
def_type = _get_field_type(field_info)
if def_type:
field_def = _get_field_def(field_name, def_type)
view_fields.append(field_def)
return view_fields return view_fields
@api.model
def _get_format_data(self, data):
data = data.replace('\'', '"')
data = data.replace(': u"', ':"')
return data
@api.multi @api.multi
def action_create(self): def _create_tree_view_arch(self):
self.ensure_one() self.ensure_one()
self._create_bve_object() def _get_field_def(name):
self._create_bve_view() return """<field name="x_{}" />""".format(
name
)
def _get_field_list(fields_info):
view_fields = []
for field_info in fields_info:
field_name = field_info['name']
if field_info['list'] and 'join_node' not in field_info:
field_def = _get_field_def(field_name)
view_fields.append(field_def)
return view_fields
fields_info = json.loads(self._get_format_data(self.data))
view_fields = _get_field_list(fields_info)
return view_fields
@api.multi @api.multi
def _create_bve_view(self): def _create_bve_view(self):
@ -140,33 +138,48 @@ class BveView(models.Model):
'model': self.model_name, 'model': self.model_name,
'priority': 16, 'priority': 16,
'arch': """<?xml version="1.0"?> 'arch': """<?xml version="1.0"?>
<pivot string="Pivot Analysis"> {} </pivot> <pivot string="Pivot Analysis">
""".format("".join(self._create_view_arch())) {}
</pivot>
""".format("".join(self._create_view_arch()))
}, { }, {
'name': 'Graph Analysis', 'name': 'Graph Analysis',
'type': 'graph', 'type': 'graph',
'model': self.model_name, 'model': self.model_name,
'priority': 16, 'priority': 16,
'arch': """<?xml version="1.0"?> 'arch': """<?xml version="1.0"?>
<graph string="Graph Analysis" <graph string="Graph Analysis"
type="bar" type="bar" stacked="True">
stacked="True"> {} </graph> {}
""".format("".join(self._create_view_arch())) </graph>
""".format("".join(self._create_view_arch()))
}, {
'name': 'Search BI View',
'type': 'search',
'model': self.model_name,
'priority': 16,
'arch': """<?xml version="1.0"?>
<search string="Search BI View">
{}
</search>
""".format("".join(self._create_view_arch()))
}] }]
for vals in view_vals: for vals in view_vals:
View.sudo().create(vals) View.sudo().create(vals)
# create Tree view # create Tree view
tree_view = View.sudo().create( tree_view = View.sudo().create({
{'name': 'Tree Analysis', 'name': 'Tree Analysis',
'type': 'tree', 'type': 'tree',
'model': self.model_name, 'model': self.model_name,
'priority': 16, 'priority': 16,
'arch': """<?xml version="1.0"?> 'arch': """<?xml version="1.0"?>
<tree string="List Analysis" create="false"> {} </tree> <tree string="List Analysis" create="false">
""".format("".join(self._create_view_arch())) {}
}) </tree>
""".format("".join(self._create_tree_view_arch()))
})
# set the Tree view as the default one # set the Tree view as the default one
action_vals = { action_vals = {
@ -188,10 +201,52 @@ class BveView(models.Model):
}) })
@api.multi @api.multi
def _create_bve_object(self): def _build_access_rules(self, model):
self.ensure_one() self.ensure_one()
def _get_fields_info(fields_data): def group_ids_with_access(model_name, access_mode):
self.env.cr.execute('''SELECT
g.id
FROM
ir_model_access a
JOIN ir_model m ON (a.model_id=m.id)
JOIN res_groups g ON (a.group_id=g.id)
LEFT JOIN ir_module_category c ON (c.id=g.category_id)
WHERE
m.model=%s AND
a.active IS True AND
a.perm_''' + access_mode, (model_name,))
return [x[0] for x in self.env.cr.fetchall()]
info = json.loads(self._get_format_data(self.data))
model_names = list(set([f['model'] for f in info]))
read_groups = set.intersection(*[set(
group_ids_with_access(model_name, 'read')
) for model_name in model_names])
# read access
for group in read_groups:
self.env['ir.model.access'].sudo().create({
'name': 'read access to ' + self.model_name,
'model_id': model.id,
'group_id': group,
'perm_read': True,
})
# read and write access
for group in self.group_ids:
self.env['ir.model.access'].sudo().create({
'name': 'read-write access to ' + self.model_name,
'model_id': model.id,
'group_id': group.id,
'perm_read': True,
'perm_write': True,
})
@api.model
def _create_sql_view(self):
def get_fields_info(fields_data):
fields_info = [] fields_info = []
for field_data in fields_data: for field_data in fields_data:
field = self.env['ir.model.fields'].browse(field_data['id']) field = self.env['ir.model.fields'].browse(field_data['id'])
@ -208,46 +263,60 @@ class BveView(models.Model):
fields_info.append(vals) fields_info.append(vals)
return fields_info return fields_info
def _build_query(): def get_join_nodes(info):
data = self.data
if not data:
raise UserError(_('No data to process.'))
formatted_data = json.loads(self._get_format_data(data))
info = _get_fields_info(formatted_data)
fields = [("{}.{}".format(f['table_alias'],
f['select_field']),
f['as_field']) for f in info if 'join_node' not in f]
tables = set([(f['table'], f['table_alias']) for f in info])
join_nodes = [ join_nodes = [
(f['table_alias'], (f['table_alias'],
f['join'], f['join'],
f['select_field']) for f in info if f['join'] is not False] f['select_field']) for f in info if f['join'] is not False]
return join_nodes
table_name = self.model_name.replace('.', '_') def get_tables(info):
tools.drop_view_if_exists(self.env.cr, table_name) tables = set([(f['table'], f['table_alias']) for f in info])
return tables
basic_fields = [ def get_fields(info):
("t0.id", "id"), return [("{}.{}".format(f['table_alias'],
("t0.write_uid", "write_uid"), f['select_field']),
("t0.write_date", "write_date"), f['as_field']) for f in info if 'join_node' not in f]
("t0.create_uid", "create_uid"),
("t0.create_date", "create_date")
]
q = """CREATE or REPLACE VIEW %s as ( def check_empty_data(data):
SELECT %s if not data or data == '[]':
FROM %s raise UserError(_('No data to process.'))
WHERE %s
)""" % (table_name, ','.join(
["{} AS {}".format(f[0], f[1])
for f in basic_fields + fields]), ','.join(
["{} AS {}".format(t[0], t[1])
for t in list(tables)]), " AND ".join(
["{}.{} = {}.id".format(j[0], j[2], j[1])
for j in join_nodes] + ["TRUE"]))
self.env.cr.execute(q) check_empty_data(self.data)
formatted_data = json.loads(self._get_format_data(self.data))
info = get_fields_info(formatted_data)
select_fields = get_fields(info)
tables = get_tables(info)
join_nodes = get_join_nodes(info)
table_name = self.model_name.replace('.', '_')
# robustness in case something went wrong
self._cr.execute('DROP TABLE IF EXISTS "%s"' % table_name)
basic_fields = [
("t0.id", "id")
]
q = """CREATE or REPLACE VIEW %s as (
SELECT %s
FROM %s
WHERE %s
)""" % (table_name, ','.join(
["{} AS {}".format(f[0], f[1])
for f in basic_fields + select_fields]), ','.join(
["{} AS {}".format(t[0], t[1])
for t in list(tables)]), " AND ".join(
["{}.{} = {}.id".format(j[0], j[2], j[1])
for j in join_nodes] + ["TRUE"]))
self.env.cr.execute(q)
@api.multi
def action_create(self):
self.ensure_one()
def _prepare_field(field_data): def _prepare_field(field_data):
if not field_data['custom']: if not field_data['custom']:
@ -268,87 +337,90 @@ class BveView(models.Model):
vals.update({'ttype': 'float'}) vals.update({'ttype': 'float'})
if field.ttype == 'selection' and not field.selection: if field.ttype == 'selection' and not field.selection:
model_obj = self.env[field.model_id.model] model_obj = self.env[field.model_id.model]
selection = model_obj._columns[field.name].selection selection = model_obj._fields[field.name].selection
selection_domain = str(selection) if callable(selection):
vals.update({'selection': selection_domain}) selection_domain = selection(model_obj)
else:
selection_domain = selection
vals.update({'selection': str(selection_domain)})
return vals return vals
def _prepare_object(): # clean dirty view (in case something went wrong)
data = json.loads(self._get_format_data(self.data)) self.action_reset()
return {
'name': self.name,
'model': self.model_name,
'field_id': [
(0, 0, _prepare_field(field))
for field in data
if 'join_node' not in field]
}
def _build_object(): # create sql view
vals = _prepare_object() self._create_sql_view()
Model = self.env['ir.model']
res_id = Model.sudo().with_context(bve=True).create(vals)
return res_id
def group_ids_with_access(model_name, access_mode): # create model and fields
self.env.cr.execute('''SELECT data = json.loads(self._get_format_data(self.data))
g.id model_vals = {
FROM 'name': self.name,
ir_model_access a 'model': self.model_name,
JOIN ir_model m ON (a.model_id=m.id) 'state': 'manual',
JOIN res_groups g ON (a.group_id=g.id) 'field_id': [
LEFT JOIN ir_module_category c ON (c.id=g.category_id) (0, 0, _prepare_field(field))
WHERE for field in data
m.model=%s AND if 'join_node' not in field]
a.active IS True AND }
a.perm_''' + access_mode, (model_name,)) Model = self.env['ir.model'].sudo().with_context(bve=True)
return [x[0] for x in self.env.cr.fetchall()] model = Model.create(model_vals)
def _build_access_rules(obj): # give access rights
info = json.loads(self._get_format_data(self.data)) self._build_access_rules(model)
models = list(set([f['model'] for f in info]))
read_groups = set.intersection(*[set(
group_ids_with_access(model, 'read')) for model in models])
# read access # create tree, graph and pivot views
for group in read_groups: self._create_bve_view()
self.env['ir.model.access'].sudo().create({
'name': 'read access to ' + self.model_name,
'model_id': obj.id,
'group_id': group,
'perm_read': True,
})
# read and write access
for group in self.group_ids:
self.env['ir.model.access'].sudo().create({
'name': 'read-write access to ' + self.model_name,
'model_id': obj.id,
'group_id': group.id,
'perm_read': True,
'perm_write': True,
})
self.model_name = 'x_bve.' + ''.join(
[x for x in self.name.lower()
if x.isalnum()]).replace('_', '.').replace(' ', '.')
_build_query()
obj = _build_object()
_build_access_rules(obj)
@api.multi @api.multi
def open_view(self): def open_view(self):
self.ensure_one() self.ensure_one()
return { [action] = self.action_id.read()
'name': _('BI View'), action['display_name'] = _('BI View')
'type': 'ir.actions.act_window', return action
'res_model': self.model_name,
'view_type': 'form',
'view_mode': 'tree,graph,pivot',
}
@api.multi @api.multi
def copy(self, default=None): def copy(self, default=None):
self.ensure_one() self.ensure_one()
default = dict(default or {}, name=_("%s (copy)") % self.name) default = dict(default or {}, name=_("%s (copy)") % self.name)
return super(BveView, self).copy(default=default) return super(BveView, self).copy(default=default)
@api.multi
def action_reset(self):
self.ensure_one()
has_menus = False
if self.action_id:
action = 'ir.actions.act_window,%d' % (self.action_id.id,)
menus = self.env['ir.ui.menu'].sudo().search(
[('action', '=', action)]
)
has_menus = True if menus else False
menus.sudo().unlink()
if self.action_id.view_id:
self.action_id.view_id.sudo().unlink()
self.action_id.sudo().unlink()
self.env['ir.ui.view'].sudo().search(
[('model', '=', self.model_name)]).unlink()
ir_models = self.env['ir.model'].sudo().search(
[('model', '=', self.model_name)])
for model in ir_models:
model.sudo().unlink()
table_name = self.model_name.replace('.', '_')
tools.drop_view_if_exists(self.env.cr, table_name)
self.state = 'draft'
if has_menus:
return {'type': 'ir.actions.client', 'tag': 'reload'}
@api.multi
def unlink(self):
for view in self:
if view.state == 'created':
raise UserError(
_('You cannot delete a created view! '
'Reset the view to draft first.'))
return super(BveView, self).unlink()

View File

@ -2,8 +2,7 @@
# Copyright 2015-2017 Onestein (<http://www.onestein.eu>) # Copyright 2015-2017 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import api, models from odoo import api, models
from openerp.modules.registry import RegistryManager
NO_BI_MODELS = [ NO_BI_MODELS = [
'temp.range', 'temp.range',
@ -42,20 +41,17 @@ def dict_for_field(field):
} }
def dict_for_model(model):
return {
'id': model.id,
'name': model.name,
'model': model.model
}
class IrModel(models.Model): class IrModel(models.Model):
_inherit = 'ir.model' _inherit = 'ir.model'
@api.model
def _filter_bi_fields(self, ir_model_field_obj):
name = ir_model_field_obj.name
model = ir_model_field_obj.model_id
model_name = model.model
Model = self.env[model_name]
if name in Model._columns:
f = Model._columns[name]
return f._classic_write
return False
@api.model @api.model
def _filter_bi_models(self, model): def _filter_bi_models(self, model):
@ -73,7 +69,6 @@ class IrModel(models.Model):
def _check_contains(model_model): def _check_contains(model_model):
if 'mail' in model_model or \ if 'mail' in model_model or \
'_' in model_model or \
'report' in model_model or \ 'report' in model_model or \
'edi.' in model_model: 'edi.' in model_model:
return 1 return 1
@ -96,92 +91,73 @@ class IrModel(models.Model):
model['model'], 'read', False) model['model'], 'read', False)
return False return False
@api.model
def sort_filter_models(self, models_list):
res = sorted(
filter(self._filter_bi_models, models_list),
key=lambda x: x['name'])
return res
@api.model
def _search_fields(self, domain):
Fields = self.env['ir.model.fields']
fields = Fields.sudo().search(domain)
return fields
@api.model @api.model
def get_related_fields(self, model_ids): def get_related_fields(self, model_ids):
""" Return list of field dicts for all fields that can be """ Return list of field dicts for all fields that can be
joined with models in model_ids joined with models in model_ids
""" """
Model = self.env['ir.model']
domain = [('id', 'in', model_ids.values())]
models = Model.sudo().search(domain)
model_names = {}
for model in models:
model_names.update({model.id: model.model})
related_fields = self._get_related_fields_list(model_ids, model_names) def get_model_list(model_ids):
return related_fields model_list = []
@api.model
def _get_related_fields_list(self, model_ids, model_names):
def _get_right_fields(model_ids, model_names):
Fields = self.env['ir.model.fields']
rfields = []
domain = [('model_id', 'in', model_ids.values()), domain = [('model_id', 'in', model_ids.values()),
('store', '=', True),
('ttype', 'in', ['many2one'])] ('ttype', 'in', ['many2one'])]
for field in filter( filtered_fields = self._search_fields(domain)
self._filter_bi_fields, for model in model_ids.items():
Fields.sudo().search(domain)): for field in filtered_fields:
for model in model_ids.items():
if model[1] == field.model_id.id: if model[1] == field.model_id.id:
rfields.append( model_list.append(
dict(dict_for_field(field), dict(dict_for_field(field),
join_node=-1, join_node=-1,
table_alias=model[0]) table_alias=model[0])
) )
return rfields return model_list
def _get_left_fields(model_ids, model_names): def get_relation_list(model_ids, model_names):
Fields = self.env['ir.model.fields'] relation_list = []
lfields = []
domain = [('relation', 'in', model_names.values()), domain = [('relation', 'in', model_names.values()),
('store', '=', True),
('ttype', 'in', ['many2one'])] ('ttype', 'in', ['many2one'])]
for field in filter( filtered_fields = self._search_fields(domain)
self._filter_bi_fields, for model in model_ids.items():
Fields.sudo().search(domain)): for field in filtered_fields:
for model in model_ids.items():
if model_names[model[1]] == field['relation']: if model_names[model[1]] == field['relation']:
lfields.append( relation_list.append(
dict(dict_for_field(field), dict(dict_for_field(field),
join_node=model[0], join_node=model[0],
table_alias=-1) table_alias=-1)
) )
return lfields
def _get_relation_list(model_ids, model_names, lfields):
relation_list = []
for model in model_ids.items():
for field in lfields:
if model_names[model[1]] == field['relation']:
relation_list.append(
dict(field, join_node=model[0])
)
return relation_list return relation_list
def _get_model_list(model_ids, rfields): models = self.sudo().browse(model_ids.values())
model_list = [] model_names = {}
for model in model_ids.items(): for model in models:
for field in rfields: model_names.update({model.id: model.model})
if model[1] == field['model_id']:
model_list.append(
dict(field, table_alias=model[0])
)
return model_list
lfields = _get_left_fields(model_ids, model_names) model_list = get_model_list(model_ids)
rfields = _get_right_fields(model_ids, model_names) relation_list = get_relation_list(model_ids, model_names)
relation_list = _get_relation_list(model_ids, model_names, lfields) return relation_list + model_list
model_list = _get_model_list(model_ids, rfields)
related_fields = relation_list + model_list
return related_fields
@api.model @api.model
def get_related_models(self, model_ids): def get_related_models(self, model_ids):
""" Return list of model dicts for all models that can be """ Return list of model dicts for all models that can be
joined with models in model_ids joined with the already selected models.
""" """
def _get_field(fields, orig, target): def _get_field(fields, orig, target):
field_list = [] field_list = []
for f in fields: for f in fields:
@ -205,35 +181,19 @@ class IrModel(models.Model):
domain = ['|', domain = ['|',
('id', 'in', list_id), ('id', 'in', list_id),
('model', 'in', list_model)] ('model', 'in', list_model)]
models = self.env['ir.model'].sudo().search(domain) for model in self.sudo().search(domain):
for model in models: models_list.append(dict_for_model(model))
models_list.append({ return self.sort_filter_models(models_list)
'id': model.id,
'name': model.name,
'model': model.model
})
return sorted(
filter(self._filter_bi_models, models_list),
key=lambda x: x['name']
)
@api.model @api.model
def get_models(self): def get_models(self):
""" Return list of model dicts for all available models. """ Return list of model dicts for all available models.
""" """
def dict_for_model(model):
return {
'id': model.id,
'name': model.name,
'model': model.model
}
models_domain = [('transient', '=', False)] models_list = []
return sorted(filter( for model in self.search([('transient', '=', False)]):
self._filter_bi_models, models_list.append(dict_for_model(model))
[dict_for_model(model) return self.sort_filter_models(models_list)
for model in self.search(models_domain)]),
key=lambda x: x['name'])
@api.model @api.model
def get_join_nodes(self, field_data, new_field): def get_join_nodes(self, field_data, new_field):
@ -252,39 +212,45 @@ class IrModel(models.Model):
for alias, model_id in model_ids.items(): for alias, model_id in model_ids.items():
if model_id == new_field['model_id']: if model_id == new_field['model_id']:
join_nodes.append({'table_alias': alias}) join_nodes.append({'table_alias': alias})
for dict_field in self.get_related_fields(model_ids): for field in self.get_related_fields(model_ids):
condition = [ c = [field['join_node'] == -1, field['table_alias'] == -1]
dict_field['join_node'] == -1, a = (new_field['model'] == field['relation'])
dict_field['table_alias'] == -1 b = (new_field['model_id'] == field['model_id'])
] if (a and c[0]) or (b and c[1]):
relation = (new_field['model'] == dict_field['relation']) join_nodes.append(field)
model = (new_field['model_id'] == dict_field['model_id'])
if (relation and condition[0]) or (model and condition[1]):
join_nodes.append(dict_field)
return join_nodes return join_nodes
def remove_duplicate_nodes(join_nodes):
seen = set()
nodes_list = []
for node in join_nodes:
node_tuple = tuple(node.items())
if node_tuple not in seen:
seen.add(node_tuple)
nodes_list.append(node)
return nodes_list
model_ids = _get_model_ids(field_data) model_ids = _get_model_ids(field_data)
keys = [(field['table_alias'], field['id']) keys = [(field['table_alias'], field['id'])
for field in field_data if field.get('join_node', -1) != -1] for field in field_data if field.get('join_node', -1) != -1]
join_nodes = _get_join_nodes_dict(model_ids, new_field) join_nodes = _get_join_nodes_dict(model_ids, new_field)
join_nodes = remove_duplicate_nodes(join_nodes)
return filter( return filter(
lambda x: 'id' not in x or lambda x: 'id' not in x or
(x['table_alias'], x['id']) not in keys, join_nodes) (x['table_alias'], x['id']) not in keys, join_nodes)
@api.model @api.model
def get_fields(self, model_id): def get_fields(self, model_id):
bi_field_domain = [ domain = [
('model_id', '=', model_id), ('model_id', '=', model_id),
('store', '=', True),
('name', 'not in', NO_BI_FIELDS), ('name', 'not in', NO_BI_FIELDS),
('ttype', 'not in', NO_BI_TTYPES) ('ttype', 'not in', NO_BI_TTYPES)
] ]
Fields = self.env['ir.model.fields']
fields = filter(
self._filter_bi_fields,
Fields.sudo().search(bi_field_domain)
)
fields_dict = [] fields_dict = []
for field in fields: filtered_fields = self._search_fields(domain)
for field in filtered_fields:
fields_dict.append( fields_dict.append(
{'id': field.id, {'id': field.id,
'model_id': model_id, 'model_id': model_id,
@ -312,16 +278,15 @@ class IrModel(models.Model):
# this sql update is necessary since a write method here would # this sql update is necessary since a write method here would
# be not working (an orm constraint is restricting the modification # be not working (an orm constraint is restricting the modification
# of the state field while updating ir.model) # of the state field while updating ir.model)
q = ("""UPDATE ir_model SET state = 'manual' q = "UPDATE ir_model SET state = 'manual' WHERE id = %s"
WHERE id = """ + str(res.id)) self.env.cr.execute(q, (res.id, ))
self.env.cr.execute(q)
# update registry # # update registry
if self._context.get('bve'): if self._context.get('bve'):
# setup models; this reloads custom models in registry # setup models; this reloads custom models in registry
self.pool.setup_models(self._cr, partial=(not self.pool.ready)) self.pool.setup_models(self._cr, partial=(not self.pool.ready))
# signal that registry has changed # signal that registry has changed
RegistryManager.signal_registry_change(self.env.cr.dbname) self.pool.signal_registry_change()
return res return res

View File

@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, models
from odoo.exceptions import UserError
from odoo.tools.translate import _
class Base(models.AbstractModel):
_inherit = 'base'
@api.model
def _bi_view(self):
return self._name[0:6] == 'x_bve.'
@api.model
def _auto_end(self):
if not self._bi_view():
super(Base, self)._auto_end()
@api.model
def _auto_init(self):
if not self._bi_view():
super(Base, self)._auto_init()
@api.model
def _setup_complete(self):
if not self._bi_view():
super(Base, self)._setup_complete()
else:
self.pool.models[self._name]._log_access = False
@api.model
def _read_group_process_groupby(self, gb, query):
if not self._bi_view():
return super(Base, self)._read_group_process_groupby(gb, query)
split = gb.split(':')
if split[0] not in self._fields:
raise UserError(
_('No data to be displayed.'))
return super(Base, self)._read_group_process_groupby(gb, query)
@api.model
def _add_magic_fields(self):
if self._bi_view():
self._log_access = False
return super(Base, self)._add_magic_fields()
@api.model_cr
def _table_exist(self):
if not self._bi_view():
return super(Base, self)._table_exist()
return 1
# @api.model_cr
# def _create_table(self):
# if not self._bi_view():
# return super(Base, self)._create_table()
# return 1

View File

@ -1,3 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_bve_view_everyone,bve.view,bi_view_editor.model_bve_view,,1,1,1,1 access_bve_view_everyone,bve.view,bi_view_editor.model_bve_view,,1,1,1,1
access_bve_view_technical_settings,bve.view,bi_view_editor.model_bve_view,base.group_no_one,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_bve_view_everyone bve.view bi_view_editor.model_bve_view 1 1 1 1
access_bve_view_technical_settings bve.view bi_view_editor.model_bve_view base.group_no_one 1 1 1 1

View File

@ -1,10 +1,65 @@
openerp.bi_view_editor = function (instance, local) { odoo.define('bi_view_editor', function (require) {
"use strict";
instance.bi_view_editor.BVEEditor = instance.web.form.AbstractField.extend({ var Core = require("web.core");
var FormCommon = require('web.form_common');
var Model = require('web.Model');
var Data = require('web.data');
var Widget = require('web.Widget');
var Dialog = require("web.Dialog");
var _t = Core._t;
var JoinNodePopup = Widget.extend({
template: "JoinNodePopup",
start: function() {
var self = this;
},
display_popup: function(choices, model_data, callback, callback_data) {
var self = this;
this.renderElement();
var joinnodes = this.$el.find('#join-nodes');
joinnodes.empty();
for (var i=0; i<choices.length; i++) {
var description = "";
if (choices[i].join_node !== -1 && choices[i].table_alias !== -1) {
description = _t("Use the field on model") + " <b>" + model_data[choices[i].table_alias].model_name + "</b>";
} else {
var new_str = "";
if (choices[i].join_node !== -1) {
new_str = "<b>" + _t("new") + "</b> ";
}
description = _t("<b>Join</b> using the field") + " <u><b>" + choices[i].description + "</b></u> " + _t("on ") + new_str + _t("model") +" <b>" + choices[i].model_name + "</b>";
}
joinnodes.append($('<a><input type="radio">' + description+ '</a>')
.data('idx', i)
.wrap('<p></p>')
.parent());
}
var dialog = new Dialog(this, {
dialogClass: 'oe_act_window',
title: _t("Choose join node"),
$content: this.$el,
buttons: [{text: _t("Cancel"),
classes: "btn-default o_form_button_cancel",
close: true
}]
}).open();
joinnodes.find('a').click(function() {
callback(callback_data, choices[$(this).data('idx')]);
dialog.close();
});
this.start();
}
});
var BiViewEditor = FormCommon.AbstractField.extend({
template: "BVEEditor", template: "BVEEditor",
activeModelMenus: [], activeModelMenus: [],
currentFilter: "", currentFilter: "",
init: function(parent, action) { init: function() {
this._super.apply(this, arguments); this._super.apply(this, arguments);
}, },
start: function() { start: function() {
@ -23,7 +78,6 @@ openerp.bi_view_editor = function (instance, local) {
drop: function (event, ui) { drop: function (event, ui) {
self.add_field(ui.draggable); self.add_field(ui.draggable);
ui.draggable.draggable('option', 'revert', false ); ui.draggable.draggable('option', 'revert', false );
ui.draggable.remove();
} }
}); });
if (!this.get("effective_readonly")) { if (!this.get("effective_readonly")) {
@ -68,6 +122,8 @@ openerp.bi_view_editor = function (instance, local) {
icons += "<span class='fa fa-bars' title='Row'></span> "; icons += "<span class='fa fa-bars' title='Row'></span> ";
if(field.measure) if(field.measure)
icons += "<span class='fa fa-bar-chart-o' title='Measure'></span> "; icons += "<span class='fa fa-bar-chart-o' title='Measure'></span> ";
if(field.list)
icons += "<span class='fa fa-list' title='List'></span> ";
return icons; return icons;
}, },
@ -80,20 +136,20 @@ openerp.bi_view_editor = function (instance, local) {
load_classes: function(scrollTo) { load_classes: function(scrollTo) {
scrollTo = (typeof scrollTo === 'undefined') ? false : scrollTo; scrollTo = (typeof scrollTo === 'undefined') ? false : scrollTo;
var self = this; var self = this;
var model = new instance.web.Model("ir.model"); var model = new Model("ir.model");
if (this.$el.find(".field-list tbody tr").length > 0) { if (this.$el.find(".field-list tbody tr").length > 0) {
model.call("get_related_models", [this.get_model_ids()], { context: new instance.web.CompoundContext() }).then(function(result) { model.call("get_related_models", [this.get_model_ids()], { context: new Data.CompoundContext() }).then(function(result) {
self.show_classes(result); self.show_classes(result);
}); });
} else { } else {
model.call("get_models", { context: new instance.web.CompoundContext() }).then(function(result) { model.call("get_models", { context: new Data.CompoundContext() }).then(function(result) {
self.show_classes(result); self.show_classes(result);
}); });
} }
}, },
show_classes: function (result) { show_classes: function (result) {
var self = this; var self = this;
var model = new instance.web.Model("ir.model"); var model = new Model("ir.model");
self.$el.find(".class-list .class").remove(); self.$el.find(".class-list .class").remove();
self.$el.find(".class-list .field").remove(); self.$el.find(".class-list .field").remove();
var css = this.get('effective_readonly') ? 'cursor: default' : 'cursor: pointer'; var css = this.get('effective_readonly') ? 'cursor: default' : 'cursor: pointer';
@ -112,7 +168,7 @@ openerp.bi_view_editor = function (instance, local) {
if(index !== -1) self.activeModelMenus.splice(index, 1); if(index !== -1) self.activeModelMenus.splice(index, 1);
} else { } else {
self.activeModelMenus.push(classel.data('model-data').id); self.activeModelMenus.push(classel.data('model-data').id);
model.call("get_fields", [classel.data('model-data').id], { context: new instance.web.CompoundContext() }).then(function(result) { model.call("get_fields", [classel.data('model-data').id], { context: new Data.CompoundContext() }).then(function(result) {
for (var i = 0; i < result.length; i++) { for (var i = 0; i < result.length; i++) {
classel.find("#bve-field-" + result[i].name).remove(); classel.find("#bve-field-" + result[i].name).remove();
self._render_field(self, i, result, classel, addField) self._render_field(self, i, result, classel, addField)
@ -122,12 +178,13 @@ openerp.bi_view_editor = function (instance, local) {
} }
} }
function renderFields(result) { function renderFields(result) {
console.log(result); if (typeof(result[0]) !== 'undefined') {
var item = self.$el.find(".class-list #bve-class-" + result[0].model_id); var item = self.$el.find(".class-list #bve-class-" + result[0].model_id);
for (var o = 0; o < result.length; o++) { for (var o = 0; o < result.length; o++) {
self._render_field(self, o, result, item, addField) self._render_field(self, o, result, item, addField)
}
item.data('bve-processed', true);
} }
item.data('bve-processed', true);
} }
for (var i = 0; i < result.length; i++) { for (var i = 0; i < result.length; i++) {
var item = $("<div style=\"" + css + "\" class=\"class\" title=\"" + result[i].model + "\" id=\"bve-class-" + result[i].id + "\">" + result[i].name + "</div>") var item = $("<div style=\"" + css + "\" class=\"class\" title=\"" + result[i].model + "\" id=\"bve-class-" + result[i].id + "\">" + result[i].name + "</div>")
@ -138,7 +195,7 @@ openerp.bi_view_editor = function (instance, local) {
var index = self.activeModelMenus.indexOf(item.find(".class").data('model-data').id); var index = self.activeModelMenus.indexOf(item.find(".class").data('model-data').id);
if(index !== -1 && !self.get("effective_readonly")) { if(index !== -1 && !self.get("effective_readonly")) {
model.call("get_fields", [self.activeModelMenus[index]], { context: new instance.web.CompoundContext() }).then(renderFields); model.call("get_fields", [self.activeModelMenus[index]], { context: new Data.CompoundContext() }).then(renderFields);
} }
self.filter(); self.filter();
} }
@ -165,15 +222,19 @@ openerp.bi_view_editor = function (instance, local) {
_contextMenu.find(identifier).attr('checked', false); _contextMenu.find(identifier).attr('checked', false);
}, },
_false_if_undefined: function(to_check) { _false_if_undefined: function(to_check) {
if (typeof check === 'undefined') return false; if (typeof to_check === 'undefined') return false;
return check; return to_check;
},
_true_if_undefined: function(to_check) {
if (typeof to_check === 'undefined') return true;
return to_check;
}, },
add_field_to_table: function(data, options) { add_field_to_table: function(data, options) {
var self = this; var self = this;
data.row = self._false_if_undefined(data.row); data.row = self._false_if_undefined(data.row);
data.column = self._false_if_undefined(data.column); data.column = self._false_if_undefined(data.column);
data.measure = self._false_if_undefined(data.measure); data.measure = self._false_if_undefined(data.measure);
data.list = self._true_if_undefined(data.list);
var n = 1; var n = 1;
var name = data.name; var name = data.name;
@ -220,10 +281,11 @@ openerp.bi_view_editor = function (instance, local) {
self.set_checkbox(currentFieldData.column, '#column-checkbox', contextMenu); self.set_checkbox(currentFieldData.column, '#column-checkbox', contextMenu);
self.set_checkbox(currentFieldData.row, '#row-checkbox', contextMenu); self.set_checkbox(currentFieldData.row, '#row-checkbox', contextMenu);
self.set_checkbox(currentFieldData.measure, '#measure-checkbox', contextMenu); self.set_checkbox(currentFieldData.measure, '#measure-checkbox', contextMenu);
self.set_checkbox(currentFieldData.list, '#list-checkbox', contextMenu);
var to_disable = false; var to_disable = false;
if(currentFieldData.type === "float" || currentFieldData.type === "integer" || currentFieldData.type === "monetary") to_disable = true; if(currentFieldData.type === "float" || currentFieldData.type === "integer" || currentFieldData.type === "monetary") to_disable = true;
var identifiers = [['#column-checkbox', 'column', to_disable], ['#row-checkbox', 'row', to_disable], ['#measure-checkbox', 'measure', !to_disable]]; var identifiers = [['#column-checkbox', 'column', to_disable], ['#row-checkbox', 'row', to_disable], ['#measure-checkbox', 'measure', !to_disable], ['#list-checkbox', 'list', false]];
identifiers.forEach(function (element) { identifiers.forEach(function (element) {
contextMenu.find(element[0]).attr('disabled', element[2]); contextMenu.find(element[0]).attr('disabled', element[2]);
}); });
@ -260,8 +322,13 @@ openerp.bi_view_editor = function (instance, local) {
self.clean_join_nodes(); self.clean_join_nodes();
self.internal_set_value(JSON.stringify(self.get_fields())); self.internal_set_value(JSON.stringify(self.get_fields()));
self.load_classes(); self.load_classes();
self.$el.find(".field-list .delete-button").hide();
self.$el.find(".field-list .delete-button:last").show();
return false; return false;
}); });
self.$el.find(".field-list .delete-button").hide();
self.$el.find(".field-list .delete-button:last").show();
}, },
clean_join_nodes: function () { clean_join_nodes: function () {
var aliases = $.makeArray(this.$el.find(".field-list tbody tr").map(function (idx, el) { var aliases = $.makeArray(this.$el.find(".field-list tbody tr").map(function (idx, el) {
@ -320,19 +387,29 @@ openerp.bi_view_editor = function (instance, local) {
self.load_classes(field); self.load_classes(field);
}, },
add_field: function(field) { add_field: function(field) {
var self = this;
// Quick fix for double click
if(self._adding) {
return;
}
self._adding = true;
setTimeout(function() {
self._adding = false;
}, 1000);
// End quick fix
var data = field.data('field-data'); var data = field.data('field-data');
var model = new instance.web.Model("ir.model"); var model = new Model("ir.model");
var model_ids = this.get_model_ids(); var model_ids = this.get_model_ids();
var field_data = this.get_fields(); var field_data = this.get_fields();
var self = this; model.call('get_join_nodes', [field_data, data], {context: new Data.CompoundContext()}).then(function(result) {
model.call('get_join_nodes', [field_data, data], {context: new instance.web.CompoundContext()}).then(function(result) {
if (result.length === 1) { if (result.length === 1) {
self.add_field_and_join_node(data, result[0]); self.add_field_and_join_node(data, result[0]);
self.internal_set_value(JSON.stringify(self.get_fields())); self.internal_set_value(JSON.stringify(self.get_fields()));
//self.load_classes(data);
} else if (result.length > 1) { } else if (result.length > 1) {
var pop = new local.JoinNodePopup(self); var pop = new JoinNodePopup(self);
pop.display_popup(result, self.get_model_data(), self.add_field_and_join_node.bind(self), data); pop.display_popup(result, self.get_model_data(), self.add_field_and_join_node.bind(self), data);
} else { } else {
// first field and table only. // first field and table only.
@ -363,49 +440,6 @@ openerp.bi_view_editor = function (instance, local) {
this.load_classes(); this.load_classes();
} }
}); });
instance.web.form.widgets.add('BVEEditor', 'instance.bi_view_editor.BVEEditor'); Core.form_widget_registry.add('BVEEditor', BiViewEditor);
local.JoinNodePopup = instance.web.Widget.extend({ });
template: "JoinNodePopup",
start: function() {
var self = this;
},
display_popup: function(choices, model_data, callback, callback_data) {
var self = this;
this.renderElement();
var joinnodes = this.$el.find('#join-nodes');
joinnodes.empty();
for (var i=0; i<choices.length; i++) {
var description = "";
if (choices[i].join_node !== -1 && choices[i].table_alias !== -1) {
description = "Use the field on table " + model_data[choices[i].table_alias].model_name;
} else {
var new_str = "";
if (choices[i].join_node !== -1) {
new_str = "new ";
}
description = "Join using the field '" + choices[i].description + "' from " + new_str + "model '" + choices[i].model_name + "'";
}
joinnodes.append($("<a>" + description+ "</a>")
.data('idx', i)
.wrap("<p></p>")
.parent());
}
var dialog = new instance.web.Dialog(this, {
dialogClass: 'oe_act_window',
title: "Choose Join Node",
$content: this.$el
}).open();
joinnodes.find('a').click(function() {
callback(callback_data, choices[$(this).data('idx')]);
dialog.close();
});
this.start();
}
});
};

View File

@ -2,7 +2,6 @@
<templates id="template" xml:space="preserve"> <templates id="template" xml:space="preserve">
<t t-name="JoinNodePopup"> <t t-name="JoinNodePopup">
<div class="oe_form_nosheet"> <div class="oe_form_nosheet">
<p>Please choose the join node</p>
<div id="join-nodes"> <div id="join-nodes">
</div> </div>
</div> </div>
@ -44,9 +43,10 @@
</div> </div>
<ul class="context-menu"> <ul class="context-menu">
<li><input type="checkbox" id="column-checkbox"/> Column</li> <li><input type="checkbox" id="column-checkbox"/> Column</li>
<li><input type="checkbox" id="row-checkbox"/> Row</li> <li><input type="checkbox" id="row-checkbox"/> Row</li>
<li><input type="checkbox" id="measure-checkbox"/> Measure</li> <li><input type="checkbox" id="measure-checkbox"/> Measure</li>
<li><input type="checkbox" id="list-checkbox"/> List</li>
</ul> </ul>
</div> </div>

View File

@ -2,8 +2,8 @@
# Copyright 2017 Onestein (<http://www.onestein.eu>) # Copyright 2017 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.tests.common import TransactionCase, at_install, post_install from odoo.tests.common import TransactionCase, at_install, post_install
from openerp.exceptions import Warning as UserError from odoo.exceptions import UserError
class TestBiViewEditor(TransactionCase): class TestBiViewEditor(TransactionCase):
@ -66,6 +66,7 @@ class TestBiViewEditor(TransactionCase):
'table_alias': 't0', 'table_alias': 't0',
'row': 0, 'row': 0,
'column': 1, 'column': 1,
'list': 1,
'measure': 0 'measure': 0
}, },
{'model_id': self.partner_model.id, {'model_id': self.partner_model.id,
@ -81,6 +82,7 @@ class TestBiViewEditor(TransactionCase):
'description': self.partner_company_field.field_description, 'description': self.partner_company_field.field_description,
'row': 0, 'row': 0,
'column': 0, 'column': 0,
'list': 1,
'measure': 0 'measure': 0
}, },
{'model_id': self.company_model.id, {'model_id': self.company_model.id,
@ -94,6 +96,7 @@ class TestBiViewEditor(TransactionCase):
'table_alias': 't1', 'table_alias': 't1',
'row': 1, 'row': 1,
'column': 0, 'column': 0,
'list': 0,
'measure': 0 'measure': 0
} }
] ]

View File

@ -18,6 +18,7 @@
<button name="action_reset" type="object" states="created" string="Reset to Draft"/> <button name="action_reset" type="object" states="created" string="Reset to Draft"/>
<button name="action_create" type="object" states="draft" string="Generate BI View" class="oe_highlight"/> <button name="action_create" type="object" states="draft" string="Generate BI View" class="oe_highlight"/>
<button name="open_view" type="object" states="created" string="Open BI View" class="oe_highlight"/> <button name="open_view" type="object" states="created" string="Open BI View" class="oe_highlight"/>
<button name="%(base.act_menu_create)d" type="action" states="created" groups="base.group_no_one" icon="fa-align-justify" string="Create a Menu" target="new"/>
<field name="state" widget="statusbar" statusbar_visible="draft,created" statusbar_colors='{"draft":"blue","created":"blue"}'/> <field name="state" widget="statusbar" statusbar_visible="draft,created" statusbar_colors='{"draft":"blue","created":"blue"}'/>
</header> </header>
<sheet> <sheet>

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import wizard_ir_model_menu_create

View File

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Onestein (<http://www.onestein.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, models
class WizardModelMenuCreate(models.TransientModel):
_inherit = 'wizard.ir.model.menu.create'
@api.multi
def menu_create(self):
if self._context.get('active_model') == 'bve.view':
self.ensure_one()
active_id = self._context.get('active_id')
bve_view = self.env['bve.view'].browse(active_id)
menu = self.env['ir.ui.menu'].create({
'name': self.name,
'parent_id': self.menu_id.id,
'action': 'ir.actions.act_window,%d' % (bve_view.action_id,)
})
self.env['ir.model.data'].create({
'name': bve_view.name + ', id=' + str(menu.id),
'noupdate': True,
'module': 'bi_view_editor',
'model': 'ir.ui.menu',
'res_id': menu.id,
})
return {'type': 'ir.actions.client', 'tag': 'reload'}
return super(WizardModelMenuCreate, self).menu_create()
@api.model
def default_get(self, fields_list):
defaults = super(WizardModelMenuCreate, self).default_get(fields_list)
if self._context.get('active_model') == 'bve.view':
active_id = self._context.get('active_id')
bve_view = self.env['bve.view'].browse(active_id)
defaults.setdefault('name', bve_view.name)
return defaults