3
0
Fork 0

[MIG]web_m2x_options: Migration to 17.0

17.0
manu 2024-07-22 17:13:53 +02:00
parent f6edfac2f9
commit 6c3884f025
18 changed files with 543 additions and 730 deletions

View File

@ -7,7 +7,7 @@ web_m2x_options
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:3a852d89e5cd927339a18898b21556fc15d261782fca8783b728cdc6a8ffa574
!! source digest: sha256:0afece0246fa101b62c0522c1df2070cea624097713b5c6991fce8a2903dc1ef
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@ -32,9 +32,8 @@ This modules modifies "many2one" and "many2manytags" form widgets so as
to add some new display control options.
Options provided includes possibility to remove "Create..." and/or
"Create and Edit..." entries from many2one drop down. You can also
change default number of proposition appearing in the drop-down. Or
prevent the dialog box poping in case of validation error.
"Create and Edit..." entries drop down. You can also change default
number of proposition appearing in the drop-down.
If not specified, the module will avoid proposing any of the create
options if the current user has no permission rights to create the
@ -53,16 +52,13 @@ in the field's options dict
``create`` *boolean* (Default: depends if user have create rights)
Whether to display the "Create..." entry in dropdown panel.
Whether to display the "Create..." entry in dropdown panel. Only for
m2o fields.
``create_edit`` *boolean* (Default: depends if user have create rights)
Whether to display "Create and Edit..." entry in dropdown panel
``m2o_dialog`` *boolean* (Default: depends if user have create rights)
Whether to display the many2one dialog in case of validation error.
``limit`` *int* (Default: odoo default value is ``8``)
Number of displayed record in drop-down panel
@ -81,21 +77,9 @@ in the field's options dict
A dictionary to link field value with a HTML color. This option has
to be used with field_color.
``no_open_edit`` *boolean* (Default: value of ``no_open`` which is
``False`` if not set)
Causes a many2one not to offer to click through in edit mode, but
well in read mode
``open`` *boolean* (Default: ``False``)
Makes many2many_tags and one2many rows buttons that open the linked
resource
``no_color_picker`` *boolean* (Default: ``False``)
Deactivates the color picker on many2many_tags buttons to do nothing
(ignored if open is set)
Makes many2one buttons that open the linked resource.
ir.config_parameter options
---------------------------
@ -117,12 +101,6 @@ create rights)
Whether to display "Create and Edit..." entry in dropdown panel for
all fields in the odoo instance.
``web_m2x_options.m2o_dialog`` *boolean* (Default: depends if user have
create rights)
Whether to display the many2one dialog in case of validation error
for all fields in the odoo instance.
``web_m2x_options.limit`` *int* (Default: odoo default value is ``8``)
Number of displayed record in drop-down panel for all fields in the
@ -142,7 +120,6 @@ To add these parameters go to Configuration -> Technical -> Parameters
- web_m2x_options.create: False
- web_m2x_options.create_edit: False
- web_m2x_options.m2o_dialog: False
- web_m2x_options.limit: 10
- web_m2x_options.search_more: True
- web_m2x_options.field_limit_entries: 5
@ -155,7 +132,7 @@ Your XML form view definition could contain:
.. code:: xml
...
<field name="partner_id" options="{'limit': 10, 'create': false, 'create_edit': false, 'search_more': true, 'field_color':'state', 'colors':{'active':'green'}}"/>
<field name="partner_id" options="{'limit': 10, 'create': false, 'create_edit': false, 'search_more': true, 'field_color':'type', 'colors':{'contact':'green', 'invoice': 'red', 'delivery': 'blue'}}"/>
...
Known issues / Roadmap
@ -170,10 +147,6 @@ verify your installation.
- Instead of making the tags rectangle clickable, I think it's better
to put the text as a clickable link, so we will get a consistent
behaviour/aspect with other clickable elements (many2one...).
- In edit mode, it would be great to add an icon like the one on
many2one fields to allow to open the many2many in a popup window.
- Include this feature as a configurable option via parameter to have
this behaviour by default in all many2many tags.
Bug Tracker
===========
@ -195,6 +168,7 @@ Authors
* ACSONE SA/NV
* 0k.io
* Tecnativa
* Sygel
Contributors
------------
@ -226,6 +200,12 @@ Contributors
- Hoang Diep <hoang@trobz.com>
- `Sygel <https://sygel.es>`__:
- Manuel Regidor <manuel.regidor@sygel.es>
- Valentín Vinagre <valentin.vinagre@sygel.es>
- Harald Panten <harald.panten@sygel.es>
Other credits
-------------

View File

@ -6,16 +6,26 @@
{
"name": "web_m2x_options",
"version": "16.0.1.1.3",
"version": "17.0.1.0.0",
"category": "Web",
"author": "initOS GmbH,"
"ACSONE SA/NV, "
"0k.io, "
"Tecnativa, "
"Sygel, "
"Odoo Community Association (OCA)",
"website": "https://github.com/OCA/web",
"license": "AGPL-3",
"depends": ["web"],
"assets": {"web.assets_backend": ["web_m2x_options/static/src/components/*"]},
"assets": {
"web.assets_backend": [
(
"before",
"web/static/src/views/fields/*",
"web_m2x_options/static/src/components/form.esm.js",
),
"web_m2x_options/static/src/components/base.xml",
]
},
"installable": True,
}

View File

@ -154,6 +154,3 @@ msgstr "als neu"
#~ msgstr ""
#~ "Sie legen eine neue %s an, sind Sie sicher, dass diese nicht bereits "
#~ "vorhanden ist?"
#~ msgid "!(widget.nodeOptions.no_open || widget.nodeOptions.no_open_edit)"
#~ msgstr "!(widget.nodeOptions.no_open || widget.nodeOptions.no_open_edit)"

View File

@ -153,6 +153,3 @@ msgstr ""
#~ msgstr ""
#~ "Vous créez un nouveau %s, est-ce que vous êtes sur qu'il n'existe pas "
#~ "déjà ?"
#~ msgid "!(widget.nodeOptions.no_open || widget.nodeOptions.no_open_edit)"
#~ msgstr "!(widget.nodeOptions.no_open || widget.nodeOptions.no_open_edit)"

View File

@ -144,7 +144,3 @@ msgstr ""
#, python-format
#~ msgid "You are creating a new %s, are you sure it does not exist yet?"
#~ msgstr "Želite kreirati novi %s, jeste li sigurni da već ne postoji?"
#, fuzzy
#~ msgid "!(widget.nodeOptions.no_open || widget.nodeOptions.no_open_edit)"
#~ msgstr "!(opcije isključuju otvaranje ili uređivanje)"

View File

@ -149,9 +149,6 @@ msgstr ""
#~ msgid "You are creating a new %s, are you sure it does not exist yet?"
#~ msgstr "U maakt een nieuw %s, weet u het zeker dat dit nog niet bestaat?"
#~ msgid "!(widget.nodeOptions.no_open || widget.nodeOptions.no_open_edit)"
#~ msgstr "!(widget.nodeOptions.no_open || widget.nodeOptions.no_open_edit)"
#~ msgid "Display Name"
#~ msgstr "Weergavenaam"

