Browse Source
Merge pull request #871 from simahawk/11-mig-web_widget_x2many_2d_matrix
Merge pull request #871 from simahawk/11-mig-web_widget_x2many_2d_matrix
[11][MIG] web_widget_x2many_2d_matrixpull/911/merge
Alexandre Fayolle
7 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 1368 additions and 0 deletions
-
1setup/web_widget_x2many_2d_matrix/odoo/addons/web_widget_x2many_2d_matrix
-
2setup/web_widget_x2many_2d_matrix/setup.cfg
-
6setup/web_widget_x2many_2d_matrix/setup.py
-
172web_widget_x2many_2d_matrix/README.rst
-
19web_widget_x2many_2d_matrix/__init__.py
-
23web_widget_x2many_2d_matrix/__manifest__.py
-
27web_widget_x2many_2d_matrix/i18n/ar.po
-
27web_widget_x2many_2d_matrix/i18n/de.po
-
26web_widget_x2many_2d_matrix/i18n/es.po
-
27web_widget_x2many_2d_matrix/i18n/fi.po
-
26web_widget_x2many_2d_matrix/i18n/fr.po
-
27web_widget_x2many_2d_matrix/i18n/hr.po
-
26web_widget_x2many_2d_matrix/i18n/it.po
-
27web_widget_x2many_2d_matrix/i18n/lt.po
-
27web_widget_x2many_2d_matrix/i18n/nl_NL.po
-
26web_widget_x2many_2d_matrix/i18n/pt_BR.po
-
26web_widget_x2many_2d_matrix/i18n/sl.po
-
27web_widget_x2many_2d_matrix/i18n/tr.po
-
BINweb_widget_x2many_2d_matrix/static/description/icon.png
-
BINweb_widget_x2many_2d_matrix/static/description/screenshot.png
-
3web_widget_x2many_2d_matrix/static/src/css/web_widget_x2many_2d_matrix.css
-
416web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js
-
172web_widget_x2many_2d_matrix/static/src/js/widget_x2many_2d_matrix.js
-
12web_widget_x2many_2d_matrix/views/assets.xml
-
41web_widget_x2many_2d_matrix_example/README.rst
-
2web_widget_x2many_2d_matrix_example/__init__.py
-
20web_widget_x2many_2d_matrix_example/__manifest__.py
-
20web_widget_x2many_2d_matrix_example/demo/x2m.demo.csv
-
1web_widget_x2many_2d_matrix_example/models/__init__.py
-
31web_widget_x2many_2d_matrix_example/models/x2m_demo.py
-
5web_widget_x2many_2d_matrix_example/security/ir.model.access.csv
-
54web_widget_x2many_2d_matrix_example/views/x2m_demo.xml
-
1web_widget_x2many_2d_matrix_example/wizard/__init__.py
-
27web_widget_x2many_2d_matrix_example/wizard/demo_wizard.py
-
21web_widget_x2many_2d_matrix_example/wizard/x2m_matrix.xml
@ -0,0 +1 @@ |
|||||
|
../../../../web_widget_x2many_2d_matrix |
@ -0,0 +1,2 @@ |
|||||
|
[bdist_wheel] |
||||
|
universal=1 |
@ -0,0 +1,6 @@ |
|||||
|
import setuptools |
||||
|
|
||||
|
setuptools.setup( |
||||
|
setup_requires=['setuptools-odoo'], |
||||
|
odoo_addon=True, |
||||
|
) |
@ -0,0 +1,172 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
=========================== |
||||
|
2D matrix for x2many fields |
||||
|
=========================== |
||||
|
|
||||
|
This module allows to show an x2many field with 3-tuples |
||||
|
($x_value, $y_value, $value) in a table |
||||
|
|
||||
|
+-----------+-------------+-------------+ |
||||
|
| | $x_value1 | $x_value2 | |
||||
|
+===========+=============+=============+ |
||||
|
| $y_value1 | $value(1/1) | $value(2/1) | |
||||
|
+-----------+-------------+-------------+ |
||||
|
| $y_value2 | $value(1/2) | $value(2/2) | |
||||
|
+-----------+-------------+-------------+ |
||||
|
|
||||
|
where `value(n/n)` is editable. |
||||
|
|
||||
|
An example use case would be: Select some projects and some employees so that |
||||
|
a manager can easily fill in the planned_hours for one task per employee. The |
||||
|
result could look like this: |
||||
|
|
||||
|
.. image:: /web_widget_x2many_2d_matrix/static/description/screenshot.png |
||||
|
:alt: Screenshot |
||||
|
|
||||
|
The beauty of this is that you have an arbitrary amount of columns with this |
||||
|
widget, trying to get this in standard x2many lists involves some quite ugly |
||||
|
hacks. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
Use this widget by saying:: |
||||
|
|
||||
|
<field name="my_field" widget="x2many_2d_matrix" /> |
||||
|
|
||||
|
This assumes that my_field refers to a model with the fields `x`, `y` and |
||||
|
`value`. If your fields are named differently, pass the correct names as |
||||
|
attributes:: |
||||
|
|
||||
|
<field name="my_field" widget="x2many_2d_matrix" field_x_axis="my_field1" field_y_axis="my_field2" field_value="my_field3"> |
||||
|
<tree> |
||||
|
<field name="my_field"/> |
||||
|
<field name="my_field1"/> |
||||
|
<field name="my_field2"/> |
||||
|
<field name="my_field3"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
|
||||
|
You can pass the following parameters: |
||||
|
|
||||
|
field_x_axis |
||||
|
The field that indicates the x value of a point |
||||
|
field_y_axis |
||||
|
The field that indicates the y value of a point |
||||
|
field_label_x_axis |
||||
|
Use another field to display in the table header |
||||
|
field_label_y_axis |
||||
|
Use another field to display in the table header |
||||
|
field_value |
||||
|
Show this field as value |
||||
|
show_row_totals |
||||
|
If field_value is a numeric field, it indicates if you want to calculate |
||||
|
row totals. True by default |
||||
|
show_column_totals |
||||
|
If field_value is a numeric field, it indicates if you want to calculate |
||||
|
column totals. True by default |
||||
|
|
||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
||||
|
:alt: Try me on Runbot |
||||
|
:target: https://runbot.odoo-community.org/runbot/162/11.0 |
||||
|
|
||||
|
Example |
||||
|
======= |
||||
|
|
||||
|
You need a data structure already filled with values. Let's assume we want to |
||||
|
use this widget in a wizard that lets the user fill in planned hours for one |
||||
|
task per project per user. In this case, we can use ``project.task`` as our |
||||
|
data model and point to it from our wizard. The crucial part is that we fill |
||||
|
the field in the default function:: |
||||
|
|
||||
|
from odoo import fields, models |
||||
|
|
||||
|
class MyWizard(models.TransientModel): |
||||
|
_name = 'my.wizard' |
||||
|
|
||||
|
def _default_task_ids(self): |
||||
|
# your list of project should come from the context, some selection |
||||
|
# in a previous wizard or wherever else |
||||
|
projects = self.env['project.project'].browse([1, 2, 3]) |
||||
|
# same with users |
||||
|
users = self.env['res.users'].browse([1, 2, 3]) |
||||
|
return [ |
||||
|
(0, 0, { |
||||
|
'name': 'Sample task name', |
||||
|
'project_id': p.id, |
||||
|
'user_id': u.id, |
||||
|
'planned_hours': 0, |
||||
|
'message_needaction': False, |
||||
|
'date_deadline': fields.Date.today(), |
||||
|
}) |
||||
|
# if the project doesn't have a task for the user, create a new one |
||||
|
if not p.task_ids.filtered(lambda x: x.user_id == u) else |
||||
|
# otherwise, return the task |
||||
|
(4, p.task_ids.filtered(lambda x: x.user_id == u)[0].id) |
||||
|
for p in projects |
||||
|
for u in users |
||||
|
] |
||||
|
|
||||
|
task_ids = fields.Many2many('project.task', default=_default_task_ids) |
||||
|
|
||||
|
Now in our wizard, we can use:: |
||||
|
|
||||
|
<field name="task_ids" widget="x2many_2d_matrix" field_x_axis="project_id" field_y_axis="user_id" field_value="planned_hours"> |
||||
|
<tree> |
||||
|
<field name="task_ids"/> |
||||
|
<field name="project_id"/> |
||||
|
<field name="user_id"/> |
||||
|
<field name="planned_hours"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
|
||||
|
|
||||
|
Known issues / Roadmap |
||||
|
====================== |
||||
|
|
||||
|
* Support extra attributes on each field cell via `field_extra_attrs` param. |
||||
|
We could set a cell as not editable, required or readonly for instance. |
||||
|
The `readonly` case will also give the ability |
||||
|
to click on m2o to open related records. |
||||
|
|
||||
|
* Support limit total records in the matrix. Ref: https://github.com/OCA/web/issues/901 |
||||
|
|
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
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. If you spotted it first, |
||||
|
help us smash it by providing a detailed and welcomed feedback. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Holger Brunn <hbrunn@therp.nl> |
||||
|
* Pedro M. Baeza <pedro.baeza@tecnativa.com> |
||||
|
* Artem Kostyuk <a.kostyuk@mobilunity.com> |
||||
|
* Simone Orsi <simone.orsi@camptocamp.com> |
||||
|
* Timon Tschanz <timon.tschanz@camptocamp.com> |
||||
|
|
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
To contribute to this module, please visit https://odoo-community.org. |
@ -0,0 +1,19 @@ |
|||||
|
############################################################################## |
||||
|
# |
||||
|
# OpenERP, Open Source Management Solution |
||||
|
# This module copyright (C) 2015 Therp BV <http://therp.nl>. |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
@ -0,0 +1,23 @@ |
|||||
|
# Copyright 2015 Holger Brunn <hbrunn@therp.nl> |
||||
|
# Copyright 2016 Pedro M. Baeza <pedro.baeza@tecnativa.com> |
||||
|
# Copyright 2018 Simone Orsi <simone.orsi@camptocamp.com> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
{ |
||||
|
"name": "2D matrix for x2many fields", |
||||
|
"version": "11.0.1.0.0", |
||||
|
"author": "Therp BV, " |
||||
|
"Tecnativa, " |
||||
|
"Camptocamp, " |
||||
|
"Odoo Community Association (OCA)", |
||||
|
"website": "https://github.com/OCA/web", |
||||
|
"license": "AGPL-3", |
||||
|
"category": "Hidden/Dependency", |
||||
|
"summary": "Show list fields as a matrix", |
||||
|
"depends": [ |
||||
|
'web', |
||||
|
], |
||||
|
"data": [ |
||||
|
'views/assets.xml', |
||||
|
], |
||||
|
"installable": True, |
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
# SaFi J. <safi2266@gmail.com>, 2015 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: web (8.0)\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2015-12-16 07:41+0000\n" |
||||
|
"PO-Revision-Date: 2015-12-16 17:24+0000\n" |
||||
|
"Last-Translator: SaFi J. <safi2266@gmail.com>\n" |
||||
|
"Language-Team: Arabic (http://www.transifex.com/oca/OCA-web-8-0/language/ar/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: ar\n" |
||||
|
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "المجموع الاجمالي" |
@ -0,0 +1,27 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
# Rudolf Schnapka <rs@techno-flex.de>, 2016 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: web (8.0)\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2016-01-10 07:31+0000\n" |
||||
|
"PO-Revision-Date: 2016-01-18 20:15+0000\n" |
||||
|
"Last-Translator: Rudolf Schnapka <rs@techno-flex.de>\n" |
||||
|
"Language-Team: German (http://www.transifex.com/oca/OCA-web-8-0/language/de/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: de\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Gesamt" |
@ -0,0 +1,26 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: web (8.0)\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2015-11-23 13:46+0000\n" |
||||
|
"PO-Revision-Date: 2015-11-07 11:29+0000\n" |
||||
|
"Last-Translator: Pedro M. Baeza <pedro.baeza@gmail.com>\n" |
||||
|
"Language-Team: Spanish (http://www.transifex.com/oca/OCA-web-8-0/language/es/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: es\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Total" |
@ -0,0 +1,27 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
# Jarmo Kortetjärvi <jarmo.kortetjarvi@gmail.com>, 2016 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: web (8.0)\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2016-01-10 07:31+0000\n" |
||||
|
"PO-Revision-Date: 2016-02-01 09:54+0000\n" |
||||
|
"Last-Translator: Jarmo Kortetjärvi <jarmo.kortetjarvi@gmail.com>\n" |
||||
|
"Language-Team: Finnish (http://www.transifex.com/oca/OCA-web-8-0/language/fi/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: fi\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Yhteensä" |
@ -0,0 +1,26 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: web (8.0)\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2016-05-06 15:50+0000\n" |
||||
|
"PO-Revision-Date: 2015-11-07 11:22+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: French (http://www.transifex.com/oca/OCA-web-8-0/language/fr/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: fr\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Total" |
@ -0,0 +1,27 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
# Ana-Maria Olujić <ana-maria.olujic@slobodni-programi.hr>, 2016 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: web (8.0)\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2016-08-25 00:51+0000\n" |
||||
|
"PO-Revision-Date: 2016-08-19 11:47+0000\n" |
||||
|
"Last-Translator: Ana-Maria Olujić <ana-maria.olujic@slobodni-programi.hr>\n" |
||||
|
"Language-Team: Croatian (http://www.transifex.com/oca/OCA-web-8-0/language/hr/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: hr\n" |
||||
|
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Ukupno" |
@ -0,0 +1,26 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: web (8.0)\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2016-03-17 07:30+0000\n" |
||||
|
"PO-Revision-Date: 2015-11-07 11:22+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: Italian (http://www.transifex.com/oca/OCA-web-8-0/language/it/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: it\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Totale" |
@ -0,0 +1,27 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
# Viktoras Norkus <viktoras@bmx.lt>, 2018 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 11.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2018-01-25 01:58+0000\n" |
||||
|
"PO-Revision-Date: 2018-02-15 12:40+0200\n" |
||||
|
"Last-Translator: Viktoras Norkus <viktoras@bmx.lt>, 2018\n" |
||||
|
"Language-Team: Lithuanian (https://www.transifex.com/oca/teams/23907/lt/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: lt\n" |
||||
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Suma" |
@ -0,0 +1,27 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
# Peter Hageman <hageman.p@gmail.com>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 11.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2018-01-03 03:50+0000\n" |
||||
|
"PO-Revision-Date: 2018-02-15 12:39+0200\n" |
||||
|
"Last-Translator: Peter Hageman <hageman.p@gmail.com>, 2017\n" |
||||
|
"Language-Team: Dutch (Netherlands) (https://www.transifex.com/oca/teams/23907/nl_NL/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: nl_NL\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Totaal" |
@ -0,0 +1,26 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: web (8.0)\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2016-03-11 02:18+0000\n" |
||||
|
"PO-Revision-Date: 2016-03-05 16:20+0000\n" |
||||
|
"Last-Translator: danimaribeiro <danimaribeiro@gmail.com>\n" |
||||
|
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/oca/OCA-web-8-0/language/pt_BR/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: pt_BR\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Total" |
@ -0,0 +1,26 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: web (8.0)\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2015-11-23 13:46+0000\n" |
||||
|
"PO-Revision-Date: 2015-11-08 05:48+0000\n" |
||||
|
"Last-Translator: Matjaž Mozetič <m.mozetic@matmoz.si>\n" |
||||
|
"Language-Team: Slovenian (http://www.transifex.com/oca/OCA-web-8-0/language/sl/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: sl\n" |
||||
|
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Skupaj" |
@ -0,0 +1,27 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * web_widget_x2many_2d_matrix |
||||
|
# |
||||
|
# Translators: |
||||
|
# Ahmet Altınışık <aaltinisik@altinkaya.com.tr>, 2015 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: web (8.0)\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2016-01-08 21:34+0000\n" |
||||
|
"PO-Revision-Date: 2015-12-30 22:00+0000\n" |
||||
|
"Last-Translator: Ahmet Altınışık <aaltinisik@altinkaya.com.tr>\n" |
||||
|
"Language-Team: Turkish (http://www.transifex.com/oca/OCA-web-8-0/language/tr/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: tr\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n" |
||||
|
|
||||
|
#. module: web_widget_x2many_2d_matrix |
||||
|
#. openerp-web |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:11 |
||||
|
#: code:addons/web_widget_x2many_2d_matrix/static/src/xml/web_widget_x2many_2d_matrix.xml:28 |
||||
|
#, python-format |
||||
|
msgid "Total" |
||||
|
msgstr "Toplam" |
After Width: 90 | Height: 90 | Size: 2.4 KiB |
After Width: 1240 | Height: 471 | Size: 22 KiB |
@ -0,0 +1,3 @@ |
|||||
|
.o_field_x2many_2d_matrix .row-total { |
||||
|
font-weight: bold; |
||||
|
} |
@ -0,0 +1,416 @@ |
|||||
|
/* Copyright 2018 Simone Orsi <simone.orsi@camptocamp.com> |
||||
|
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
|
||||
|
|
||||
|
odoo.define('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer', function (require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
// heavily inspired by Odoo's `ListRenderer`
|
||||
|
var BasicRenderer = require('web.BasicRenderer'); |
||||
|
var config = require('web.config'); |
||||
|
var field_utils = require('web.field_utils'); |
||||
|
var utils = require('web.utils'); |
||||
|
var FIELD_CLASSES = { |
||||
|
// copied from ListRenderer
|
||||
|
float: 'o_list_number', |
||||
|
integer: 'o_list_number', |
||||
|
monetary: 'o_list_number', |
||||
|
text: 'o_list_text', |
||||
|
}; |
||||
|
|
||||
|
var X2Many2dMatrixRenderer = BasicRenderer.extend({ |
||||
|
|
||||
|
init: function (parent, state, params) { |
||||
|
this._super.apply(this, arguments); |
||||
|
this.editable = params.editable; |
||||
|
this.columns = params.matrix_data.columns; |
||||
|
this.rows = params.matrix_data.rows; |
||||
|
this.matrix_data = params.matrix_data; |
||||
|
}, |
||||
|
/** |
||||
|
* Main render function for the matrix widget. It is rendered as a table. For now, |
||||
|
* this method does not wait for the field widgets to be ready. |
||||
|
* |
||||
|
* @override |
||||
|
* @private |
||||
|
* returns {Deferred} this deferred is resolved immediately |
||||
|
*/ |
||||
|
_renderView: function () { |
||||
|
var self = this; |
||||
|
|
||||
|
this.$el |
||||
|
.removeClass('table-responsive') |
||||
|
.empty(); |
||||
|
|
||||
|
var $table = $('<table>').addClass('o_list_view table table-condensed table-striped'); |
||||
|
this.$el |
||||
|
.addClass('table-responsive') |
||||
|
.append($table); |
||||
|
|
||||
|
this._computeColumnAggregates(); |
||||
|
this._computeRowAggregates(); |
||||
|
|
||||
|
$table |
||||
|
.append(this._renderHeader()) |
||||
|
.append(this._renderBody()); |
||||
|
if (self.matrix_data.show_column_totals) { |
||||
|
$table.append(this._renderFooter()); |
||||
|
} |
||||
|
return this._super(); |
||||
|
}, |
||||
|
/** |
||||
|
* Render the table body. Looks for the table body and renders the rows in it. |
||||
|
* Also it sets the tabindex on every input element. |
||||
|
* |
||||
|
* @private |
||||
|
* return {jQueryElement} The table body element that was just filled. |
||||
|
*/ |
||||
|
_renderBody: function () { |
||||
|
var $body = $('<tbody>').append(this._renderRows()); |
||||
|
_.each($body.find('input'), function (td, i) { |
||||
|
$(td).attr('tabindex', i); |
||||
|
}); |
||||
|
return $body; |
||||
|
}, |
||||
|
/** |
||||
|
* Render the table head of our matrix. Looks for the first table head |
||||
|
* and inserts the header into it. |
||||
|
* |
||||
|
* @private |
||||
|
* @return {jQueryElement} The thead element that was inserted into. |
||||
|
*/ |
||||
|
_renderHeader: function () { |
||||
|
var $tr = $('<tr>').append('<th/>'); |
||||
|
$tr= $tr.append(_.map(this.columns, this._renderHeaderCell.bind(this))); |
||||
|
if (this.matrix_data.show_row_totals) { |
||||
|
$tr.append($('<th/>', {class: 'total'})); |
||||
|
} |
||||
|
return $('<thead>').append($tr); |
||||
|
}, |
||||
|
/** |
||||
|
* Render a single header cell. Creates a th and adds the description as text. |
||||
|
* |
||||
|
* @private |
||||
|
* @param {jQueryElement} node |
||||
|
* @returns {jQueryElement} the created <th> node. |
||||
|
*/ |
||||
|
_renderHeaderCell: function (node) { |
||||
|
var name = node.attrs.name; |
||||
|
var field = this.state.fields[name]; |
||||
|
var $th = $('<th>'); |
||||
|
if (!field) { |
||||
|
return $th; |
||||
|
} |
||||
|
var description; |
||||
|
if (node.attrs.widget) { |
||||
|
description = this.state.fieldsInfo.list[name].Widget.prototype.description; |
||||
|
} |
||||
|
if (description === undefined) { |
||||
|
description = node.attrs.string || field.string; |
||||
|
} |
||||
|
$th.text(description).data('name', name); |
||||
|
|
||||
|
if (field.type === 'float' || field.type === 'integer' || field.type === 'monetary') { |
||||
|
$th.addClass('text-right'); |
||||
|
} |
||||
|
|
||||
|
if (config.debug) { |
||||
|
var fieldDescr = { |
||||
|
field: field, |
||||
|
name: name, |
||||
|
string: description || name, |
||||
|
record: this.state, |
||||
|
attrs: node.attrs, |
||||
|
}; |
||||
|
this._addFieldTooltip(fieldDescr, $th); |
||||
|
} |
||||
|
return $th; |
||||
|
}, |
||||
|
/** |
||||
|
* Proxy call to function rendering single row. |
||||
|
* |
||||
|
* @private |
||||
|
* @returns {String} a string with the generated html. |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
_renderRows: function () { |
||||
|
return _.map(this.rows, this._renderRow.bind(this)); |
||||
|
}, |
||||
|
/** |
||||
|
* Render a single row with all its columns. Renders all the cells and then wraps them with a <tr>. |
||||
|
* If aggregate is set on the row it also will generate the aggregate cell. |
||||
|
* |
||||
|
* @private |
||||
|
* @param {Object} row: The row that will be rendered. |
||||
|
* @returns {jQueryElement} the <tr> element that has been rendered. |
||||
|
*/ |
||||
|
_renderRow: function (row) { |
||||
|
var self = this; |
||||
|
var $tr = $('<tr/>', {class: 'o_data_row'}); |
||||
|
$tr = $tr.append(self._renderLabelCell(row.data[0])); |
||||
|
var $cells = _.map(this.columns, function (node, index) { |
||||
|
var record = row.data[index]; |
||||
|
// make the widget use our field value for each cell
|
||||
|
node.attrs.name = self.matrix_data.field_value; |
||||
|
return self._renderBodyCell(record, node, index, {mode:''}); |
||||
|
}); |
||||
|
$tr = $tr.append($cells); |
||||
|
if (row.aggregate) { |
||||
|
$tr.append(self._renderAggregateRowCell(row)); |
||||
|
} |
||||
|
return $tr; |
||||
|
}, |
||||
|
/** |
||||
|
* Renders the label for a specific row. |
||||
|
* |
||||
|
* @private |
||||
|
* @params {Object} record: Contains the information about the record. |
||||
|
* @params {jQueryElement} the cell that was rendered. |
||||
|
*/ |
||||
|
_renderLabelCell: function(record) { |
||||
|
var $td = $('<td>'); |
||||
|
var value = record.data[this.matrix_data.field_y_axis]; |
||||
|
if (value.type == 'record') { |
||||
|
// we have a related record
|
||||
|
value = value.data.display_name; |
||||
|
} |
||||
|
// get 1st column filled w/ Y label
|
||||
|
$td.text(value); |
||||
|
return $td; |
||||
|
}, |
||||
|
/** |
||||
|
* Create a cell and fill it with the aggregate value. |
||||
|
* |
||||
|
* @private |
||||
|
* @param {Object} row: the row object to aggregate. |
||||
|
* @returns {jQueryElement} The rendered cell. |
||||
|
*/ |
||||
|
_renderAggregateRowCell: function (row) { |
||||
|
var $cell = $('<td/>', {class: 'row-total text-right'}); |
||||
|
this._apply_aggregate_value($cell, row.aggregate); |
||||
|
return $cell; |
||||
|
}, |
||||
|
/** |
||||
|
* Render a single body Cell. |
||||
|
* Gets the field and renders the widget. We force the edit mode, since |
||||
|
* we always want the widget to be editable. |
||||
|
* |
||||
|
* @private |
||||
|
* @param {Object} record: Contains the data for this cell |
||||
|
* @param {jQueryElement} node: The HTML of the field. |
||||
|
* @param {int} colIndex: The index of the current column. |
||||
|
* @param {Object} options: The obtions used for the widget |
||||
|
* @returns {jQueryElement} the rendered cell. |
||||
|
*/ |
||||
|
_renderBodyCell: function (record, node, colIndex, options) { |
||||
|
var tdClassName = 'o_data_cell'; |
||||
|
if (node.tag === 'button') { |
||||
|
tdClassName += ' o_list_button'; |
||||
|
} else if (node.tag === 'field') { |
||||
|
var typeClass = FIELD_CLASSES[this.state.fields[node.attrs.name].type]; |
||||
|
if (typeClass) { |
||||
|
tdClassName += (' ' + typeClass); |
||||
|
} |
||||
|
if (node.attrs.widget) { |
||||
|
tdClassName += (' o_' + node.attrs.widget + '_cell'); |
||||
|
} |
||||
|
} |
||||
|
// TODO roadmap: here we should collect possible extra params
|
||||
|
// the user might want to attach to each single cell.
|
||||
|
var $td = $('<td>', { |
||||
|
'class': tdClassName, |
||||
|
'data-form-id': record.id, |
||||
|
'data-id': record.data.id, |
||||
|
}); |
||||
|
// We register modifiers on the <td> element so that it gets the correct
|
||||
|
// modifiers classes (for styling)
|
||||
|
var modifiers = this._registerModifiers(node, record, $td, _.pick(options, 'mode')); |
||||
|
// If the invisible modifiers is true, the <td> element is left empty.
|
||||
|
// Indeed, if the modifiers was to change the whole cell would be
|
||||
|
// rerendered anyway.
|
||||
|
if (modifiers.invisible && !(options && options.renderInvisible)) { |
||||
|
return $td; |
||||
|
} |
||||
|
options.mode = 'edit'; // enforce edit mode
|
||||
|
var widget = this._renderFieldWidget(node, record, _.pick(options, 'mode')); |
||||
|
this._handleAttributes(widget.$el, node); |
||||
|
return $td.append(widget.$el); |
||||
|
}, |
||||
|
/** |
||||
|
* Wraps the column aggregate with a tfoot element |
||||
|
* |
||||
|
* @private |
||||
|
* @returns {jQueryElement} The footer element with the cells in it. |
||||
|
*/ |
||||
|
_renderFooter: function () { |
||||
|
var $cells = this._renderAggregateColCells(); |
||||
|
if ($cells) { |
||||
|
return $('<tfoot>').append($('<tr>').append('<td/>').append($cells)); |
||||
|
} |
||||
|
return; |
||||
|
}, |
||||
|
/** |
||||
|
* Render the Aggregate cells for the column. |
||||
|
* |
||||
|
* @private |
||||
|
* @returns {List} the rendered cells |
||||
|
*/ |
||||
|
_renderAggregateColCells: function () { |
||||
|
var self = this; |
||||
|
return _.map(this.columns, function (column, index) { |
||||
|
var $cell = $('<td>', {class: 'col-total text-right'}); |
||||
|
if (column.aggregate) { |
||||
|
self._apply_aggregate_value($cell, column.aggregate); |
||||
|
} |
||||
|
return $cell; |
||||
|
}); |
||||
|
}, |
||||
|
/** |
||||
|
* Compute the column aggregates. |
||||
|
* This function is called everytime the value is changed. |
||||
|
* |
||||
|
* @private |
||||
|
*/ |
||||
|
_computeColumnAggregates: function () { |
||||
|
if (!this.matrix_data.show_column_totals) { |
||||
|
return; |
||||
|
} |
||||
|
var self = this, |
||||
|
fname = this.matrix_data.field_value, |
||||
|
field = this.state.fields[fname]; |
||||
|
if (!field) { return; } |
||||
|
var type = field.type; |
||||
|
if (type !== 'integer' && type !== 'float' && type !== 'monetary') { |
||||
|
return; |
||||
|
} |
||||
|
_.each(self.columns, function (column, index) { |
||||
|
column.aggregate = { |
||||
|
fname: fname, |
||||
|
ftype: type, |
||||
|
// TODO: translate
|
||||
|
help: 'Sum', |
||||
|
value: 0 |
||||
|
}; |
||||
|
_.each(self.rows, function (row) { |
||||
|
// var record = _.findWhere(self.state.data, {id: col.data.id});
|
||||
|
column.aggregate.value += row.data[index].data[fname]; |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
/** |
||||
|
* Compute the row aggregates. |
||||
|
* This function is called everytime the value is changed. |
||||
|
* |
||||
|
* @private |
||||
|
*/ |
||||
|
_computeRowAggregates: function () { |
||||
|
if (!this.matrix_data.show_row_totals) { |
||||
|
return; |
||||
|
} |
||||
|
var self = this, |
||||
|
fname = this.matrix_data.field_value, |
||||
|
field = this.state.fields[fname]; |
||||
|
if (!field) { return; } |
||||
|
var type = field.type; |
||||
|
if (type !== 'integer' && type !== 'float' && type !== 'monetary') { |
||||
|
return; |
||||
|
} |
||||
|
_.each(self.rows, function (row) { |
||||
|
row.aggregate = { |
||||
|
fname: fname, |
||||
|
ftype: type, |
||||
|
// TODO: translate
|
||||
|
help: 'Sum', |
||||
|
value: 0 |
||||
|
}; |
||||
|
_.each(row.data, function (col) { |
||||
|
row.aggregate.value += col.data[fname]; |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
/** |
||||
|
* Takes the given Value, formats it and adds it to the given cell. |
||||
|
* |
||||
|
* @private |
||||
|
* @param {jQueryElement} $cell: The Cell where the aggregate should be added. |
||||
|
* @param {Object} aggregate: The object which contains the information about the aggregate value |
||||
|
*/ |
||||
|
_apply_aggregate_value: function ($cell, aggregate) { |
||||
|
var field = this.state.fields[aggregate.fname], |
||||
|
formatter = field_utils.format[field.type]; |
||||
|
var formattedValue = formatter(aggregate.value, field, {escape: true, }); |
||||
|
$cell.addClass('total').attr('title', aggregate.help).html(formattedValue); |
||||
|
}, |
||||
|
/** |
||||
|
* Check if the change was successful and then update the grid. |
||||
|
* This function is required on relational fields. |
||||
|
* |
||||
|
* @params {Object} state: Contains the current state of the field & all the data |
||||
|
* @params {String} id: the id of the updated object. |
||||
|
* @params {Array} fields: The fields we have in the view. |
||||
|
* @params {Object} ev: The event object. |
||||
|
* @returns {Deferred} The deferred object thats gonna be resolved when the change is made. |
||||
|
*/ |
||||
|
confirmUpdate: function (state, id, fields, ev) { |
||||
|
var self = this; |
||||
|
this.state = state; |
||||
|
return this.confirmChange(state, id, fields, ev).then(function () { |
||||
|
self._refresh(id); |
||||
|
}); |
||||
|
}, |
||||
|
/** |
||||
|
* Refresh our grid. |
||||
|
* |
||||
|
* @private |
||||
|
*/ |
||||
|
_refresh: function (id) { |
||||
|
this._updateRow(id); |
||||
|
this._refreshColTotals(); |
||||
|
this._refreshRowTotals(); |
||||
|
}, |
||||
|
/** |
||||
|
*Update row data in our internal rows. |
||||
|
* |
||||
|
* @params {String} id: The id of the row that needs to be updated. |
||||
|
*/ |
||||
|
_updateRow: function (id) { |
||||
|
var self = this, |
||||
|
record = _.findWhere(self.state.data, {id: id}); |
||||
|
_.each(self.rows, function(row) { |
||||
|
_.each(row.data, function(col, i) { |
||||
|
if (col.id == id) { |
||||
|
row.data[i] = record; |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
/** |
||||
|
* Update the row total. |
||||
|
*/ |
||||
|
_refreshColTotals: function () { |
||||
|
this._computeColumnAggregates(); |
||||
|
this.$('tfoot').replaceWith(this._renderFooter()); |
||||
|
}, |
||||
|
/** |
||||
|
* Update the column total. |
||||
|
*/ |
||||
|
_refreshRowTotals: function () { |
||||
|
var self = this; |
||||
|
this._computeRowAggregates(); |
||||
|
var $rows = self.$el.find('tr.o_data_row'); |
||||
|
_.each(self.rows, function(row, i) { |
||||
|
if (row.aggregate) { |
||||
|
$($rows[i]).find('.row-total') |
||||
|
.replaceWith(self._renderAggregateRowCell(row)); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
/* |
||||
|
x2m fields expect this |
||||
|
*/ |
||||
|
getEditableRecordID: function (){ return false;} |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
return X2Many2dMatrixRenderer; |
||||
|
}); |
@ -0,0 +1,172 @@ |
|||||
|
/* Copyright 2015 Holger Brunn <hbrunn@therp.nl> |
||||
|
* Copyright 2016 Pedro M. Baeza <pedro.baeza@tecnativa.com> |
||||
|
* Copyright 2018 Simone Orsi <simone.orsi@camptocamp.com> |
||||
|
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
|
||||
|
|
||||
|
odoo.define('web_widget_x2many_2d_matrix.widget', function (require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
var core = require('web.core'); |
||||
|
// var FieldManagerMixin = require('web.FieldManagerMixin');
|
||||
|
var field_registry = require('web.field_registry'); |
||||
|
var relational_fields = require('web.relational_fields'); |
||||
|
var weContext = require('web_editor.context'); |
||||
|
// var Helpers = require('web_widget_x2many_2d_matrix.helpers');
|
||||
|
var AbstractField = require('web.AbstractField'); |
||||
|
var X2Many2dMatrixRenderer = require('web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer'); |
||||
|
|
||||
|
var WidgetX2Many2dMatrix = relational_fields.FieldOne2Many.extend({ |
||||
|
widget_class: 'o_form_field_x2many_2d_matrix', |
||||
|
/** |
||||
|
* Initialize the widget & parameters. |
||||
|
* |
||||
|
* @param {Object} parent: contains the form view. |
||||
|
* @param {String} name: the name of the field. |
||||
|
* @param {Object} record: Contains the information about the database records. |
||||
|
* @param {Object} options: Contains the view options. |
||||
|
*/ |
||||
|
init: function (parent, name, record, options) { |
||||
|
this._super(parent, name, record, options); |
||||
|
this.init_params(); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* Initialize the widget specific parameters. |
||||
|
* Sets the axis and the values. |
||||
|
*/ |
||||
|
init_params: function () { |
||||
|
var node = this.attrs; |
||||
|
this.by_x_axis = {}; |
||||
|
this.by_y_axis = {}; |
||||
|
this.field_x_axis = node.field_x_axis || this.field_x_axis; |
||||
|
this.field_y_axis = node.field_y_axis || this.field_y_axis; |
||||
|
this.field_label_x_axis = node.field_label_x_axis || this.field_x_axis; |
||||
|
this.field_label_y_axis = node.field_label_y_axis || this.field_y_axis; |
||||
|
this.x_axis_clickable = this.parse_boolean(node.x_axis_clickable || '1'); |
||||
|
this.y_axis_clickable = this.parse_boolean(node.y_axis_clickable || '1'); |
||||
|
this.field_value = node.field_value || this.field_value; |
||||
|
// TODO: is this really needed? Holger?
|
||||
|
for (var property in node) { |
||||
|
if (property.startsWith("field_att_")) { |
||||
|
this.fields_att[property.substring(10)] = node[property]; |
||||
|
} |
||||
|
} |
||||
|
// and this?
|
||||
|
this.field_editability = node.field_editability || this.field_editability; |
||||
|
this.show_row_totals = this.parse_boolean(node.show_row_totals || '1'); |
||||
|
this.show_column_totals = this.parse_boolean(node.show_column_totals || '1'); |
||||
|
this.init_matrix(); |
||||
|
}, |
||||
|
/** |
||||
|
* Initializes the Value matrix. |
||||
|
* Puts the values in the grid. If we have related items we use the display name. |
||||
|
*/ |
||||
|
init_matrix: function(){ |
||||
|
var self = this, |
||||
|
records = self.recordData[this.name].data; |
||||
|
_.each(records, function(record) { |
||||
|
var x = record.data[self.field_x_axis], |
||||
|
y = record.data[self.field_y_axis]; |
||||
|
if (x.type == 'record') { |
||||
|
// we have a related record
|
||||
|
x = x.data.display_name; |
||||
|
} |
||||
|
if (y.type == 'record') { |
||||
|
// we have a related record
|
||||
|
y = y.data.display_name; |
||||
|
} |
||||
|
self.by_x_axis[x] = self.by_x_axis[x] || {}; |
||||
|
self.by_y_axis[y] = self.by_y_axis[y] || {}; |
||||
|
self.by_x_axis[x][y] = record; |
||||
|
self.by_y_axis[y][x] = record; |
||||
|
}); |
||||
|
// init columns
|
||||
|
self.columns = []; |
||||
|
$.each(self.by_x_axis, function(x){ |
||||
|
self.columns.push(self._make_column(x)); |
||||
|
}); |
||||
|
self.rows = []; |
||||
|
$.each(self.by_y_axis, function(y){ |
||||
|
self.rows.push(self._make_row(y)); |
||||
|
}); |
||||
|
self.matrix_data = { |
||||
|
'field_value': self.field_value, |
||||
|
'field_x_axis': self.field_x_axis, |
||||
|
'field_y_axis': self.field_y_axis, |
||||
|
'columns': self.columns, |
||||
|
'rows': self.rows, |
||||
|
'show_row_totals': self.show_row_totals, |
||||
|
'show_column_totals': self.show_column_totals |
||||
|
}; |
||||
|
|
||||
|
}, |
||||
|
/** |
||||
|
* Create scaffold for a column. |
||||
|
* |
||||
|
* @params {String} x: The string used as a column title |
||||
|
*/ |
||||
|
_make_column: function(x){ |
||||
|
return { |
||||
|
// simulate node parsed on xml arch
|
||||
|
'tag': 'field', |
||||
|
'attrs': { |
||||
|
'name': this.field_x_axis, |
||||
|
'string': x |
||||
|
} |
||||
|
}; |
||||
|
}, |
||||
|
/** |
||||
|
* Create scaffold for a row. |
||||
|
* |
||||
|
* @params {String} x: The string used as a row title |
||||
|
*/ |
||||
|
_make_row: function(y){ |
||||
|
var self = this; |
||||
|
// use object so that we can attach more data if needed
|
||||
|
var row = {'data': []}; |
||||
|
$.each(self.by_x_axis, function(x) { |
||||
|
row.data.push(self.by_y_axis[y][x]); |
||||
|
}); |
||||
|
return row; |
||||
|
}, |
||||
|
/** |
||||
|
*Parse a String containing a Python bool or 1 and convert it to a proper bool. |
||||
|
* |
||||
|
* @params {String} val: the string to be parsed. |
||||
|
* @returns {Boolean} The parsed boolean. |
||||
|
*/ |
||||
|
parse_boolean: function(val) { |
||||
|
if (val.toLowerCase() === 'true' || val === '1') { |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
}, |
||||
|
/** |
||||
|
*Create the matrix renderer and add its output to our element |
||||
|
* |
||||
|
* @returns {Deferred} A deferred object to be completed when it finished rendering. |
||||
|
*/ |
||||
|
_render: function () { |
||||
|
if (!this.view) { |
||||
|
return this._super(); |
||||
|
} |
||||
|
var arch = this.view.arch, |
||||
|
viewType = 'list'; |
||||
|
this.renderer = new X2Many2dMatrixRenderer(this, this.value, { |
||||
|
arch: arch, |
||||
|
editable: true, |
||||
|
viewType: viewType, |
||||
|
matrix_data: this.matrix_data |
||||
|
}); |
||||
|
this.$el.addClass('o_field_x2many o_field_x2many_2d_matrix'); |
||||
|
return this.renderer.appendTo(this.$el); |
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
field_registry.add('x2many_2d_matrix', WidgetX2Many2dMatrix); |
||||
|
|
||||
|
return { |
||||
|
WidgetX2Many2dMatrix: WidgetX2Many2dMatrix |
||||
|
}; |
||||
|
}); |
@ -0,0 +1,12 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<template id="assets_backend" name="web_widget_x2many_2d_matrix assets" inherit_id="web.assets_backend"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" src="/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js" /> |
||||
|
<script type="text/javascript" src="/web_widget_x2many_2d_matrix/static/src/js/widget_x2many_2d_matrix.js" /> |
||||
|
<link rel="stylesheet" href="/web_widget_x2many_2d_matrix/static/src/css/web_widget_x2many_2d_matrix.css"/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,41 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
=================================== |
||||
|
2D matrix for x2many fields example |
||||
|
=================================== |
||||
|
|
||||
|
Install it and click on the menu item `Demo x2m matrix widget`. |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
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. If you spotted it first, |
||||
|
help us smash it by providing a detailed and welcomed feedback. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Simone Orsi <simone.orsi@camptocamp.com> |
||||
|
|
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
To contribute to this module, please visit https://odoo-community.org. |
@ -0,0 +1,2 @@ |
|||||
|
from . import models |
||||
|
from . import wizard |
@ -0,0 +1,20 @@ |
|||||
|
{ |
||||
|
'name': 'web_widget_x2many_2d_matrix example', |
||||
|
'summary': "A small example on how to use `web_widget_x2many_2d_matrix`.", |
||||
|
"version": "11.0.1.0.0", |
||||
|
"author": "Camptocamp, " |
||||
|
"Odoo Community Association (OCA)", |
||||
|
"website": "https://github.com/OCA/web", |
||||
|
"license": "AGPL-3", |
||||
|
"category": "Hidden/Dependency", |
||||
|
"depends": [ |
||||
|
'web_widget_x2many_2d_matrix', |
||||
|
], |
||||
|
"data": [ |
||||
|
'security/ir.model.access.csv', |
||||
|
'demo/x2m.demo.csv', |
||||
|
'views/x2m_demo.xml', |
||||
|
'wizard/x2m_matrix.xml', |
||||
|
], |
||||
|
"installable": True, |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
id,name,line_ids/user_id/id,line_ids/name,line_ids/value |
||||
|
web_widget_x2many_2d_matrix_example.x2m_demo_5,One,,, |
||||
|
,,base.user_demo,A,1 |
||||
|
,,base.user_demo,B,2 |
||||
|
,,base.user_demo,C,3 |
||||
|
web_widget_x2many_2d_matrix_example.x2m_demo_3,Two,,, |
||||
|
,,base.user_demo,E,5 |
||||
|
,,base.user_demo,F,6 |
||||
|
web_widget_x2many_2d_matrix_example.x2m_demo_2,Three,,, |
||||
|
,,base.user_root,G,8 |
||||
|
,,base.user_demo,H,9 |
||||
|
,,base.user_root,I,10 |
||||
|
web_widget_x2many_2d_matrix_example.x2m_demo_1,Four,,, |
||||
|
,,base.user_root,L,12 |
||||
|
,,base.user_demo,M,13 |
||||
|
,,base.user_demo,N,14 |
||||
|
,,base.user_demo,O,15 |
||||
|
,,base.user_root,P,16 |
||||
|
web_widget_x2many_2d_matrix_example.x2m_demo_4,Five,,, |
||||
|
,,base.user_demo,Q,18 |
@ -0,0 +1 @@ |
|||||
|
from . import x2m_demo |
@ -0,0 +1,31 @@ |
|||||
|
from odoo import models, api, fields |
||||
|
|
||||
|
|
||||
|
class X2MDemo(models.Model): |
||||
|
_name = 'x2m.demo' |
||||
|
|
||||
|
name = fields.Char() |
||||
|
line_ids = fields.One2many('x2m.demo.line', 'demo_id') |
||||
|
|
||||
|
@api.multi |
||||
|
def open_x2m_matrix(self): |
||||
|
wiz = self.env['x2m.matrix.demo.wiz'].create({}) |
||||
|
return { |
||||
|
'name': 'Try x2many 2D matrix widget', |
||||
|
'type': 'ir.actions.act_window', |
||||
|
'view_type': 'form', |
||||
|
'view_mode': 'form', |
||||
|
'res_model': 'x2m.matrix.demo.wiz', |
||||
|
'target': 'new', |
||||
|
'res_id': wiz.id, |
||||
|
'context': self.env.context, |
||||
|
} |
||||
|
|
||||
|
|
||||
|
class X2MDemoLine(models.Model): |
||||
|
_name = 'x2m.demo.line' |
||||
|
|
||||
|
name = fields.Char() |
||||
|
demo_id = fields.Many2one('x2m.demo') |
||||
|
user_id = fields.Many2one('res.users') |
||||
|
value = fields.Integer() |
@ -0,0 +1,5 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_x2m_demo_line,access_x2m_demo_line,model_x2m_demo_line,base.group_user,1,0,0,0 |
||||
|
access_x2m_demo_line_admin,access_x2m_demo_line_admin,model_x2m_demo_line,base.group_system,1,1,1,1 |
||||
|
access_x2m_demo,access_x2m_demo,model_x2m_demo,base.group_user,1,0,0,0 |
||||
|
access_x2m_demo_admin,access_x2m_demo_admin,model_x2m_demo,base.group_system,1,1,1,1 |
@ -0,0 +1,54 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
|
||||
|
<record id="view_x2m_demo_form" model="ir.ui.view"> |
||||
|
<field name="name">x2m.demo.form</field> |
||||
|
<field name="model">x2m.demo</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form> |
||||
|
<sheet> |
||||
|
<group> |
||||
|
<field name="name" /> |
||||
|
<field name="line_ids"> |
||||
|
<tree> |
||||
|
<field name="name" /> |
||||
|
<field name="value" /> |
||||
|
<field name="user_id" /> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</group> |
||||
|
<footer> |
||||
|
<button name="open_x2m_matrix" type="object" |
||||
|
string="Try x2m 2d matrix" |
||||
|
class="oe_stat_button" icon="fa-edit" /> |
||||
|
</footer> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.ui.view" id="view_x2m_demo_tree"> |
||||
|
<field name="name">Demo - Tree</field> |
||||
|
<field name="model">x2m.demo</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree> |
||||
|
<field name="name" /> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="action_x2m_demo" model="ir.actions.act_window"> |
||||
|
<field name="name">Demo</field> |
||||
|
<field name="res_model">x2m.demo</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="view_id" ref="view_x2m_demo_tree"/> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem |
||||
|
id="base_matrix_widget_menu" |
||||
|
name="Demo x2m matrix widget" |
||||
|
action="action_x2m_demo" |
||||
|
/> |
||||
|
|
||||
|
</odoo> |
@ -0,0 +1 @@ |
|||||
|
from . import demo_wizard |
@ -0,0 +1,27 @@ |
|||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class DemoWizard(models.TransientModel): |
||||
|
_name = 'x2m.matrix.demo.wiz' |
||||
|
|
||||
|
line_ids = fields.Many2many( |
||||
|
'x2m.demo.line', default=lambda self: self._default_line_ids()) |
||||
|
|
||||
|
def _default_line_ids(self): |
||||
|
recs = self.env['x2m.demo'].search([]) |
||||
|
# same with users |
||||
|
users = self.env['x2m.demo.line'].search([]).mapped('user_id') |
||||
|
return [ |
||||
|
(0, 0, { |
||||
|
'name': "{}'s task on {}".format(usr.name, rec.name), |
||||
|
'demo_id': rec.id, |
||||
|
'user_id': usr.id, |
||||
|
'value': 0, |
||||
|
}) |
||||
|
# if the project doesn't have a task for the user, create a new one |
||||
|
if not rec.line_ids.filtered(lambda x: x.user_id == usr) else |
||||
|
# otherwise, return the task |
||||
|
(4, rec.line_ids.filtered(lambda x: x.user_id == usr)[0].id) |
||||
|
for rec in recs |
||||
|
for usr in users |
||||
|
] |
@ -0,0 +1,21 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
|
||||
|
<record id="x2many_2d_matrix_demo" model="ir.ui.view"> |
||||
|
<field name="name">x2m.matrix.demo.wiz</field> |
||||
|
<field name="model">x2m.matrix.demo.wiz</field> |
||||
|
<field name="type">form</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form> |
||||
|
<field name="line_ids" widget="x2many_2d_matrix" field_x_axis="demo_id" field_y_axis="user_id" field_value="value"> |
||||
|
<tree> |
||||
|
<field name="demo_id"/> |
||||
|
<field name="user_id"/> |
||||
|
<field name="value"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue