web/web_widget_one2many_product...
Alexandre D. Díaz f36b75005d [IMP] web_widget_one2many_product_picker: Modify rpc request context 2021-07-29 13:40:44 +02:00
..
i18n [ADD] web_widget_one2many_product_picker 2021-07-29 13:40:44 +02:00
readme [IMP] web_widget_one2many_product_picker: Modify rpc request context 2021-07-29 13:40:44 +02:00
static [IMP] web_widget_one2many_product_picker: Modify rpc request context 2021-07-29 13:40:44 +02:00
templates [ADD] web_widget_one2many_product_picker 2021-07-29 13:40:44 +02:00
README.rst [IMP] web_widget_one2many_product_picker: Modify rpc request context 2021-07-29 13:40:44 +02:00
__init__.py [ADD] web_widget_one2many_product_picker 2021-07-29 13:40:44 +02:00
__manifest__.py [ADD] web_widget_one2many_product_picker 2021-07-29 13:40:44 +02:00

README.rst

==================================
Web Widget One2Many Product Picker
==================================

.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   !! This file is generated by oca-gen-addon-readme !!
   !! changes will be overwritten.                   !!
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
    :target: https://odoo-community.org/page/development-status
    :alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
    :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
    :alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
    :target: https://github.com/OCA/web/tree/12.0/web_widget_one2many_product_picker
    :alt: OCA/web
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
    :target: https://translation.odoo-community.org/projects/web-12-0/web-12-0-web_widget_one2many_product_picker
    :alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
    :target: https://runbot.odoo-community.org/runbot/162/12.0
    :alt: Try me on Runbot

|badge1| |badge2| |badge3| |badge4| |badge5| 

Adds the 'one2many_product_picker' friendly mobile widget to create one2many lines linked with product.product records.

**Table of contents**

.. contents::
   :local:

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
=====

You need to define the view fields. The view must be of ``form`` type.
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>


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>

** In this example we don't use 'field_map' option because the default match with the sale.order.line field names.


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


Preview:
~~~~~~~~

  .. image:: https://raw.githubusercontent.com/OCA/web/12.0/web_widget_one2many_product_picker/static/img/product_picker.gif

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 elements to apply correct effects.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_widget_one2many_product_picker%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Tecnativa

Contributors
~~~~~~~~~~~~

* `Tecnativa <https://www.tecnativa.com>`_:

    * Alexandre D. Díaz
    * Pedro M. Baeza
    * David Vidal

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
   :alt: Odoo Community Association
   :target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/web <https://github.com/OCA/web/tree/12.0/web_widget_one2many_product_picker>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.