[IMP] web_widget_one2many_product_picker: Modify rpc request context

pull/1858/head
Alexandre D. Díaz 2020-12-09 15:08:20 +01:00
parent 148b60b6fb
commit f36b75005d
10 changed files with 495 additions and 79 deletions

View File

@ -37,6 +37,141 @@ Installation
It's advisable to install 'web_widget_numeric_step' to have a better usability on touch screens.
Configuration
=============
Create or edit a new view and use the new widget called 'one2many_product_picker'.
You need to define the view fields. The view must be of ``form`` type.
Widget options:
~~~~~~~~~~~~~~~
* product_per_page > Integer -> Used to control the load more behaviour (16 by default)
* groups > Array of dictionaries -> Declare the groups
* name -> The group name
* string -> The text displayed
* domain -> Forced domain to use
* order -> The order
* name -> The field name to order
* asc -> Flag to use 'asc' order
* currency_field > Model field used to format monetary values ('currency_id' by default)
* field_map > Dictionary:
* product -> The field that represent the product (`product_id` by default)
* name -> The field that represent a name ('name' by default)
* product_uom -> The field that represent a product_uom ('product_uom' by default)
* product_uom_qty -> The field that represent a product_uom_qty ('product_uom_qty' by default)
* price_unit -> The field that represent a price_unit ('price_unit' by default)
* discount -> The field that represent a discount ('discount' by default)
* search > Array of dictionaries or Array of 'triplets' ([[field_map.name, 'ilike', '$search']] by default)
* name -> The name to display
* domain -> The domain to use
* $search -> Replaces it with the current value of the searchbox
* $number_search -> Replaces all the leaf with the current value of the searchbox as a number
* edit_discount > Enable/Disable discount edits (False by default)
* edit_price > Enable/Disable price edits (True by default)
* show_discount > Enable/Disable display discount (False by default)
* show_subtotal > Enable/Disable show subtotal (True by default)
All widget options are optional.
Notice that you can call '_' method to use translations. This only can be used with this widget.
Example:
.. code::
options="{'search': [{'name': _('Starts With'), 'domain': [('name', '=like', '$search%')]}], 'groups': [{'name': 'cheap', 'string': _('Cheap'), 'domain': [('list_price', '<', 10.0)], 'field_map': { 'product': 'my_product_id' }}]}"
Default context:
~~~~~~~~~~~~~~~~
The widget sends a defaults context with the 'search_read' request:
* active_search_group_name > Contains the name of the active search group
* 'all' > Is the hard-coded name for the 'All' group
* 'main_lines' > Is the hard-coded name for the 'Lines' group
* active_search_involved_fields > Contains an array of dictionaries with the fields used with the searchbox content
* 'type' > Can be 'text' or 'number'
* 'field' > The field name
* 'oper' > The operator used
Examples:
~~~~~~~~~
This is an example that uses the 'sale.order.line' fields:
.. code:: xml
<field
name="order_line"
attrs="{'readonly': [('state', 'in', ('done','cancel'))]}"
nolabel="1"
mode="form"
widget="one2many_product_picker"
options="{'search': [{'name': 'Test', 'domain': [['name', 'ilike', '$search']]}] ,'edit_discount': True, 'show_discount': True, 'groups': [{'name': 'desk', 'string': _('Desks'), 'domain': [('name', 'ilike', '%desk%')], 'order': [{'name': 'id', 'asc': true}]}, {'name': 'chair', 'string': _('Chairs'), 'domain': [('name', 'ilike', '%chair%')]}]}"
>
<form>
<field name="state" invisible="1" />
<field name="display_type" invisible="1" />
<field name="currency_id" invisible="1" />
<field name="discount" widget="numeric_step" options="{'max': 100}" invisible="1"/>
<field name="price_unit" widget="numeric_step" invisible="1"/>
<field name="name" invisible="1" />
<field name="product_id" invisible="1" />
<field name="order_id" invisible="1"/>
<field name="product_uom_qty" class="mb-1" widget="numeric_step" context="{
'partner_id': parent.partner_id,
'quantity': product_uom_qty,
'pricelist': parent.pricelist_id,
'uom': product_uom,
'company_id': parent.company_id
}" />
<field name="product_uom" force_save="1" attrs="{
'readonly': [('state', 'in', ('sale','done', 'cancel'))],
'required': [('display_type', '=', False)],
}" context="{'company_id': parent.company_id}" class="mb-2" options="{'no_open': True, 'no_create': True, 'no_edit': True}" />
</form>
</field>
** In this example we don't use 'field_map' option because the default match with the sale.order.line field names.
Other example for 'purchase.order.line' fields:
.. code:: xml
<field
name="order_line"
attrs="{'readonly': [('state', 'in', ('done','cancel'))]}"
nolabel="1"
widget="one2many_product_picker"
mode="form"
options="{'search': [{'name': _('Name'), 'domain': [['name', 'ilike', '$search']]}, {'name': _('Price'), 'domain': [['list_price', '=', $number_search]]}], 'field_map': {'product_uom_qty': 'product_qty'}, 'groups': [{'name': _('Desk'), 'domain': [['name', 'ilike', 'desk']], 'order': {'name': 'id', 'asc': true}}, {'name': _('Chairs'), 'domain': [['name', 'ilike', 'chair']]}]}"
>
<form>
<field name="name" invisible="1" />
<field name="product_id" invisible="1" />
<field name="price_unit" invisible="1" />
<field name="currency_id" invisible="1" />
<field name="order_id" invisible="1" />
<field name="date_planned" class="mb-1" />
<field name="product_qty" class="mb-1" widget="numeric_step" required="1" />
<field name="product_uom" class="mb-2" options="{'no_open': True, 'no_create': True, 'no_edit': True}" />
</form>
</field>
Usage
=====
@ -87,7 +222,7 @@ Other example for 'purchase.order.line' fields:
nolabel="1"
widget="one2many_product_picker"
mode="form"
options="{'search': [{'name': _('Name'), 'domain': [['name', 'ilike', '$search']]}, {'name': _('Price'), 'domain': [['list_price', '=', $number_search]]}], 'field_map': {'name': 'name', 'product': 'product_id', 'product_uom': 'product_uom', 'price': 'price_unit', 'parent_id': 'order_id', 'product_uom_qty': 'product_qty'}, 'groups': [{'name': _('Desk'), 'domain': [['name', 'ilike', 'desk']], 'order': {'name': 'id', 'asc': true}}, {'name': _('Chairs'), 'domain': [['name', 'ilike', 'chair']]}]}"
options="{'search': [{'name': _('Name'), 'domain': [['name', 'ilike', '$search']]}, {'name': _('Price'), 'domain': [['list_price', '=', $number_search]]}], 'field_map': {'product_uom_qty': 'product_qty'}, 'groups': [{'name': _('Desk'), 'domain': [['name', 'ilike', 'desk']], 'order': {'name': 'id', 'asc': true}}, {'name': _('Chairs'), 'domain': [['name', 'ilike', 'chair']]}]}"
>
<form>
<field name="name" invisible="1" />
@ -114,6 +249,12 @@ The widget sends a defaults context with the 'search_read' request:
* 'all' > Is the hard-coded name for the 'All' group
* 'main_lines' > Is the hard-coded name for the 'Lines' group
* active_search_involved_fields > Contains an array of dictionaries with the fields used with the searchbox content
* 'type' > Can be 'text' or 'number'
* 'field' > The field name
* 'oper' > The operator used
Preview:
~~~~~~~~
@ -124,7 +265,7 @@ Known issues / Roadmap
======================
* Translations in the xml 'options' attribute of the field that use the widget can't be exported automatically to be translated
* The product card animations can be improved. Currently the card is recreated, so we lost some states to apply correct effects.
* The product card animations can be improved. Currently the card is recreated, so we lost some elements to apply correct effects.
Bug Tracker
===========