View File

@ -151,6 +151,3 @@ msgstr "como um novo"
#~ msgid "You are creating a new %s, are you sure it does not exist yet?"
#~ msgstr ""
#~ "Você está criando um novo %s, você tem certeza de que ainda não existe?"
#~ msgid "!(widget.nodeOptions.no_open || widget.nodeOptions.no_open_edit)"
#~ msgstr "!(widget.options.no_open || widget.nodeOptions.no_open_edit)"

View File

@ -148,6 +148,3 @@ msgstr ""
#, python-format
#~ msgid "You are creating a new %s, are you sure it does not exist yet?"
#~ msgstr "你正在创建一个新的%s你确定它还不存在吗"
#~ msgid "!(widget.nodeOptions.no_open || widget.nodeOptions.no_open_edit)"
#~ msgstr "!(widget.nodeOptions.no_open || widget.nodeOptions.no_open_edit)"

View File

@ -11,8 +11,8 @@ class IrConfigParameter(models.Model):
"web_m2x_options.create_edit",
"web_m2x_options.limit",
"web_m2x_options.search_more",
"web_m2x_options.m2o_dialog",
"web_m2x_options.field_limit_entries",
"web_m2x_options.open",
]
values = self.sudo().search_read([["key", "in", opts]], ["key", "value"])
return {res["key"]: res["value"] for res in values}

View File

