Merge PR #1484 into 13.0

Signed-off-by simahawk
pull/1541/head
OCA-git-bot 2020-03-06 07:22:08 +00:00
commit a7b55d8aba
48 changed files with 3680 additions and 0 deletions

View File

@ -0,0 +1,237 @@
===========================
2D matrix for x2many fields
===========================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
:target: https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix
:alt: OCA/web
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_widget_x2many_2d_matrix
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/162/13.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
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:: https://raw.githubusercontent.com/OCA/web/12.0/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.
**Table of contents**
.. contents::
:local:
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:
.. code-block:: xml
<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
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:
.. code-block:: python
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:
.. code-block:: xml
<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
* Support cell traversal through keyboard arrows.
* Entering the widget from behind by pressing ``Shift+TAB`` in your keyboard
will enter into the 1st cell until https://github.com/odoo/odoo/pull/26490
is merged.
* Support extra invisible fields inside each cell.
* Support kanban mode. Current behaviour forces list mode.
Changelog
=========
12.0.1.0.1 (2018-12-07)
~~~~~~~~~~~~~~~~~~~~~~~
* [FIX] Cells are unable to render property.
(`#1126 <https://github.com/OCA/web/issues/1126>`_)
12.0.1.0.0 (2018-11-20)
~~~~~~~~~~~~~~~~~~~~~~~
* [12.0][MIG] web_widget_x2many_2d_matrix
(`#1101 <https://github.com/OCA/web/issues/1101>`_)
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 smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_widget_x2many_2d_matrix%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Therp BV
* Tecnativa
* Camptocamp
* Brainbean Apps
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>
* Jairo Llopis <jairo.llopis@tecnativa.com>
* Dennis Sluijk <d.sluijk@onestein.nl>
* Alexey Pelykh <alexey.pelykh@brainbeanapps.com>
* Adrià Gil Sorribes <adria.gil@forgeflow.com>
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
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.
This module is part of the `OCA/web <https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -0,0 +1 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

View File

@ -0,0 +1,22 @@
# 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": "13.0.1.0.0",
"author": (
"Therp BV, "
"Tecnativa, "
"Camptocamp, "
"Brainbean Apps, "
"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,
}

View File

@ -0,0 +1,43 @@
# 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"
"Language: ar\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \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/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, fuzzy, python-format
msgid "Sum Total"
msgstr "المجموع الاجمالي"

View File

@ -0,0 +1,42 @@
# 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"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \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/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, fuzzy, python-format
msgid "Sum Total"
msgstr "Gesamt"

View File

@ -0,0 +1,41 @@
# 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"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \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/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, fuzzy, python-format
msgid "Sum Total"
msgstr "Total"

View File

@ -0,0 +1,42 @@
# 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"
"Language: fi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \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/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, fuzzy, python-format
msgid "Sum Total"
msgstr "Yhteensä"

View File

@ -0,0 +1,42 @@
# 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: 2019-08-06 12:44+0000\n"
"Last-Translator: Nicolas JEUDY <njeudy@panda-chi.io>\n"
"Language-Team: French (http://www.transifex.com/oca/OCA-web-8-0/language/fr/)"
"\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 3.7.1\n"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr "Désolé il n'y a pas de donnée matrice à afficher."
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr "Somme"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, python-format
msgid "Sum Total"
msgstr "Total"

View File

@ -0,0 +1,44 @@
# 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: 2019-11-14 10:34+0000\n"
"Last-Translator: Bole <bole@dajmi5.com>\n"
"Language-Team: Croatian (http://www.transifex.com/oca/OCA-web-8-0/language/"
"hr/)\n"
"Language: hr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \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"
"X-Generator: Weblate 3.8\n"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr "Oprostite, nema matrice podataka za prikaz."
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr "Suma"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, python-format
msgid "Sum Total"
msgstr "Ukupno"

View File

@ -0,0 +1,42 @@
# 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: 2019-05-03 11:03+0000\n"
"Last-Translator: gslabit <giovanni@gslab.it>\n"
"Language-Team: Italian (http://www.transifex.com/oca/OCA-web-8-0/language/"
"it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 3.5.1\n"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr "Spiacenti, nessun dato da visualizzare."
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr "Somma"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, python-format
msgid "Sum Total"
msgstr "Totale"

View File

@ -0,0 +1,42 @@
# 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"
"Language: lt\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \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/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, fuzzy, python-format
msgid "Sum Total"
msgstr "Suma"

View File

@ -0,0 +1,42 @@
# 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"
"Language: nl_NL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \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/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, fuzzy, python-format
msgid "Sum Total"
msgstr "Totaal"

View File

@ -0,0 +1,42 @@
# 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: 2019-09-03 01:23+0000\n"
"Last-Translator: Rodrigo Macedo <rmsolucoeseminformatic4@gmail.com>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/oca/OCA-web-8-0/"
"language/pt_BR/)\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 3.8\n"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr "Desculpe não há dados de matriz para exibir."
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr "Soma"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, python-format
msgid "Sum Total"
msgstr "Soma Total"

View File

@ -0,0 +1,42 @@
# 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"
"Language: sl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \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/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, fuzzy, python-format
msgid "Sum Total"
msgstr "Skupaj"

View File

@ -0,0 +1,42 @@
# 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"
"Language: tr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \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/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, fuzzy, python-format
msgid "Sum Total"
msgstr "Toplam"

View File

@ -0,0 +1,37 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_widget_x2many_2d_matrix
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr ""
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, python-format
msgid "Sum Total"
msgstr ""

View File

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_widget_x2many_2d_matrix
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2019-09-01 17:23+0000\n"
"Last-Translator: 黎伟杰 <674416404@qq.com>\n"
"Language-Team: none\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 3.8\n"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:65
#, python-format
msgid "Sorry no matrix data to display."
msgstr "抱歉没有要显示的矩阵数据。"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:400
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:475
#, python-format
msgid "Sum"
msgstr "总和"
#. module: web_widget_x2many_2d_matrix
#. openerp-web
#: code:addons/web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js:394
#, python-format
msgid "Sum Total"
msgstr "总和"

View File

@ -0,0 +1,9 @@
* 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>
* Jairo Llopis <jairo.llopis@tecnativa.com>
* Dennis Sluijk <d.sluijk@onestein.nl>
* Alexey Pelykh <alexey.pelykh@brainbeanapps.com>
* Adrià Gil Sorribes <adria.gil@forgeflow.com>

View File

@ -0,0 +1,23 @@
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:: https://raw.githubusercontent.com/OCA/web/12.0/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.

View File

@ -0,0 +1,11 @@
12.0.1.0.1 (2018-12-07)
~~~~~~~~~~~~~~~~~~~~~~~
* [FIX] Cells are unable to render property.
(`#1126 <https://github.com/OCA/web/issues/1126>`_)
12.0.1.0.0 (2018-11-20)
~~~~~~~~~~~~~~~~~~~~~~~
* [12.0][MIG] web_widget_x2many_2d_matrix
(`#1101 <https://github.com/OCA/web/issues/1101>`_)

