Compare commits

...

5 Commits

Author SHA1 Message Date
Bastien Fafchamps (bafa) aec28ffc20 [FIX] web: adapted Dropdown component documentation to new api
This commit adapts the documentation to reflect changes made to the Dropdown
component after its refactor, namely:
- Adapted props list
- Adapted code snippets
- Added DropdownGroup component documentation
- More consise examples

task-id: 3266145
2024-03-20 15:17:55 +01:00
KC (ksc) 7612732f7f [IMP] subscriptions: products fix misleading info
closes odoo/documentation#6818

X-original-commit: ff2cabf621
Signed-off-by: Zachary Straub (zst) <zst@odoo.com>
2023-12-07 03:31:02 +00:00
Zachary Straub (ZST) f08db8544a [IMP] sales: update quote_template for 16
closes odoo/documentation#6804

X-original-commit: 675eaa8068
Signed-off-by: Zachary Straub (zst) <zst@odoo.com>
2023-12-07 03:31:01 +00:00
KC (ksc) de4795724b [IMP] sales: update orders and variants for 16
closes odoo/documentation#6810

X-original-commit: af7c7afa34
Signed-off-by: Zachary Straub (zst) <zst@odoo.com>
2023-12-07 02:23:40 +00:00
Julien Castiaux 556b5c4bc3 [FIX] administration/install: wkhtmltopdf 0.12.6
Official packages for wkhtmltopdf 0.12.5 are no more released since the
release of wkhtmltopdf 0.12.6 in 2020. Debian 10 "Buster" and Ubuntu
20.04 "Focal" were the last system for which 0.12.5 was built[^1].
Installing 0.12.5 on a Ubuntu 22.04 "Jammy" (using the Focal package)
fails for outdated dependencies.

Official packages for wkhtmltopdf 0.12.6 are published on another
repository[^2] than 0.12.5 used to, it includes packages for 0.12.6 for
both Debian 11 "Bullseye" and Ubuntu 22.04 "Jammy". Version 0.12.6.1-r3
is compatible out-of-the-box with Odoo and has been used by runbot to
test all 16.x, 17.x and master branches for the past month.

This work makes it official that [wkhtmltopdf 0.12.6.1-r3] must be used
for Odoo 16.0 and onward.

[^1]: https://github.com/wkhtmltopdf/wkhtmltopdf/releases/tag/0.12.5
[^2]: https://github.com/wkhtmltopdf/packaging/releases
[wkhtmltopdf 0.12.6.1-r3]: https://github.com/wkhtmltopdf/packaging/releases/tag/0.12.6.1-3

closes odoo/documentation#6800