@ -22,3 +22,8 @@
- [Trobz](https://trobz.com):
- Hoang Diep \<<hoang@trobz.com>\>
- [Sygel](https://sygel.es):
- Manuel Regidor \<<manuel.regidor@sygel.es>\>
- Valentín Vinagre \<<valentin.vinagre@sygel.es>\>
- Harald Panten \<<harald.panten@sygel.es>\>

View File

@ -2,9 +2,8 @@ This modules modifies "many2one" and "many2manytags" form widgets so as
to add some new display control options.
Options provided includes possibility to remove "Create..." and/or
"Create and Edit..." entries from many2one drop down. You can also
change default number of proposition appearing in the drop-down. Or
prevent the dialog box poping in case of validation error.
"Create and Edit..." entries drop down. You can also change default
number of proposition appearing in the drop-down.
If not specified, the module will avoid proposing any of the create
options if the current user has no permission rights to create the

View File

@ -7,7 +7,3 @@ your installation.
- Instead of making the tags rectangle clickable, I think it's better to
put the text as a clickable link, so we will get a consistent
behaviour/aspect with other clickable elements (many2one...).
- In edit mode, it would be great to add an icon like the one on
many2one fields to allow to open the many2many in a popup window.
- Include this feature as a configurable option via parameter to have
this behaviour by default in all many2many tags.

View File

@ -2,16 +2,12 @@
`create` *boolean* (Default: depends if user have create rights)
> Whether to display the "Create..." entry in dropdown panel.
> Whether to display the "Create..." entry in dropdown panel. Only for m2o fields.
`create_edit` *boolean* (Default: depends if user have create rights)
> Whether to display "Create and Edit..." entry in dropdown panel
`m2o_dialog` *boolean* (Default: depends if user have create rights)
> Whether to display the many2one dialog in case of validation error.
`limit` *int* (Default: odoo default value is `8`)
> Number of displayed record in drop-down panel
@ -30,21 +26,9 @@
> A dictionary to link field value with a HTML color. This option has to
> be used with field_color.
`no_open_edit` *boolean* (Default: value of `no_open` which is `False`
if not set)
> Causes a many2one not to offer to click through in edit mode, but well
> in read mode
`open` *boolean* (Default: `False`)
> Makes many2many_tags and one2many rows buttons that open the linked
> resource
`no_color_picker` *boolean* (Default: `False`)
> Deactivates the color picker on many2many_tags buttons to do nothing
> (ignored if open is set)
> Makes many2one buttons that open the linked resource.
## ir.config_parameter options
@ -65,12 +49,6 @@ create rights)
> Whether to display "Create and Edit..." entry in dropdown panel for
> all fields in the odoo instance.
`web_m2x_options.m2o_dialog` *boolean* (Default: depends if user have
create rights)
> Whether to display the many2one dialog in case of validation error for
> all fields in the odoo instance.
`web_m2x_options.limit` *int* (Default: odoo default value is `8`)
> Number of displayed record in drop-down panel for all fields in the
@ -90,7 +68,6 @@ To add these parameters go to Configuration -\> Technical -\> Parameters
- web_m2x_options.create: False
- web_m2x_options.create_edit: False
- web_m2x_options.m2o_dialog: False
- web_m2x_options.limit: 10
- web_m2x_options.search_more: True
- web_m2x_options.field_limit_entries: 5
@ -101,6 +78,6 @@ Your XML form view definition could contain:
``` xml
...
<field name="partner_id" options="{'limit': 10, 'create': false, 'create_edit': false, 'search_more': true, 'field_color':'state', 'colors':{'active':'green'}}"/>
<field name="partner_id" options="{'limit': 10, 'create': false, 'create_edit': false, 'search_more': true, 'field_color':'type', 'colors':{'contact':'green', 'invoice': 'red', 'delivery': 'blue'}}"/>
...
```

View File

@ -1,20 +1,19 @@
<?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.12: http://docutils.sourceforge.net/" />
<title>Add new options for many2one field</title>
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>web_m2x_options</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7614 2013-02-21 15:55:51Z milde $
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z 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
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
@ -37,6 +36,14 @@ table.borderless td, table.borderless th {
.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 }
@ -161,12 +168,12 @@ h2.subtitle {
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left {
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 {
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
@ -177,6 +184,11 @@ img.align-center, .figure.align-center, object.align-center {
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
@ -194,6 +206,15 @@ div.align-right {
/* 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 }
@ -338,74 +359,198 @@ ul.auto-toc {
</style>
</head>
<body>
<div class="document" id="add-new-options-for-many2one-field">
<h1 class="title">Add new options for many2one field</h1>
<div class="document" id="web-m2x-options">
<h1 class="title">web_m2x_options</h1>
<div class="section" id="description">
<h1>Description</h1>
<p>This modules modifies &quot;many2one&quot; and &quot;many2manytags&quot; form widgets so as to add some new display
control options.</p>
<p><strong>New: support many2manytags widget !</strong></p>
<p><strong>New: support global option management with ir.config_parameter !</strong></p>
<p>Options provided includes possibility to remove &quot;Create...&quot; and/or &quot;Create and
Edit...&quot; entries from many2one drop down. You can also change default number of
proposition appearing in the drop-down. Or prevent the dialog box poping in
case of validation error.</p>
<p>If not specified, the module will avoid proposing any of the create options
if the current user have no permission rights to create the related object.</p>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:0afece0246fa101b62c0522c1df2070cea624097713b5c6991fce8a2903dc1ef
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" 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 image-reference" 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 image-reference" href="https://github.com/OCA/web/tree/17.0/web_m2x_options"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/web-17-0/web-17-0-web_m2x_options"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/web&amp;target_branch=17.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This modules modifies “many2one” and “many2manytags” form widgets so as
to add some new display control options.</p>
<p>Options provided includes possibility to remove “Create…” and/or
“Create and Edit…” entries drop down. You can also change default
number of proposition appearing in the drop-down.</p>
<p>If not specified, the module will avoid proposing any of the create
options if the current user has no permission rights to create the
related object.</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="toc-entry-1">Usage</a><ul>
<li><a class="reference internal" href="#in-the-field-s-options-dict" id="toc-entry-2">in the fields options dict</a></li>
<li><a class="reference internal" href="#ir-config-parameter-options" id="toc-entry-3">ir.config_parameter options</a></li>
<li><a class="reference internal" href="#example" id="toc-entry-4">Example</a></li>
</ul>
</li>
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-5">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-6">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-7">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-8">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-9">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="toc-entry-10">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-11">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="requirements">
<h1>Requirements</h1>
<p>Was tested on openerp 8.0, trunk, saas-5 branch. New way to import js file. (thanks to tfossoul)</p>
</div>
<div class="section" id="new-options">
<h1>New options</h1>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<div class="section" id="in-the-field-s-options-dict">
<h2><a class="toc-backref" href="#toc-entry-2">in the fields options dict</a></h2>
<p><tt class="docutils literal">create</tt> <em>boolean</em> (Default: depends if user have create rights)</p>
<blockquote>
Whether to display the &quot;Create...&quot; entry in dropdown panel.</blockquote>
Whether to display the “Create…” entry in dropdown panel. Only for
m2o fields.</blockquote>
<p><tt class="docutils literal">create_edit</tt> <em>boolean</em> (Default: depends if user have create rights)</p>
<blockquote>
Whether to display &quot;Create and Edit...&quot; entry in dropdown panel</blockquote>
<p><tt class="docutils literal">m2o_dialog</tt> <em>boolean</em> (Default: depends if user have create rights)</p>
<blockquote>
Whether to display the many2one dialog in case of validation error.</blockquote>
<p><tt class="docutils literal">limit</tt> <em>int</em> (Default: openerp default value is <tt class="docutils literal">7</tt>)</p>
Whether to display “Create and Edit…” entry in dropdown panel</blockquote>
<p><tt class="docutils literal">limit</tt> <em>int</em> (Default: odoo default value is <tt class="docutils literal">8</tt>)</p>
<blockquote>
Number of displayed record in drop-down panel</blockquote>
<p><tt class="docutils literal">search_more</tt> <em>boolean</em></p>
<blockquote>
Used to force disable/enable search more button.</blockquote>
<p><tt class="docutils literal">field_color</tt> <em>string</em></p>
<blockquote>
A string to define the field used to define color. This option has to
be used with colors.</blockquote>
<p><tt class="docutils literal">colors</tt> <em>dictionary</em></p>
<blockquote>
A dictionary to link field value with a HTML color. This option has
to be used with field_color.</blockquote>
<p><tt class="docutils literal">open</tt> <em>boolean</em> (Default: <tt class="docutils literal">False</tt>)</p>
<blockquote>
Makes many2one buttons that open the linked resource.</blockquote>
</div>
<div class="section" id="ir-config-parameter-options">
<h1>ir.config_parameter options</h1>
<p>Now you can disable &quot;Create...&quot; and &quot;Create and Edit...&quot; entry for all widgets in the odoo instance.
If you disable one option, you can enable it for particular field by setting &quot;create: True&quot; option directly on the field definition.</p>
<p><tt class="docutils literal">web_m2x_options.create</tt> <em>boolean</em> (Default: depends if user have create rights)</p>
<h2><a class="toc-backref" href="#toc-entry-3">ir.config_parameter options</a></h2>
<p>Now you can disable “Create…” and “Create and Edit…” entry for all
widgets in the odoo instance. If you disable one option, you can enable
it for particular field by setting “create: True” option directly on the
field definition.</p>
<p><tt class="docutils literal">web_m2x_options.create</tt> <em>boolean</em> (Default: depends if user have
create rights)</p>
<blockquote>
Whether to display the &quot;Create...&quot; entry in dropdown panel for all fields in the odoo instance.</blockquote>
<p><tt class="docutils literal">web_m2x_options.create_edit</tt> <em>boolean</em> (Default: depends if user have create rights)</p>
Whether to display the “Create…” entry in dropdown panel for all
fields in the odoo instance.</blockquote>
<p><tt class="docutils literal">web_m2x_options.create_edit</tt> <em>boolean</em> (Default: depends if user have
create rights)</p>
<blockquote>
Whether to display &quot;Create and Edit...&quot; entry in dropdown panel for all fields in the odoo instance.</blockquote>
<p><tt class="docutils literal">web_m2x_options.limit</tt> <em>int</em> (Default: openerp default value is <tt class="docutils literal">7</tt>)</p>
Whether to display “Create and Edit…” entry in dropdown panel for
all fields in the odoo instance.</blockquote>
<p><tt class="docutils literal">web_m2x_options.limit</tt> <em>int</em> (Default: odoo default value is <tt class="docutils literal">8</tt>)</p>
<blockquote>
Number of displayed record in drop-down panel for all fields in the odoo instance</blockquote>
<p>To add these parameters go to Configuration -&gt; Technical -&gt; Parameters -&gt; System Parameters and add new parameters like:</p>
Number of displayed record in drop-down panel for all fields in the
odoo instance</blockquote>
<p><tt class="docutils literal">web_m2x_options.search_more</tt> <em>boolean</em> (Default: default value is
<tt class="docutils literal">False</tt>)</p>
<blockquote>
Whether the field should always show “Search more…” entry or not.</blockquote>
<p><tt class="docutils literal">web_m2x_options.field_limit_entries</tt> <em>int</em></p>
<blockquote>
Number of displayed lines on all One2many fields</blockquote>
<p>To add these parameters go to Configuration -&gt; Technical -&gt; Parameters
-&gt; System Parameters and add new parameters like:</p>
<ul class="simple">
<li>web_m2x_options.create: False</li>
<li>web_m2x_options.create_edit: False</li>
<li>web_m2x_options.limit: 10</li>
<li>web_m2x_options.search_more: True</li>
<li>web_m2x_options.field_limit_entries: 5</li>
</ul>
</div>
<div class="section" id="example">
<h1>Example</h1>
<h2><a class="toc-backref" href="#toc-entry-4">Example</a></h2>
<p>Your XML form view definition could contain:</p>
<pre class="literal-block">
...
&lt;field name=&quot;partner_id&quot; options=&quot;{'limit': 10, 'create': false, 'create_edit': false}&quot;/&gt;
...
<pre class="code xml literal-block">
...<span class="w">
</span><span class="nt">&lt;field</span><span class="w"> </span><span class="na">name=</span><span class="s">&quot;partner_id&quot;</span><span class="w"> </span><span class="na">options=</span><span class="s">&quot;{'limit': 10, 'create': false, 'create_edit': false, 'search_more': true, 'field_color':'type', 'colors':{'contact':'green', 'invoice': 'red', 'delivery': 'blue'}}&quot;</span><span class="nt">/&gt;</span><span class="w">
</span>...
</pre>
</div>
<div class="section" id="note">
<h1>Note</h1>
<p>Double check that you have no inherited view that remote <tt class="docutils literal">options</tt> you set on a field !
If nothing work, add a debugger in the first ligne of <tt class="docutils literal">get_search_result method</tt> and enable debug mode in OpenERP. When you write something in a many2one field, javascript debugger should pause. If not verify your installation.</p>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#toc-entry-5">Known issues / Roadmap</a></h1>
<p>Double check that you have no inherited view that remove <tt class="docutils literal">options</tt> you
set on a field ! If nothing works, add a debugger in the first line of
<tt class="docutils literal">_search method</tt> and enable debug mode in Odoo. When you write
something in a many2one field, javascript debugger should pause. If not
verify your installation.</p>
<ul class="simple">
<li>Instead of making the tags rectangle clickable, I think its better
to put the text as a clickable link, so we will get a consistent
behaviour/aspect with other clickable elements (many2one…).</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-6">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 to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_m2x_options%0Aversion:%2017.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="#toc-entry-7">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-8">Authors</a></h2>
<ul class="simple">
<li>initOS GmbH</li>
<li>ACSONE SA/NV</li>
<li>0k.io</li>
<li>Tecnativa</li>
<li>Sygel</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-9">Contributors</a></h2>
<ul class="simple">
<li>David Coninckx &lt;<a class="reference external" href="mailto:davconinckx&#64;gmail.com">davconinckx&#64;gmail.com</a>&gt;</li>
<li>Emanuel Cino &lt;<a class="reference external" href="mailto:ecino&#64;compassion.ch">ecino&#64;compassion.ch</a>&gt;</li>
<li>Holger Brunn &lt;<a class="reference external" href="mailto:hbrunn&#64;therp.nl">hbrunn&#64;therp.nl</a>&gt;</li>
<li>Nicolas JEUDY &lt;<a class="reference external" href="mailto:nicolas&#64;sudokeys.com">nicolas&#64;sudokeys.com</a>&gt;</li>
<li>Yannick Vaucher &lt;<a class="reference external" href="mailto:yannick.vaucher&#64;camptocamp.com">yannick.vaucher&#64;camptocamp.com</a>&gt;</li>
<li>Zakaria Makrelouf &lt;<a class="reference external" href="mailto:z.makrelouf&#64;gmail.com">z.makrelouf&#64;gmail.com</a>&gt;</li>
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
<li>Jairo Llopis &lt;<a class="reference external" href="mailto:jairo.llopis&#64;tecnativa.com">jairo.llopis&#64;tecnativa.com</a>&gt;</li>
<li>David Vidal &lt;<a class="reference external" href="mailto:david.vidal&#64;tecnativa.com">david.vidal&#64;tecnativa.com</a>&gt;</li>
<li>Ernesto Tejeda &lt;<a class="reference external" href="mailto:ernesto.tejeda87&#64;gmail.com">ernesto.tejeda87&#64;gmail.com</a>&gt;</li>
<li>Carlos Roca</li>
</ul>
</li>
<li>Bhavesh Odedra &lt;<a class="reference external" href="mailto:bodedra&#64;opensourceintegrators.com">bodedra&#64;opensourceintegrators.com</a>&gt;</li>
<li>Dhara Solanki &lt;<a class="reference external" href="mailto:dhara.solanki&#64;initos.com">dhara.solanki&#64;initos.com</a>&gt; (<a class="reference external" href="http://www.initos.com">http://www.initos.com</a>)</li>
<li><a class="reference external" href="https://trobz.com">Trobz</a>:<ul>
<li>Hoang Diep &lt;<a class="reference external" href="mailto:hoang&#64;trobz.com">hoang&#64;trobz.com</a>&gt;</li>
</ul>
</li>
<li><a class="reference external" href="https://sygel.es">Sygel</a>:<ul>
<li>Manuel Regidor &lt;<a class="reference external" href="mailto:manuel.regidor&#64;sygel.es">manuel.regidor&#64;sygel.es</a>&gt;</li>
<li>Valentín Vinagre &lt;<a class="reference external" href="mailto:valentin.vinagre&#64;sygel.es">valentin.vinagre&#64;sygel.es</a>&gt;</li>
<li>Harald Panten &lt;<a class="reference external" href="mailto:harald.panten&#64;sygel.es">harald.panten&#64;sygel.es</a>&gt;</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="other-credits">
<h2><a class="toc-backref" href="#toc-entry-10">Other credits</a></h2>
<p>The migration of this module from 15.0 to 16.0 was financially supported
by Camptocamp</p>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-11">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/17.0/web_m2x_options">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>

View File

@ -3,7 +3,6 @@
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<templates xml:space="preserve">
<t
t-name="web_m2x_options.AutoComplete"
t-inherit="web.AutoComplete"
@ -15,32 +14,17 @@
</xpath>
</t>
<t
<t
t-name="web_m2x_options.Many2ManyTagsField"
t-inherit="web.Many2ManyTagsField"
t-inherit-mode="extension"
owl="1"
>
<xpath expr="//Many2XAutocomplete" position="attributes">
<attribute name="nodeOptions">props.nodeOptions</attribute>
<attribute name="searchLimit">props.searchLimit</attribute>
<attribute name="fieldColor">props.fieldColor</attribute>
<attribute name="fieldColorOptions">props.fieldColorOptions</attribute>
</xpath>
</t>
<t t-name="web_m2x_options.Many2OneField.CreateConfirmationDialog" owl="1">
<Dialog title="title" size="'md'">
<div>
You are creating a new <strong t-esc="props.value" /> as a new <t
t-esc="props.name"
/>, are you sure it does not exist yet?
</div>
<t t-set-slot="footer">
<button class="btn btn-primary" t-on-click="onCreate">Create</button>
<button
class="btn btn-primary"
t-on-click="onCreateEdit"
>Create and Edit</button>
<button class="btn" t-on-click="() => props.close()">Discard</button>
</t>
</Dialog>
</t>
</templates>

View File

@ -1,403 +1,362 @@
/** @odoo-module **/
import {
Many2ManyTagsField,
Many2ManyTagsFieldColorEditable,
many2ManyTagsField,
} from "@web/views/fields/many2many_tags/many2many_tags_field";
import {Dialog} from "@web/core/dialog/dialog";
import {Many2OneField, many2OneField} from "@web/views/fields/many2one/many2one_field";
import {FormController} from "@web/views/form/form_controller";
import {FormViewDialog} from "@web/views/view_dialogs/form_view_dialog";
import {Many2OneAvatarField} from "@web/views/fields/many2one_avatar/many2one_avatar_field";
import {Many2OneBarcodeField} from "@web/views/fields/many2one_barcode/many2one_barcode_field";
import {Many2OneField} from "@web/views/fields/many2one/many2one_field";
import {ReferenceField} from "@web/views/fields/reference/reference_field";
import {X2ManyField} from "@web/views/fields/x2many/x2many_field";
import {Many2XAutocomplete} from "@web/views/fields/relational_utils";
import {evaluateBooleanExpr} from "@web/core/py_js/py";
import {isX2Many} from "@web/views/utils";
import {is_option_set} from "@web_m2x_options/components/relational_utils.esm";
import {patch} from "@web/core/utils/patch";
import {sprintf} from "@web/core/utils/strings";
import {useService} from "@web/core/utils/hooks";
const {Component} = owl;
/**
* Patch Many2ManyTagsField
**/
patch(Many2ManyTagsField.prototype, "web_m2x_options.Many2ManyTagsField", {
setup() {
this._super(...arguments);
this.actionService = useService("action");
},
/**
* @override
*/
getTagProps(record) {
const props = this._super(...arguments);
props.onClick = (ev) => this.onMany2ManyBadgeClick(ev, record);
return props;
},
async onMany2ManyBadgeClick(event, record) {
var self = this;
if (self.props.open) {
var context = self.context;
var id = record.data.id;
if (self.props.readonly) {
event.preventDefault();
event.stopPropagation();
const action = await self.orm.call(
self.props.relation,
"get_formview_action",
[[id]],
{context: context}
);
self.actionService.doAction(action);
} else {
const view_id = await self.orm.call(
self.props.relation,
"get_formview_id",
[[id]],
{context: context}
);
const write_access = await self.orm.call(
self.props.relation,
"check_access_rights",
[],
{operation: "write", raise_exception: false}
);
var can_write = self.props.canWrite;
self.dialog.add(FormViewDialog, {
resModel: self.props.relation,
resId: id,
context: context,
title: self.env._t("Open: ") + self.string,
viewId: view_id,
mode: !can_write || !write_access ? "readonly" : "edit",
onRecordSaved: () => self.props.value.model.load(),
});
}
}
},
});
Many2ManyTagsField.props = {
...Many2ManyTagsField.props,
open: {type: Boolean, optional: true},
canWrite: {type: Boolean, optional: true},
nodeOptions: {type: Object, optional: true},
};
const Many2ManyTagsFieldExtractProps = Many2ManyTagsField.extractProps;
Many2ManyTagsField.extractProps = ({attrs, field}) => {
const canOpen = Boolean(attrs.options.open);
const canWrite = attrs.can_write && Boolean(JSON.parse(attrs.can_write));
return Object.assign(Many2ManyTagsFieldExtractProps({attrs, field}), {
open: canOpen,
canWrite: canWrite,
nodeOptions: attrs.options,
});
};
/**
* Many2ManyTagsFieldColorEditable
**/
patch(
Many2ManyTagsFieldColorEditable.prototype,
"web_m2x_options.Many2ManyTagsFieldColorEditable",
{
async onBadgeClick(event, record) {
if (this.props.canEditColor && !this.props.open) {
this._super(...arguments);
}
if (this.props.open) {
Many2ManyTagsField.prototype.onMany2ManyBadgeClick.bind(this)(
event,
record
);
}
},
}
);
Many2ManyTagsFieldColorEditable.props = {
...Many2ManyTagsFieldColorEditable.props,
open: {type: Boolean, optional: true},
canWrite: {type: Boolean, optional: true},
nodeOptions: {type: Object, optional: true},
};
/**
* CreateConfirmationDialog
* New customized component for Many2One Field
**/
class CreateConfirmationDialog extends Component {
get title() {
return sprintf(this.env._t("New: %s"), this.props.name);
}
async onCreate() {
await this.props.create();
this.props.close();
}
async onCreateEdit() {
await this.props.createEdit();
this.props.close();
}
}
CreateConfirmationDialog.components = {Dialog};
CreateConfirmationDialog.template =
"web_m2x_options.Many2OneField.CreateConfirmationDialog";
/**
* Many2OneField
**/
patch(Many2OneField.prototype, "web_m2x_options.Many2OneField", {
setup() {
this._super(...arguments);
this.ir_options = Component.env.session.web_m2x_options;
},
/**
* @override
*/
get Many2XAutocompleteProps() {
const props = this._super(...arguments);
return {
...props,
searchLimit: this.props.searchLimit,
searchMore: this.props.searchMore,
canCreate: this.props.canCreate,
nodeOptions: this.props.nodeOptions,
};
},
async openConfirmationDialog(request) {
var m2o_dialog_opt =
is_option_set(this.props.nodeOptions.m2o_dialog) ||
(_.isUndefined(this.props.nodeOptions.m2o_dialog) &&
is_option_set(this.ir_options["web_m2x_options.m2o_dialog"])) ||
(_.isUndefined(this.props.nodeOptions.m2o_dialog) &&
_.isUndefined(this.ir_options["web_m2x_options.m2o_dialog"]));
if (this.props.canCreate && this.state.isFloating && m2o_dialog_opt) {
return new Promise((resolve, reject) => {
this.addDialog(CreateConfirmationDialog, {
value: request,
name: this.props.string,
create: async () => {
try {
await this.quickCreate(request);
resolve();
} catch (e) {
reject(e);
}
},
createEdit: async () => {
try {
await this.quickCreate(request);
await this.props.record.model.load();
this.openMany2X({
resId: this.props.value[0],
context: this.user_context,
});
resolve();
} catch (e) {
reject(e);
}
},
});
});
}
},
});
const Many2OneFieldExtractProps = Many2OneField.extractProps;
Many2OneField.extractProps = ({attrs, field}) => {
return Object.assign(Many2OneFieldExtractProps({attrs, field}), {
searchLimit: attrs.options.limit,
searchMore: attrs.options.search_more,
nodeOptions: attrs.options,
});
};
import {session} from "@web/session";
Many2OneField.props = {
...Many2OneField.props,
searchMore: {type: Boolean, optional: true},
nodeOptions: {type: Object, optional: true},
noSearchMore: {type: Boolean, optional: true},
fieldColor: {type: String, optional: true},
fieldColorOptions: {type: Object, optional: true},
};
Many2XAutocomplete.props = {
...Many2XAutocomplete.props,
fieldColor: {type: String, optional: true},
fieldColorOptions: {type: Object, optional: true},
};
/**
* FIXME: find better way to extend props in Many2OneField
* Override ReferenceField
* Since extracted/added props: nodeOptions and searchMore into Many2OneField props
* and this component inherited props from Many2OneField
* So, must override props here to avoid constraint validateProps (props schema) in owl core
*/
ReferenceField.props = {
...ReferenceField.props,
searchMore: {type: Boolean, optional: true},
nodeOptions: {type: Object, optional: true},
};
/**
* FIXME: find better way to extend props in Many2OneField
* Override Many2OneBarcodeField
* Since extracted/added props: nodeOptions and searchMore into Many2OneField props
* and this component inherited props from Many2OneField
* So, must override props here to avoid constraint validateProps (props schema) in owl core
*/
Many2OneBarcodeField.props = {
...Many2OneBarcodeField.props,
searchMore: {type: Boolean, optional: true},
nodeOptions: {type: Object, optional: true},
};
/**
* FIXME: find better way to extend props in Many2OneField
* Override Many2OneAvatarField
* Since extracted/added props: nodeOptions and searchMore into Many2OneField props
* and this component inherited props from Many2OneField
* So, must override props here to avoid constraint validateProps (props schema) in owl core
*/
Many2OneAvatarField.props = {
...Many2OneAvatarField.props,
searchMore: {type: Boolean, optional: true},
nodeOptions: {type: Object, optional: true},
noSearchMore: {type: Boolean, optional: true},
fieldColor: {type: String, optional: true},
fieldColorOptions: {type: Object, optional: true},
};
/**
* FIXME: find better way to extend props in Many2OneField
* Override mailing_m2o_filter
* Since extracted/added props: nodeOptions and searchMore into Many2OneField props
* and this component inherited props from Many2OneField
* So, must override props here to avoid constraint validateProps (props schema) in owl core
* This component is in module mass_mailing as optional module,
* So need to import dynamic way
*/
try {
(async () => {
// Make sure component mailing_m2o_filter in mass mailing module loaded
const installed_mass_mailing = await odoo.ready(
"@mass_mailing/js/mailing_m2o_filter"
);
if (installed_mass_mailing) {
const {FieldMany2OneMailingFilter} = await odoo.runtimeImport(
"@mass_mailing/js/mailing_m2o_filter"
);
FieldMany2OneMailingFilter.props = {
...FieldMany2OneMailingFilter.props,
searchMore: {type: Boolean, optional: true},
nodeOptions: {type: Object, optional: true},
};
}
})();
} catch {
console.log(
"Ignore overriding props of component mailing_m2o_filter since the module is not installed"
);
}
Many2ManyTagsField.props = {
...Many2ManyTagsField.props,
searchLimit: {type: Number, optional: true},
fieldColor: {type: String, optional: true},
fieldColorOptions: {type: Object, optional: true},
};
/**
* X2ManyField
**/
patch(X2ManyField.prototype, "web_m2x_options.X2ManyField", {
/**
* @override
*/
async openRecord(record) {
var self = this;
var open = this.props.open;
if (open && self.props.readonly) {
var res_id = record.data.id;
const action = await self.env.model.orm.call(
self.props.value.resModel,
"get_formview_action",
[[res_id]]
);
return self.env.model.actionService.doAction(action);
Many2ManyTagsFieldColorEditable.props = {
...Many2ManyTagsFieldColorEditable.props,
searchLimit: {type: Number, optional: true},
fieldColor: {type: String, optional: true},
fieldColorOptions: {type: Object, optional: true},
};
patch(many2OneField, {
m2o_options_props_create(props, attrs, options) {
const ir_options = session.web_m2x_options;
if (options.create === false) {
props.canQuickCreate = false;
} else if (options.create) {
props.canQuickCreate = attrs.can_create
? evaluateBooleanExpr(attrs.can_create)
: true;
} else if (
ir_options["web_m2x_options.create"] === "False" &&
props.canQuickCreate
) {
props.canQuickCreate = false;
} else if (
ir_options["web_m2x_options.create"] === "True" &&
!props.canQuickCreate
) {
props.canQuickCreate = attrs.can_create
? evaluateBooleanExpr(attrs.can_create)
: true;
}
return this._super.apply(this, arguments);
return props;
},
m2o_options_props_create_edit(props, attrs, options) {
const ir_options = session.web_m2x_options;
if (options.create_edit === false) {
props.canCreateEdit = false;
} else if (options.create_edit) {
// Same condition set in web/views/fields/many2one/many2one_field
props.canCreateEdit = attrs.can_create
? evaluateBooleanExpr(attrs.can_create)
: true;
} else if (
ir_options["web_m2x_options.create_edit"] === "False" &&
props.canCreateEdit
) {
props.canCreateEdit = false;
} else if (
ir_options["web_m2x_options.create_edit"] === "True" &&
!props.canCreateEdit
) {
// Same condition set in web/views/fields/many2one/many2one_field
props.canCreateEdit = attrs.can_create
? evaluateBooleanExpr(attrs.can_create)
: true;
}
return props;
},
m2o_options_props_limit(props, attrs, options) {
const ir_options = session.web_m2x_options;
if (Number(options.limit)) {
props.searchLimit = Number(options.limit);
} else if (Number(ir_options["web_m2x_options.limit"])) {
props.searchLimit = Number(ir_options["web_m2x_options.limit"]);
}
return props;
},
m2o_options_props_search_more(props, attrs, options) {
const ir_options = session.web_m2x_options;
if (options.search_more) {
props.noSearchMore = false;
} else if (options.search_more === false) {
props.noSearchMore = true;
} else if (
ir_options["web_m2x_options.search_more"] === "True" &&
props.noSearchMore
) {
props.noSearchMore = false;
} else if (ir_options["web_m2x_options.search_more"] === "False") {
props.noSearchMore = true;
}
return props;
},
m2o_options_props_open(props, attrs, options) {
const ir_options = session.web_m2x_options;
if (options.open) {
props.canOpen = true;
} else if (options.open === false) {
props.canOpen = false;
} else if (ir_options["web_m2x_options.open"] === "True") {
props.canOpen = true;
} else if (ir_options["web_m2x_options.open"] === "False") {
props.canOpen = false;
}
return props;
},
m2o_options_props(props, attrs, options) {
props = this.m2o_options_props_create(props, attrs, options);
props = this.m2o_options_props_create_edit(props, attrs, options);
props = this.m2o_options_props_limit(props, attrs, options);
props = this.m2o_options_props_search_more(props, attrs, options);
props = this.m2o_options_props_open(props, attrs, options);
props.fieldColor = options.field_color;
props.fieldColorOptions = options.colors;
return props;
},
extractProps({attrs, context, decorations, options, string}, dynamicInfo) {
const props = super.extractProps(
{attrs, context, decorations, options, string},
dynamicInfo
);
const new_props = this.m2o_options_props(props, attrs, options);
return new_props;
},
});
const X2ManyFieldExtractProps = X2ManyField.extractProps;
X2ManyField.extractProps = ({attrs}) => {
const canOpen = Boolean(attrs.options.open);
return Object.assign(X2ManyFieldExtractProps({attrs}), {
open: canOpen,
});
};
patch(Many2OneField.prototype, {
get Many2XAutocompleteProps() {
const search_limit = this.props.searchLimit;
const no_search_more = this.props.noSearchMore;
const field_color = this.props.fieldColor;
const field_color_options = this.props.fieldColorOptions;
const props = super.Many2XAutocompleteProps;
const ret_props = {...props};
if (Number(search_limit) && Number(search_limit) > 1) {
ret_props.searchLimit = search_limit - 1;
}
if (no_search_more) {
ret_props.noSearchMore = no_search_more;
}
if (field_color && field_color_options) {
ret_props.fieldColor = field_color;
ret_props.fieldColorOptions = field_color_options;
}
return ret_props;
},
});
X2ManyField.props = {
...X2ManyField.props,
open: {type: Boolean, optional: true},
};
patch(many2ManyTagsField, {
m2m_options_props_create(props, attrs, options) {
const ir_options = session.web_m2x_options;
// Create option already available for m2m fields
if (!options.create) {
if (
ir_options["web_m2x_options.create"] === "False" &&
props.canQuickCreate
) {
props.canQuickCreate = false;
} else if (
ir_options["web_m2x_options.create"] === "True" &&
!props.canQuickCreate
) {
props.canQuickCreate = attrs.can_create
? evaluateBooleanExpr(attrs.can_create)
: true;
}
}
return props;
},
/**
* FormController
**/
patch(FormController.prototype, "web_m2x_options.FormController", {
m2m_options_props_create_edit(props, attrs, options) {
const ir_options = session.web_m2x_options;
if (options.create_edit === false) {
props.canCreateEdit = false;
} else if (options.create_edit) {
// Same condition set in web/views/fields/many2one/many2one_field
props.canCreateEdit = attrs.can_create
? evaluateBooleanExpr(attrs.can_create)
: true;
} else if (
ir_options["web_m2x_options.create_edit"] === "False" &&
props.canCreateEdit
) {
props.canCreateEdit = false;
} else if (
ir_options["web_m2x_options.create_edit"] === "True" &&
!props.canCreateEdit
) {
// Same condition set in web/views/fields/many2one/many2one_field
props.canCreateEdit = attrs.can_create
? evaluateBooleanExpr(attrs.can_create)
: true;
}
return props;
},
m2m_options_props_limit(props, attrs, options) {
const ir_options = session.web_m2x_options;
if (Number(options.limit) && options.limit > 1) {
props.searchLimit = Number(options.limit) - 1;
} else if (
Number(ir_options["web_m2x_options.limit"]) &&
ir_options["web_m2x_options.limit"] > 1
) {
props.searchLimit = Number(ir_options["web_m2x_options.limit"]) - 1;
}
return props;
},
m2m_options_props_search_more(props, attrs, options) {
const ir_options = session.web_m2x_options;
if (options.search_more) {
props.noSearchMore = false;
} else if (options.search_more === false) {
props.noSearchMore = true;
} else if (
ir_options["web_m2x_options.search_more"] === "True" &&
props.noSearchMore
) {
props.noSearchMore = false;
} else if (ir_options["web_m2x_options.search_more"] === "False") {
props.noSearchMore = true;
}
return props;
},
m2m_options_props(props, attrs, options) {
props = this.m2m_options_props_create(props, attrs, options);
props = this.m2m_options_props_create_edit(props, attrs, options);
props = this.m2m_options_props_limit(props, attrs, options);
props = this.m2m_options_props_search_more(props, attrs, options);
props.fieldColor = options.field_color;
props.fieldColorOptions = options.colors;
return props;
},
extractProps({attrs, options, string}, dynamicInfo) {
const props = super.extractProps({attrs, options, string}, dynamicInfo);
const new_props = this.m2m_options_props(props, attrs, options);
return new_props;
},
});
patch(Many2XAutocomplete.prototype, {
setup() {
super.setup();
this.ir_options = session.web_m2x_options;
},
async loadOptionsSource(request) {
var options = await super.loadOptionsSource(request);
this.field_color = this.props.fieldColor;
this.colors = this.props.fieldColorOptions;
if (this.colors && this.field_color) {
var value_ids = options.map((result) => result.value);
const objects = await this.orm.call(
this.props.resModel,
"search_read",
[],
{
domain: [["id", "in", value_ids]],
fields: [this.field_color],
}
);
for (var index in objects) {
for (var index_value in options) {
if (options[index_value].value === objects[index].id) {
// Find value in values by comparing ids
var option = options[index_value];
// Find color with field value as key
var color =
this.colors[objects[index][this.field_color]] || "black";
option.style = "color:" + color;
break;
}
}
}
}
return options;
},
});
patch(FormController.prototype, {
/**
* @override
*/
setup() {
var self = this;
this._super(...arguments);
/** Due to problem of 2 onWillStart in native web core
* (see: https://github.com/odoo/odoo/blob/16.0/addons/web/static/src/views/model.js#L142)
* do the trick to override beforeLoadResolver here to customize viewLimit
*/
this.superBeforeLoadResolver = this.beforeLoadResolver;
this.beforeLoadResolver = async () => {
await self._setSubViewLimit();
self.superBeforeLoadResolver();
};
super.setup(...arguments);
this._setSubViewLimit();
},
/**
* @override
* add more method to add subview limit on formview
*/
async _setSubViewLimit() {
const ir_options = Component.env.session.web_m2x_options;
const activeFields = this.archInfo.activeFields,
fields = this.props.fields,
const ir_options = session.web_m2x_options;
const activeFields = this.archInfo.fieldNodes,
isSmall = this.user;
var limit = ir_options["web_m2x_options.field_limit_entries"];
if (!_.isUndefined(limit)) {
if (!(typeof limit === "undefined")) {
limit = parseInt(limit, 10);
}
for (const fieldName in activeFields) {
const field = fields[fieldName];
const field = activeFields[fieldName];
if (!isX2Many(field)) {
// What follows only concerns x2many fields
continue;
}
const fieldInfo = activeFields[fieldName];
if (fieldInfo.modifiers.invisible === true) {
// Const fieldInfo = activeFields[fieldName];
if (field.invisible) {
// No need to fetch the sub view if the field is always invisible
continue;
}
if (!fieldInfo.FieldComponent.useSubView) {
if (!field.field.useSubView) {
// The FieldComponent used to render the field doesn't need a sub view
continue;
}
let viewType = fieldInfo.viewMode || "list,kanban";
let viewType = field.viewMode || "list,kanban";
viewType = viewType.replace("tree", "list");
if (viewType.includes(",")) {
viewType = isSmall ? "kanban" : "list";
}
fieldInfo.viewMode = viewType;
if (fieldInfo.views[viewType] && limit) {
fieldInfo.views[viewType].limit = limit;
field.viewMode = viewType;
if (field.views[viewType] && limit) {
field.views[viewType].limit = limit;
}
}
},

View File

@ -1,221 +0,0 @@
/** @odoo-module **/
import {Many2XAutocomplete} from "@web/views/fields/relational_utils";
import {patch} from "@web/core/utils/patch";
import {sprintf} from "@web/core/utils/strings";
const {Component} = owl;
export function is_option_set(option) {
if (_.isUndefined(option)) return false;
if (typeof option === "string") return option === "true" || option === "True";
if (typeof option === "boolean") return option;
return false;
}
patch(Many2XAutocomplete.prototype, "web_m2x_options.Many2XAutocomplete", {
setup() {
this._super(...arguments);
this.ir_options = Component.env.session.web_m2x_options;
},
async loadOptionsSource(request) {
if (this.lastProm) {
this.lastProm.abort(false);
}
// Add options limit used to change number of selections record
// returned.
if (!_.isUndefined(this.ir_options["web_m2x_options.limit"])) {
this.props.searchLimit = parseInt(
this.ir_options["web_m2x_options.limit"],
10
);
this.limit = this.props.searchLimit;
}
if (typeof this.props.nodeOptions.limit === "number") {
this.props.searchLimit = this.props.nodeOptions.limit;
this.limit = this.props.searchLimit;
}
// Add options field_color and colors to color item(s) depending on field_color value
this.field_color = this.props.nodeOptions.field_color;
this.colors = this.props.nodeOptions.colors;
this.lastProm = this.orm.call(this.props.resModel, "name_search", [], {
name: request,
operator: "ilike",
args: this.props.getDomain(),
limit: this.props.searchLimit + 1,
context: this.props.context,
});
const records = await this.lastProm;
var options = records.map((result) => ({
value: result[0],
id: result[0],
label: result[1].split("\n")[0],
}));
// Limit results if there is a custom limit options
if (this.limit) {
options = options.slice(0, this.props.searchLimit);
}
// Search result value colors
if (this.colors && this.field_color) {
var value_ids = options.map((result) => result.value);
const objects = await this.orm.call(
this.props.resModel,
"search_read",
[],
{
domain: [["id", "in", value_ids]],
fields: [this.field_color],
}
);
for (var index in objects) {
for (var index_value in options) {
if (options[index_value].id === objects[index].id) {
// Find value in values by comparing ids
var option = options[index_value];
// Find color with field value as key
var color =
this.colors[objects[index][this.field_color]] || "black";
option.style = "color:" + color;
break;
}
}
}
}
// Quick create
// Note: Create should be before `search_more` (reserve native order)
// One more reason: when calling `onInputBlur`, native select the first option (activeSourceOption)
// which triggers m2o_dialog if m2o_dialog=true
var create_enabled =
this.props.quickCreate && !this.props.nodeOptions.no_create;
var raw_result = _.map(records, function (x) {
return x[1];
});
var quick_create = is_option_set(this.props.nodeOptions.create),
quick_create_undef = _.isUndefined(this.props.nodeOptions.create),
m2x_create_undef = _.isUndefined(this.ir_options["web_m2x_options.create"]),
m2x_create = is_option_set(this.ir_options["web_m2x_options.create"]);
var show_create =
(!this.props.nodeOptions && (m2x_create_undef || m2x_create)) ||
(this.props.nodeOptions &&
(quick_create ||
(quick_create_undef && (m2x_create_undef || m2x_create))));
if (
create_enabled &&
!this.props.nodeOptions.no_quick_create &&
request.length > 0 &&
!_.contains(raw_result, request) &&
show_create
) {
options.push({
label: sprintf(this.env._t(`Create "%s"`), request),
classList: "o_m2o_dropdown_option o_m2o_dropdown_option_create",
action: async (params) => {
try {
await this.props.quickCreate(request, params);
} catch {
const context = this.getCreationContext(request);
return this.openMany2X({context});
}
},
});
}
// Search more...
// Resolution order:
// 1- check if "search_more" is set locally in node's options
// 2- if set locally, apply its value
// 3- if not set locally, check if it's set globally via ir.config_parameter
// 4- if set globally, apply its value
// 5- if not set globally either, check if returned values are more than node's limit
var search_more = false;
if (!_.isUndefined(this.props.nodeOptions.search_more)) {
search_more = is_option_set(this.props.nodeOptions.search_more);
} else if (!_.isUndefined(this.ir_options["web_m2x_options.search_more"])) {
search_more = is_option_set(this.ir_options["web_m2x_options.search_more"]);
} else {
search_more =
!this.props.noSearchMore && this.props.searchLimit < records.length;
}
if (search_more) {
options.push({
label: this.env._t("Search More..."),
action: this.onSearchMore.bind(this, request),
classList: "o_m2o_dropdown_option o_m2o_dropdown_option_search_more",
});
}
// Create and Edit
const canCreateEdit =
"createEdit" in this.activeActions
? this.activeActions.createEdit
: this.activeActions.create;
if (
!request.length &&
!this.props.value &&
(this.props.quickCreate || canCreateEdit)
) {
options.push({
label: this.env._t("Start typing..."),
classList: "o_m2o_start_typing",
unselectable: true,
});
}
// Create and edit ...
var create_edit =
is_option_set(this.props.nodeOptions.create) ||
is_option_set(this.props.nodeOptions.create_edit),
create_edit_undef =
_.isUndefined(this.props.nodeOptions.create) &&
_.isUndefined(this.props.nodeOptions.create_edit),
m2x_create_edit_undef = _.isUndefined(
this.ir_options["web_m2x_options.create_edit"]
),
m2x_create_edit = is_option_set(
this.ir_options["web_m2x_options.create_edit"]
);
var show_create_edit =
(!this.props.nodeOptions && (m2x_create_edit_undef || m2x_create_edit)) ||
(this.props.nodeOptions &&
(create_edit ||
(create_edit_undef && (m2x_create_edit_undef || m2x_create_edit))));
if (
create_enabled &&
!this.props.nodeOptions.no_create_edit &&
show_create_edit &&
request.length &&
canCreateEdit
) {
const context = this.getCreationContext(request);
options.push({
label: this.env._t("Create and edit..."),
classList: "o_m2o_dropdown_option o_m2o_dropdown_option_create_edit",
action: () => this.openMany2X({context}),
});
}
// No records
if (!records.length && !this.activeActions.create) {
options.push({
label: this.env._t("No records"),
classList: "o_m2o_no_result",
unselectable: true,
});
}
return options;
},
});
Many2XAutocomplete.defaultProps = {
...Many2XAutocomplete.defaultProps,
nodeOptions: {},
};

View File

@ -7,17 +7,16 @@ from odoo.tests import common
class TestIrConfigParameter(common.TransactionCase):
@classmethod
def setUpClass(cls):
super(TestIrConfigParameter, cls).setUpClass()
super().setUpClass()
cls.env["ir.config_parameter"].set_param("web_m2x_options.limit", 10)
cls.env["ir.config_parameter"].set_param("web_m2x_options.create_edit", "True")
cls.env["ir.config_parameter"].set_param("web_m2x_options.create", "True")
cls.env["ir.config_parameter"].set_param("web_m2x_options.search_more", "False")
cls.env["ir.config_parameter"].set_param("web_m2x_options.m2o_dialog", "True")
def test_web_m2x_options_key(self):
web_m2x_options = self.env["ir.config_parameter"].get_web_m2x_options()
self.assertIn("web_m2x_options.limit", web_m2x_options)
self.assertNotIn("web_m2x_options.m2o_dialog_test", web_m2x_options)
self.assertNotIn("web_m2x_options.search_more_test", web_m2x_options)
def test_web_m2x_options_value(self):
web_m2x_options = self.env["ir.config_parameter"].get_web_m2x_options()
@ -25,4 +24,3 @@ class TestIrConfigParameter(common.TransactionCase):
self.assertTrue(bool(web_m2x_options["web_m2x_options.create_edit"]))
self.assertTrue(bool(web_m2x_options["web_m2x_options.create"]))
self.assertEqual(web_m2x_options["web_m2x_options.search_more"], "False")
self.assertTrue(bool(web_m2x_options["web_m2x_options.m2o_dialog"]))