[MIG] web_pivot_computed_measure: Migration to 15.0

pull/2341/head
CarlosRoca13 2022-11-22 13:46:39 +01:00
parent 292be551f7
commit 93d07f491d
20 changed files with 560 additions and 596 deletions

View File

@ -14,13 +14,13 @@ Web Pivot Computed Measure
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3 :alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
:target: https://github.com/OCA/web/tree/13.0/web_pivot_computed_measure :target: https://github.com/OCA/web/tree/15.0/web_pivot_computed_measure
:alt: OCA/web :alt: OCA/web
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_pivot_computed_measure :target: https://translation.odoo-community.org/projects/web-15-0/web-15-0-web_pivot_computed_measure
:alt: Translate me on Weblate :alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/162/13.0 :target: https://runbot.odoo-community.org/runbot/162/15.0
:alt: Try me on Runbot :alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5| |badge1| |badge2| |badge3| |badge4| |badge5|
@ -65,6 +65,7 @@ Known issues / Roadmap
====================== ======================
#. Add support to define a style for a computed measure (ex. colored) #. Add support to define a style for a computed measure (ex. colored)
#. Use t-model to data-binding instad of jquery selectors
Bug Tracker Bug Tracker
=========== ===========
@ -72,7 +73,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_. Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_.
In case of trouble, please check there if your issue has already been reported. In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_pivot_computed_measure%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. `feedback <https://github.com/OCA/web/issues/new?body=module:%20web_pivot_computed_measure%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues. Do not contact contributors directly about support or help with technical issues.
@ -92,6 +93,7 @@ Contributors
* Alexandre D. Díaz * Alexandre D. Díaz
* Pedro M. Baeza * Pedro M. Baeza
* Ernesto Tejeda * Ernesto Tejeda
* Carlos Roca
Maintainers Maintainers
~~~~~~~~~~~ ~~~~~~~~~~~
@ -106,6 +108,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use. promote its widespread use.
This module is part of the `OCA/web <https://github.com/OCA/web/tree/13.0/web_pivot_computed_measure>`_ project on GitHub. This module is part of the `OCA/web <https://github.com/OCA/web/tree/15.0/web_pivot_computed_measure>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -1,16 +1,26 @@
# Copyright 2020 Tecnativa - Alexandre Díaz # Copyright 2020 Tecnativa - Alexandre Díaz
# 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)
{ {
"name": "Web Pivot Computed Measure", "name": "Web Pivot Computed Measure",
"category": "web", "category": "web",
"version": "13.0.1.1.0", "version": "15.0.1.0.0",
"author": "Tecnativa, Odoo Community Association (OCA)", "author": "Tecnativa, Odoo Community Association (OCA)",
"license": "AGPL-3", "license": "AGPL-3",
"website": "https://github.com/OCA/web", "website": "https://github.com/OCA/web",
"depends": ["web"], "depends": ["web"],
"data": ["view/assets.xml"],
"qweb": ["static/src/xml/web_pivot_computed_measure.xml"],
"auto_install": False, "auto_install": False,
"installable": True, "installable": True,
"assets": {
"web.assets_qweb": [
"/web_pivot_computed_measure/static/src/**/*.xml",
],
"web.assets_backend": [
"/web_pivot_computed_measure/static/src/**/*.esm.js",
"/web_pivot_computed_measure/static/src/**/*.scss",
("remove", "/web_pivot_computed_measure/static/src/test/*.esm.js"),
],
"web.assets_tests": [
"/web_pivot_computed_measure/static/src/test/test.esm.js",
],
},
} }

View File

