[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. 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 Usage
===== =====
@ -87,7 +222,7 @@ Other example for 'purchase.order.line' fields:
nolabel="1" nolabel="1"
widget="one2many_product_picker" widget="one2many_product_picker"
mode="form" 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> <form>
<field name="name" invisible="1" /> <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 * 'all' > Is the hard-coded name for the 'All' group
* 'main_lines' > Is the hard-coded name for the 'Lines' 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: 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 * 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 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 * 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" nolabel="1"
widget="one2many_product_picker" widget="one2many_product_picker"
mode="form" 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> <form>
<field name="name" invisible="1" /> <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 * 'all' > Is the hard-coded name for the 'All' group
* 'main_lines' > Is the hard-coded name for the 'Lines' 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: Preview:
~~~~~~~~ ~~~~~~~~

View File

@ -372,28 +372,194 @@ ul.auto-toc {
<p><strong>Table of contents</strong></p> <p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents"> <div class="contents local topic" id="contents">
<ul class="simple"> <ul class="simple">
<li><a class="reference internal" href="#installation" id="id1">Installation</a></li> <li><a class="reference internal" href="#installation" id="id2">Installation</a></li>
<li><a class="reference internal" href="#usage" id="id2">Usage</a><ul> <li><a class="reference internal" href="#configuration" id="id3">Configuration</a><ul>
<li><a class="reference internal" href="#default-context" id="id3">Default context:</a></li> <li><a class="reference internal" href="#widget-options" id="id4">Widget options:</a></li>
<li><a class="reference internal" href="#preview" id="id4">Preview:</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> </ul>
</li> </li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id5">Known issues / Roadmap</a></li> <li><a class="reference internal" href="#usage" id="id7">Usage</a><ul>
<li><a class="reference internal" href="#bug-tracker" id="id6">Bug Tracker</a></li> <li><a class="reference internal" href="#id1" id="id8">Default context:</a></li>
<li><a class="reference internal" href="#credits" id="id7">Credits</a><ul> <li><a class="reference internal" href="#preview" id="id9">Preview:</a></li>
<li><a class="reference internal" href="#authors" id="id8">Authors</a></li> </ul>
<li><a class="reference internal" href="#contributors" id="id9">Contributors</a></li> </li>
<li><a class="reference internal" href="#maintainers" id="id10">Maintainers</a></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> </ul>
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="installation"> <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> <p>Its advisable to install web_widget_numeric_step to have a better usability on touch screens.</p>
</div> </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"> <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. <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> This is an example that uses the sale.order.line fields:</p>
<pre class="code xml literal-block"> <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">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">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">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">&gt;</span>
<span class="nt">&lt;form&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;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> <span class="nt">&lt;/field&gt;</span>
</pre> </pre>
<p>** In this example we dont use field_map option because the default match with the sale.order.line field names.</p> <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"> <div class="section" id="id1">
<h2><a class="toc-backref" href="#id3">Default context:</a></h2> <h2><a class="toc-backref" href="#id8">Default context:</a></h2>
<p>The widget sends a defaults context with the search_read request:</p> <p>The widget sends a defaults context with the search_read request:</p>
<blockquote> <blockquote>
<ul> <ul>
@ -464,25 +630,34 @@ This is an example that uses the sale.order.line fields:</p>
</ul> </ul>
</blockquote> </blockquote>
</li> </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> </ul>
</blockquote> </blockquote>
</div> </div>
<div class="section" id="preview"> <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> <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" /> <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> </blockquote>
</div> </div>
</div> </div>
<div class="section" id="known-issues-roadmap"> <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"> <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>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> </ul>
</div> </div>
<div class="section" id="bug-tracker"> <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>. <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. 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 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> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <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"> <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"> <ul class="simple">
<li>Tecnativa</li> <li>Tecnativa</li>
</ul> </ul>
</div> </div>
<div class="section" id="contributors"> <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> <ul>
<li><p class="first"><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:</p> <li><p class="first"><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:</p>
<blockquote> <blockquote>
@ -512,7 +687,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
</ul> </ul>
</div> </div>
<div class="section" id="maintainers"> <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> <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> <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 <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(); this._updateButtons();
} else { } else {
this.update({}, {reload: false}).then(function(){ this.update({}, {reload: false}).then(function(){
debugger;
self.model.unsetDirty(self.handle); self.model.unsetDirty(self.handle);
self.trigger_up("restore_flip_card"); self.trigger_up("restore_flip_card");
self._updateButtons(); 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 tools = require("web_widget_one2many_product_picker.tools");
var ProductPickerQuickModifPriceForm = require( var ProductPickerQuickModifPriceForm = require(
"web_widget_one2many_product_picker.ProductPickerQuickModifPriceForm"); "web_widget_one2many_product_picker.ProductPickerQuickModifPriceForm");
var ProductPickerQuickCreateForm = require(
"web_widget_one2many_product_picker.ProductPickerQuickCreateForm");
var qweb = core.qweb; var qweb = core.qweb;

View File

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