View File

@ -1,47 +0,0 @@
Create or edit a new view and use the new widget called 'one2many_product_picker'.
Widget options:
~~~~~~~~~~~~~~~
* product_per_page > Integer -> Used to control the load more behaviour (16 by default)
* groups > Array of dictionaries -> Declare the groups
* name -> The group name
* string -> The text displayed
* domain -> Forced domain to use
* order -> The order
* name -> The field name to order
* asc -> Flag to use 'asc' order
* currency_field > Model field used to format monetary values ('currency_id' by default)
* field_map > Dictionary:
* product -> The field that represent the product (`product_id` by default)
* name -> The field that represent a name ('name' by default)
* product_uom -> The field that represent a product_uom ('product_uom' by default)
* product_uom_qty -> The field that represent a product_uom_qty ('product_uom_qty' by default)
* price_unit -> The field that represent a price_unit ('price_unit' by default)
* discount -> The field that represent a discount ('discount' by default)
* search > Array of dictionaries or Array of 'triplets' ([[field_map.name, 'ilike', '$search']] by default)
* name -> The name to display
* domain -> The domain to use
* $search -> Replaces it with the current value of the searchbox
* $number_search -> Replaces all the leaf with the current value of the searchbox as a number
* edit_discount > Enable/Disable discount edits (False by default)
* edit_price > Enable/Disable price edits (True by default)
* show_discount > Enable/Disable display discount (False by default)
* show_subtotal > Enable/Disable show subtotal (True by default)
All widget options are optional.
Notice that you can call '_' method to use translations. This only can be used with this widget.
Example:
.. code::
options="{'search': [{'name': _('Starts With'), 'domain': [('name', '=like', '$search%')]}], 'groups': [{'name': 'cheap', 'string': _('Cheap'), 'domain': [('list_price', '<', 10.0)], 'field_map': { 'product': 'my_product_id' }}]}"