@ -6,145 +6,153 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 12.0\n" "Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2020-09-16 14:00+0000\n" "POT-Creation-Date: 2022-11-22 12:42+0000\n"
"PO-Revision-Date: 2022-11-22 13:43+0100\n"
"Last-Translator: claudiagn <claudia.gargallo@qubiq.es>\n" "Last-Translator: claudiagn <claudia.gargallo@qubiq.es>\n"
"Language-Team: none\n" "Language-Team: none\n"
"Language: es\n" "Language: es\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: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.10\n" "X-Generator: Poedit 2.3\n"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/view.xml:0
#, python-format
msgid "!measure.startsWith('__computed_')"
msgstr ""
#. module: web_pivot_computed_measure
#. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Add" msgid "Add"
msgstr "Añadir" msgstr "Añadir"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Can be empty" msgid "Can be empty"
msgstr "Puede estar vacío" msgstr "Puede estar vacío"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Computed Measure" msgid "Computed Measure"
msgstr "Medida computada" msgstr "Medida computada"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Custom" msgid "Custom"
msgstr "Customizado" msgstr "Customizado"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Div (m1 / m2)" msgid "Div (m1 / m2)"
msgstr "Div (m1 / m2)" msgstr "Div (m1 / m2)"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Float" msgid "Float"
msgstr "Flotador" msgstr "Flotador"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Format" msgid "Format"
msgstr "Formato" msgstr "Formato"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Formula" msgid "Formula"
msgstr "Fórmula" msgstr "Fórmula"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Integer" msgid "Integer"
msgstr "Entero" msgstr "Entero"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Measure 1" msgid "Measure 1"
msgstr "Medida 1" msgstr "Medida 1"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Measure 2" msgid "Measure 2"
msgstr "Medida 2" msgstr "Medida 2"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Mult (m1 * m2)" msgid "Mult (m1 * m2)"
msgstr "Mult (m1 * m2)" msgstr "Mult (m1 * m2)"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Name" msgid "Name"
msgstr "Nombre" msgstr "Nombre"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Operation" msgid "Operation"
msgstr "Operación" msgstr "Operación"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Perc (m1 * 100 / m2)" msgid "Perc (m1 * 100 / m2)"
msgstr "Perc (m1 * 100 / m2)" msgstr "Perc (m1 * 100 / m2)"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Percentage" msgid "Percentage"
msgstr "Porcentaje" msgstr "Porcentaje"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Sub (m1 - m2)" msgid "Sub (m1 - m2)"
msgstr "Sub (m1 - m2)" msgstr "Sub (m1 - m2)"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Sum (m1 + m2)" msgid "Sum (m1 + m2)"
msgstr "Sum (m1 + m2)" msgstr "Sum (m1 + m2)"
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/js/pivot_model.js:0 #: code:addons/web_pivot_computed_measure/static/src/pivot/pivot_model.js:0
#, python-format #, python-format
msgid "" msgid ""
"This measure is currently used by a 'computed measure'. Please, disable the " "This measure is currently used by a 'computed measure'. Please, disable the "

View File

@ -4,8 +4,10 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 13.0\n" "Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-22 12:42+0000\n"
"PO-Revision-Date: 2022-11-22 12:42+0000\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -15,133 +17,140 @@ msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/view.xml:0
#, python-format
msgid "!measure.startsWith('__computed_')"
msgstr ""
#. module: web_pivot_computed_measure
#. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Add" msgid "Add"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Can be empty" msgid "Can be empty"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Computed Measure" msgid "Computed Measure"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Custom" msgid "Custom"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Div (m1 / m2)" msgid "Div (m1 / m2)"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Float" msgid "Float"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Format" msgid "Format"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Formula" msgid "Formula"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Integer" msgid "Integer"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Measure 1" msgid "Measure 1"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Measure 2" msgid "Measure 2"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Mult (m1 * m2)" msgid "Mult (m1 * m2)"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Name" msgid "Name"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Operation" msgid "Operation"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Perc (m1 * 100 / m2)" msgid "Perc (m1 * 100 / m2)"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Percentage" msgid "Percentage"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Sub (m1 - m2)" msgid "Sub (m1 - m2)"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/xml/web_pivot_computed_measure.xml:0 #: code:addons/web_pivot_computed_measure/static/src/dropdown_item_custom_measure/dropdown_item_custom_measure.xml:0
#, python-format #, python-format
msgid "Sum (m1 + m2)" msgid "Sum (m1 + m2)"
msgstr "" msgstr ""
#. module: web_pivot_computed_measure #. module: web_pivot_computed_measure
#. openerp-web #. openerp-web
#: code:addons/web_pivot_computed_measure/static/src/js/pivot_model.js:0 #: code:addons/web_pivot_computed_measure/static/src/pivot/pivot_model.js:0
#, python-format #, python-format
msgid "" msgid ""
"This measure is currently used by a 'computed measure'. Please, disable the " "This measure is currently used by a 'computed measure'. Please, disable the "

View File

@ -3,3 +3,4 @@
* Alexandre D. Díaz * Alexandre D. Díaz
* Pedro M. Baeza * Pedro M. Baeza
* Ernesto Tejeda * Ernesto Tejeda
* Carlos Roca

View File

@ -1 +1,2 @@
#. Add support to define a style for a computed measure (ex. colored) #. Add support to define a style for a computed measure (ex. colored)
#. Use t-model to data-binding instad of jquery selectors

View File