X-original-commit: e5d77ee285
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
2023-12-06 18:55:19 +00:00
42 changed files with 659 additions and 404 deletions
+4 -4
View File
@@ -54,10 +54,10 @@ Odoo needs a `PostgreSQL <https://www.postgresql.org/>`_ server to run properly.
$ sudo systemctl start postgresql
.. warning::
`wkhtmltopdf` is not installed through **pip** and must be installed manually in `version 0.12.5
<https://github.com/wkhtmltopdf/wkhtmltopdf/releases/tag/0.12.5>`_ for it to support headers and
footers. Check out the `wkhtmltopdf wiki <https://github.com/odoo/odoo/wiki/Wkhtmltopdf>`_ for
more details on the various versions.
`wkhtmltopdf` is not installed through **pip** and must be installed manually in `version 0.12.6
<https://github.com/wkhtmltopdf/packaging/releases/tag/0.12.6.1-3>`_ for it to support headers
and footers. Check out the `wkhtmltopdf wiki <https://github.com/odoo/odoo/wiki/Wkhtmltopdf>`_
for more details on the various versions.
Repository
----------
+4 -4
View File
@@ -413,10 +413,10 @@ Dependencies
$ sudo npm install -g rtlcss
.. warning::
`wkhtmltopdf` is not installed through **pip** and must be installed manually in `version 0.12.5
<https://github.com/wkhtmltopdf/wkhtmltopdf/releases/tag/0.12.5>`_ for it to support headers and
footers. Check out the `wkhtmltopdf wiki <https://github.com/odoo/odoo/wiki/Wkhtmltopdf>`_ for
more details on the various versions.
`wkhtmltopdf` is not installed through **pip** and must be installed manually in `version 0.12.6
<https://github.com/wkhtmltopdf/packaging/releases/tag/0.12.6.1-3>`_ for it to support headers
and footers. Check out the `wkhtmltopdf wiki <https://github.com/odoo/odoo/wiki/Wkhtmltopdf>`_
for more details on the various versions.
.. _install/source/running_odoo:
@@ -1,79 +1,116 @@
===================================================
Use product variants on quotations and sales orders
===================================================
===============================================
Product variants on quotations and sales orders
===============================================
Product variants can be added to quotations and sales orders using the Product Configurator,
Variant Grid Entry, or both.
Before getting into detail about how to use product variants on quotations and sales orders, it's
recommended to learn about :doc:`../products_prices/products/variants` in Odoo.
Configuration
=============
To enable product variants on quotations and sales orders, go to :menuselection:`Sales -->
Configuration --> Settings --> Product Catalog` and activate one or both of the
:guilabel:`Product Configurator` and :guilabel:`Variant Grid Entry` settings. Finally, click
:guilabel:`Save` to apply the settings.
.. image:: orders_and_variants/activating-entry-type-settings.png
:align: center
:alt: Activating entry type settings.
After saving the settings, configure the product form. Head over to :menuselection:`Sales -->
Products --> Products` and select any product (or click :guilabel:`Create` to create a new one).
On the product form, click :guilabel:`Edit`, and then click on the :guilabel:`Variants` tab. Under
:guilabel:`Sales Variant Selection`, choose either :guilabel:`Product Configurator` or
:guilabel:`Order Grid Entry`. This selection determines which method is used to add the product to
quotations or sales orders. Finally, click :guilabel:`Save` to apply the setting.
.. image:: orders_and_variants/sales-variant-selection.png
:align: center
:alt: Sales variant selection.
Once familiarized with the basics surrounding product variants, the following covers how product
variants can be added to quotations and sales orders using the *product configurator* or *order grid
entry*.
.. note::
The product must have at least two variants (one attribute with two values) created in order for
the :guilabel:`Sales Variant Selection` option to appear. Click :guilabel:`Add a line` under
:guilabel:`Attribute` to add attributes and values to this product and create product variants.
It should be noted that the setting is titled, *Variant Grid Entry* on the *Sales* app settings
page, and titled, *Order Grid Entry* on product forms. So, be sure to keep that in mind.
Use the Product Configurator
============================
Settings
========
The :guilabel:`Product Configurator` appears on a quotation or sales order when products are added
that have both variants configured and the :guilabel:`Product Configurator` option selected.
When working with product variants, Odoo uses the product configurator, by default. To add the
variant grid entry option, that feature **must** be enabled in the Odoo *Sales* application. The
variant grid entry option provides a pop-up window on the quotation/sales order to simplify the
variant selection process.
The :guilabel:`Product Configurator` lets salespeople choose exactly which product variant to add
to the quotation or sales order using a format similar to online shopping. Color options display
any HTML color codes set up in the :guilabel:`Color` attribute. Features with an additional cost
will display the additional cost next to their name. Once the desired product variant attributes
are selected, click :guilabel:`Add` to add the product variant to the quotation or sales order.
To enable that setting, go to :menuselection:`Sales app --> Configuration --> Settings`, and scroll
to the :guilabel:`Product Catalog` section. Then, check the box next to the :guilabel:`Variant Grid
Entry` option, and click :guilabel:`Save`.
.. image:: orders_and_variants/configurator-price-extras.png
.. image:: orders_and_variants/order-grid-entry-setting.png
:align: center
:alt: Product Configurator and Price Extras.
:alt: The variant grid entry setting in the Odoo Sales application.
By default, the product variant attributes are displayed on the quotation or sales order in the
:guilabel:`Description` column, but the :guilabel:`Product Variant` column can be added through the
additional options menu (3 vertical dots icon).
.. note::
Of course, the :guilabel:`Variants` feature **must** also be activated, in order to use product
variants on quotations and sales orders.
Use Variant Grid Entries
========================
Product configuration
=====================
:guilabel:`Variant Grid Entries` appear on a quotation or sales order when products are added that
have both variants configured and the :guilabel:`Order Grid Entry` option selected. Grid entry can
streamline the process of creating large, varied quotations by letting salespeople enter exact
quantities of each product variant all at once.
Once the :guilabel:`Variant Grid Entry` setting is enabled, both options (*Product Configurator* and
*Order Grid Entry*) become available on every product form.
:guilabel:`Variant Grid Entry` displays a grid of every variant available for the selected product.
Choose the exact quantities of each product variant for a quotation or sales order by typing in the
number or using the arrows. :guilabel:`Not Available` is displayed when a particular variant has
been deactivated in the database. Once all the product variants and their quantities have been set,
click :guilabel:`Confirm` to add them to the quotation or sales order.
To configure a product form to use either a product configurator or variant grid entry, start by
navigating to :menuselection:`Sales app --> Products --> Products` to view all the products in the
database.
.. image:: orders_and_variants/grid-entry-popup-amounts.png
Then, select the desired product to configure, or click :guilabel:`New`, to create a new product
from scratch. Once on the product form, click into the :guilabel:`Attributes \& Variants` tab, where
product variants can be viewed, modified, and added.
At the bottom of the :guilabel:`Attributes \& Variants` tab, there is a :guilabel:`Sales Variant
Selection` section with two options: :guilabel:`Product Configurator` and :guilabel:`Order Grid
Entry`.
.. note::
It should be noted that these options **only** appear if at least two values of an attribute have
been added to the record.
.. image:: orders_and_variants/attributes-variants-tab-selection-options.png
:align: center
:alt: Variant Grid Entry pop-up.
:alt: Sales variant selection options on the attributes and variants tab on product form.
Each product variant appears as an individual line item on the quotation or sales order, because
each of these items has its own stock.
These options determine which method is used when adding product variants to quotations or sales
orders.
.. image:: orders_and_variants/grid-variants-line-items.png
The :guilabel:`Product Configurator` provides a pop-up window that neatly displays all the available
product variants for that particular product when it's added to a quotation. However, only one
variant can be selected/added at a time.
The :guilabel:`Order Grid Entry` provides the same information as the :guilabel:`Product
Configurator` in a table layout, allowing the user to select larger numbers of unique product
variants, and add them to a quotation/sales order, in a single view.
Product configurator
====================
The product configurator feature appears as a :guilabel:`Configure` pop-up window, as soon as a
product with (at least two) variants is added to a quotation or sales order, but **only** if the
:guilabel:`Product Configurator` option is selected on its product form.
.. image:: orders_and_variants/product-configurator-window.png
:align: center
:alt: Line items for grid variants.
:alt: The product configurator pop-up window that appears on a quotation or sales order.
.. note::
This :guilabel:`Configure` pop-up window also appears if the :guilabel:`Order Grid Entry` setting
is **not** activated, as it is the default option Odoo uses when dealing with product variants on
quotations and/or sales orders.
The :guilabel:`Product Configurator` option lets salespeople choose exactly which product variant to
add to the quotation or sales order using a format similar to online shopping.
Order grid entry
================
The order grid entry feature appears as a :guilabel:`Choose Product Variants` pop-up window, as soon
as a product with (at least two) variants is added to a quotation or sales order, but **only** if
the :guilabel:`Order Grid Entry` option is selected on its product form.
.. image:: orders_and_variants/choose-product-variants-popup.png
:align: center
:alt: The choose product variants pop-up window that appears on a quotation in Odoo.
The :guilabel:`Choose Product Variants` pop-up window features all the variant options for that
particular product. From this pop-up window, the salesperson can designate how many of each variant
they'd like to add to the quotation/sales order at once.
When all the desired quantities and variants have been selected, the salesperson simply clicks
:guilabel:`Confirm`, and those orders are instantly added to the quotation/sales order in the
:guilabel:`Order Lines` tab.
.. image:: orders_and_variants/order-grid-entry-order-lines-tab.png
:align: center
:alt: Populated order lines tab after order grid entry has been chosen to select products.
.. seealso::
:doc:`../products_prices/products/variants`
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