View File

@ -1 +0,0 @@
It's recommendable install 'web_widget_numeric_step' to have a better usability on touch screens.

View File

@ -0,0 +1,131 @@
Create or edit a new view and use the new widget called 'one2many_product_picker'.
You need to define the view fields. The view must be of ``form`` type.
Widget options:
~~~~~~~~~~~~~~~
* product_per_page > Integer -> Used to control the load more behaviour (16 by default)
* groups > Array of dictionaries -> Declare the groups
* name -> The group name
* string -> The text displayed
* domain -> Forced domain to use
* order -> The order
* name -> The field name to order
* asc -> Flag to use 'asc' order
* currency_field > Model field used to format monetary values ('currency_id' by default)
* field_map > Dictionary:
* product -> The field that represent the product (`product_id` by default)
* name -> The field that represent a name ('name' by default)
* product_uom -> The field that represent a product_uom ('product_uom' by default)
* product_uom_qty -> The field that represent a product_uom_qty ('product_uom_qty' by default)
* price_unit -> The field that represent a price_unit ('price_unit' by default)
* discount -> The field that represent a discount ('discount' by default)
* search > Array of dictionaries or Array of 'triplets' ([[field_map.name, 'ilike', '$search']] by default)
* name -> The name to display
* domain -> The domain to use
* $search -> Replaces it with the current value of the searchbox
* $number_search -> Replaces all the leaf with the current value of the searchbox as a number
* edit_discount > Enable/Disable discount edits (False by default)
* edit_price > Enable/Disable price edits (True by default)
* show_discount > Enable/Disable display discount (False by default)
* show_subtotal > Enable/Disable show subtotal (True by default)
All widget options are optional.
Notice that you can call '_' method to use translations. This only can be used with this widget.
Example:
.. code::
options="{'search': [{'name': _('Starts With'), 'domain': [('name', '=like', '$search%')]}], 'groups': [{'name': 'cheap', 'string': _('Cheap'), 'domain': [('list_price', '<', 10.0)], 'field_map': { 'product': 'my_product_id' }}]}"
Default context:
~~~~~~~~~~~~~~~~
The widget sends a defaults context with the 'search_read' request:
* active_search_group_name > Contains the name of the active search group
* 'all' > Is the hard-coded name for the 'All' group
* 'main_lines' > Is the hard-coded name for the 'Lines' group
* active_search_involved_fields > Contains an array of dictionaries with the fields used with the searchbox content
* 'type' > Can be 'text' or 'number'
* 'field' > The field name
* 'oper' > The operator used
Examples:
~~~~~~~~~
This is an example that uses the 'sale.order.line' fields:
.. code:: xml
<field
name="order_line"
attrs="{'readonly': [('state', 'in', ('done','cancel'))]}"
nolabel="1"
mode="form"
widget="one2many_product_picker"
options="{'search': [{'name': 'Test', 'domain': [['name', 'ilike', '$search']]}] ,'edit_discount': True, 'show_discount': True, 'groups': [{'name': 'desk', 'string': _('Desks'), 'domain': [('name', 'ilike', '%desk%')], 'order': [{'name': 'id', 'asc': true}]}, {'name': 'chair', 'string': _('Chairs'), 'domain': [('name', 'ilike', '%chair%')]}]}"
>
<form>
<field name="state" invisible="1" />
<field name="display_type" invisible="1" />
<field name="currency_id" invisible="1" />
<field name="discount" widget="numeric_step" options="{'max': 100}" invisible="1"/>
<field name="price_unit" widget="numeric_step" invisible="1"/>
<field name="name" invisible="1" />
<field name="product_id" invisible="1" />
<field name="order_id" invisible="1"/>
<field name="product_uom_qty" class="mb-1" widget="numeric_step" context="{
'partner_id': parent.partner_id,
'quantity': product_uom_qty,
'pricelist': parent.pricelist_id,
'uom': product_uom,
'company_id': parent.company_id
}" />
<field name="product_uom" force_save="1" attrs="{
'readonly': [('state', 'in', ('sale','done', 'cancel'))],
'required': [('display_type', '=', False)],
}" context="{'company_id': parent.company_id}" class="mb-2" options="{'no_open': True, 'no_create': True, 'no_edit': True}" />
</form>
</field>
** In this example we don't use 'field_map' option because the default match with the sale.order.line field names.
Other example for 'purchase.order.line' fields:
.. code:: xml
<field
name="order_line"
attrs="{'readonly': [('state', 'in', ('done','cancel'))]}"
nolabel="1"
widget="one2many_product_picker"
mode="form"
options="{'search': [{'name': _('Name'), 'domain': [['name', 'ilike', '$search']]}, {'name': _('Price'), 'domain': [['list_price', '=', $number_search]]}], 'field_map': {'product_uom_qty': 'product_qty'}, 'groups': [{'name': _('Desk'), 'domain': [['name', 'ilike', 'desk']], 'order': {'name': 'id', 'asc': true}}, {'name': _('Chairs'), 'domain': [['name', 'ilike', 'chair']]}]}"
>
<form>
<field name="name" invisible="1" />
<field name="product_id" invisible="1" />
<field name="price_unit" invisible="1" />
<field name="currency_id" invisible="1" />
<field name="order_id" invisible="1" />
<field name="date_planned" class="mb-1" />
<field name="product_qty" class="mb-1" widget="numeric_step" required="1" />
<field name="product_uom" class="mb-2" options="{'no_open': True, 'no_create': True, 'no_edit': True}" />
</form>
</field>

View File

@ -1,2 +1,2 @@
* Translations in the xml 'options' attribute of the field that use the widget can't be exported automatically to be translated
* The product card animations can be improved. Currently the card is recreated, so we lost some states to apply correct effects.
* The product card animations can be improved. Currently the card is recreated, so we lost some elements to apply correct effects.

View File

@ -45,7 +45,7 @@ Other example for 'purchase.order.line' fields:
nolabel="1"
widget="one2many_product_picker"
mode="form"
options="{'search': [{'name': _('Name'), 'domain': [['name', 'ilike', '$search']]}, {'name': _('Price'), 'domain': [['list_price', '=', $number_search]]}], 'field_map': {'name': 'name', 'product': 'product_id', 'product_uom': 'product_uom', 'price': 'price_unit', 'parent_id': 'order_id', 'product_uom_qty': 'product_qty'}, 'groups': [{'name': _('Desk'), 'domain': [['name', 'ilike', 'desk']], 'order': {'name': 'id', 'asc': true}}, {'name': _('Chairs'), 'domain': [['name', 'ilike', 'chair']]}]}"
options="{'search': [{'name': _('Name'), 'domain': [['name', 'ilike', '$search']]}, {'name': _('Price'), 'domain': [['list_price', '=', $number_search]]}], 'field_map': {'product_uom_qty': 'product_qty'}, 'groups': [{'name': _('Desk'), 'domain': [['name', 'ilike', 'desk']], 'order': {'name': 'id', 'asc': true}}, {'name': _('Chairs'), 'domain': [['name', 'ilike', 'chair']]}]}"
>
<form>
<field name="name" invisible="1" />
@ -72,6 +72,12 @@ The widget sends a defaults context with the 'search_read' request:
* 'all' > Is the hard-coded name for the 'All' group
* 'main_lines' > Is the hard-coded name for the 'Lines' group
* active_search_involved_fields > Contains an array of dictionaries with the fields used with the searchbox content
* 'type' > Can be 'text' or 'number'
* 'field' > The field name
* 'oper' > The operator used
Preview:
~~~~~~~~