@ -3,7 +3,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils: http://docutils.sourceforge.net/" />
<title>Web Pivot Computed Measure</title> <title>Web Pivot Computed Measure</title>
<style type="text/css"> <style type="text/css">
@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !! !! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !! !! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/web/tree/13.0/web_pivot_computed_measure"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_pivot_computed_measure"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/162/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> <p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/web/tree/15.0/web_pivot_computed_measure"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/web-15-0/web-15-0-web_pivot_computed_measure"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/162/15.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>Adds support for computed measures on the pivot view.</p> <p>Adds support for computed measures on the pivot view.</p>
<p><strong>Table of contents</strong></p> <p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents"> <div class="contents local topic" id="contents">
@ -432,6 +432,7 @@ cant be deactivated until you have deactivate the computed measure.</p>
<h1><a class="toc-backref" href="#id2">Known issues / Roadmap</a></h1> <h1><a class="toc-backref" href="#id2">Known issues / Roadmap</a></h1>
<ol class="arabic simple"> <ol class="arabic simple">
<li>Add support to define a style for a computed measure (ex. colored)</li> <li>Add support to define a style for a computed measure (ex. colored)</li>
<li>Use t-model to data-binding instad of jquery selectors</li>
</ol> </ol>
</div> </div>
<div class="section" id="bug-tracker"> <div class="section" id="bug-tracker">
@ -439,7 +440,7 @@ cant be deactivated until you have deactivate the computed measure.</p>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>. <p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported. In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_pivot_computed_measure%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> <a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_pivot_computed_measure%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <div class="section" id="credits">
@ -457,6 +458,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<li>Alexandre D. Díaz</li> <li>Alexandre D. Díaz</li>
<li>Pedro M. Baeza</li> <li>Pedro M. Baeza</li>
<li>Ernesto Tejeda</li> <li>Ernesto Tejeda</li>
<li>Carlos Roca</li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -468,7 +470,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose <p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use.</p> promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/web/tree/13.0/web_pivot_computed_measure">OCA/web</a> project on GitHub.</p> <p>This module is part of the <a class="reference external" href="https://github.com/OCA/web/tree/15.0/web_pivot_computed_measure">OCA/web</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> <p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div> </div>
</div> </div>

View File

@ -0,0 +1,51 @@
/** @odoo-module **/
/* Copyright 2022 Tecnativa - Carlos Roca
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */
const {Component, QWeb} = owl;
const {useState} = owl.hooks;
/**
* @extends Component
*/
export class DropdownItemCustomMeasure extends Component {
setup() {
this.isOpen = useState({value: false});
}
onClickComputedMeasure() {
this.isOpen.value = !this.isOpen.value;
}
addMeasure(ev) {
const $target = $(ev.target).closest("#add_computed_measure_wrapper");
const id = new Date().getTime();
const field1 = $target.find("#computed_measure_field_1").val();
const field2 = $target.find("#computed_measure_field_2").val();
let operation = $target.find("#computed_measure_operation").val();
if (operation === "custom") {
operation = $target.find("#computed_measure_operation_custom").val();
}
const name = $target.find("#computed_measure_name").val();
const format = $target.find("#computed_measure_format").val();
this.props.model.addComputedMeasure(
id,
field1,
field2,
operation,
name,
format
);
// Click on measures button to close the modal and recompute the measures added
$(ev.target).closest(".dropdown").find(".dropdown-toggle").trigger("click");
}
}
DropdownItemCustomMeasure.template =
"web_pivot_computed_measure.DropdownItemCustomMeasure";
DropdownItemCustomMeasure.props = {
measures: Object,
// Set as model because this module can be extended to be used on views that
// uses Measures like the graph view.
model: Object,
};
QWeb.registerComponent("DropdownItemCustomMeasure", DropdownItemCustomMeasure);

View File

@ -1,10 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<!-- <templates xml:space="preserve">
Copyright 2020 Tecnativa - Alexandre Díaz <t t-name="web_pivot_computed_measure.ComputedMeasureOperations" owl="1">
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<templates>
<t t-name="web_pivot_computed_measure.ComputedMeasureOperations">
<option name="sum" value="m1+m2"> <option name="sum" value="m1+m2">
Sum (m1 + m2) Sum (m1 + m2)
</option> </option>
@ -24,7 +20,8 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
Custom Custom
</option> </option>
</t> </t>
<t t-name="web_pivot_computed_measure.ComputedMeasureFormats">
<t t-name="web_pivot_computed_measure.ComputedMeasureFormats" owl="1">
<option name="int" value="integer"> <option name="int" value="integer">
Integer Integer
</option> </option>
@ -35,30 +32,19 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
Percentage Percentage
</option> </option>
</t> </t>
<t t-name="web_pivot_computed_measure.ExtendedMenu">
<div role="separator" class="dropdown-divider" /> <t t-name="web_pivot_computed_measure.DropdownItemCustomMeasure" owl="1">
<t t-foreach="computed_measures" t-as="cm"> <div class="o_menu_item dropdown-item" data-id="__computed__">
<a <a href="#" role="menuitem" t-on-click="onClickComputedMeasure">
role="menuitem"
href="#"
t-attf-class="dropdown-item {{cm[1].active and 'selected' or ''}}"
t-data-computed="1"
t-att-data-field="cm[0]"
>
<t t-esc="cm[1].string" />
</a>
</t>
<div class="o_menu_item" data-id="__computed__">
<a href="#" role="menuitem" class="dropdown-item">
Computed Measure Computed Measure
<span class="o_submenu_switcher" data-id="__computed__"> <span class="o_submenu_switcher" data-id="__computed__">
<span <span
t-att-class="isOpen ? 'fa fa-caret-down' : 'fa fa-caret-right'" t-att-class="isOpen.value ? 'fa fa-caret-down' : 'fa fa-caret-right'"
/> />
</span> </span>
</a> </a>
<t t-if="isOpen"> <t t-if="isOpen.value">
<div id="add_computed_measure_wrapper" class="d-table"> <div id="add_computed_measure_wrapper" class="d-table">
<div class="d-table-row"> <div class="d-table-row">
<div class="d-table-cell"> <div class="d-table-cell">
@ -66,9 +52,16 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</div> </div>
<div class="d-table-cell"> <div class="d-table-cell">
<select class="o_input" id="computed_measure_field_1"> <select class="o_input" id="computed_measure_field_1">
<t t-foreach="measures" t-as="measure"> <t
<option t-att-value="measure[0]"> t-foreach="props.measures"
<t t-esc="measure[1].string" /> t-as="measure"
t-key="measure"
>
<option
t-att-value="measure"
t-if="measure != '__count'"
>
<t t-esc="props.measures[measure].string" />
</option> </option>
</t> </t>
</select> </select>
@ -80,9 +73,16 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</div> </div>
<div class="d-table-cell"> <div class="d-table-cell">
<select class="o_input" id="computed_measure_field_2"> <select class="o_input" id="computed_measure_field_2">
<t t-foreach="measures" t-as="measure"> <t
<option t-att-value="measure[0]"> t-foreach="props.measures"
<t t-esc="measure[1].string" /> t-as="measure"
t-key="measure"
>
<option
t-att-value="measure"
t-if="measure != '__count'"
>
<t t-esc="props.measures[measure].string" />
</option> </option>
</t> </t>
</select> </select>
@ -148,6 +148,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<button <button
class="btn btn-primary o_add_computed_measure" class="btn btn-primary o_add_computed_measure"
type="button" type="button"
t-on-click="addMeasure"
>Add</button> >Add</button>
</div> </div>
</div> </div>
@ -155,4 +156,5 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</t> </t>
</div> </div>
</t> </t>
</templates> </templates>

View File

@ -1,198 +0,0 @@
/* Copyright 2020 Tecnativa - Alexandre Díaz
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */
odoo.define("web_pivot_computed_measure.PivotController", function (require) {
"use strict";
const core = require("web.core");
const config = require("web.config");
const PivotController = require("web.PivotController");
const QWeb = core.qweb;
PivotController.include({
custom_events: _.extend({}, PivotController.prototype.custom_events, {
add_measure: "_onAddMeasure",
remove_measure: "_onRemoveMeasure",
}),
computed_measures_open: false,
/**
* Add the computed measures to the context. This
* will be used when save a filter.
*
* @override
*/
getOwnedQueryParams: function () {
const res = this._super.apply(this, arguments);
const state = this.model.get({raw: true});
res.context.pivot_computed_measures = state.computed_measures;
return res;
},
/**
* @override
*/
renderButtons: function ($node) {
this._super.apply(this, arguments);
if ($node) {
this._renderComputedMeasures();
}
},
/**
* Handle click event on measures menu to support computed measures sub-menu
*
* @override
*/
_onButtonClick: function (event) {
const $target = $(event.target);
if ($target.parents("div[data-id='__computed__']").length) {
let hideMenu = false;
event.preventDefault();
if (
$target.hasClass("dropdown-item") ||
$target.hasClass("o_submenu_switcher")
) {
this.computed_measures_open = !this.computed_measures_open;
this._renderComputedMeasures();
} else if ($target.hasClass("o_add_computed_measure")) {
hideMenu = true;
const field1 = this.$buttons_measures_ex
.find("#computed_measure_field_1")
.val();
const field2 = this.$buttons_measures_ex
.find("#computed_measure_field_2")
.val();
let oper = this.$buttons_measures_ex
.find("#computed_measure_operation")
.val();
if (oper === "custom") {
oper = this.$buttons_measures_ex
.find("#computed_measure_operation_custom")
.val();
}
const name = this.$buttons_measures_ex
.find("#computed_measure_name")
.val();
const format = this.$buttons_measures_ex
.find("#computed_measure_format")
.val();
const uniqueId = new Date().getTime();
this.model
.createComputedMeasure(
uniqueId,
field1,
field2,
oper,
name,
format
)
.then(this.update.bind(this, {}, {reload: false}));
}
if (!hideMenu) {
event.stopPropagation();
}
return;
}
this._super.apply(this, arguments);
},
/**
* Render computed measures menu
*
* @private
*/
_renderComputedMeasures: function () {
if (this.$buttons_measures_ex && this.$buttons_measures_ex.length) {
this.$buttons_measures_ex.remove();
}
const measures = _.sortBy(
_.pairs(_.omit(this.measures, "__count")),
(x) => {
return x[1].string.toLowerCase();
}
);
this.$buttons_measures_ex = $(
QWeb.render("web_pivot_computed_measure.ExtendedMenu", {
isOpen: this.computed_measures_open,
debug: config.isDebug(),
measures: measures,
computed_measures: _.map(
_.reject(measures, (item) => {
return !item[1].__computed_id;
}),
(item) => {
item[1].active = _.contains(
this.model.data.measures,
item[0]
);
return item;
}
),
})
);
this.$buttons_measures_ex
.find("#computed_measure_operation")
.on("change", this._onChangeComputedMeasureOperation.bind(this));
if (this.$buttons)
this.$buttons
.find(".o_pivot_measures_list")
.append(this.$buttons_measures_ex);
},
/**
* Custom event to add a new measure
*
* @private
* @param {CustomEvent} ev
*/
_onAddMeasure: function (ev) {
this.measures[ev.data.id] = ev.data.def;
this._renderComputedMeasures();
},
/**
* Custom event to remove a measure
*
* @private
* @param {CustomEvent} ev
*/
_onRemoveMeasure: function (ev) {
delete this.measures[ev.data.id];
this._renderComputedMeasures();
},
/**
* Set default values related with the selected operation
*
* @private
* @param {ChangeEvent} ev
*/
_onChangeComputedMeasureOperation: function (ev) {
const $option = $(ev.target.options[ev.target.selectedIndex]);
if ($(ev.target).val() === "custom") {
this.$buttons_measures_ex
.find("#container_computed_measure_operation_custom")
.removeClass("d-none")
.addClass("d-table-row");
} else {
const format = $option.data("format");
if (format) {
this.$buttons_measures_ex
.find("#computed_measure_format")
.val(format);
}
this.$buttons_measures_ex
.find("#container_computed_measure_operation_custom")
.removeClass("d-table-row")
.addClass("d-none");
}
},
});
});

View File

@ -1,294 +0,0 @@
/* Copyright 2020 Tecnativa - Alexandre Díaz
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */
odoo.define("web_pivot_computed_measure.PivotModel", function (require) {
"use strict";
const core = require("web.core");
const PivotModel = require("web.PivotModel");
const _t = core._t;
PivotModel.include({
_computed_measures: [],
/**
* Create a new computed measure
*
* @param {String} id
* @param {String} field1
* @param {String} field2
* @param {String} operation
* @param {String} name
* @param {String} format
* @returns a promise
*/
createComputedMeasure: function (id, field1, field2, operation, name, format) {
const measure = _.find(this._computed_measures, (item) => {
return (
item.field1 === field1 &&
item.field2 === field2 &&
item.operation === operation
);
});
if (measure) {
return Promise.resolve();
}
const fieldM1 = this.fields[field1];
const fieldM2 = this.fields[field2];
const cmId = "__computed_" + id;
const oper = operation.replace(/m1/g, field1).replace(/m2/g, field2);
const oper_human = operation
.replace(
/m1/g,
fieldM1.__computed_id ? "(" + fieldM1.string + ")" : fieldM1.string
)
.replace(
/m2/g,
fieldM2.__computed_id ? "(" + fieldM2.string + ")" : fieldM2.string
);
const cmTotal = this._computed_measures.push({
field1: field1,
field2: field2,
operation: oper,
name: name || oper_human,
id: cmId,
format: format,
});
return this._createVirtualMeasure(this._computed_measures[cmTotal - 1]);
},
/**
* Create and enable a measure based on a 'fake' field
*
* @private
* @param {Object} cmDef
* @param {List} fields *Optional*
* @returns a promise
*/
_createVirtualMeasure: function (cmDef, fields) {
const arrFields = fields || this.fields;
// This is a minimal 'fake' field info
arrFields[cmDef.id] = {
// Used to format the value
type: cmDef.format,
// Used to print the header name
string: cmDef.name,
// Used to know if is a computed measure field
__computed_id: cmDef.id,
};
this.trigger_up("add_measure", {
id: cmDef.id,
def: arrFields[cmDef.id],
});
return this._activeMeasures([cmDef.field1, cmDef.field2, cmDef.id]);
},
/*
* @private
* @param {List of Strings} fields
*/
_activeMeasures: function (fields) {
let needLoad = false;
for (const field of fields) {
if (!this._isMeasureEnabled(field)) {
this.data.measures.push(field);
needLoad = true;
}
}
if (needLoad) {
return this._loadData();
}
return Promise.resolve();
},
/*
* @private
* @param {String} field
*/
_isMeasureEnabled: function (field) {
return _.contains(this.data.measures, field);
},
/**
* Helper function to add computed measure fields data into a 'subGroupData'
*
* @private
* @param {Object} subGroupData
*/
_fillComputedMeasuresData: function (subGroupData) {
for (const cm of this._computed_measures) {
if (!this._isMeasureEnabled(cm.id)) return;
if (subGroupData.__count === 0) {
subGroupData[cm.id] = false;
} else {
// eslint-disable-next-line no-undef
subGroupData[cm.id] = py.eval(cm.operation, subGroupData);
}
}
},
/**
* Fill the groupSubdivisions with the computed measures and their values
*
* @override
*/
_prepareData: function (group, groupSubdivisions) {
for (const groupSubdivision of groupSubdivisions) {
for (const subGroup of groupSubdivision.subGroups) {
this._fillComputedMeasuresData(subGroup);
}
}
this._super.apply(this, arguments);
},
/**
* _getGroupSubdivision method invokes the read_group method of the
* model via rpc and the passed 'fields' argument is the list of
* measure names that is in this.data.measures, so we remove the
* computed measures form this.data.measures before calling _super
* to prevent an exception
*
* @override
*/
_getGroupSubdivision: function () {
const computed_measures = [];
for (let i = 0; i < this.data.measures.length; i++)
if (this.data.measures[i].startsWith("__computed_")) {
computed_measures.push(this.data.measures[i]);
this.data.measures.splice(i, 1);
i--;
}
const res = this._super.apply(this, arguments);
$.merge(this.data.measures, computed_measures);
return res;
},
/**
* Load the computed measures in context. This is used by filters.
*
* @override
*/
load: function (params) {
this._computed_measures =
params.context.pivot_computed_measures ||
params.computed_measures ||
[];
const toActive = [];
for (const cmDef of this._computed_measures) {
params.fields[cmDef.id] = {
type: cmDef.format,
string: cmDef.name,
__computed_id: cmDef.id,
};
toActive.push(cmDef.field1, cmDef.field2, cmDef.id);
}
return this._super(params).then(() => {
_.defer(() => {
for (const cmDef of this._computed_measures) {
this.trigger_up("add_measure", {
id: cmDef.id,
def: this.fields[cmDef.id],
});
}
});
this._activeMeasures(toActive);
});
},
/**
* Load the computed measures in context. This is used by filters.
*
* @override
*/
reload: function (handle, params) {
if ("context" in params) {
this._computed_measures =
params.context.pivot_computed_measures ||
params.computed_measures ||
[];
}
for (const cmDef of this._computed_measures) {
this._createVirtualMeasure(cmDef);
}
const fieldNames = Object.keys(this.fields);
for (const fieldName of fieldNames) {
const field = this.fields[fieldName];
if (field.__computed_id) {
const cm = _.find(this._computed_measures, {
id: field.__computed_id,
});
if (!cm) {
delete this.fields[fieldName];
this.data.measures = _.without(this.data.measures, fieldName);
this.trigger_up("remove_measure", {
id: fieldName,
});
}
}
}
return this._super.apply(this, arguments);
},
/**
* Add the computed measures to the state. This is used by filters.
*
* @override
*/
get: function () {
const res = this._super.apply(this, arguments);
res.computed_measures = this._computed_measures;
return res;
},
/**
* Adds a rule to deny that measures can be disabled if are being used by a computed measure.
* In the other hand, when enables a measure analyzes it to active all involved measures.
*
* @override
*/
toggleMeasure: function (field) {
if (this._isMeasureEnabled(field)) {
// Measure is disabled
const umeasures = _.filter(this._computed_measures, (item) => {
return item.field1 === field || item.field2 === field;
});
if (umeasures.length && this._isMeasureEnabled(umeasures[0].id)) {
return Promise.reject(
_t(
"This measure is currently used by a 'computed measure'. Please, disable the computed measure first."
)
);
}
} else {
// Mesaure is enabled
const toEnable = [];
const toAnalize = [field];
while (toAnalize.length) {
const afield = toAnalize.shift();
const fieldDef = this.fields[afield];
if (fieldDef.__computed_id) {
const cm = _.find(this._computed_measures, {
id: fieldDef.__computed_id,
});
toAnalize.push(cm.field1, cm.field2);
const toEnableFields = [];
if (!this.fields[cm.field1].__computed_id) {
toEnableFields.push(cm.field1);
}
if (!this.fields[cm.field2].__computed_id) {
toEnableFields.push(cm.field2);
}
toEnableFields.push(afield);
toEnable.push(toEnableFields);
}
}
if (toEnable.length) {
return this._activeMeasures(_.flatten(toEnable.reverse()));
}
}
return this._super.apply(this, arguments);
},
});
});