@@ -3,9 +3,10 @@ Quotation templates
===================
In Odoo *Sales*, salespeople have the ability to create reusable quotation templates for common
product or service offerings that the business offers. By using these templates, quotations can be
tailored and sent to customers at a much faster pace, without having to create new quotations from
scratch every time a sales negotiation occurs.
products or services that the business offers.
By using these templates, quotations can be tailored and sent to customers at a much faster pace,
without having to create new quotations from scratch every time a sales negotiation occurs.
.. _sales/send_quotations/templates:
@@ -13,10 +14,10 @@ Configuration
=============
Begin by activating the setting in :menuselection:`Sales app --> Configuration --> Settings`, and
scroll to the :guilabel:`Quotations & Orders` heading.
scroll to the :guilabel:`Quotations \& Orders` heading.
In that section, check the box beside the :guilabel:`Quotation Templates` option. Doing so reveals
a new :guilabel:`Default Template` field, in which a default quotation template can be chosen from a
In that section, check the box beside the :guilabel:`Quotation Templates` option. Doing so reveals a
new :guilabel:`Default Template` field, in which a default quotation template can be chosen from a
drop-down menu.
.. image:: quote_template/quotations-templates-setting.png
@@ -24,18 +25,13 @@ drop-down menu.
:alt: How to enable quotation templates on Odoo Sales.
Also, upon activating the :guilabel:`Quotation Template` feature, an internal :guilabel:`➡️
Quotation Templates` link appears beneath the :guilabel:`Default Template` field. Clicking that link
reveals the :guilabel:`Quotation Templates` page, from which templates can be created, viewed, and
edited.
.. tip::
Consider activating the :guilabel:`PDF Quote Builder` option in the :guilabel:`Settings`, as
well, which is located in the right column beside the :guilabel:`Quotation Templates` option.
This feature enables the creation of beautiful quotations using various PDF.
Quotation Templates` link appears beneath the :guilabel:`Default Template` field.
Clicking that link reveals the :guilabel:`Quotation Templates` page, from which templates can be
created, viewed, and edited.
Before leaving the :guilabel:`Settings` page, don't forget to click the :guilabel:`Save` button to
activate the feature(s) and save all changes made during the session.
save all changes made during the session.
Create quotation templates
==========================
@@ -44,62 +40,234 @@ Click the :guilabel:`Quotation Templates` link on the :guilabel:`Settings` page,
:menuselection:`Sales app --> Configuration --> Quotation Templates`. Both options reveal the
:guilabel:`Quotation Templates` page, where quotation templates can be created, viewed, and edited.
To create a new quotation template, click the :guilabel:`Create` button, located in the upper-left
.. image:: quote_template/quotation-templates-page.png
:align: center
:alt: Quotation templates page in the Odoo Sales application.
To create a new quotation template, click the :guilabel:`New` button, located in the upper-left
corner. Doing so reveals a blank quotation template form that can be customized in a number of ways.
.. image:: quote_template/blank-quotation-template.png
.. image:: quote_template/blank-quotation-form.png
:align: center
:alt: Create a new quotation template on Odoo Sales.
Start by entering a name for the template in the :guilabel:`Quotation Template` field. Then, in the
:guilabel:`Quotation expires after` field, designate how many days the quotation template will
remain valid for, or leave the field on the default `0` to keep the template valid indefinitely.
Start by entering a name for the template in the :guilabel:`Quotation Template` field.
In the :guilabel:`Company` field, designate to which company this quotation template applies, if
working in a multi-company environment.
Then, in the :guilabel:`Quotation expires after` field, designate how many days the quotation
template will remain valid for, or leave the field on the default `0` to keep the template valid
indefinitely.
Beneath those fields are three tabs: :guilabel:`Lines`, :guilabel:`Optional Products`,
:guilabel:`Confirmation`.
If the :guilabel:`Online Signature` and/or :guilabel:`Online Payment` features are activated in the
:guilabel:`Settings` (:menuselection:`Sales app --> Configuration --> Settings`), those options are
available in the :guilabel:`Online confirmation` field.
In the :guilabel:`Online confirmation` field, check the box beside :guilabel:`Signature` to request
an online signature from the customer to confirm an order. Check the box beside :guilabel:`Payment`
to request an online payment from the customer to confirm an order.
Both options can be enabled simultaneously, in which case the customer must provide **both** a
signature **and** a payment to confirm an order.
Next, in the :guilabel:`Confirmation Mail` field, click the blank field to reveal a drop-down menu.
From the drop-down menu, select a pre-configured email template to be sent to customers upon
confirmation of an order.
.. tip::
To create a new email template directly from the :guilabel:`Confirmation Mail` field, start
typing the name of the new email template in the field, and select either: :guilabel:`Create` or
:guilabel:`Create and edit...` from the drop-down menu that appears.
Selecting :guilabel:`Create` creates the email template, which can be edited later. Selecting
:guilabel:`Create and edit...` creates the email template, and a :guilabel:`Create Confirmation
Mail` pop-up window appears, in which the email template can be customized and configured right
away.
.. image:: quote_template/create-confirmation-mail-popup.png
:align: center
:alt: Create confirmation mail pop-up window from the quotation template form in Odoo Sales.
When all modifications are complete, click :guilabel:`Save \& Close` to save the email template
and return to the quotation form.
If working in a multi-company environment, use the :guilabel:`Company` field to designate to which
company this quotation template applies.
In the :guilabel:`Recurrence` field, choose from a variety of pre-configured amounts of time (e.g.
:guilabel:`Monthly`, :guilabel:`Quarterly`) to designate how often this quotation template should
occur.
.. note::
The :guilabel:`Recurrence` field **only** applies to subscription plans. For more information,
check out the documentation on :doc:`../../subscriptions/plans`.
Lines tab
---------
In the :guilabel:`Lines` tab, products can be added to the quotation template by clicking
:guilabel:`Add a product`, organized by clicking `Add a section` (and dragging/dropping section
headers accordingly), and further explained with discretionary information (such as warranty
details, terms, etc.) by clicking :guilabel:`Add a note`.
:guilabel:`Add a product`, organized by clicking :guilabel:`Add a section` (and dragging/dropping
section headers), and further explained with discretionary information (such as warranty details,
terms, etc.) by clicking :guilabel:`Add a note`.
In the :guilabel:`Optional Products` tab, :guilabel:`Add a line` for each compatible cross-selling
product related to the original items in the :guilabel:`Lines` tab, if applicable. The products
added here ideally compliment the original offering as added value for the prospective buyer.
Lastly, in the :guilabel:`Confirmation` tab, enable options, as needed, to require an
:guilabel:`Online Signature` and/or an :guilabel:`Online Payment`, which each allow buyers to
confirm orders automatically using the web portal view after the required action is taken.
There's also an option to add a :guilabel:`Confirmation Mail` to the quotation template, as well -
meaning whenever this template is used, and an order is confirmed, an email is sent to the customer
informing them that their order has been confirmed.
.. image:: quote_template/quotations-templates-confirmation-tab.png
.. image:: quote_template/lines-tab-quotation-template.png
:align: center
:alt: Allow customers to sign electronically or to pay online on Odoo Sales.
:alt: Populated lines tab on a quotation template form in Odoo Sales.
To add a product to a quotation template, click :guilabel:`Add a product` in the :guilabel:`Lines`
tab of a quotation template form. Doing so reveals a blank field in the :guilabel:`Product` column.
When clicked, a drop-down menu with existing products in the database appear. Select the desired
product from the drop-down menu to add it to the quotation template.
.. tip::
If the desired product isn't readily visible, type the name of the desired product in the
:guilabel:`Product` field, and the option appears in the drop-down menu. Products can also be
found by clicking :guilabel:`Search More...` from the drop-down menu.
.. note::
When a product is added to a quotation template, the default :guilabel:`Quantity` is `1`, but
that can be edited at any time.
Then, drag-and-drop the product to the desired position, via the :guilabel:`six squares` icon,
located to the left of each line item.
To add a *section*, which serves as a header to organize the lines of a sales order, click
:guilabel:`Add a section` in the :guilabel:`Lines` tab. When clicked, a blank field appears, in
which the desired name of the section can be typed. When the name has been entered, click away to
secure the section name.
Then, drag-and-drop the section name to the desired position, via the :guilabel:`six squares` icon,
located to the left of each line item.
To add a note, which would appear as a piece of text for the customer on the quotation, click
:guilabel:`Add a note` in the :guilabel:`Lines` tab. When clicked, a blank field appears, in which
the desired note can be typed. When the note has been entered, click away to secure the note.
Then, drag-and-drop the note to the desired position, via the :guilabel:`six squares` icon.
To delete any line item from the :guilabel:`Lines` tab (product, section, and/or note), click the
:guilabel:`🗑️ (trash can)` icon on the far-right side of the line.
Optional Products tab
---------------------
The use of *optional products* is a marketing strategy that involves the cross-selling of products
along with a core product. The aim is to offer useful and related products to customers, which may
result in an increased sale.
For instance, if a customer wants to buy a car, they have the choice to order massaging seats, as
well, or ignore the offer and simply buy the car. Presenting the choice to purchase optional
products enhances the customer experience.
Optional products appear as a section on the bottom of sales orders and eCommerce pages. Customers
can immediately add them to their online sales orders themselves, if desired.
.. image:: quote_template/optional-products-on-sales-order.png
:align: center
:alt: Optional products appearing on a typical sales order with Odoo Sales.
In the :guilabel:`Optional Products` tab, :guilabel:`Add a line` for each cross-selling product
related to the original items in the :guilabel:`Lines` tab, if applicable. The products added here
ideally complement the original offering as added value for the prospective buyer.
.. image:: quote_template/optional-products-tab-quotation-template.png
:align: center
:alt: Populated optional products tab on a quotation template in Odoo Sales.
Clicking :guilabel:`Add a line` reveals a blank field in the :guilabel:`Product` column.
When clicked, a drop-down menu with products from the database appear. Select the desired product
from the drop-down menu to add it as an optional product to the quotation template.
To delete any line item from the :guilabel:`Optional Products` tab, click the :guilabel:`🗑️ (trash
can)` icon.
.. note::
Optional products are **not** required to create a quotation template.
Terms \& Conditions tab
-----------------------
The :guilabel:`Terms \& Conditions` tab provides the opportunity to add terms and conditions to the
quotation template. To add terms and conditions, simply type (or copy/paste) the desired terms and
conditions in this tab.
.. image:: quote_template/terms-and-conditions-tab.png
:align: center
:alt: Terms and conditions tab in a quotation template form in Odoo Sales.
.. seealso::
:doc:`../../../finance/accounting/customer_invoices/terms_conditions`
.. note::
Terms and conditions are **not** required to create a quotation template.
Design quotation templates
==========================
In the upper-left corner of the quotation template form, there's a :guilabel:`Design Template`
button.
.. image:: quote_template/design-template-button.png
:align: center
:alt: Design template button in the upper-left corner of quotation template form.
When clicked, Odoo reveals a preview of the quotation template, through the Odoo *Website*
application, as it will appear on the front-end of the website to the customer.
.. note::
This feature is **only** available if the *Website* application is installed.
Odoo uses numerous blue placeholder blocks to signify where certain elements appear, and what they
contain (e.g. :guilabel:`Template Header`, :guilabel:`Product`).
To edit the content, appearance, and overall design of the quotation template via the *Website*
application, click the :guilabel:`Edit` button in the upper-right corner.
.. image:: quote_template/design-template-edit-button.png
:align: center
:alt: Design template edit button in the upper-right corner of quotation template design.
When :guilabel:`Edit` is clicked, Odoo reveals a sidebar filled with a variety of design elements
and feature-rich building blocks. These building blocks can be dragged-and-dropped anywhere on the
quotation template design.
.. image:: quote_template/design-quotation-building-blocks.png
:align: center
:alt: Design quotation template building blocks sidebar in Odoo Website.
After a block has been dropped in the desired position, it can be customized and configured to fit
any unique need, look, or style.
.. tip::
Quotation template design uses the same methodology and functionality with design building blocks
as a typical web page design with Odoo *Website*. Be sure to check out the
:doc:`../../../websites/website` documentation to learn more.
When all blocks and customizations are complete, click the :guilabel:`Save` button to put those
configurations into place.
There is also a blue banner at the top of the quotation template design with a link to quickly
return :guilabel:`Back to edit mode`. When clicked, Odoo returns to the quotation template form in
the back-end of the *Sales* application.
Use quotation templates
=======================
When creating a quotation (:menuselection:`Sales app --> Create`), choose a preconfigured template
in the :guilabel:`Quotation Template` field drop-down menu.
When creating a quotation (:menuselection:`Sales app --> New`), choose a pre-configured template in
the :guilabel:`Quotation Template` field.
.. image:: quote_template/quotations-templates-field.png
.. image:: quote_template/quotation-templates-field.png
:align: center
:alt: Select a specific template on Odoo Sales.
:alt: Quotation templates field on a standard quotation form in Odoo Sales.
To view what the customer will see, click the :guilabel:`Customer Preview` smart button to see how
the quotation template will look on the front-end of the website.
To view what the customer will see, click the :guilabel:`Preview` button at the top of the page to
see how the quotation template appears on the front-end of the website through Odoo's customer
portal.
.. tip::
Go to :menuselection:`Sales --> Configuration --> Settings` to select a :guilabel:`Default
Template`.
.. image:: quote_template/quotations-templates-preview.png
:align: center
:alt: Customer preview of a quotation template in Odoo Sales.
.. seealso::
- :doc:`/applications/sales/sales/send_quotations/get_signature_to_validate`
- :doc:`/applications/sales/sales/send_quotations/get_paid_to_validate`
- :doc:`get_signature_to_validate`
- :doc:`get_paid_to_validate`
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@@ -2,7 +2,7 @@
Subscription products
=====================
By integrating closely with the Odoo *Sales* app, the *Subscriptions* app enables users to sell
By closely integrating with the Odoo *Sales* app, the *Subscriptions* app enables users to sell
subscription products alongside regular sales products. While regular products are sold on a
one-time basis, subscription products are sold on a renewing basis, generating recurring revenue.
@@ -11,78 +11,107 @@ In Odoo, subscription products are also called *recurring* products.
Configure recurrence periods
============================
To get started with subscriptions, first make sure that the *recurrence periods* are configured as
needed.
To get started with subscriptions, the *recurrence periods* must be properly configured, as needed.
Recurrence periods are the time periods in which subscriptions renew. They designate how often the
customer pays for (and receives) subscription products.
To configure recurrence periods, go to :menuselection:`Subscriptions --> Configuration -->
Recurrence Periods`.
To configure recurrence periods, go to :menuselection:`Subscriptions app --> Configuration -->
Recurrence periods`.
The *Subscriptions* app comes with some basic recurrence periods already configured: Daily, Monthly,
Quarterly, Weekly, Yearly, 3 Years, and 5 Years. These can be edited as needed, and any number of
new recurrence periods can be added.
.. image:: products/recurrence-periods-page.png
:align: center
:alt: The recurrence periods page in Odoo Subscriptions application.
To create a new recurrence period, click :guilabel:`New` on the recurrence periods dashboard. Then,
type in the :guilabel:`Name` and :guilabel:`Duration` of the recurrence period, and select the
The *Subscriptions* app comes with some basic recurrence periods already configured:
- :guilabel:`Monthly`
- :guilabel:`Quarterly`
- :guilabel:`Weekly`
- :guilabel:`2 Weeks`
- :guilabel:`Yearly`
- :guilabel:`3 Years`
- :guilabel:`5 Years`
New recurrence periods can be added and/or edited at any time.
To create a new recurrence period, click :guilabel:`New` on the :guilabel:`Recurrence Periods` page.
Doing so reveals a blank recurrence period form.
.. image:: products/recurrence-period-form.png
:align: center
:alt: A recurrence period form in Odoo Subscriptions application.
Then, type in the :guilabel:`Name` and :guilabel:`Duration` of the recurrence period, and select the
:guilabel:`Unit` that defines the duration.
.. example::
To create a recurrence period for a subscription that will renew every two weeks, set the
:guilabel:`Duration` to `2` and the :guilabel:`Unit` to `Weeks`.
.. important::
The unit :guilabel:`Days` *cannot* be used as a recurrence period on subscriptions. The daily
recurrence is meant for rentals, and **cannot** be added on recurring subscription sales orders.
.. image:: products/recurrence-period-form.png
:align: center
:alt: A recurrence period of 2 weeks.
This limitation is there to avoid sales orders that would generate daily invoices.
Configure the product form
Product form configuration
==========================
To create a new subscription product, navigate to the :menuselection:`Subscriptions` app. Then go to
:menuselection:`Subscriptions --> Products`, and click :guilabel:`New` to create a new product.
Enter a :guilabel:`Product Name`.
To create a new subscription product, navigate to :menuselection:`Subscriptions app --> Products -->
Products`, and click :guilabel:`New`.
The :guilabel:`Product Type` for the new product is automatically set to :guilabel:`Service`.
Subscription products can be set to other types as well; however, they currently *cannot* be set to
:guilabel:`Storable Product`.
Doing so reveals a blank product form, which can be configured and customized in a number of ways.
The new product automatically has the :guilabel:`Recurring` checkbox activated. This enables Odoo to
recognize it as a subscription product. Be sure to leave the :guilabel:`Recurring` and
:guilabel:`Can be Sold` options enabled.
.. note::
By default, the :guilabel:`Recurring` option is already enabled, prompting Odoo to recognize it
as a subscription product. Be sure to leave the :guilabel:`Recurring` and :guilabel:`Can be Sold`
options enabled.
.. image:: products/recurring-product-form.png
The :guilabel:`Product Type` field is set to :guilabel:`Service` by default, as well. However,
subscription products *can* be set to other types, if needed.
.. image:: products/subscription-product-form.png
:align: center
:alt: The "Recurring" checkbox on the product form.
:alt: A basic subscription product form in Odoo Subscriptions application.
Time-based pricing
------------------
Next, configure the :guilabel:`Time-based pricing` tab on the product form.
Once the desired fields in the :guilabel:`General Information` tab have been entered, click the
:guilabel:`Time-based pricing` tab on the product form.
Click :guilabel:`Add a price` to begin defining recurring prices. In the :guilabel:`Period` column,
select a recurrence period. In the :guilabel:`Price` column, enter the price for that recurrence
period.
.. image:: products/time-based-pricing-tab.png
:align: center
:alt: The time-based pricing tab on a subscription product form in Odoo Subscriptions.
From here, click :guilabel:`Add a price` to begin defining recurring prices.
In the :guilabel:`Period` column, select a desired recurrence period. In the :guilabel:`Pricelist`
column, select a pricelist, if needed. Then, in the :guilabel:`Price` column, enter the price for
that recurrence period.
.. note::
:guilabel:`Daily` and :guilabel:`Hourly` periods cannot be used on recurring products.
:guilabel:`Daily` and :guilabel:`Hourly` periods **cannot** be used on recurring products.
Add as many lines as needed to the :guilabel:`Time-based pricing` table.
.. image:: products/validation-error-popup.png
:align: center
:alt: The validation error pop-up window that appears in Odoo Subscriptions.
.. note::
An existing product can be made into a subscription product simply by marking it as
:guilabel:`Recurring` and configuring :guilabel:`Time-based pricing` on the product form.
There is *no limit* to how many lines can be added to the :guilabel:`Time-based pricing` table.
A subscription product can still be sold as a regular product by adding it to a quotation and
.. tip::
An existing product can be made into a subscription product, simply by marking it as
:guilabel:`Recurring`, and configuring :guilabel:`Time-based pricing` on the product form.
A subscription product can still be sold as a regular product, by adding it to a quotation and
*not* selecting a :guilabel:`Recurrence` on the quotation.
Pricelists
~~~~~~~~~~
Use :doc:`pricelists </applications/sales/sales/products_prices/prices/pricing>` with subscription
products to give special pricing to customers included in pricelists. This can be configured either
in the :guilabel:`Time-based pricing` tab of the product form, or on the pricelist form in the
*Sales* app.
:doc:`Pricelists <../sales/products_prices/prices/pricing>` can be used with subscription products
to give special pricing to customers included in pricelists.
This can be configured either in the :guilabel:`Time-based pricing` tab of the product form, or on
the pricelist form in the *Sales* application.
To create recurring price rules for specific pricelists in the :guilabel:`Time-based pricing` tab of
the product form, select a pricelist in the :guilabel:`Pricelist` column.
@@ -94,13 +123,28 @@ the product form, select a pricelist in the :guilabel:`Pricelist` column.
When pricelists are added to the :guilabel:`Time-based pricing` tab, the pricelist form in the
*Sales* app is automatically updated.
Time-based pricing rules can also be configured directly on the pricelist form. To do this, go to
:menuselection:`Sales --> Products --> Pricelists` and select a pricelist (or click :guilabel:`New`
to create a new pricelist). In the :guilabel:`Time-based rules` tab, click :guilabel:`Add a line`.
Time-based pricing rules can also be configured directly on the pricelist form.
To do this, go to :menuselection:`Sales app --> Products --> Pricelists`, and select a pricelist (or
click :guilabel:`New` to create a new pricelist).
.. note::
Pricelists are also accessible through the Odoo *Subscriptions* app by following the same menu
steps.
Then, on the pricelist form, under the :guilabel:`Time-based rules` tab, click :guilabel:`Add a
line`.
.. image:: products/pricelist-form-time-based-rules-tab.png
:align: center
:alt: The time-based rules tab on a pricelist form in Odoo Sales.
Then, select a subscription product in the :guilabel:`Products` column, and select a recurrence
period in the :guilabel:`Period` column. Enter a :guilabel:`Price` for that particular product and
period. Add as many lines as needed.
period in the :guilabel:`Period` column. Lastly, enter a :guilabel:`Price` for that particular
product and period. Add as many lines as needed.
When :guilabel:`Time-based rules` are added to the pricelist form, the :guilabel:`Time-based
pricing` tab of the product form is automatically updated.
.. seealso::
:doc:`ecommerce`
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

@@ -420,271 +420,277 @@ Location
Description
~~~~~~~~~~~
Dropdowns are surprisingly complicated components. They need to provide many
features such as:
The Dropdown lets you show a menu with a list of items when a toggle is
clicked on. They can be combined with DropdownItems to invoke callbacks
and close the menu when items are selected.
Dropdowns are surprisingly complicated components, the list of features they
provide is as follow:
- Toggle the item list on click
- Direct siblings dropdowns: when one is open, toggle others on hover
- Close on outside click
- Call a function when items are selected
- Optionally close the item list when an item is selected
- Call a function when the item is selected
- Support sub dropdowns, up to any level
- SIY: style it yourself
- Support sub dropdowns, up to any level
- Configurable hotkey to open/close a dropdown or select a dropdown item
- Keyboard navigation (arrows, tab, shift+tab, home, end, enter and escape)
- Reposition itself whenever the page scrolls or is resized
- Smartly chose the direction it should open (right-to-left direction is automatically handled).
To solve these issues once and for all, the Odoo framework provides a set of two
components: a `Dropdown` component (the actual dropdown), and `DropdownItem`,
for each element in the item list.
.. code-block:: xml
<Dropdown>
<t t-set-slot="toggler">
<!-- "toggler" slot content is rendered inside a button -->
Click me to toggle the dropdown menu !
</t>
<!-- "default" slot content is rendered inside a div -->
<DropdownItem onSelected="selectItem1">Menu Item 1</DropdownItem>
<DropdownItem onSelected="selectItem2">Menu Item 2</DropdownItem>
</Dropdown>
Props
~~~~~
A `<Dropdown/>` component is simply a `<div class="dropdown"/>` having a
`<button class="dropdown-toggle"/>` next to menu div
(`<div class="dropdown-menu"/>`). The button is responsible for the menu
being present in the DOM or not.
.. list-table::
:widths: 20 20 60
:header-rows: 1
* - Dropdown
- Type
- Description
* - `startOpen`
- boolean
- initial dropdown open state (defaults to `false`)
* - `menuClass`
- string
- additional css class applied to the dropdown menu `<div class="dropdown-menu"/>`
* - `togglerClass`
- string
- additional css class applied to the toggler `<button class="dropdown-toggle"/>`
* - `hotkey`
- string
- hotkey to toggle the opening through keyboard
* - `tooltip`
- string
- add a tooltip on the toggler
* - `beforeOpen`
- function
- hook to execute logic just before opening. May be asynchronous.
* - `manualOnly`
- boolean
- if true, only toggle the dropdown when the button is clicked on (defaults to `false`)
* - `disabled`
- boolean
- disable (if true) the dropdown button (defaults to `false`)
* - `title`
- string
- title attribute content for the `<button class="dropdown-toggle"/>` (default: none)
* - `position`
- string
- defines the desired menu opening position. RTL direction is automatically applied. Should be a valid :ref:`usePosition <frontend/hooks/useposition>` hook position. (default: `bottom-start`)
* - `toggler`
- `"parent"` or `undefined`
- when set to `"parent"` the `<button class="dropdown-toggle"/>` is not
rendered (thus `toggler` slot is ignored) and the toggling feature is handled by the parent node (e.g. use
case: pivot cells). (default: `undefined`)
A `<DropdownItem/>` is simply a span (`<span class="dropdown-item"/>`).
When a `<DropdownItem/>` is selected, it calls its `onSelected` prop. If this prop is a method, make sure it is bound if the method need to use the `this` value.
.. list-table::
:widths: 20 20 60
:header-rows: 1
* - DropdownItem
- Type
- Description
* - `onSelected`
- Function
- a function that will be called when the dropdown item is selected.
* - `parentClosingMode`
- `none` | `closest` | `all`
- when the item is selected, control which parent dropdown will get closed:
none, closest or all (default = `all`)
* - `hotkey`
- string
- optional hotkey to select the item
* - `href`
- string
- if provided the DropdownItem will become an `<a href="value" class="dropdown-item"/>` instead of a `<span class="dropdown-item"/>`. (default: not provided)
* - `title`
- string
- optional title attribute which will be passed to the root node of the DropdownItem. (default: not provided)
* - `dataset`
- Object
- optional object containing values that should be added to the root element's dataset. This can be used so that the element is easier to find programmatically, for example in tests or tours.
Technical notes
~~~~~~~~~~~~~~~
The rendered DOM is structured like this:
.. code-block:: html
<div class="dropdown">
<button class="dropdown-toggle">Click me !</button>
<!-- following <div/> will or won't appear in the DOM depending on the state controlled by the preceding button -->
<div class="dropdown-menu">
<span class="dropdown-item">Menu Item 1</span>
<span class="dropdown-item">Menu Item 2</span>
</div>
</div>
- Direct siblings dropdowns: when one is open, toggle others on hover
To properly use a `<Dropdown/>` component, you need to populate two
`OWL slots <https://github.com/odoo/owl/blob/master/doc/reference/slots.md>`_ :
- `toggler` slot: it contains the *toggler* elements of your dropdown and is
rendered inside the dropdown `button` (unless the `toggler` prop is set to `parent`),
- `default` slot: it contains the *elements* of the dropdown menu itself and is
rendered inside the `<div class="dropdown-menu"/>`. Although it is not mandatory, there is usually at least one
`DropdownItem` inside the `menu` slot.
When several dropdowns share the same parent element in the DOM, then they are
considered part of a group, and will notify each other about their state changes.
This means that when one of these dropdowns is open, the others will automatically
open themselves on mouse hover, without the need for a click.
Example: Direct Siblings Dropdown
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When one dropdown toggler is clicked (**File** , **Edit** or **About**), the
others will open themselves on hover.
.. code-block:: xml
<div>
<Dropdown>
<t t-set-slot="toggler">File</t>
<DropdownItem onSelected="() => this.onItemSelected('file-open')">Open</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('file-new-document')">New Document</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('file-new-spreadsheet')">New Spreadsheet</DropdownItem>
</Dropdown>
<Dropdown>
<t t-set-slot="toggler">Edit</t>
<DropdownItem onSelected="() => this.onItemSelected('edit-undo')">Undo</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('edit-redo')">Redo</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('edit-find')">Search</DropdownItem>
</Dropdown>
<Dropdown>
<t t-set-slot="toggler">About</t>
<DropdownItem onSelected="() => this.onItemSelected('about-help')">Help</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('about-update')">Check update</DropdownItem>
</Dropdown>
</div>
Example: Multi-level Dropdown (with `t-call`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This example shows how one could make a `File` dropdown menu, with submenus for
the `New` and `Save as...` sub elements.
.. code-block:: xml
<t t-name="addon.Dropdown.File">
<Dropdown>
<t t-set-slot="toggler">File</t>
<DropdownItem onSelected="() => this.onItemSelected('file-open')">Open</DropdownItem>
<t t-call="addon.Dropdown.File.New"/>
<DropdownItem onSelected="() => this.onItemSelected('file-save')">Save</DropdownItem>
<t t-call="addon.Dropdown.File.Save.As"/>
</Dropdown>
</t>
<t t-name="addon.Dropdown.File.New">
<Dropdown>
<t t-set-slot="toggler">New</t>
<DropdownItem onSelected="() => this.onItemSelected('file-new-document')">Document</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('file-new-spreadsheet')">Spreadsheet</DropdownItem>
</Dropdown>
</t>
<t t-name="addon.Dropdown.File.Save.As">
<Dropdown>
<t t-set-slot="toggler">Save as...</t>
<DropdownItem onSelected="() => this.onItemSelected('file-save-as-csv')">CSV</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('file-save-as-pdf')">PDF</DropdownItem>
</Dropdown>
</t>
Example: Multi-level Dropdown (nested)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- `default` slot: it contains the *toggle* elements of your dropdown. By default, click events will
be attached to this element to open and close the dropdown.
- `content` slot: it contains the *elements* of the dropdown menu itself and is rendered inside a popover.
Although it is not mandatory, you can put some `DropdownItem` inside this slot, the dropdown will
automatically close when these items are selected.
.. code-block:: xml
<Dropdown>
<t t-set-slot="toggler">File</t>
<DropdownItem onSelected="() => this.onItemSelected('file-open')">Open</DropdownItem>
<Dropdown>
<t t-set-slot="toggler">New</t>
<DropdownItem onSelected="() => this.onItemSelected('file-new-document')">Document</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('file-new-spreadsheet')">Spreadsheet</DropdownItem>
</Dropdown>
<DropdownItem onSelected="() => this.onItemSelected('file-save')">Save</DropdownItem>
<Dropdown>
<t t-set-slot="toggler">Save as...</t>
<DropdownItem onSelected="() => this.onItemSelected('file-save-as-csv')">CSV</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('file-save-as-pdf')">PDF</DropdownItem>
</Dropdown>
<!-- The content of the "default" slot is the component's toggle -->
<button class="my-btn" type="button">
Click me to toggle the dropdown menu!
</button>
<!-- The "content" slot is rendered inside the menu that pops up next to the toggle -->
<t t-set-slot="content">
<DropdownItem onSelected="selectItem1">Menu Item 1</DropdownItem>
<DropdownItem onSelected="selectItem2">Menu Item 2</DropdownItem>
</t>
</Dropdown>
Example: Recursive Multi-level Dropdown
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dropdown Props
~~~~~~~~~~~~~~
In this example, we recursively call a template to display a tree-like structure.
.. list-table::
:widths: 20 20 60
:header-rows: 1
.. code-block:: xml
* - Name
- Type
- Description
* - `menuClass`
- `String`
- Optional classname added to the dropdown's menu
* - `disabled`
- `Boolean`
- Optional, if true, disables the dropdown so the user is not able to open it anymore. (default: `false`)
* - `items`
- `Array`
- Optional list of items to be displayed as DropdownItems inside the dropdown's menu
* - `position`
- `String`
- Optionally defines the desired menu opening position. RTL direction is automatically applied. Should be a valid :ref:`usePosition <frontend/hooks/useposition>` hook position. (default: `bottom-start`)
* - `beforeOpen`
- `Function`
- Optional function called just before opening. May be asynchronous.
* - `onOpened`
- `Function`
- Optional function called just after opening.
* - `onStateChanged`
- `Function`
- Optional function called after opening or closing (gives a boolean as single argument that represents whether the dropdown is open or not).
* - `state`
- `Object`
- Optional object with `open()`, `close()` and `isOpen` properties to manually control when the dropdown opens and closes.
* - `manual`
- `Boolean`
- Optional, when true, the Dropdown component will not add click event listeners to the toggler. This allows for more control as when to open the dropdown. (This should be used in tandem with the `state` prop)
* - `navigationOptions`
- `Boolean`
- Optionally overrides the navigation options of the dropdown, (see `web/core/navigation/navigation`).
* - `holdOnHover`
- `Boolean`
- Optional, if true, keeps the Dropdown's menu at the same position while the mouse is hovering it, creating a better UX when the menu's content changes.
* - `menuRef`
- `Function`
- Optional, allows to get a ref of the dropdown's menu, (expects a function returned from `useChildRef`)
<t t-name="addon.MainTemplate">
<div>
<t t-call="addon.RecursiveDropdown">
<t t-set="name" t-value="'Main Menu'" />
<t t-set="items" t-value="state.menuItems" />
</t>
</div>
</t>
DropdownItem Props
~~~~~~~~~~~~~~~~~~
.. list-table::
:widths: 20 20 60
:header-rows: 1
* - Name
- Type
- Description
* - `class`
- `String` or `Object`
- Optional value added to the root span classname (supports both strings and `OWL classname object notation <https://github.com/odoo/owl/blob/master/doc/reference/templates.md#dynamic-class-attribute>`_).
* - `onSelected`
- `Function`
- Optional function called when the dropdown item is selected.
* - `closingMode`
- `"none"` | `"closest"` | `"all"`
- Optional, controls which parent dropdown should close when the item is selected:
`none`: the dropdown will not close, `closest`: the direct parent will close, `all`: every nested parent dropdown will close (default: `all`)
* - `attrs`
- `Object`
- Optional object representing attributes that are added to the root element. `<DropdownItem attrs="{ title: 'A tooltip', 'data-hotkey': 'shift+a' }">`. (If `href` is set, the element will automatically become an `a` element).
.. important::
When writing custom css for you components, do not forget that the menu elements are not next to the toggle
but inside the overlay container, at the bottom of the document. Thus, use the `menuClass` and `class` props to more
easily write your selectors. (This DOM magic let us avoid lots of z-index issues.)
Nested Dropdown
~~~~~~~~~~~~~~~
Dropdown can be nested, to do this simply put new Dropdown components inside other dropdown's content slot. When the parent
dropdown is open, child dropdowns will open automatically on hover.
By default, selecting a DropdownItem will close the whole Dropdown tree.
.. example::
This example shows how one could make a nested File dropdown menu, with submenus for the New sub elements.
.. code-block:: xml
<t t-name="addon.RecursiveDropdown">
<Dropdown>
<t t-set-slot="toggler"><t t-esc="name"/></t>
<t t-foreach="items" t-as="item" t-key="item.id">
<button>File</button>
<t t-set-slot="content">
<DropdownItem onSelected="() => this.onItemSelected('file-save')">Save</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('file-open')">Open</DropdownItem>
<!-- If this item has no child: make it a <DropdownItem/> -->
<t t-if="!item.childrenTree.length">
<DropdownItem onSelected="() => this.onItemSelected(item)" t-esc="item.name"/>
<Dropdown>
<button>New</button>
<t t-set-slot="content">
<DropdownItem onSelected="() => this.onItemSelected('file-new-document')">Document</DropdownItem>
<DropdownItem onSelected="() => this.onItemSelected('file-new-spreadsheet')">Spreadsheet</DropdownItem>
</t>
<!-- Else: recursively call the current dropdown template. -->
<t t-else="" t-call="addon.RecursiveDropdown">
<t t-set="name" t-value="item.name" />
<t t-set="items" t-value="item.childrenTree" />
</t>
</t>
</Dropdown>
</t>
</Dropdown>
</t>
In the example bellow, we recursively call a template to display a tree-like structure.
.. code-block:: xml
<t t-name="addon.MainTemplate">
<div>
<t t-call="addon.RecursiveDropdown">
<t t-set="name" t-value="'Main Menu'" />
<t t-set="items" t-value="state.menuItems" />
</t>
</div>
</t>
<t t-name="addon.RecursiveDropdown">
<Dropdown>
<button t-esc="name"></button>
<t t-set-slot="content">
<t t-foreach="items" t-as="item" t-key="item.id">
<!-- If this item has no child: make it a <DropdownItem/> -->
<DropdownItem t-if="!item.childrenTree.length" onSelected="() => this.onItemSelected(item)" t-esc="item.name"/>
<!-- Else: recursively call the current dropdown template. -->
<t t-else="" t-call="addon.RecursiveDropdown">
<t t-set="name" t-value="item.name" />
<t t-set="items" t-value="item.childrenTree" />
</t>
</t>
</t>
</Dropdown>
</t>
Controlled Dropdown
~~~~~~~~~~~~~~~~~~~
If needed, you can also open or close the dropdown using code. To do this you must use the `useDropdownState` hook along
with the `state` prop. `useDropdownState` returns an object that has an `open` and a `close` method (as well as an `isOpen` getter).
Give the object to the `state` prop of the dropdown you want to control and calling the respective functions should now open and
close your dropdown.
You can also set `manual` to `true` if you don't want the default click handlers to be added on the toggle.
.. example::
The following example shows a dropdown that opens automatically when mounted and only has a 50% chance
of closing when clicking on the button inside.
.. code-block:: javascript
import { Component, onMounted } from "@odoo/owl";
import { Dropdown } from "@web/core/dropdown/dropdown";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { useDropdownState } from "@web/core/dropdown/dropdown_hooks";
class MyComponent extends Component {
static components = { Dropdown, DropdownItem };
static template = xml`
<Dropdown state="this.dropdown">
<div>My Dropdown</div>
<t t-set-slot="content">
<button t-on-click="() => this.mightClose()">Close It!<button>
</t>
</Dropdown>
`;
setup() {
this.dropdown = useDropdownState();
onMounted(() => {
this.dropdown.open();
});
}
mightClose() {
if (Math.random() > 0.5) {
this.dropdown.close();
}
}
}
DropdownGroup
~~~~~~~~~~~~~
**Location:** `@web/core/dropdown/dropdown_group`
You can use the DropdownGroup component to make Dropdowns share a common group, this means that when
one of these Dropdown is open, the others will automatically open themselves on mouse hover, without
the need for a click.
To do this, either surround all the Dropdowns with a single DropdownGroup or surround them with
DropdownGroups with the same `group` key.
.. example::
In the example bellow, all dropdown in the snippet bellow will share the same group:
.. code-block:: xml
<DropdownGroup>
<Dropdown>...</Dropdown>
<Dropdown>...</Dropdown>
<Dropdown>...</Dropdown>
</DropdownGroup>
Whereas in the following snippet, only the first, second and fourth dropdown share the same group:
.. code-block:: xml
<DropdownGroup group="'my-group'">
<Dropdown>...</Dropdown>
<Dropdown>...</Dropdown>
</DropdownGroup>
<DropdownGroup group="'my-other-group'">
<Dropdown>...</Dropdown>
</DropdownGroup>
<DropdownGroup group="'my-group'">
<Dropdown>...</Dropdown>
</DropdownGroup>
.. _frontend/owl/notebook: