Browse Source

Merge pull request #871 from simahawk/11-mig-web_widget_x2many_2d_matrix

[11][MIG] web_widget_x2many_2d_matrix
pull/911/merge
Alexandre Fayolle 6 years ago
committed by GitHub
parent
commit
8bd835071e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      setup/web_widget_x2many_2d_matrix/odoo/addons/web_widget_x2many_2d_matrix
  2. 2
      setup/web_widget_x2many_2d_matrix/setup.cfg
  3. 6
      setup/web_widget_x2many_2d_matrix/setup.py
  4. 172
      web_widget_x2many_2d_matrix/README.rst
  5. 19
      web_widget_x2many_2d_matrix/__init__.py
  6. 23
      web_widget_x2many_2d_matrix/__manifest__.py
  7. 27
      web_widget_x2many_2d_matrix/i18n/ar.po
  8. 27
      web_widget_x2many_2d_matrix/i18n/de.po
  9. 26
      web_widget_x2many_2d_matrix/i18n/es.po
  10. 27
      web_widget_x2many_2d_matrix/i18n/fi.po
  11. 26
      web_widget_x2many_2d_matrix/i18n/fr.po
  12. 27
      web_widget_x2many_2d_matrix/i18n/hr.po
  13. 26
      web_widget_x2many_2d_matrix/i18n/it.po
  14. 27
      web_widget_x2many_2d_matrix/i18n/lt.po
  15. 27
      web_widget_x2many_2d_matrix/i18n/nl_NL.po
  16. 26
      web_widget_x2many_2d_matrix/i18n/pt_BR.po
  17. 26
      web_widget_x2many_2d_matrix/i18n/sl.po
  18. 27
      web_widget_x2many_2d_matrix/i18n/tr.po
  19. BIN
      web_widget_x2many_2d_matrix/static/description/icon.png
  20. BIN
      web_widget_x2many_2d_matrix/static/description/screenshot.png
  21. 3
      web_widget_x2many_2d_matrix/static/src/css/web_widget_x2many_2d_matrix.css
  22. 416
      web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js
  23. 172
      web_widget_x2many_2d_matrix/static/src/js/widget_x2many_2d_matrix.js
  24. 12
      web_widget_x2many_2d_matrix/views/assets.xml
  25. 41
      web_widget_x2many_2d_matrix_example/README.rst
  26. 2
      web_widget_x2many_2d_matrix_example/__init__.py
  27. 20
      web_widget_x2many_2d_matrix_example/__manifest__.py
  28. 20
      web_widget_x2many_2d_matrix_example/demo/x2m.demo.csv
  29. 1
      web_widget_x2many_2d_matrix_example/models/__init__.py
  30. 31
      web_widget_x2many_2d_matrix_example/models/x2m_demo.py
  31. 5
      web_widget_x2many_2d_matrix_example/security/ir.model.access.csv
  32. 54
      web_widget_x2many_2d_matrix_example/views/x2m_demo.xml
  33. 1
      web_widget_x2many_2d_matrix_example/wizard/__init__.py
  34. 27
      web_widget_x2many_2d_matrix_example/wizard/demo_wizard.py
  35. 21
      web_widget_x2many_2d_matrix_example/wizard/x2m_matrix.xml

1
setup/web_widget_x2many_2d_matrix/odoo/addons/web_widget_x2many_2d_matrix

@ -0,0 +1 @@
../../../../web_widget_x2many_2d_matrix

2
setup/web_widget_x2many_2d_matrix/setup.cfg

@ -0,0 +1,2 @@
[bdist_wheel]
universal=1

6
setup/web_widget_x2many_2d_matrix/setup.py

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)

172
web_widget_x2many_2d_matrix/README.rst

@ -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.

19
web_widget_x2many_2d_matrix/__init__.py

@ -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/>.
#
##############################################################################

23
web_widget_x2many_2d_matrix/__manifest__.py

@ -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,
}

27
web_widget_x2many_2d_matrix/i18n/ar.po

@ -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 "المجموع الاجمالي"

27
web_widget_x2many_2d_matrix/i18n/de.po

@ -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"

26
web_widget_x2many_2d_matrix/i18n/es.po

@ -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"

27
web_widget_x2many_2d_matrix/i18n/fi.po

@ -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ä"

26
web_widget_x2many_2d_matrix/i18n/fr.po

@ -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"

27
web_widget_x2many_2d_matrix/i18n/hr.po

@ -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"

26
web_widget_x2many_2d_matrix/i18n/it.po

@ -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"

27
web_widget_x2many_2d_matrix/i18n/lt.po

@ -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"

27
web_widget_x2many_2d_matrix/i18n/nl_NL.po

@ -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"

26
web_widget_x2many_2d_matrix/i18n/pt_BR.po

@ -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"

26
web_widget_x2many_2d_matrix/i18n/sl.po

@ -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"

27
web_widget_x2many_2d_matrix/i18n/tr.po

@ -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"

BIN
web_widget_x2many_2d_matrix/static/description/icon.png

After

Width: 90  |  Height: 90  |  Size: 2.4 KiB

BIN
web_widget_x2many_2d_matrix/static/description/screenshot.png

After

Width: 1240  |  Height: 471  |  Size: 22 KiB

3
web_widget_x2many_2d_matrix/static/src/css/web_widget_x2many_2d_matrix.css

@ -0,0 +1,3 @@
.o_field_x2many_2d_matrix .row-total {
font-weight: bold;
}

416
web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js

@ -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;
});

172
web_widget_x2many_2d_matrix/static/src/js/widget_x2many_2d_matrix.js

@ -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
};
});

12
web_widget_x2many_2d_matrix/views/assets.xml

@ -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>

41
web_widget_x2many_2d_matrix_example/README.rst

@ -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.

2
web_widget_x2many_2d_matrix_example/__init__.py

@ -0,0 +1,2 @@
from . import models
from . import wizard

20
web_widget_x2many_2d_matrix_example/__manifest__.py

@ -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,
}

20
web_widget_x2many_2d_matrix_example/demo/x2m.demo.csv

@ -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

1
web_widget_x2many_2d_matrix_example/models/__init__.py

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

31
web_widget_x2many_2d_matrix_example/models/x2m_demo.py

@ -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()

5
web_widget_x2many_2d_matrix_example/security/ir.model.access.csv

@ -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

54
web_widget_x2many_2d_matrix_example/views/x2m_demo.xml

@ -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>

1
web_widget_x2many_2d_matrix_example/wizard/__init__.py

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

27
web_widget_x2many_2d_matrix_example/wizard/demo_wizard.py

@ -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
]

21
web_widget_x2many_2d_matrix_example/wizard/x2m_matrix.xml

@ -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>
Loading…
Cancel
Save