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