View File

@ -0,0 +1,238 @@
/** @odoo-module **/
/* Copyright 2020 Tecnativa - Alexandre Díaz
* Copyright 2022 Tecnativa - Carlos Roca
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */
import {PivotModel} from "@web/views/pivot/pivot_model";
import {patch} from "web.utils";
patch(PivotModel.prototype, "web_pivot_computed_measure.PivotModel", {
/**
* Add _computed_measures to avoid recompute them until page is recharged
*
* @override
*/
setup() {
this._super(...arguments);
this._computed_measures = [];
},
/**
* Create a new computed measure
*
* @param {String} id
* @param {String} field1
* @param {String} field2
* @param {String} operation
* @param {String} name
* @param {String} format
* @returns a promise
*/
addComputedMeasure(id, field1, field2, operation, name, format) {
const measure = _.find(this._computed_measures, (item) => {
return (
item.field1 === field1 &&
item.field2 === field2 &&
item.operation === operation
);
});
if (measure) {
return Promise.resolve();
}
const fieldM1 = this.metaData.fields[field1];
const fieldM2 = this.metaData.fields[field2];
const cmId = "__computed_" + id;
const oper = operation.replace(/m1/g, field1).replace(/m2/g, field2);
const oper_human = operation
.replace(
/m1/g,
fieldM1.__computed_id ? "(" + fieldM1.string + ")" : fieldM1.string
)
.replace(
/m2/g,
fieldM2.__computed_id ? "(" + fieldM2.string + ")" : fieldM2.string
);
const cmTotal = this._computed_measures.push({
field1: field1,
field2: field2,
operation: oper,
name: name || oper_human,
id: cmId,
format: format,
});
return this._createVirtualMeasure(this._computed_measures[cmTotal - 1]);
},
/**
* Create and enable a measure based on a 'fake' field
*
* @private
* @param {Object} cmDef
* @param {List} fields *Optional*
* @returns a promise
*/
_createVirtualMeasure(cmDef, fields) {
const arrFields = fields || this.metaData.fields;
// This is a minimal 'fake' field info
arrFields[cmDef.id] = {
// Used to format the value
type: cmDef.format,
// Used to print the header name
string: cmDef.name,
// Referenced on payload prop at DropdownItem, used to interact with
// created measures
name: cmDef.id,
// Used to know if is a computed measure field
__computed_id: cmDef.id,
// Operator used for group the measure added.
group_operator: "sum",
};
this.metaData.measures[cmDef.id] = arrFields[cmDef.id];
// Activate computed field
return this.toggleMeasure(cmDef.id);
},
/**
* Active the measures related to the 'fake' field
*
* @private
* @param {List of Strings} fields
*/
async _activeMeasures(fields) {
let needLoad = false;
for (const field of fields) {
if (await !this._isMeasureEnabled(field)) {
this.metaData.activeMeasures.push(field);
needLoad = true;
}
}
if (needLoad) {
const config = {metaData: this.metaData, data: this.data};
return this._loadData(config).then(() => {
// Notify changes to renderer for show it on the pivot view
this.notify();
});
}
return Promise.resolve();
},
/**
* Check if the measure is enabled
*
* @private
* @param {String} field
*/
_isMeasureEnabled(field) {
return _.contains(this.metaData.activeMeasures, field);
},
/**
* Helper function to add computed measure fields data into a 'subGroupData'
*
* @private
* @param {Object} subGroupData
*/
_fillComputedMeasuresData(subGroupData) {
for (const cm of this._computed_measures) {
if (!this._isMeasureEnabled(cm.id)) return;
if (subGroupData.__count === 0) {
subGroupData[cm.id] = false;
} else {
// eslint-disable-next-line no-undef
subGroupData[cm.id] = py.eval(cm.operation, subGroupData);
}
}
},
/**
* Fill the groupSubdivisions with the computed measures and their values
*
* @override
*/
_prepareData(group, groupSubdivisions) {
for (const groupSubdivision of groupSubdivisions) {
for (const subGroup of groupSubdivision.subGroups) {
this._fillComputedMeasuresData(subGroup);
}
}
this._super(...arguments);
},
/**
* _getGroupSubdivision method invokes the read_group method of the
* model via rpc and the passed 'fields' argument is the list of
* measure names that is in this.metaData.activeMeasures, so we remove the
* computed measures form this.metaData.activeMeasures before calling _super
* to prevent any possible exception.
*
* @override
*/
_getGroupSubdivision(group, rowGroupBy, colGroupBy, config) {
const computed_measures = [];
for (let i = 0; i < config.metaData.activeMeasures.length; i++)
if (config.metaData.activeMeasures[i].startsWith("__computed_")) {
computed_measures.push(config.metaData.activeMeasures[i]);
config.metaData.activeMeasures.splice(i, 1);
i--;
}
const res = this._super(...arguments);
$.merge(config.metaData.activeMeasures, computed_measures);
return res;
},
/**
* Adds a rule to deny that measures can be disabled if are being used by a computed measure.
* In the other hand, when enables a measure analyzes it to active all involved measures.
*
* @override
*/
toggleMeasure(fieldName) {
if (this._isMeasureEnabled(fieldName)) {
// Mesaure is enabled
const umeasures = _.filter(this._computed_measures, (item) => {
return item.field1 === fieldName || item.field2 === fieldName;
});
if (umeasures.length && this._isMeasureEnabled(umeasures[0].id)) {
return Promise.reject(
this.env._t(
"This measure is currently used by a 'computed measure'. Please, disable the computed measure first."
)
);
}
} else {
// Measure is disabled
const toEnable = [];
const toAnalyze = [fieldName];
while (toAnalyze.length) {
// Analyze all items involved on computed measures to enable them
const afield = toAnalyze.shift();
const fieldDef = this.metaData.fields[afield];
// Need to check if fieldDef exists to avoid problems with __count
if (fieldDef && fieldDef.__computed_id) {
const cm = _.find(this._computed_measures, {
id: fieldDef.__computed_id,
});
toAnalyze.push(cm.field1, cm.field2);
const toEnableFields = [];
if (!this.metaData.fields[cm.field1].__computed_id) {
toEnableFields.push(cm.field1);
}
if (!this.metaData.fields[cm.field2].__computed_id) {
toEnableFields.push(cm.field2);
}
toEnableFields.push(afield);
toEnable.push(toEnableFields);
}
}
if (toEnable.length) {
this._activeMeasures(
// Transform the array of arrays to a simple array.
// [1, [2, 3]] => [1, 2, 3]
_.flatten(toEnable.reverse())
);
}
}
return this._super(...arguments);
},
});

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<t t-inherit="web.PivotView.Buttons" t-inherit-mode="extension" owl="1">
<xpath expr="//t[@t-call='web.ReportViewMeasures']" position="inside">
<t t-set="add_computed_measures" t-value="true" />
<t t-set="model" t-value="model" />
</xpath>
</t>
</templates>