View File

@ -0,0 +1,16 @@
* 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
* Support cell traversal through keyboard arrows.
* Entering the widget from behind by pressing ``Shift+TAB`` in your keyboard
will enter into the 1st cell until https://github.com/odoo/odoo/pull/26490
is merged.
* Support extra invisible fields inside each cell.
* Support kanban mode. Current behaviour forces list mode.

View File

@ -0,0 +1,92 @@
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:
.. code-block:: xml
<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
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:
.. code-block:: python
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:
.. code-block:: xml
<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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,595 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<title>2D matrix for x2many fields</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="d-matrix-for-x2many-fields">
<h1 class="title">2D matrix for x2many fields</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_widget_x2many_2d_matrix"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/162/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module allows to show an x2many field with 3-tuples
($x_value, $y_value, $value) in a table</p>
<table border="1" class="docutils">
<colgroup>
<col width="30%" />
<col width="35%" />
<col width="35%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">&nbsp;</th>
<th class="head">$x_value1</th>
<th class="head">$x_value2</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>$y_value1</td>
<td>$value(1/1)</td>
<td>$value(2/1)</td>
</tr>
<tr><td>$y_value2</td>
<td>$value(1/2)</td>
<td>$value(2/2)</td>
</tr>
</tbody>
</table>
<p>where <cite>value(n/n)</cite> is editable.</p>
<p>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:</p>
<img alt="Screenshot" src="https://raw.githubusercontent.com/OCA/web/12.0/web_widget_x2many_2d_matrix/static/description/screenshot.png" />
<p>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.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="id5">Usage</a><ul>
<li><a class="reference internal" href="#example" id="id6">Example</a></li>
</ul>
</li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id7">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#changelog" id="id8">Changelog</a><ul>
<li><a class="reference internal" href="#id1" id="id9">12.0.1.0.1 (2018-12-07)</a></li>
<li><a class="reference internal" href="#id3" id="id10">12.0.1.0.0 (2018-11-20)</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="id11">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id12">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id13">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id14">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id15">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id5">Usage</a></h1>
<p>Use this widget by saying:</p>
<pre class="literal-block">
&lt;field name=&quot;my_field&quot; widget=&quot;x2many_2d_matrix&quot; /&gt;
</pre>
<p>This assumes that my_field refers to a model with the fields <cite>x</cite>, <cite>y</cite> and
<cite>value</cite>. If your fields are named differently, pass the correct names as
attributes:</p>
<pre class="code xml literal-block">
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;my_field&quot;</span> <span class="na">widget=</span><span class="s">&quot;x2many_2d_matrix&quot;</span> <span class="na">field_x_axis=</span><span class="s">&quot;my_field1&quot;</span> <span class="na">field_y_axis=</span><span class="s">&quot;my_field2&quot;</span> <span class="na">field_value=</span><span class="s">&quot;my_field3&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;tree&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;my_field&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;my_field1&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;my_field2&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;my_field3&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/tree&gt;</span>
<span class="nt">&lt;/field&gt;</span>
</pre>
<p>You can pass the following parameters:</p>
<dl class="docutils">
<dt>field_x_axis</dt>
<dd>The field that indicates the x value of a point</dd>
<dt>field_y_axis</dt>
<dd>The field that indicates the y value of a point</dd>
<dt>field_label_x_axis</dt>
<dd>Use another field to display in the table header</dd>
<dt>field_label_y_axis</dt>
<dd>Use another field to display in the table header</dd>
<dt>field_value</dt>
<dd>Show this field as value</dd>
<dt>show_row_totals</dt>
<dd>If field_value is a numeric field, it indicates if you want to calculate
row totals. True by default</dd>
<dt>show_column_totals</dt>
<dd>If field_value is a numeric field, it indicates if you want to calculate
column totals. True by default</dd>
</dl>
<div class="section" id="example">
<h2><a class="toc-backref" href="#id6">Example</a></h2>
<p>You need a data structure already filled with values. Lets 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 <tt class="docutils literal">project.task</tt> as our
data model and point to it from our wizard. The crucial part is that we fill
the field in the default function:</p>
<pre class="code python literal-block">
<span class="kn">from</span> <span class="nn">odoo</span> <span class="kn">import</span> <span class="n">fields</span><span class="p">,</span> <span class="n">models</span>
<span class="k">class</span> <span class="nc">MyWizard</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">TransientModel</span><span class="p">):</span>
<span class="n">_name</span> <span class="o">=</span> <span class="s1">'my.wizard'</span>
<span class="k">def</span> <span class="nf">_default_task_ids</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># your list of project should come from the context, some selection</span>
<span class="c1"># in a previous wizard or wherever else</span>
<span class="n">projects</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="p">[</span><span class="s1">'project.project'</span><span class="p">]</span><span class="o">.</span><span class="n">browse</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
<span class="c1"># same with users</span>
<span class="n">users</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="p">[</span><span class="s1">'res.users'</span><span class="p">]</span><span class="o">.</span><span class="n">browse</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
<span class="k">return</span> <span class="p">[</span>
<span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">{</span>
<span class="s1">'name'</span><span class="p">:</span> <span class="s1">'Sample task name'</span><span class="p">,</span>
<span class="s1">'project_id'</span><span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>
<span class="s1">'user_id'</span><span class="p">:</span> <span class="n">u</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>
<span class="s1">'planned_hours'</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s1">'message_needaction'</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
<span class="s1">'date_deadline'</span><span class="p">:</span> <span class="n">fields</span><span class="o">.</span><span class="n">Date</span><span class="o">.</span><span class="n">today</span><span class="p">(),</span>
<span class="p">})</span>
<span class="c1"># if the project doesn't have a task for the user,</span>
<span class="c1"># create a new one</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">p</span><span class="o">.</span><span class="n">task_ids</span><span class="o">.</span><span class="n">filtered</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">user_id</span> <span class="o">==</span> <span class="n">u</span><span class="p">)</span> <span class="k">else</span>
<span class="c1"># otherwise, return the task</span>
<span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">task_ids</span><span class="o">.</span><span class="n">filtered</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">user_id</span> <span class="o">==</span> <span class="n">u</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">projects</span>
<span class="k">for</span> <span class="n">u</span> <span class="ow">in</span> <span class="n">users</span>
<span class="p">]</span>
<span class="n">task_ids</span> <span class="o">=</span> <span class="n">fields</span><span class="o">.</span><span class="n">Many2many</span><span class="p">(</span><span class="s1">'project.task'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">_default_task_ids</span><span class="p">)</span>
</pre>
<p>Now in our wizard, we can use:</p>
<pre class="code xml literal-block">
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;task_ids&quot;</span> <span class="na">widget=</span><span class="s">&quot;x2many_2d_matrix&quot;</span> <span class="na">field_x_axis=</span><span class="s">&quot;project_id&quot;</span> <span class="na">field_y_axis=</span><span class="s">&quot;user_id&quot;</span> <span class="na">field_value=</span><span class="s">&quot;planned_hours&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;tree&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;task_ids&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;project_id&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;user_id&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;planned_hours&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/tree&gt;</span>
<span class="nt">&lt;/field&gt;</span>
</pre>
</div>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id7">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Support extra attributes on each field cell via <cite>field_extra_attrs</cite> param.
We could set a cell as not editable, required or readonly for instance.
The <cite>readonly</cite> case will also give the ability
to click on m2o to open related records.</li>
<li>Support limit total records in the matrix. Ref: <a class="reference external" href="https://github.com/OCA/web/issues/901">https://github.com/OCA/web/issues/901</a></li>
<li>Support cell traversal through keyboard arrows.</li>
<li>Entering the widget from behind by pressing <tt class="docutils literal">Shift+TAB</tt> in your keyboard
will enter into the 1st cell until <a class="reference external" href="https://github.com/odoo/odoo/pull/26490">https://github.com/odoo/odoo/pull/26490</a>
is merged.</li>
<li>Support extra invisible fields inside each cell.</li>
<li>Support kanban mode. Current behaviour forces list mode.</li>
</ul>
</div>
<div class="section" id="changelog">
<h1><a class="toc-backref" href="#id8">Changelog</a></h1>
<div class="section" id="id1">
<h2><a class="toc-backref" href="#id9">12.0.1.0.1 (2018-12-07)</a></h2>
<ul class="simple">
<li>[FIX] Cells are unable to render property.
(<a class="reference external" href="https://github.com/OCA/web/issues/1126">#1126</a>)</li>
</ul>
</div>
<div class="section" id="id3">
<h2><a class="toc-backref" href="#id10">12.0.1.0.0 (2018-11-20)</a></h2>
<ul class="simple">
<li>[12.0][MIG] web_widget_x2many_2d_matrix
(<a class="reference external" href="https://github.com/OCA/web/issues/1101">#1101</a>)</li>
</ul>
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id11">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_widget_x2many_2d_matrix%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id12">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id13">Authors</a></h2>
<ul class="simple">
<li>Therp BV</li>
<li>Tecnativa</li>
<li>Camptocamp</li>
<li>Brainbean Apps</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id14">Contributors</a></h2>
<ul class="simple">
<li>Holger Brunn &lt;<a class="reference external" href="mailto:hbrunn&#64;therp.nl">hbrunn&#64;therp.nl</a>&gt;</li>
<li>Pedro M. Baeza &lt;<a class="reference external" href="mailto:pedro.baeza&#64;tecnativa.com">pedro.baeza&#64;tecnativa.com</a>&gt;</li>
<li>Artem Kostyuk &lt;<a class="reference external" href="mailto:a.kostyuk&#64;mobilunity.com">a.kostyuk&#64;mobilunity.com</a>&gt;</li>
<li>Simone Orsi &lt;<a class="reference external" href="mailto:simone.orsi&#64;camptocamp.com">simone.orsi&#64;camptocamp.com</a>&gt;</li>
<li>Timon Tschanz &lt;<a class="reference external" href="mailto:timon.tschanz&#64;camptocamp.com">timon.tschanz&#64;camptocamp.com</a>&gt;</li>
<li>Jairo Llopis &lt;<a class="reference external" href="mailto:jairo.llopis&#64;tecnativa.com">jairo.llopis&#64;tecnativa.com</a>&gt;</li>
<li>Dennis Sluijk &lt;<a class="reference external" href="mailto:d.sluijk&#64;onestein.nl">d.sluijk&#64;onestein.nl</a>&gt;</li>
<li>Alexey Pelykh &lt;<a class="reference external" href="mailto:alexey.pelykh&#64;brainbeanapps.com">alexey.pelykh&#64;brainbeanapps.com</a>&gt;</li>
<li>Adrià Gil Sorribes &lt;<a class="reference external" href="mailto:adria.gil&#64;forgeflow.com">adria.gil&#64;forgeflow.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id15">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix">OCA/web</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,622 @@
/* Copyright 2018 Simone Orsi <simone.orsi@camptocamp.com>
* Copyright 2018 Brainbean Apps
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
odoo.define("web_widget_x2many_2d_matrix.X2Many2dMatrixRenderer", function(require) {
"use strict";
var BasicRenderer = require("web.BasicRenderer");
var config = require("web.config");
var core = require("web.core");
var field_utils = require("web.field_utils");
var utils = require("web.utils");
var _t = core._t;
var FIELD_CLASSES = {
float: "o_list_number",
integer: "o_list_number",
monetary: "o_list_number",
text: "o_list_text",
};
// X2Many2dMatrixRenderer is heavily inspired by Odoo's ListRenderer
// and is reusing portions of code from list_renderer.js
var X2Many2dMatrixRenderer = BasicRenderer.extend({
/**
* @override
*/
init: function(parent, state, params) {
this._super.apply(this, arguments);
this.editable = params.editable;
this._saveMatrixData(params.matrix_data);
},
/**
* Update matrix data in current renderer instance.
*
* @param {Object} matrixData Contains the matrix data
*/
_saveMatrixData: function(matrixData) {
this.columns = matrixData.columns;
this.rows = matrixData.rows;
this.matrix_data = matrixData;
},
/**
* 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();
// Display a nice message if there's no data to display
if (!self.rows.length) {
var $alert = $("<div>", {class: "alert alert-info"});
$alert.text(_t("Sorry no matrix data to display."));
this.$el.append($alert);
return this._super();
}
var $table = $("<table>").addClass(
"o_list_view table table-condensed table-striped " +
"o_x2many_2d_matrix "
);
this.$el.addClass("table-responsive").append($table);
this._computeColumnAggregates();
this._computeRowAggregates();
// We need to initialize the deferred list object for inherited functions that use this.defs even if it
// is empty at the moment.
var defs = [];
this.defs = defs;
$table.append(this._renderHeader()).append(this._renderBody());
if (self.matrix_data.show_column_totals) {
$table.append(this._renderFooter());
}
delete this.defs;
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
* @returns {jQueryElement} The table body element 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
* @returns {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 = null;
if (node.attrs.widget) {
description = this.state.fieldsInfo.list[name].Widget.prototype
.description;
}
if (_.isNull(description)) {
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");
} else {
$th.addClass("text-center");
}
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,
function(row) {
row.attrs.name = this.matrix_data.field_value;
return this._renderRow(row);
}.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 $tr = $("<tr/>", {class: "o_data_row"}),
_data = _.without(row.data, undefined);
$tr = $tr.append(this._renderLabelCell(_data[0]));
var $cells = this.columns.map(
function(column, index) {
var record = row.data[index];
// Make the widget use our field value for each cell
column.attrs.name = this.matrix_data.field_value;
return this._renderBodyCell(record, column, index, {mode: ""});
}.bind(this)
);
$tr = $tr.append($cells);
if (row.aggregate) {
$tr.append(this._renderAggregateRowCell(row));
}
return $tr;
},
/**
* Renders the label for a specific row.
*
* @private
* @param {Object} record Contains the information about the record.
* @returns {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"});
this.applyAggregateValue($cell, row);
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 === "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,
});
if (_.isUndefined(record)) {
// Without record, nothing elese to do
return $td;
}
$td.attr({
"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;
}
// Enforce mode of the parent
options.mode = this.getParent().mode;
if (node.tag === "widget") {
return $td.append(this._renderWidget(record, node));
}
var $el = this._renderFieldWidget(node, record, _.pick(options, "mode"));
return $td.append($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) {
var $tr = $("<tr>")
.append("<td/>")
.append($cells);
var $total_cell = this._renderTotalCell();
if ($total_cell) {
$tr.append($total_cell);
}
return $("<tfoot>").append($tr);
}
},
/**
* Renders the total cell (of all rows / columns)
*
* @private
* @returns {jQueryElement} The td element with the total in it.
*/
_renderTotalCell: function() {
if (
!this.matrix_data.show_column_totals ||
!this.matrix_data.show_row_totals
) {
return;
}
var $cell = $("<td>", {class: "col-total"});
this.applyAggregateValue($cell, this.total);
return $cell;
},
/**
* Render the Aggregate cells for the column.
*
* @private
* @returns {List} the rendered cells
*/
_renderAggregateColCells: function() {
var self = this;
return _.map(this.columns, function(column) {
var $cell = $("<td>");
if (config.debug) {
$cell.addClass(column.attrs.name);
}
if (column.aggregate) {
self.applyAggregateValue($cell, column);
}
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 fname = this.matrix_data.field_value,
field = this.state.fields[fname];
if (!field) {
return;
}
var type = field.type;
if (!~["integer", "float", "monetary"].indexOf(type)) {
return;
}
this.total = {
attrs: {
name: fname,
},
aggregate: {
help: _t("Sum Total"),
value: 0,
},
};
_.each(
this.columns,
function(column, index) {
column.aggregate = {
help: _t("Sum"),
value: 0,
};
_.each(this.rows, function(row) {
// TODO Use only one _.propertyOf in underscore 1.9.0+
try {
column.aggregate.value += row.data[index].data[fname];
} catch (error) {
// Nothing to do
}
});
this.total.aggregate.value += column.aggregate.value;
}.bind(this)
);
},
_getRecord: function(recordId) {
var record = null;
utils.traverse_records(this.state, function(r) {
if (r.id === recordId) {
record = r;
}
});
return record;
},
/**
* @override
*/
updateState: function(state, params) {
if (params.matrix_data) {
this._saveMatrixData(params.matrix_data);
}
return this._super.apply(this, arguments);
},
/**
* Traverse the fields matrix with the keyboard
*
* @override
* @private
* @param {OdooEvent} event "navigation_move" event
*/
_onNavigationMove: function(event) {
var widgets = this.__parentedChildren,
index = widgets.indexOf(event.target),
first = index === 0,
last = index === widgets.length - 1,
move = 0;
// Guess if we have to move the focus
if (event.data.direction === "next" && !last) {
move = 1;
} else if (event.data.direction === "previous" && !first) {
move = -1;
}
// Move focus
if (move) {
var target = widgets[index + move];
index = this.allFieldWidgets[target.record.id].indexOf(target);
this._activateFieldWidget(target.record, index, {inc: 0});
event.stopPropagation();
}
},
/**
* 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 fname = this.matrix_data.field_value,
field = this.state.fields[fname];
if (!field) {
return;
}
var type = field.type;
if (!~["integer", "float", "monetary"].indexOf(type)) {
return;
}
_.each(this.rows, function(row) {
row.aggregate = {
help: _t("Sum"),
value: 0,
};
_.each(row.data, function(col) {
// TODO Use _.property in underscore 1.9+
try {
row.aggregate.value += col.data[fname];
} catch (error) {
// Nothing to do
}
});
});
},
/**
* 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} axis
* The object which contains the information about the aggregate value axis
*/
applyAggregateValue: function($cell, axis) {
var field = this.state.fields[axis.attrs.name];
var value = axis.aggregate.value;
var help = axis.aggregate.help;
var fieldInfo = this.state.fieldsInfo.list[axis.attrs.name];
var formatFunc =
field_utils.format[fieldInfo.widget ? fieldInfo.widget : field.type];
var formattedValue = formatFunc(value, field, {escape: true});
$cell
.addClass("o_list_number")
.attr("title", help)
.html(formattedValue);
},
/**
* Check if the change was successful and then update the grid.
* This function is required on relational fields.
*
* @param {Object} state
* Contains the current state of the field & all the data
*
* @param {String} id
* the id of the updated object.
*
* @param {Array} fields
* The fields we have in the view.
*
* @param {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
* @param {String} id Datapoint ID
*/
_refresh: function(id) {
this._updateRow(id);
this._refreshColTotals();
this._refreshRowTotals();
},
/**
*Update row data in our internal rows.
*
* @param {String} id: The id of the row that needs to be updated.
*/
_updateRow: function(id) {
var record = _.findWhere(this.state.data, {id: id}),
_id = _.property("id");
_.each(this.rows, function(row) {
_.each(row.data, function(col, i) {
if (_id(col) === 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));
}
});
},
/**
* X2many fields expect this
*
* @returns {null}
*/
getEditableRecordID: function() {
return null;
},
});
return X2Many2dMatrixRenderer;
});

View File

@ -0,0 +1,22 @@
/* Copyright 2019 Alexandre Díaz
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
odoo.define("web_widget_x2many_2d_matrix.X2Many2dMatrixView", function(require) {
"use strict";
var BasicView = require("web.BasicView");
BasicView.include({
_processField: function(viewType, field, attrs) {
// Workaround for kanban mode rendering.
// Source of the issue: https://github.com/OCA/OCB/blob/12.0/addons/web/static/src/js/views/basic/basic_view.js#L303 .
// See https://github.com/OCA/web/pull/1404#pullrequestreview-305813206 .
// In the long term we should a way to handle kanban mode
// better (eg: a specific renderer).
if (attrs.widget === "x2many_2d_matrix") {
attrs.mode = "tree";
}
return this._super(viewType, field, attrs);
},
});
});

View File

@ -0,0 +1,16 @@
odoo.define("web_widget_x2many_2d_matrix.matrix_limit_extend", function(require) {
"use strict";
var FormView = require("web.FormView");
FormView.include({
// We extend this method so that the view is not limited to
// just 40 cells when the 'x2many_2d_matrix' widget is used.
_setSubViewLimit: function(attrs) {
this._super(attrs);
if (attrs.widget === "x2many_2d_matrix") {
attrs.limit = Infinity;
}
},
});
});

View File

@ -0,0 +1,261 @@
/* 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 field_registry = require("web.field_registry");
var relational_fields = require("web.relational_fields");
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 information about the database records.
* @param {Object} options 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_y_axis = {};
this.x_axis = [];
this.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];
}
}
var field_defs = this.recordData[this.name].fields;
// TODO: raise when any of the fields above don't exist with a
// helpful error message
if (!field_defs[this.field_value]) {
throw new Error(
_.str.sprintf(
"You need to include %s in your view definition",
this.field_value
)
);
}
this.show_row_totals = this.parse_boolean(
node.show_row_totals ||
this.is_aggregatable(field_defs[this.field_value])
? "1"
: ""
);
this.show_column_totals = this.parse_boolean(
node.show_column_totals ||
this.is_aggregatable(field_defs[this.field_value])
? "1"
: ""
);
},
/**
* Initializes the Value matrix.
*
* Puts the values in the grid.
* If we have related items we use the display name.
*/
init_matrix: function() {
var records = this.recordData[this.name].data;
// Wipe the content if something still exists
this.by_y_axis = {};
this.x_axis = [];
this.y_axis = [];
_.each(
records,
function(record) {
var x = record.data[this.field_x_axis],
y = record.data[this.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;
}
this.by_y_axis[y] = this.by_y_axis[y] || {};
this.by_y_axis[y][x] = record;
if (this.y_axis.indexOf(y) === -1) {
this.y_axis.push(y);
}
if (this.x_axis.indexOf(x) === -1) {
this.x_axis.push(x);
}
}.bind(this)
);
// Init columns
this.columns = [];
_.each(
this.x_axis,
function(x) {
this.columns.push(this._make_column(x));
}.bind(this)
);
this.rows = [];
_.each(
this.y_axis,
function(y) {
this.rows.push(this._make_row(y));
}.bind(this)
);
this.matrix_data = {
field_value: this.field_value,
field_x_axis: this.field_x_axis,
field_y_axis: this.field_y_axis,
columns: this.columns,
rows: this.rows,
show_row_totals: this.show_row_totals,
show_column_totals: this.show_column_totals,
};
console.log(this.matrix_data);
},
/**
* Create scaffold for a column.
*
* @param {String} x The string used as a column title
* @returns {Object}
*/
_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.
*
* @param {String} y The string used as a row title
* @returns {Object}
*/
_make_row: function(y) {
var self = this;
// Use object so that we can attach more data if needed
var row = {
tag: "field",
attrs: {
name: this.field_y_axis,
string: y,
},
data: [],
};
_.each(self.x_axis, function(x) {
row.data.push(self.by_y_axis[y][x]);
});
return row;
},
/**
* Determine if a field represented by field_def can be aggregated
*/
is_aggregatable: function(field_def) {
return field_def.type in {float: 1, monetary: 1, integer: 1};
},
/**
* Parse a String containing a bool and convert it to a JS bool.
*
* @param {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();
}
// Ensure widget is re initiated when rendering
this.init_matrix();
var arch = this.view.arch;
// Update existing renderer
if (!_.isUndefined(this.renderer)) {
return this.renderer.updateState(this.value, {
matrix_data: this.matrix_data,
});
}
// Create a new matrix renderer
this.renderer = new X2Many2dMatrixRenderer(this, this.value, {
arch: arch,
editable: this.mode === "edit" && arch.attrs.editable,
viewType: "list",
matrix_data: this.matrix_data,
});
this.$el.addClass("o_field_x2many o_field_x2many_2d_matrix");
return this.renderer.appendTo(this.$el);
},
/**
* Activate the widget.
*
* @override
*/
activate: function(options) {
// Won't work fine without https://github.com/odoo/odoo/pull/26490
// TODO Use _.propertyOf in underscore 1.9+
try {
this._backwards = options.event.data.direction === "previous";
} catch (error) {
this._backwards = false;
}
var result = this._super.apply(this, arguments);
delete this._backwards;
return result;
},
/**
* Get first element to focus.
*
* @override
*/
getFocusableElement: function() {
return this.$(".o_input:" + (this._backwards ? "last" : "first"));
},
});
field_registry.add("x2many_2d_matrix", WidgetX2Many2dMatrix);
return {
WidgetX2Many2dMatrix: WidgetX2Many2dMatrix,
};
});

View File

@ -0,0 +1,72 @@
$x2many_2d_matrix_max_height: 450px;
.o_form_view .o_field_x2many_2d_matrix {
.table-responsive {
max-height: $x2many_2d_matrix_max_height;
overflow-y: auto;
}
.o_x2many_2d_matrix.o_list_view {
> thead > tr > th {
white-space: pre-line;
position: sticky;
top: 0;
z-index: 1;
background-color: $o-list-footer-bg-color;
&.total {
right: 0;
}
}
> tbody {
> tr {
&:nth-of-type(2n + 1) td.row-total,
&:nth-of-type(2n + 1) td:first-child {
background-color: mix(#000, #fff, 1%);
}
&:nth-of-type(2n) td.row-total,
&:nth-of-type(2n) td:first-child {
background-color: white;
}
> td {
text-align: left;
&:first-child {
position: sticky;
left: 0;
border-right-width: 1px;
border-right-color: $gray-300;
border-right-style: solid;
box-shadow: -1px 5px 10px $gray-300;
}
&.row-total {
font-weight: bold;
position: sticky;
right: 0;
border-left-width: 1px;
border-left-color: $gray-300;
border-left-style: solid;
box-shadow: -1px 5px 10px $gray-300;
}
}
}
}
> tfoot > tr > td {
padding: 0.75rem;
text-align: left;
background-color: $o-list-footer-bg-color;
position: sticky;
bottom: 0;
&.col-total {
right: 0;
border-left-width: 1px;
border-left-color: $gray-300;
border-left-style: solid;
}
}
}
}

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!--
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<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_view.js"
/>
<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"
/>
<script
type="text/javascript"
src="/web_widget_x2many_2d_matrix/static/src/js/abstract_view_matrix_limit_extend.js"
/>
<link
rel="stylesheet"
href="/web_widget_x2many_2d_matrix/static/src/scss/web_widget_x2many_2d_matrix.scss"
/>
</xpath>
</template>
</odoo>

View File

@ -0,0 +1,74 @@
===================================
web_widget_x2many_2d_matrix example
===================================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
:target: https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix_example
:alt: OCA/web
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_widget_x2many_2d_matrix_example
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/162/13.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
Install it and click on the menu item `Demo x2m matrix widget`.
**Table of contents**
.. contents::
:local:
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 smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_widget_x2many_2d_matrix_example%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Camptocamp
Contributors
~~~~~~~~~~~~
* Simone Orsi <simone.orsi@camptocamp.com>
* Anand Kansagra <kansagraanand@hotmail.com>
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
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.
This module is part of the `OCA/web <https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix_example>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -0,0 +1,3 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models
from . import wizard

View File

@ -0,0 +1,18 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "web_widget_x2many_2d_matrix example",
"summary": "A small example on how to use `web_widget_x2many_2d_matrix`.",
"version": "13.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,
}

View File

@ -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 id name line_ids/user_id/id line_ids/name line_ids/value
2 web_widget_x2many_2d_matrix_example.x2m_demo_5 One
3 base.user_demo A 1
4 base.user_demo B 2
5 base.user_demo C 3
6 web_widget_x2many_2d_matrix_example.x2m_demo_3 Two
7 base.user_demo E 5
8 base.user_demo F 6
9 web_widget_x2many_2d_matrix_example.x2m_demo_2 Three
10 base.user_root G 8
11 base.user_demo H 9
12 base.user_root I 10
13 web_widget_x2many_2d_matrix_example.x2m_demo_1 Four
14 base.user_root L 12
15 base.user_demo M 13
16 base.user_demo N 14
17 base.user_demo O 15
18 base.user_root P 16
19 web_widget_x2many_2d_matrix_example.x2m_demo_4 Five
20 base.user_demo Q 18

View File

@ -0,0 +1,147 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_widget_x2many_2d_matrix_example
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__create_uid
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__create_uid
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__create_uid
msgid "Created by"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__create_date
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__create_date
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__create_date
msgid "Created on"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.actions.act_window,name:web_widget_x2many_2d_matrix_example.action_x2m_demo
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__demo_id
msgid "Demo"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.ui.menu,name:web_widget_x2many_2d_matrix_example.base_matrix_widget_menu
msgid "Demo x2m matrix widget"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__display_name
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__display_name
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__display_name
msgid "Display Name"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__id
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__id
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__id
msgid "ID"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo____last_update
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line____last_update
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz____last_update
msgid "Last Modified on"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__write_uid
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__write_uid
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__write_uid
msgid "Last Updated by"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__write_date
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__write_date
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__write_date
msgid "Last Updated on"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__line_ids
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__line_ids
msgid "Line"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__name
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__name
msgid "Name"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model_terms:ir.ui.view,arch_db:web_widget_x2many_2d_matrix_example.view_x2m_demo_form
msgid "Try x2m 2d matrix"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model_terms:ir.ui.view,arch_db:web_widget_x2many_2d_matrix_example.view_x2m_demo_form
msgid "Try x2m 2d matrix (many2one)"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model_terms:ir.ui.view,arch_db:web_widget_x2many_2d_matrix_example.view_x2m_demo_form
msgid "Try x2m 2d matrix (selection)"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__user_id
msgid "User"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__value
msgid "Value"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: selection:x2m.demo.line,value_selection:0
msgid "Value 1"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: selection:x2m.demo.line,value_selection:0
msgid "Value 2"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__value_many2one
msgid "Value Many2One"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__value_selection
msgid "Value Selection"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model,name:web_widget_x2many_2d_matrix_example.model_x2m_demo
msgid "X2Many Demo"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model,name:web_widget_x2many_2d_matrix_example.model_x2m_demo_line
msgid "X2Many Demo Line"
msgstr ""
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model,name:web_widget_x2many_2d_matrix_example.model_x2m_matrix_demo_wiz
msgid "X2Many Matrix Demo Wizard"
msgstr ""

View File

@ -0,0 +1,149 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * web_widget_x2many_2d_matrix_example
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2019-09-17 19:24+0000\n"
"Last-Translator: 黎伟杰 <674416404@qq.com>\n"
"Language-Team: none\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 3.8\n"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__create_uid
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__create_uid
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__create_uid
msgid "Created by"
msgstr "创建者"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__create_date
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__create_date
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__create_date
msgid "Created on"
msgstr "创建时间"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.actions.act_window,name:web_widget_x2many_2d_matrix_example.action_x2m_demo
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__demo_id
msgid "Demo"
msgstr "演示"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.ui.menu,name:web_widget_x2many_2d_matrix_example.base_matrix_widget_menu
msgid "Demo x2m matrix widget"
msgstr "演示x2m矩阵小部件"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__display_name
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__display_name
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__display_name
msgid "Display Name"
msgstr "显示名称"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__id
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__id
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__id
msgid "ID"
msgstr "ID"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo____last_update
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line____last_update
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz____last_update
msgid "Last Modified on"
msgstr "最后修改时间"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__write_uid
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__write_uid
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__write_uid
msgid "Last Updated by"
msgstr "最后更新者"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__write_date
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__write_date
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__write_date
msgid "Last Updated on"
msgstr "最后更新时间"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__line_ids
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_matrix_demo_wiz__line_ids
msgid "Line"
msgstr "行"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo__name
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__name
msgid "Name"
msgstr "名称"
#. module: web_widget_x2many_2d_matrix_example
#: model_terms:ir.ui.view,arch_db:web_widget_x2many_2d_matrix_example.view_x2m_demo_form
msgid "Try x2m 2d matrix"
msgstr "试试x2m 2d矩阵"
#. module: web_widget_x2many_2d_matrix_example
#: model_terms:ir.ui.view,arch_db:web_widget_x2many_2d_matrix_example.view_x2m_demo_form
msgid "Try x2m 2d matrix (many2one)"
msgstr "试试x2m 2d矩阵(many2one)"
#. module: web_widget_x2many_2d_matrix_example
#: model_terms:ir.ui.view,arch_db:web_widget_x2many_2d_matrix_example.view_x2m_demo_form
msgid "Try x2m 2d matrix (selection)"
msgstr "试试x2m 2d矩阵 (selection)"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__user_id
msgid "User"
msgstr "用户"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__value
msgid "Value"
msgstr "值"
#. module: web_widget_x2many_2d_matrix_example
#: selection:x2m.demo.line,value_selection:0
msgid "Value 1"
msgstr "值1"
#. module: web_widget_x2many_2d_matrix_example
#: selection:x2m.demo.line,value_selection:0
msgid "Value 2"
msgstr "值2"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__value_many2one
msgid "Value Many2One"
msgstr "值 Many2One"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model.fields,field_description:web_widget_x2many_2d_matrix_example.field_x2m_demo_line__value_selection
msgid "Value Selection"
msgstr "值Selection"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model,name:web_widget_x2many_2d_matrix_example.model_x2m_demo
msgid "X2Many Demo"
msgstr "X2Many演示"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model,name:web_widget_x2many_2d_matrix_example.model_x2m_demo_line
msgid "X2Many Demo Line"
msgstr "X2Many演示行"
#. module: web_widget_x2many_2d_matrix_example
#: model:ir.model,name:web_widget_x2many_2d_matrix_example.model_x2m_matrix_demo_wiz
msgid "X2Many Matrix Demo Wizard"
msgstr "X2Many Matrix演示向导"

View File

@ -0,0 +1,2 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import x2m_demo

View File

@ -0,0 +1,48 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class X2MDemo(models.Model):
_name = "x2m.demo"
_description = "X2Many Demo"
name = fields.Char()
line_ids = fields.One2many("x2m.demo.line", "demo_id")
def _open_x2m_matrix(self, view_xmlid):
wiz = self.env["x2m.matrix.demo.wiz"].create({})
view_id = self.env.ref(
"web_widget_x2many_2d_matrix_example.%s" % view_xmlid,
).id
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,
"view_id": view_id,
"context": self.env.context,
}
def open_x2m_matrix(self):
return self._open_x2m_matrix("x2many_2d_matrix_demo")
def open_x2m_matrix_selection(self):
return self._open_x2m_matrix("x2many_2d_matrix_demo_selection")
def open_x2m_matrix_many2one(self):
return self._open_x2m_matrix("x2many_2d_matrix_demo_many2one")
class X2MDemoLine(models.Model):
_name = "x2m.demo.line"
_description = "X2Many Demo Line"
name = fields.Char()
demo_id = fields.Many2one("x2m.demo")
user_id = fields.Many2one("res.users")
value = fields.Integer()
value_selection = fields.Selection([("val1", "Value 1"), ("val2", "Value 2")],)
value_many2one = fields.Many2one("res.groups")

View File

@ -0,0 +1,2 @@
* Simone Orsi <simone.orsi@camptocamp.com>
* Anand Kansagra <kansagraanand@hotmail.com>

View File

@ -0,0 +1 @@
Install it and click on the menu item `Demo x2m matrix widget`.

View File

@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_x2m_demo_line access_x2m_demo_line model_x2m_demo_line base.group_user 1 0 0 0
3 access_x2m_demo_line_admin access_x2m_demo_line_admin model_x2m_demo_line base.group_system 1 1 1 1
4 access_x2m_demo access_x2m_demo model_x2m_demo base.group_user 1 0 0 0
5 access_x2m_demo_admin access_x2m_demo_admin model_x2m_demo base.group_system 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,420 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<title>web_widget_x2many_2d_matrix example</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="web-widget-x2many-2d-matrix-example">
<h1 class="title">web_widget_x2many_2d_matrix example</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix_example"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/web-13-0/web-13-0-web_widget_x2many_2d_matrix_example"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/162/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>Install it and click on the menu item <cite>Demo x2m matrix widget</cite>.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="id1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id5">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id1">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_widget_x2many_2d_matrix_example%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id2">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id3">Authors</a></h2>
<ul class="simple">
<li>Camptocamp</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id4">Contributors</a></h2>
<ul class="simple">
<li>Simone Orsi &lt;<a class="reference external" href="mailto:simone.orsi&#64;camptocamp.com">simone.orsi&#64;camptocamp.com</a>&gt;</li>
<li>Anand Kansagra &lt;<a class="reference external" href="mailto:kansagraanand&#64;hotmail.com">kansagraanand&#64;hotmail.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id5">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/web/tree/13.0/web_widget_x2many_2d_matrix_example">OCA/web</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,68 @@
<?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="value_selection" />
<field name="value_many2one" />
<field name="user_id" />
</tree>
</field>
</group>
<footer>
<button
name="open_x2m_matrix"
type="object"
string="Try x2m 2d matrix"
class="oe_link"
icon="fa-edit"
/>
<button
name="open_x2m_matrix_selection"
type="object"
string="Try x2m 2d matrix (selection)"
class="oe_link"
icon="fa-edit"
/>
<button
name="open_x2m_matrix_many2one"
type="object"
string="Try x2m 2d matrix (many2one)"
class="oe_link"
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_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>

View File

@ -0,0 +1,2 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import x2m_matrix

View File

@ -0,0 +1,34 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class X2mMatrixDemoWiz(models.TransientModel):
_name = "x2m.matrix.demo.wiz"
_description = "X2Many Matrix Demo Wizard"
line_ids = fields.Many2many(
"x2m.demo.line", default=lambda self: self._default_line_ids()
)
def _default_line_ids(self):
"""take care that the widget gets records passed for every combination
of x2m.demo and res.users involved"""
recs = self.env["x2m.demo"].search([])
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,
},
)
# if there isn't a demo line record for the user, create a new one
if not rec.line_ids.filtered(lambda x: x.user_id == usr) else
# otherwise, return the line
(4, rec.line_ids.filtered(lambda x: x.user_id == usr)[0].id)
for rec in recs
for usr in users
]

View File

@ -0,0 +1,72 @@
<?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>
<record id="x2many_2d_matrix_demo_selection" 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_selection"
>
<tree>
<field name="demo_id" />
<field name="user_id" />
<field name="value_selection" />
</tree>
</field>
</form>
</field>
</record>
<record id="x2many_2d_matrix_demo_many2one" 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_many2one"
>
<tree>
<field name="demo_id" />
<field name="user_id" />
<field
name="value_many2one"
domain="[('users', '=', user_id)]"
/>
</tree>
</field>
</form>
</field>
</record>
</odoo>