View File

@ -372,28 +372,194 @@ ul.auto-toc {
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="id1">Installation</a></li>
<li><a class="reference internal" href="#usage" id="id2">Usage</a><ul>
<li><a class="reference internal" href="#default-context" id="id3">Default context:</a></li>
<li><a class="reference internal" href="#preview" id="id4">Preview:</a></li>
<li><a class="reference internal" href="#installation" id="id2">Installation</a></li>
<li><a class="reference internal" href="#configuration" id="id3">Configuration</a><ul>
<li><a class="reference internal" href="#widget-options" id="id4">Widget options:</a></li>
<li><a class="reference internal" href="#default-context" id="id5">Default context:</a></li>
<li><a class="reference internal" href="#examples" id="id6">Examples:</a></li>
</ul>
</li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id5">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id6">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id7">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id8">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id9">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id10">Maintainers</a></li>
<li><a class="reference internal" href="#usage" id="id7">Usage</a><ul>
<li><a class="reference internal" href="#id1" id="id8">Default context:</a></li>
<li><a class="reference internal" href="#preview" id="id9">Preview:</a></li>
</ul>
</li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id10">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id11">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id12">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id13">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id14">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id15">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="installation">
<h1><a class="toc-backref" href="#id1">Installation</a></h1>
<h1><a class="toc-backref" href="#id2">Installation</a></h1>
<p>Its advisable to install web_widget_numeric_step to have a better usability on touch screens.</p>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#id3">Configuration</a></h1>
<p>Create or edit a new view and use the new widget called one2many_product_picker.
You need to define the view fields. The view must be of <tt class="docutils literal">form</tt> type.</p>
<div class="section" id="widget-options">
<h2><a class="toc-backref" href="#id4">Widget options:</a></h2>
<ul>
<li><p class="first">product_per_page &gt; Integer -&gt; Used to control the load more behaviour (16 by default)</p>
</li>
<li><p class="first">groups &gt; Array of dictionaries -&gt; Declare the groups</p>
<blockquote>
<ul>
<li><p class="first">name -&gt; The group name</p>
</li>
<li><p class="first">string -&gt; The text displayed</p>
</li>
<li><p class="first">domain -&gt; Forced domain to use</p>
</li>
<li><p class="first">order -&gt; The order</p>
<blockquote>
<ul class="simple">
<li>name -&gt; The field name to order</li>
<li>asc -&gt; Flag to use asc order</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
</li>
<li><p class="first">currency_field &gt; Model field used to format monetary values (currency_id by default)</p>
</li>
<li><p class="first">field_map &gt; Dictionary:</p>
<blockquote>
<ul class="simple">
<li>product -&gt; The field that represent the product (<cite>product_id</cite> by default)</li>
<li>name -&gt; The field that represent a name (name by default)</li>
<li>product_uom -&gt; The field that represent a product_uom (product_uom by default)</li>
<li>product_uom_qty -&gt; The field that represent a product_uom_qty (product_uom_qty by default)</li>
<li>price_unit -&gt; The field that represent a price_unit (price_unit by default)</li>
<li>discount -&gt; The field that represent a discount (discount by default)</li>
</ul>
</blockquote>
</li>
<li><p class="first">search &gt; Array of dictionaries or Array of triplets ([[field_map.name, ilike, $search]] by default)</p>
<blockquote>
<ul>
<li><p class="first">name -&gt; The name to display</p>
</li>
<li><p class="first">domain -&gt; The domain to use</p>
<blockquote>
<ul class="simple">
<li>$search -&gt; Replaces it with the current value of the searchbox</li>
<li>$number_search -&gt; Replaces all the leaf with the current value of the searchbox as a number</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
</li>
<li><p class="first">edit_discount &gt; Enable/Disable discount edits (False by default)</p>
</li>
<li><p class="first">edit_price &gt; Enable/Disable price edits (True by default)</p>
</li>
<li><p class="first">show_discount &gt; Enable/Disable display discount (False by default)</p>
</li>
<li><p class="first">show_subtotal &gt; Enable/Disable show subtotal (True by default)</p>
</li>
</ul>
<p>All widget options are optional.
Notice that you can call _ method to use translations. This only can be used with this widget.</p>
<p>Example:</p>
<pre class="code literal-block">
options=&quot;{'search': [{'name': _('Starts With'), 'domain': [('name', '=like', '$search%')]}], 'groups': [{'name': 'cheap', 'string': _('Cheap'), 'domain': [('list_price', '&lt;', 10.0)], 'field_map': { 'product': 'my_product_id' }}]}&quot;
</pre>
</div>
<div class="section" id="default-context">
<h2><a class="toc-backref" href="#id5">Default context:</a></h2>
<p>The widget sends a defaults context with the search_read request:</p>
<blockquote>
<ul>
<li><p class="first">active_search_group_name &gt; Contains the name of the active search group</p>
<blockquote>
<ul class="simple">
<li>all &gt; Is the hard-coded name for the All group</li>
<li>main_lines &gt; Is the hard-coded name for the Lines group</li>
</ul>
</blockquote>
</li>
<li><p class="first">active_search_involved_fields &gt; Contains an array of dictionaries with the fields used with the searchbox content</p>
<blockquote>
<ul class="simple">
<li>type &gt; Can be text or number</li>
<li>field &gt; The field name</li>
<li>oper &gt; The operator used</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
</div>
<div class="section" id="examples">
<h2><a class="toc-backref" href="#id6">Examples:</a></h2>
<p>This is an example that uses the sale.order.line fields:</p>
<pre class="code xml literal-block">
<span class="nt">&lt;field</span>
<span class="na">name=</span><span class="s">&quot;order_line&quot;</span>
<span class="na">attrs=</span><span class="s">&quot;{'readonly': [('state', 'in', ('done','cancel'))]}&quot;</span>
<span class="na">nolabel=</span><span class="s">&quot;1&quot;</span>
<span class="na">mode=</span><span class="s">&quot;form&quot;</span>
<span class="na">widget=</span><span class="s">&quot;one2many_product_picker&quot;</span>
<span class="na">options=</span><span class="s">&quot;{'search': [{'name': 'Test', 'domain': [['name', 'ilike', '$search']]}] ,'edit_discount': True, 'show_discount': True, 'groups': [{'name': 'desk', 'string': _('Desks'), 'domain': [('name', 'ilike', '%desk%')], 'order': [{'name': 'id', 'asc': true}]}, {'name': 'chair', 'string': _('Chairs'), 'domain': [('name', 'ilike', '%chair%')]}]}&quot;</span>
<span class="nt">&gt;</span>
<span class="nt">&lt;form&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;state&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;display_type&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;currency_id&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;discount&quot;</span> <span class="na">widget=</span><span class="s">&quot;numeric_step&quot;</span> <span class="na">options=</span><span class="s">&quot;{'max': 100}&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;price_unit&quot;</span> <span class="na">widget=</span><span class="s">&quot;numeric_step&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;name&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;product_id&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;order_id&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;product_uom_qty&quot;</span> <span class="na">class=</span><span class="s">&quot;mb-1&quot;</span> <span class="na">widget=</span><span class="s">&quot;numeric_step&quot;</span> <span class="na">context=</span><span class="s">&quot;{
'partner_id': parent.partner_id,
'quantity': product_uom_qty,
'pricelist': parent.pricelist_id,
'uom': product_uom,
'company_id': parent.company_id
}&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;product_uom&quot;</span> <span class="na">force_save=</span><span class="s">&quot;1&quot;</span> <span class="na">attrs=</span><span class="s">&quot;{
'readonly': [('state', 'in', ('sale','done', 'cancel'))],
'required': [('display_type', '=', False)],
}&quot;</span> <span class="na">context=</span><span class="s">&quot;{'company_id': parent.company_id}&quot;</span> <span class="na">class=</span><span class="s">&quot;mb-2&quot;</span> <span class="na">options=</span><span class="s">&quot;{'no_open': True, 'no_create': True, 'no_edit': True}&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/form&gt;</span>
<span class="nt">&lt;/field&gt;</span>
</pre>
<p>** In this example we dont use field_map option because the default match with the sale.order.line field names.</p>
<p>Other example for purchase.order.line fields:</p>
<pre class="code xml literal-block">
<span class="nt">&lt;field</span>
<span class="na">name=</span><span class="s">&quot;order_line&quot;</span>
<span class="na">attrs=</span><span class="s">&quot;{'readonly': [('state', 'in', ('done','cancel'))]}&quot;</span>
<span class="na">nolabel=</span><span class="s">&quot;1&quot;</span>
<span class="na">widget=</span><span class="s">&quot;one2many_product_picker&quot;</span>
<span class="na">mode=</span><span class="s">&quot;form&quot;</span>
<span class="na">options=</span><span class="s">&quot;{'search': [{'name': _('Name'), 'domain': [['name', 'ilike', '$search']]}, {'name': _('Price'), 'domain': [['list_price', '=', $number_search]]}], 'field_map': {'product_uom_qty': 'product_qty'}, 'groups': [{'name': _('Desk'), 'domain': [['name', 'ilike', 'desk']], 'order': {'name': 'id', 'asc': true}}, {'name': _('Chairs'), 'domain': [['name', 'ilike', 'chair']]}]}&quot;</span>
<span class="nt">&gt;</span>
<span class="nt">&lt;form&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;name&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;product_id&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;price_unit&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;currency_id&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;order_id&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;date_planned&quot;</span> <span class="na">class=</span><span class="s">&quot;mb-1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;product_qty&quot;</span> <span class="na">class=</span><span class="s">&quot;mb-1&quot;</span> <span class="na">widget=</span><span class="s">&quot;numeric_step&quot;</span> <span class="na">required=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;product_uom&quot;</span> <span class="na">class=</span><span class="s">&quot;mb-2&quot;</span> <span class="na">options=</span><span class="s">&quot;{'no_open': True, 'no_create': True, 'no_edit': True}&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/form&gt;</span>
<span class="nt">&lt;/field&gt;</span>
</pre>
</div>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id2">Usage</a></h1>
<h1><a class="toc-backref" href="#id7">Usage</a></h1>
<p>You need to define the view fields. The view must be of <tt class="docutils literal">form</tt> type.
This is an example that uses the sale.order.line fields:</p>
<pre class="code xml literal-block">
@ -436,7 +602,7 @@ This is an example that uses the sale.order.line fields:</p>
<span class="na">nolabel=</span><span class="s">&quot;1&quot;</span>
<span class="na">widget=</span><span class="s">&quot;one2many_product_picker&quot;</span>
<span class="na">mode=</span><span class="s">&quot;form&quot;</span>
<span class="na">options=</span><span class="s">&quot;{'search': [{'name': _('Name'), 'domain': [['name', 'ilike', '$search']]}, {'name': _('Price'), 'domain': [['list_price', '=', $number_search]]}], 'field_map': {'name': 'name', 'product': 'product_id', 'product_uom': 'product_uom', 'price': 'price_unit', 'parent_id': 'order_id', 'product_uom_qty': 'product_qty'}, 'groups': [{'name': _('Desk'), 'domain': [['name', 'ilike', 'desk']], 'order': {'name': 'id', 'asc': true}}, {'name': _('Chairs'), 'domain': [['name', 'ilike', 'chair']]}]}&quot;</span>
<span class="na">options=</span><span class="s">&quot;{'search': [{'name': _('Name'), 'domain': [['name', 'ilike', '$search']]}, {'name': _('Price'), 'domain': [['list_price', '=', $number_search]]}], 'field_map': {'product_uom_qty': 'product_qty'}, 'groups': [{'name': _('Desk'), 'domain': [['name', 'ilike', 'desk']], 'order': {'name': 'id', 'asc': true}}, {'name': _('Chairs'), 'domain': [['name', 'ilike', 'chair']]}]}&quot;</span>
<span class="nt">&gt;</span>
<span class="nt">&lt;form&gt;</span>
<span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">&quot;name&quot;</span> <span class="na">invisible=</span><span class="s">&quot;1&quot;</span> <span class="nt">/&gt;</span>
@ -451,8 +617,8 @@ This is an example that uses the sale.order.line fields:</p>
<span class="nt">&lt;/field&gt;</span>
</pre>
<p>** In this example we dont use field_map option because the default match with the sale.order.line field names.</p>
<div class="section" id="default-context">
<h2><a class="toc-backref" href="#id3">Default context:</a></h2>
<div class="section" id="id1">
<h2><a class="toc-backref" href="#id8">Default context:</a></h2>
<p>The widget sends a defaults context with the search_read request:</p>
<blockquote>
<ul>
@ -464,25 +630,34 @@ This is an example that uses the sale.order.line fields:</p>
</ul>
</blockquote>
</li>
<li><p class="first">active_search_involved_fields &gt; Contains an array of dictionaries with the fields used with the searchbox content</p>
<blockquote>
<ul class="simple">
<li>type &gt; Can be text or number</li>
<li>field &gt; The field name</li>
<li>oper &gt; The operator used</li>
</ul>
</blockquote>
</li>
</ul>
</blockquote>
</div>
<div class="section" id="preview">
<h2><a class="toc-backref" href="#id4">Preview:</a></h2>
<h2><a class="toc-backref" href="#id9">Preview:</a></h2>
<blockquote>
<img alt="https://raw.githubusercontent.com/OCA/web/12.0/web_widget_one2many_product_picker/static/img/product_picker.gif" src="https://raw.githubusercontent.com/OCA/web/12.0/web_widget_one2many_product_picker/static/img/product_picker.gif" />
</blockquote>
</div>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id5">Known issues / Roadmap</a></h1>
<h1><a class="toc-backref" href="#id10">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Translations in the xml options attribute of the field that use the widget cant be exported automatically to be translated</li>
<li>The product card animations can be improved. Currently the card is recreated, so we lost some states to apply correct effects.</li>
<li>The product card animations can be improved. Currently the card is recreated, so we lost some elements to apply correct effects.</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id6">Bug Tracker</a></h1>
<h1><a class="toc-backref" href="#id11">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
@ -490,15 +665,15 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<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="#id7">Credits</a></h1>
<h1><a class="toc-backref" href="#id12">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id8">Authors</a></h2>
<h2><a class="toc-backref" href="#id13">Authors</a></h2>
<ul class="simple">
<li>Tecnativa</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id9">Contributors</a></h2>
<h2><a class="toc-backref" href="#id14">Contributors</a></h2>
<ul>
<li><p class="first"><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:</p>
<blockquote>
@ -512,7 +687,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id10">Maintainers</a></h2>
<h2><a class="toc-backref" href="#id15">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose

View File

@ -259,7 +259,6 @@ odoo.define("web_widget_one2many_product_picker.ProductPickerQuickCreateFormView
this._updateButtons();
} else {
this.update({}, {reload: false}).then(function(){
debugger;
self.model.unsetDirty(self.handle);
self.trigger_up("restore_flip_card");
self._updateButtons();

View File

@ -13,8 +13,6 @@ odoo.define("web_widget_one2many_product_picker.One2ManyProductPickerRecord", fu
var tools = require("web_widget_one2many_product_picker.tools");
var ProductPickerQuickModifPriceForm = require(
"web_widget_one2many_product_picker.ProductPickerQuickModifPriceForm");
var ProductPickerQuickCreateForm = require(
"web_widget_one2many_product_picker.ProductPickerQuickCreateForm");
var qweb = core.qweb;

View File

@ -302,6 +302,7 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
var soptions = options || {};
var context = _.extend({
'active_search_group_name': this._activeSearchGroup.name,
'active_search_involved_fields': this._searchContext.involvedFields,
},this.state.data[this.name].getContext());
return $.Deferred(function (d) {
@ -420,6 +421,7 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
*/
_getFullSearchDomain: function (domain) {
var sdomain = _.clone(domain);
this._searchContext.involvedFields = [];
if (!sdomain) {
sdomain = _.clone(this._searchContext.domain) || [];
if (this._searchContext.text) {
@ -427,6 +429,7 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
if (!(search_domain[0] instanceof Array)) {
search_domain = search_domain[this._searchMode].domain;
}
var involved_fields = [];
// Iterate domain triplets and logic operators
for (var index in search_domain) {
var domain = _.clone(search_domain[index]);
@ -435,12 +438,23 @@ odoo.define("web_widget_one2many_product_picker.FieldOne2ManyProductPicker", fun
// Replace right leaf with the current value of the search input
if (domain[2] === "$number_search") {
domain[2] = Number(this._searchContext.text);
involved_fields.push({
type: 'number',
field: domain[0],
oper: domain[1],
});
} else if (typeof(domain[2]) === "string" && domain[2].includes("$search")) {
domain[2] = domain[2].replace(/\$search/, this._searchContext.text)
domain[2] = domain[2].replace(/\$search/, this._searchContext.text);
involved_fields.push({
type: 'text',
field: domain[0],
oper: domain[1],
});
}
}
sdomain.push(domain);
}
this._searchContext.involvedFields = involved_fields;
}
}
return sdomain || [];