View File

@ -0,0 +1,65 @@
/** @odoo-module **/
/* Copyright 2022 Tecnativa - Carlos Roca
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */
import tour from "web_tour.tour";
tour.register(
"web_pivot_computed_measure_tour",
{
url: "/web",
test: true,
},
[
tour.stepUtils.showAppsMenuItem(),
{
trigger: 'a[data-menu-xmlid="base.menu_administration"]',
},
{
trigger: 'button[data-menu-xmlid="base.menu_users"]',
},
{
trigger: 'a[data-menu-xmlid="base.menu_action_res_users"]',
},
{
trigger: "button.o_pivot",
},
{
trigger: 'button:contains(" Measures ")',
},
{
trigger: 'a:contains(" Computed Measure ")',
},
{
trigger: "select#computed_measure_field_1",
run: "text user_year_now",
},
{
trigger: "select#computed_measure_field_2",
run: "text user_year_born",
},
{
trigger: "select#computed_measure_operation",
run: "text m1-m2",
},
{
trigger: "select#computed_measure_format",
run: "text integer",
},
{
trigger: "button.o_add_computed_measure",
},
{
trigger: 'th.o_pivot_measure_row:contains("User Year Now")',
extra_trigger: 'div.o_value:contains("2,022")',
},
{
trigger: 'th.o_pivot_measure_row:contains("User Year Born")',
extra_trigger: 'div.o_value:contains("1,998")',
},
{
trigger: 'th.o_pivot_measure_row:contains("User Year Now-User Year Born")',
extra_trigger: 'div.o_value:contains("24")',
},
]
);

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<t t-inherit="web.ReportViewMeasures" t-inherit-mode="extension" owl="1">
<xpath expr="//DropdownItem" position="attributes">
<attribute name="t-if">!measure.startsWith('__computed_')</attribute>
</xpath>
<xpath expr="//t[@t-foreach='measures']" position="after">
<div role="separator" class="dropdown-divider" t-if="add_computed_measures" />
<t t-foreach="measures" t-as="measure" t-key="measure_value.name">
<DropdownItem
t-if="add_computed_measures and measure.startsWith('__computed_')"
class="o_menu_item dropdown-item"
t-att-class="{ selected: activeMeasures.includes(measure) }"
payload="{ measure: measure_value.name }"
parentClosingMode="'none'"
>
<t t-esc="measures[measure].string" />
</DropdownItem>
</t>
<DropdownItemCustomMeasure
measures="measures"
model="model"
t-if="add_computed_measures"
/>
</xpath>
</t>
</templates>

View File

@ -0,0 +1 @@
from . import test_ui_pivot

View File

@ -0,0 +1,12 @@
# Copyright 2022 Tecnativa - Carlos Roca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from odoo import fields, models
class ResUsersFake(models.Model):
_inherit = "res.users"
user_year_born = fields.Integer()
user_year_now = fields.Integer()

View File

@ -0,0 +1,37 @@
# Copyright 2022 Tecnativa - Carlos Roca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from odoo_test_helper import FakeModelLoader
from odoo.tests import common, tagged
@tagged("post_install", "-at_install")
class TestUIPivot(common.HttpCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.loader = FakeModelLoader(cls.env, cls.__module__)
cls.loader.backup_registry()
from .res_users_fake import ResUsersFake
cls.loader.update_registry((ResUsersFake,))
cls.env["res.users"].create(
{
"name": "User 1",
"login": "us_1",
# Fake fields
"user_year_born": 1998,
"user_year_now": 2022,
}
)
# Set pivot view to company action
action = cls.env.ref("base.action_res_users")
action.view_mode += ",pivot"
def test_ui(self):
self.start_tour(
"/web",
"web_pivot_computed_measure_tour",
login="admin",
step_delay=100,
)

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<template id="assets_backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script
type="text/javascript"
src="/web_pivot_computed_measure/static/src/js/pivot_model.js"
/>
<script
type="text/javascript"
src="/web_pivot_computed_measure/static/src/js/pivot_controller.js"
/>
<link
rel="stylesheet"
href="/web_pivot_computed_measure/static/src/scss/web_pivot_computed_measure.scss"
/>
</xpath>
</template>
</odoo>