Compare commits

...

15 Commits

Author SHA1 Message Date
Antoine Vandevenne (anv)
bac0f08299 [IMP] supported_version: release 16.0 and deprecate 13.0
X-original-commit: 3c61d24b1d
2022-10-11 21:12:03 +02:00
Demesmaeker
d41a66758f [IMP] sale_amazon: support all marketplaces
task-2939972

closes odoo/documentation#2806

X-original-commit: 91f3859a53
Related: odoo/enterprise#32699
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
2022-10-11 16:57:18 +02:00
Victor Feyens
3a7be7730d [IMP] developer/orm: environment documentation
Move Environment explanation to the class docstring and autogenerate the
doc

Add documentation on some util methods.

closes odoo/documentation#2803

X-original-commit: 7c42ab8eaf
Related: odoo/odoo#102969
Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
2022-10-10 19:55:40 +02:00
Victor Feyens
c8ab0c1535 [FIX] developer/iap: wrong :class: element
X-original-commit: b7f5b3e04b
Part-of: odoo/documentation#2803
2022-10-10 19:55:40 +02:00
Antoine Vandevenne (anv)
0e567a08de [IMP] reference/payment: auto-document the method _get_removal_values
Task - 3002532

closes odoo/documentation#2802

X-original-commit: 7696235acb
Related: odoo/odoo#102951
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
2022-10-10 19:03:20 +02:00
Antoine Vandevenne (anv)
9baab389c9 [ADD] reference/standard_modules: API reference for the payment engine
task-2804999

closes odoo/documentation#2797

X-original-commit: 668ac2c650
Related: odoo/odoo#102716
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
2022-10-09 09:11:46 +02:00
Xavier-Do
46a80f60c5 [ADD] developer/reference: add a reference page on performance
closes odoo/documentation#2794

X-original-commit: 4d8e3f9785
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
Co-authored-by: Antoine Vandevenne (anv) <anv@odoo.com>
2022-10-06 18:01:00 +02:00
Julien Van Roy
aab2d6615a [IMP] accounting/electronic_invoicing: update factur-x usage
Update Factur-X mentions and screenshot.

task-2957808
https://github.com/odoo/odoo/pull/99699

closes odoo/documentation#2789

X-original-commit: 1387c5e8c3
Related: odoo/odoo#102311
Related: odoo/enterprise#32344
Signed-off-by: Julien Van Roy <juvr@odoo.com>
Signed-off-by: Castillo Jonathan (jcs) <jcs@odoo.com>
2022-10-06 10:43:01 +02:00
Denis Ledoux
991b8142fe [IMP] developer/reference: move model view related methods out of orm
The model method `get_views` and `get_view` are moved
from `odoo/models.py` to `odoo/addons/base/models/ir_ui_view.py`.

The documentation is updated accordingly,
to put the documentation related to `get_views` in the
views chapter of the documentation.

closes odoo/documentation#2786

X-original-commit: 0bdf714112
Related: odoo/odoo#102117
Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
2022-10-04 18:06:37 +02:00
Aleksander
f4bbbcb6c1 [FW][IMP] howtos/rdtraining: give the meaning of "ACL"
closes odoo/documentation#2779

Forward-port-of: odoo/documentation#2774
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
2022-09-30 12:34:44 +02:00
Jonathan Quique (jqu)
768ab1b586 [IMP] email_communication: can't use Odoo STMP with another mail server
Customer may want to use their own SMTP for email marketing, and Odoo default SMTP for everything else. There is no good way to do this. Previously we suggested adding Odoo SMTP as an outgoing email server but we don't want to share credentials anymore.
R&D is working on a solution (e.g. showing the Odoo default email server in the list rather than keeping it as an "hidden feature") but for the time being, if you use an outgoing email server, you give up using the Odoo default SMTP.

closes odoo/documentation#2771

X-original-commit: 7b21e6001b
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
2022-09-29 14:23:59 +02:00
Jonathan Castillo (jcs)
7424e4176c [IMP] website: register domain name menu path
closes odoo/documentation#2766

X-original-commit: 81352e98b2
Signed-off-by: Castillo Jonathan (jcs) <jcs@odoo.com>
2022-09-28 00:20:45 +02:00
Wesley Kao (weka)
8287c88bd4 [IMP] MRP: updated Variants BOM Management rst content
closes odoo/documentation#2764

X-original-commit: b3d5e928aa
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
2022-09-27 19:14:46 +02:00
Xavier-Do
53e7277b6a [FIX]: fix odoo_version detection
Right now if the version is not "final (and not alpha)"
documentation will say 16.0beta != 16.0

closes odoo/documentation#2748

X-original-commit: 406f3aac18
Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
2022-09-26 09:35:48 +02:00
Fabrice Henrion
2c7d61f938 [FIX] accounting: grammar fix in ponto
closes odoo/documentation#2759

X-original-commit: dad110c7cc
Signed-off-by: Castillo Jonathan (jcs) <jcs@odoo.com>
2022-09-23 11:22:40 +02:00
46 changed files with 883 additions and 867 deletions

View File

@@ -95,7 +95,7 @@ else:
import odoo.addons
odoo.addons.__path__.append(str(odoo_dir) + '/addons')
from odoo import release as odoo_release # Don't collide with Sphinx's 'release' config option
odoo_version = odoo_release.version.replace('~', '-') # Change saas~XX.Y to saas-XX.Y
odoo_version = '.'.join(str(s) for s in odoo_release.version_info[:2]).replace('~', '-') # Change saas~XX.Y to saas-XX.Y
odoo_version = 'master' if 'alpha' in odoo_release.version else odoo_version
if release != odoo_version:
_logger.warning(
@@ -187,6 +187,8 @@ sphinx.transforms.i18n.docname_to_domain = (
# is populated. If a version is passed to `versions` but is not listed here, it will not be shown.
versions_names = {
'master': "Master",
'16.0': "Odoo 16",
'saas-15.3': "Odoo Online",
'saas-15.2': "Odoo Online",
'15.0': "Odoo 15",
'14.0': "Odoo 14",

View File

@@ -62,11 +62,11 @@ database manager.
- This offer doesn't include any mailbox. However, you can :ref:`configure your MX records
<domain-name/odoo-manage>` to use your own email server or solution such as Google Workspace.
To do so, go to :menuselection:`Website --> Go to website --> Promote --> Domain Name`.
Alternatively, open your `database manager <https://www.odoo.com/my/databases>`_, click on the
:guilabel:`settings` button next to your database, then on :guilabel:`Domain names`.
To do so, go to :menuselection:`Website --> Domain Name`. Alternatively, open your `database manager
<https://www.odoo.com/my/databases>`_, click on the :guilabel:`settings` button next to your
database, then on :guilabel:`Domain names`.
.. image:: domain_names/register-promote.png
.. image:: domain_names/register-menu.png
:align: center
:alt: Clicking on Domain Names from an Odoo website

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -25,6 +25,8 @@ This matrix shows the support status of every version.
+-----------------+-------------+----------+-------------+----------------+------------------------+
| | Odoo Online | Odoo.sh | On-Premise | Release date | End of support |
+=================+=============+==========+=============+================+========================+
| **Odoo 16.0** | |green| | |green| | |green| | October 2022 | October 2025 (planned) |
+-----------------+-------------+----------+-------------+----------------+------------------------+
| Odoo saas~15.2 | |green| | N/A | N/A | March 2022 | |
+-----------------+-------------+----------+-------------+----------------+------------------------+
| Odoo saas~15.1 | |red| | N/A | N/A | February 2022 | |
@@ -33,7 +35,7 @@ This matrix shows the support status of every version.
+-----------------+-------------+----------+-------------+----------------+------------------------+
| **Odoo 14.0** | |green| | |green| | |green| | October 2020 | October 2023 (planned) |
+-----------------+-------------+----------+-------------+----------------+------------------------+
| **Odoo 13.0** | |green| | |green| | |green| | October 2019 | October 2022 (planned) |
| **Odoo 13.0** | |red| | |red| | |red| | October 2019 | October 2022 |
+-----------------+-------------+----------+-------------+----------------+------------------------+
| Odoo saas~12.3 | |red| | N/A | N/A | August 2019 | |
+-----------------+-------------+----------+-------------+----------------+------------------------+

View File

@@ -64,8 +64,8 @@ Link your Ponto account with your Odoo database
#. Finish the flow.
.. note::
You have to authorize all the accounts you want to access in Odoo but, Odoo will filter the
accounts based on the institution you selected at the second step.
You have to authorize all the accounts you want to access in Odoo, but Odoo will filter the
accounts based on the institution you selected in the second step.
Update your synchronization credentials
---------------------------------------

View File

@@ -20,8 +20,8 @@ Odoo supports, among others, the following formats.
* - Format Name
- Applicability
* - Factur-X (CII)
- Default format on Odoo (enabled by default)
* - Factur-X (PDF/A-3)
- For French and German companies
* - Peppol BIS Billing 3.0 (UBL)
- For companies whose countries are part of the `EAS list
<https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/>`_
@@ -68,8 +68,9 @@ visible in the attachment section, or embedded in the PDF.
.. note::
- For E-FFF, the xml file only appears after having generated the PDF (:guilabel:`Print` or
:guilabel:`Send & Print` button), since the PDF needs to be embedded inside the xml.
- By default, the :guilabel:`Factur-X` option is enabled. It means that an XML file is
automatically included in the PDF document that is sent.
- Every PDF generated from Odoo contains a :guilabel:`Factur-X` XML file (for interoperability purpose).
For German and French companies, the option :guilabel:`Factur-X (PDF/A-3)` in addition enables
validation checks on the invoice and generates a PDF/A-3 compliant file, required by plaftorms like Chorus Pro.
- The formats available depend on the country registered in your company's :guilabel:`General
Information`.
- Odoo supports the **Peppol BIS Billing 3.0** format that can be used via existing access

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -59,6 +59,8 @@ debug mode, add `?debug=0` instead.
:ref:`assets mode <frontend/framework/assets_debug_mode>`, and `?debug=tests` enables
the :ref:`tests mode <frontend/framework/tests_debug_mode>`.
.. _developer-mode/mode-tools:
Locate the mode tools
=====================

View File

@@ -1,240 +1,210 @@
====================================================
Send and Receive Emails in Odoo with an Email Server
Send and receive emails in Odoo with an email server
====================================================
If you are a user of Odoo Online or Odoo.sh...
==============================================
Odoo Online or Odoo.sh users
============================
You have nothing to do! **Odoo sets up its own mail servers for your database.**
Outgoing and incoming emails work out-of-the-box!
Unless you plan to send large batches of mass mailing that could require the
use of an external mail server, simply enjoy your new Odoo database.
Since **Odoo sets up its own mail servers for the database**, outgoing and incoming emails already
work out-of-the-box. So for **Odoo Online** and **Odoo.sh** customers, nothing needs to be done!
Unless an external mail server is required to send large batches of mass mailing, simply use the
standard online Odoo database normally since it has already been preconfigured for email.
Scope of this documentation
===========================
This document is **mainly dedicated to Odoo on-premise users** who don't
benefit from an out-of-the-box solution to send and receive emails in Odoo,
unlike `Odoo Online <https://www.odoo.com/trial>`_ & `Odoo.sh <https://www.odoo.sh>`_.
This document is **mainly dedicated to Odoo on-premise users** who don't benefit from an
out-of-the-box solution to send and receive emails in Odoo, unlike `Odoo Online <https://www.odoo.
com/trial>`_ and `Odoo.sh <https://www.odoo.sh>`_.
The following sections below contain information on how to integrate an external email server with
Odoo.
.. warning::
If no one in your company is used to manage email servers, we strongly recommend that
you opt for those Odoo hosting solutions. Their email system
works instantly and is monitored by professionals.
Nevertheless you can still use your own email servers if you want
to manage your email server's reputation yourself.
If no one in the company is used to managing email servers, Odoo Online and Odoo.sh are strongly
recommended. Those Odoo hosting types' email systems work instantly and are monitored by
professionals. Nevertheless, a company can use their own email server if they want to manage the
email server's reputation themselves.
You will find here some useful
information on how to integrate your own email solution with Odoo.
.. note::
Office 365 email servers don't easily allow the sending of external emails from hosts like Odoo.
Refer to `Microsoft's documentation <https://support.office.com/en-us/article/How-to-set-up-a-
multifunction-device-or-application-to-send-email-using-Office-365-69f58e99-c550-4274-ad18-
c805d654b4c4>`_ to make it work.
.. note::
Office 365 email servers don't easily allow to send external emails from hosts like Odoo. Refer
to `Microsoft's documentation <https://support.office.com/en-us/article/How-to-set-up-a-multifunction-device-or-application-to-send-email-using-Office-365-69f58e99-c550-4274-ad18-c805d654b4c4>`_
to make it work.
Manage outbound messages
========================
How to manage outbound messages
===============================
As a system admin, go to :menuselection:`Settings --> General Settings`
and check *External Email Servers*. Then, click *Outgoing Mail Servers* to create one and reference
the SMTP data of your email server. Once all the information has been filled out, click on
*Test Connection*.
As a system admin, go to :menuselection:`Settings --> General Settings --> Discuss` in Odoo, and
enable the :guilabel:`External Email Servers` option. Then, click :guilabel:`Save`. Next, click
:guilabel:`Outgoing Email Servers` and click :guilabel:`Create` to create a new outgoing mail
server record in Odoo. Reference the SMTP data of the external email server. Once all the
information has been filled out, click :guilabel:`Test Connection`.
Here is a typical configuration for a G Suite server.
.. image:: email_servers/outgoing-server.png
:align: center
:align: center
:alt: The typical G Suite configuration on Odoo.
Then set your email domain name in the General Settings.
Then, go back to :menuselection:`Settings --> General Settings --> Discuss` and set the email
domain name in the :guilabel:`Alias Domain` name. Finally, click :guilabel:`Save` to finish setting
up the email server.
.. note::
If you get a ``[AUTHENTICATIONFAILED] Invalid credentials (Failure)`` warning when you *Test
Connection* on a Gmail address, activate the *Less secure app access* option. A direct link can
be `accessed here <https://myaccount.google.com/lesssecureapps?pli=1>`_.
If an `[AUTHENTICATION FAILED] Invalid credentials (Failure)` warning appears when
:guilabel:`Test Connection` is clicked for a Gmail address, activate the :guilabel:`Less secure
app access` option. A direct link can be `accessed here <https://myaccount.google.com/
lesssecureapps?pli=1>`_.
In addition to that, enable the IMAP setting on your Gmail account.
In addition to that, enable the :guilabel:`IMAP setting` on the Gmail account.
Use an Office 365 server
------------------------
Can I use an Office 365 server
------------------------------
You can use an Office 365 server if you run Odoo on-premise.
Office 365 SMTP relays are not compatible with Odoo Online unless you configure
Odoo to :ref:`force the outgoing "From" address <email_communication/default_from>` .
An Office 365 server can be used if the database's hosting type is **Odoo on-premise**. Office 365
SMTP relays are not compatible with Odoo Online or Odoo.sh unless Odoo is configured to
:ref:`force the outgoing "From" address <email_communication/default_from>`.
Please refer to `Microsoft's documentation
<https://support.office.com/en-us/article/How-to-set-up-a-multifunction-device-or-application-to-send-email-using-Office-365-69f58e99-c550-4274-ad18-c805d654b4c4>`_
to configure a SMTP relay for your Odoo's IP address.
Please refer to `Microsoft's documentation <https://support.office.com/en-us/article/How-to-set-up-
a-multifunction-device-or-application-to-send-email-using-Office-365-69f58e99-c550-4274-ad18-
c805d654b4c4>`_ to configure an SMTP relay for the Odoo database's IP address.
How to use a G Suite server
---------------------------
You can use an G Suite server for any Odoo hosting type.
To do so you need to setup the SMTP relay service. The configuration steps are explained in
`Google documentation <https://support.google.com/a/answer/2956491?hl=en>`__.
Use a G Suite server
--------------------
A G Suite server can be used for any Odoo hosting type. To do so, set up the SMTP relay service.
The configuration steps are explained in `Google documentation <https://support.google.com
/a/answer/2956491?hl=en>`__.
Restriction
-----------
Please note that port 25 is blocked for security reasons on our SaaS and Odoo.sh platform. Try using
465, 587, or 2525.
Please note that port 25 is blocked for security reasons on the SaaS and Odoo.sh platforms. Try
using ports 465, 587, or 2525 instead.
.. _email_communication/default_from:
Use a default "From" email address
----------------------------------
Sometimes, an email's "From" (outgoing) address can belong to a
different domain, and that can be a problem.
Sometimes, an email's "From" (outgoing) address can belong to a different domain, and that can be a
problem.
For example, if a customer with address *mary@customer.example.com* responds to
a message, Odoo will try to redistribute that same email to other subscribers
in the thread. But if the domain *customer.example.com* forbids that kind of
usage for security, the Odoo's redistributed email would get
rejected by some recipients' mail servers.
For example, if a customer with the email address *mary\@customer.example.com* responds to a
message, Odoo will try to redistribute that same email to the other subscribers in the thread.
However, if the domain *customer.example.com* forbids that kind of usage for security, the email
that Odoo is trying to redistribute would get rejected by some recipients' email servers.
To avoid those kind of problems, you should make sure all emails use a "From"
address from your authorized domain.
To avoid that problem, make sure all emails use a "From" address from the same authorized domain.
If your MTA supports `SRS (Sender Rewriting Scheme)
<https://en.wikipedia.org/wiki/Sender_Rewriting_Scheme>`_, you can enable it
to handle these situations. However, that is more complex and requires more
technical knowledge that is not meant to be covered by this documentation.
If the MTA supports `SRS (Sender Rewriting Scheme) <https://en.wikipedia.org/wiki/Sender_Rewriting
_Scheme>`_, SRS can be enabled to handle these situations. However, that is more complex and
requires more technical knowledge that is not meant to be covered by this documentation.
Instead, you can also configure Odoo to do something similar by itself:
Instead, Odoo can be configured to do something similar by itself:
#. Set your domain name in the General Settings.
#. Set the :guilabel:`Alias Domain` name in the :menuselection:`Settings --> General Settings
--> Discuss`.
.. image:: email_servers/alias-domain.png
:align: center
.. image:: email_servers/alias-domain.png
:alt: Setting the domain alias configuration on Odoo.
#. Click on *Outgoing Mail Servers*
#. Turn on :doc:`developer mode </applications/general/developer_mode>`.
#. Go to :menuselection:`Settings --> Technical --> Parameters --> System Parameters`.
#. Add one system parameter from the following list:
#. Create a new one.
#. Fill its *From Filter*.
.. image:: email_servers/outgoing_server_from_filter.png
:align: center
* Use a domain (such as ``mycompany.example.com``) to keep the original "From"
address for mails that come from that domain.
* Use an address (such as ``outgoing@mycompany.example.com``) to allow only
that outgoing address.
* Keep it empty to use this server for any email address.
With this configuration in place, if Odoo sends an email that doesn't match any
of the *from filters*, it will alter the email's "From" before sending it to
the MTA.
It will use the default outgoing email address, composed like this:
``{mail.default.from}@{mail.catchall.domain}``.
#. In developer mode, go to :menuselection:`Settings --> Technical -->
Parameters --> System Parameters`.
#. Add these system parameters:
* ``mail.default.from``: local part of default outgoing email address.
* ``mail.catchall.domain``: domain part of default outgoing email address.
* To use the same "From" address for *all* outgoing messages, use the key `mail.force.smtp.from`
and set that address as value (such as `outgoing@mycompany.example.com`).
* To keep the original "From" address for emails that use the same domain, but change it for
emails that use a different domain, use the key `mail.dynamic.smtp.from` and set the value as
the email address that should be used in those cases (such as `outgoing@mycompany.example.com`
).
.. _email_communication/inbound_messages:
How to manage inbound messages
==============================
Manage inbound messages
=======================
Odoo relies on generic email aliases to fetch incoming messages.
* **Reply messages** of messages sent from Odoo are routed to their original
discussion thread (and to the inbox of all its followers) by the
catchall alias (**catchall@**).
* **Bounced messages** are routed to **bounce@** in order to track them in Odoo.
This is especially used in `Odoo Email Marketing <https://www.odoo.com/page/email-marketing>`__
to opt-out invalid recipients.
* **Original messages**: Several business objects have their own alias to
create new records in Odoo from incoming emails:
* **Reply messages** of messages sent from Odoo are routed to their original discussion thread (and
to the inbox of all its followers) by the catchall alias (**catchall@**).
* **Bounced messages** are routed to **bounce@** in order to track them in Odoo. This is especially
used in `Odoo Email Marketing <https://www.odoo.com/page/email-marketing>`__ to opt-out invalid
recipients.
* **Original messages**: Several business objects have their own alias to create new records in
Odoo from incoming emails:
* Sales Channel (to create Leads or Opportunities in `Odoo CRM <https://www.odoo.com/page/crm>`__),
* Support Channel (to create Tickets in `Odoo Helpdesk <https://www.odoo.com/page/helpdesk>`__),
* Projects (to create new Tasks in `Odoo Project <https://www.odoo.com/page/project-management>`__),
* Job Positions (to create Applicants in `Odoo Recruitment <https://www.odoo.com/page/recruitment>`__),
* Projects (to create new Tasks in `Odoo Project <https://www.odoo.com/page
/project-management>`__),
* Job Positions (to create Applicants in `Odoo Recruitment <https://www.odoo.com/page
/recruitment>`__),
* etc.
Depending on your mail server, there might be several methods to fetch emails.
The easiest and most recommended method is to manage one email address per Odoo
alias in your mail server.
Depending on the mail server, there might be several methods to fetch emails. The easiest and most
recommended method is to manage one email address per Odoo alias in the mail server.
* Create the corresponding email addresses in your mail server
(catchall@, bounce@, sales@, etc.).
* Set your domain name in the General Settings.
* Create the corresponding email addresses in the mail server (catchall@, bounce@, sales@, etc.).
* Set the :guilabel:`Alias Domain` name in :menuselection:`Settings --> General Settings -->
Discuss`.
.. image:: email_servers/alias-domain.png
* If the database's hosting type is Odoo on-premise, create an :guilabel:`Incoming Mail Server` in
Odoo for each alias. This can be done from the General Settings as well. Fill out the form
according to the email provider's settings. Leave the :guilabel:`Actions to Perform on Incoming
Mails` field blank. Once all the information has been filled out, click on :guilabel:`TEST &
CONFIRM`.
.. image:: email_servers/incoming-server.png
:align: center
:alt: Incoming mail server configuration on Odoo.
* If the database's hosting type is Odoo Online or Odoo.sh, redirecting incoming messages to Odoo's
domain name instead of the external email server is recommended. That way, incoming messages can
be received without delay. Odoo Online only fetches incoming messages of external servers once
every hour. Redirections for all email addresses should be set to Odoo's domain name in the email
server (e.g. *catchall\@mydomain.ext* to *catchall\@mycompany.odoo.com*).
All the aliases are customizable in Odoo. Object aliases can be edited from their respective
configuration view.
.. tip::
To edit catchall and bounce aliases, first activate the :ref:`developer mode <developer-mode>`.
Then, go to :menuselection:`Settings --> Technical --> Parameters --> System Parameters` to
customize the aliases (*mail.catchall.alias* & *mail.bounce.alias*).
.. image:: email_servers/system-parameters.png
:align: center
:alt: System parameters with catchall configuration in Odoo.
* If you use Odoo on-premise, create an *Incoming Mail Server* in Odoo for each alias.
You can do it from the General Settings as well. Fill out the form according
to your email providers settings.
Leave the *Actions to Perform on Incoming Mails* blank. Once all the
information has been filled out, click on *TEST & CONFIRM*.
By default, inbound messages are fetched every 5 minutes in Odoo on-premise.
.. image:: email_servers/incoming-server.png
:align: center
* If you use Odoo Online or Odoo.sh, We do recommend to redirect incoming messages
to Odoo's domain name rather than exclusively use your own email server.
That way you will receive incoming messages without delay. Indeed, Odoo Online is fetching
incoming messages of external servers once per hour only.
You should set redirections for all the email addresses to Odoo's domain name in your
email server (e.g. *catchall@mydomain.ext* to *catchall@mycompany.odoo.com*).
.. tip:: All the aliases are customizable in Odoo.
Object aliases can be edited from their respective configuration view.
To edit catchall and bounce aliases, you first need to activate the
:ref:`developer mode <developer-mode>`.
Then go to :menuselection:`Settings --> Technical --> Parameters --> System Parameters`
to customize the aliases (*mail.catchall.alias* & * mail.bounce.alias*).
.. image:: email_servers/system-parameters.png
:align: center
.. note:: By default inbound messages are fetched every 5 minutes in Odoo on-premise.
You can change this value in :ref:`developer mode <developer-mode>`.
Go to :menuselection:`Settings --> Technical --> Automation -->
Scheduled Actions` and look for *Mail: Fetchmail Service*.
.. note::
This value can be changed in :ref:`developer mode <developer-mode>`. Go to
:menuselection:`Settings --> Technical --> Automation --> Scheduled Actions` and look for
:guilabel:`Mail: Fetchmail Service`.
Set up different dedicated servers for transactional and mass mails
===================================================================
Odoo is subject to a :ref:`daily email limit <email_communication/daily_limit_mail>` to prevent abuse.
However, if needed, you can use a separate Mail Transfer Agent (MTA) servers for transactional
e-mails and mass mailings.
Example: use Odoo's own mail server for transactional e-mails, and Sendgrid, Amazon SES, or Mailgun
for mass mailings. Another alternative is to use Postmark for transactional e-mails, and Amazon SES
or Sendgrid for mass mailings.
In Odoo a separate Mail Transfer Agent (MTA) server can be used for transactional emails and mass
mailings. Example: Use Postmark or SendinBlue for transactional emails, and Amazon SES, Mailgun or
Sendgrid for mass mailings.
.. note::
A default outgoing email server is already configured. You should not create an alternative one
unless you want to use a specific external outgoing email server for technical reasons.
.. tip::
A default outgoing email server is already configured. Do not create an alternative one unless a
specific external outgoing email server is needed for technical reasons.
To do this, you should first activate the :ref:`developer mode <developer-mode>` and then go to
:menuselection:`Settings --> Technical --> Outgoing` e-mail servers. There you have to create two
e-mail MTA server settings. One for transactional e-mails and one for mass mail servers. Be sure to
mark the priority of transactional e-mail servers as low as the mass email servers.
To do this, first activate the :ref:`developer mode <developer-mode>`, and then go to
:menuselection:`Settings --> Technical --> Outgoing` email servers. There, create two email MTA
server settings; one for the transactional emails and one for the mass mailing server. Make sure
to give priority to the transactional server over the mass mailing server by providing a lower
priority number for the transactional MTA server.
Now, go to :menuselection:`Email Marketing --> Settings` and enable *Dedicated Server*.
Now, go to :menuselection:`Email Marketing --> Settings` and enable :guilabel:`Dedicated Server`.
With these settings, Odoo uses the server with the lower priority for transactional emails, and the
server here selected for mass mails.
Note that in this case, you have to set your domain's Sender Policy Framework (SPF) records to
include both transactional and mass mail servers. If your server resides with xxxx.odoo.com, the
available options are Sendinblue and Mailchimp, as your e-mails would be originated from the
xxxx.odoo.com domain.
server here selected for mass mails. Note that in this case, the domain's Sender Policy Framework
(SPF) records must be set to include both transactional and mass mail servers.

View File

@@ -1,35 +1,45 @@
=======================
Variants BOM Management
=======================
==================================
Managing BoMs for product variants
==================================
Odoo allows you to use one bill of materials for multiple variants of
the same product. To activate variants, simply go to :menuselection:`Configuration --> Settings
--> Variants`.
Odoo allows one bill of materials (BoM) to be used for multiple variants of the same product.
Having a consolidated BoM for a product with variants saves time by preventing the need to manage
multiple BoMs.
.. image:: product_variants/bom-variants1.png
:align: center
Activate product variants
=========================
You will then be able to specify which BOM component lines are to be used in
the manufacture of each product variant. You may specify multiple
variants for each line. If no variant is specified on a component line,
then this component will be used in the BOM of all variants.
To activate variants, simply navigate to :menuselection:`Inventory --> Configuration --> Settings
--> Products`, and then enable the :guilabel:`Variants` option. After that, click :guilabel:`Save`
to apply the setting. For more information on configuring product variants, refer to :doc:`this
page <../../../sales/sales/products_prices/products/variants>`.
When defining variant BoMs on a line-item-basis, the **Product
Variant** field in the main section of the BoM should be left blank as shown
below. This field is used when creating a BoM for one specific variant
of a product only.
.. image:: product_variants/inventory-variants-settings.png
:align: center
:alt: Selecting "Variants" from Inventory app settings.
Apply BoM components to product variants
========================================
.. image:: product_variants/kit-bom1.png
:align: center
Next, create a new BoM or edit an existing one by going to :menuselection:`Manufacturing -->
Products --> Bills of Materials`. Then, click :guilabel:`Edit`. The :guilabel:`Apply on Variants`
option to assign components to specific product variants on the BoM is available once the
:guilabel:`Variants` setting is activated from the :guilabel:`Inventory` application. If the
:guilabel:`Apply on Variants` field is not immediately visible, activate it from the additional
options menu.
Note that the same principle applies for the configuration
of operations.
.. image:: product_variants/variants-kebab-menu.png
:align: center
:alt: "Apply on Variants" option on the additional options menu.
.. image:: product_variants/kit-bom2.png
:align: center
Each component can be assigned to multiple variants. Components with no variants specified are used
in every variant of the product. The same principle applies when configuring operations and
by-products.
And for the production of by-products.
When defining variant BoMs by component assignment, the :guilabel:`Product Variant` field in the
main section of the BoM should be left blank, as shown below. This field is used only when creating
a BoM specifically for one product variant.
.. image:: product_variants/kit-bom3.png
:align: center
.. image:: product_variants/apply-on-variants-bom.png
:align: center
:alt: Applying components to multiple variants.

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -54,35 +54,10 @@ The connector is able to:
Supported Marketplaces
======================
The Amazon Connector currently supports 9 marketplaces.
If a marketplace is not listed below, it may be possible for you to :ref:`add it as an unsupported
marketplace <amazon/add-unsupported-marketplace>`.
The Amazon Connector supports all the current marketplaces.
If a marketplace is not listed in your Amazon marketplaces, you can :ref:`add a new marketplace
<amazon/add-new-marketplace>`.
+-------------------------------+
| **North America region** |
+===============+===============+
| Canada | Amazon.ca |
+---------------+---------------+
| Mexico | Amazon.com.mx |
+---------------+---------------+
| US | Amazon.com |
+---------------+---------------+
+-------------------------------+
| **Europe region** |
+===============+===============+
| Germany | Amazon.de |
+---------------+---------------+
| Spain | Amazon.es |
+---------------+---------------+
| France | Amazon.fr |
+---------------+---------------+
| UK | Amazon.co.uk |
+---------------+---------------+
| Italy | Amazon.it |
+---------------+---------------+
| Netherlands | Amazon.nl |
+---------------+---------------+
.. seealso::
- :doc:`setup`

View File

@@ -70,49 +70,35 @@ the subtotals between Seller Central and Odoo.
that order totals differ by a few cents from that on Seller Central. Those differences can be
resolved with a write-off when reconciling the payments in Odoo.
.. _amazon/add-unsupported-marketplace:
.. _amazon/add-new-marketplace:
Add an unsupported marketplace
==============================
Add a new marketplace
=====================
Some Amazon Marketplaces, such as Amazon Brazil, are not created by default as they are not
officially supported by Odoo but might be compatible with your seller account. These marketplaces
can be added manually should you wish to use them. See :ref:`here <amazon/supported-marketplaces>`
for the exhaustive list of natively supported marketplaces.
:ref:`All marketplaces are supported by the Amazon Connector <amazon/supported-marketplaces>`, but
recently created ones might be missing from your database. To add a new marketplace, proceed as
follows:
.. tip::
To find out if a marketplace is eventually compatible, check the `Amazon Documentation
<https://developer-docs.amazon.com/amazon-shipping/docs/seller-central-urls>`_. The marketplace
must belong to the same region as that of your seller account.
To add a new marketplace, activate the :ref:`developer mode <developer-mode>`.
Once that is done, go to :menuselection:`Sales --> Configuration --> Settings --> Connectors -->
Amazon Sync --> Amazon Marketplaces`.
From there, create a new marketplace record. Enter the Marketplace ID and select the Amazon Region
for your marketplace as described in the `Amazon Documentation for marketplace IDs
<https://developer-docs.amazon.com/amazon-shipping/docs/marketplace-ids>`_, and the Seller Central
URL as described in the `Amazon Documentation for seller central URLs
<https://developer-docs.amazon.com/amazon-shipping/docs/seller-central-urls>`_.
Set the name of the record to ``Amazon.<country code>`` to easily retrieve it (e.g.: ``Amazon.se``).
The :guilabel:`API Identifier`, the :guilabel:`Region` and the :guilabel:`Seller Central URL` fields
should respectively hold the *MarketplaceId*, the selected Amazon region and the *Seller Central
URL* values from the Amazon Documentation.
Once the marketplace is saved, update the Amazon Account configuration by going to
:menuselection:`Sales --> Configuration --> Settings --> Connectors --> Amazon Sync -->
Amazon Accounts`. Open the account on which you wish to use the new marketplace, go to the
:guilabel:`Marketplaces` tab and click on :guilabel:`Update available marketplaces` (an animation
should confirm the success of the operation). Newly added marketplaces are automatically added to
the list of synchronized marketplaces. If the new marketplace is not added to the list, it means
that it is either incompatible or unavailable for your seller account.
.. important::
As manually added marketplaces are not officially supported by Odoo, there is no guarantee that
adding one as described above will work, nor can this be considered as a bug when contacting Odoo
Support.
#. Activate the :ref:`developer mode <developer-mode>`.
#. Go to :menuselection:`Sales --> Configuration --> Settings --> Connectors --> Amazon Sync -->
Amazon Marketplaces`.
#. Create a new marketplace record. Enter the :guilabel:`Marketplace ID` and select the
:guilabel:`Amazon Region` for your marketplace as described in the `Amazon Documentation for
marketplace IDs and regions
<https://developer-docs.amazon.com/amazon-shipping/docs/marketplace-ids>`_, and the
:guilabel:`Seller Central URL` as described in the `Amazon Documentation for seller central URLs
<https://developer-docs.amazon.com/amazon-shipping/docs/seller-central-urls>`_.
#. Set the name of the record to `Amazon.<country code>` to easily retrieve it (e.g.:
**Amazon.se**). The :guilabel:`API Identifier`, the :guilabel:`Region` and the :guilabel:`Seller
Central URL` fields should respectively hold the *MarketplaceId*, the selected Amazon region and
the *Seller Central URL* values from the Amazon Documentation.
#. Once the marketplace is saved, update the Amazon Account configuration by going to
:menuselection:`Sales --> Configuration --> Settings --> Connectors --> Amazon Sync -->
Amazon Accounts`. Open the account on which you wish to use the new marketplace, go to the
:guilabel:`Marketplaces` tab and click on :guilabel:`Update available marketplaces` (an animation
should confirm the success of the operation). Newly added marketplaces are automatically added to
the list of synchronized marketplaces. If the new marketplace is not added to the list, it means
that it is either incompatible or unavailable for your seller account.
.. seealso::
- :doc:`features`

View File

@@ -589,32 +589,6 @@ Programming in Odoo
- As in python, use ``filtered``, ``mapped``, ``sorted``, ... methods to
ease code reading and performance.
Make your method work in batch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When adding a function, make sure it can process multiple records by iterating
on self to treat each record.
.. code-block:: python
def my_method(self)
for record in self:
record.do_cool_stuff()
For performance issue, when developing a 'stat button' (for instance), do not
perform a ``search`` or a ``search_count`` in a loop. It
is recommended to use ``read_group`` method, to compute all value in only one request.
.. code-block:: python
def _compute_equipment_count(self):
""" Count the number of equipment per category """
equipment_data = self.env['hr.equipment'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id'])
mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in equipment_data])
for category in self:
category.equipment_count = mapped_data.get(category.id, 0)
Propagate the context
~~~~~~~~~~~~~~~~~~~~~
The context is a ``frozendict`` that cannot be modified. To call a method with

View File

@@ -141,7 +141,7 @@ The service has *seven* important fields:
* :samp:`name` - :class:`ServiceName`: This is the string you will need to provide inside
the client's :ref:`app <iap-odoo-app>` when requesting a transaction from Odoo. (e.g.
:class:`self.env['iap.account].get(name)`). As good practice, this should match the
`self.env['iap.account].get(name)`). As good practice, this should match the
technical name of your app.
* :samp:`label` - :class:`Label`: The name displayed on the shopping portal for the

View File

@@ -709,8 +709,9 @@ Database Population
.. program:: odoo-bin populate
Odoo CLI supports database population features. If the feature is
:ref:`implemented on a given model <reference/testing/populate/methods>`, it allows automatic data
generation of the model's records to test your modules in databases containing non-trivial amounts of records.
:ref:`implemented on a given model <reference/performance/populate/methods>`, it allows automatic
data generation of the model's records to test your modules in databases containing non-trivial
amounts of records.
.. code-block:: console
@@ -727,8 +728,7 @@ generation of the model's records to test your modules in databases containing n
of a given model (cf. the :file:`populate` folder of modules for further details).
.. seealso::
:ref:`reference/testing/populate`
:ref:`reference/performance/populate`
.. _reference/cmdline/cloc:

View File

@@ -12,7 +12,6 @@ Tutorials
howtos/website
howtos/backend
howtos/web_services
howtos/profilecode
howtos/company
howtos/accounting_localization
howtos/translations

View File

@@ -1,131 +0,0 @@
===================
Profiling Odoo code
===================
.. warning::
This tutorial requires :ref:`having installed Odoo <setup/install>`
and :doc:`writing Odoo code <backend>`
Graph a method
==============
Odoo embeds a profiler of code. This embedded profiler output can be used to
generate a graph of calls triggered by the method, number of queries, percentage
of time taken in the method itself as well as the time that the method took and
its sub-called methods.
.. code:: python
from odoo.tools.misc import profile
[...]
@profile('/temp/prof.profile')
def mymethod(...)
This produces a file called /temp/prof.profile
A tool called *gprof2dot* will produce a graph with this result:
.. code:: bash
gprof2dot -f pstats -o /temp/prof.xdot /temp/prof.profile
A tool called *xdot* will display the resulting graph:
.. code:: bash
xdot /temp/prof.xdot
Log a method
============
Another profiler can be used to log statistics on a method:
.. code:: python
from odoo.tools.profiler import profile
[...]
@profile
@api.model
def mymethod(...):
The statistics will be displayed into the logs once the method to be analysed is
completely reviewed.
.. code:: bash
2018-03-28 06:18:23,196 22878 INFO openerp odoo.tools.profiler:
calls queries ms
project.task ------------------------ /home/odoo/src/odoo/addons/project/models/project.py, 638
1 0 0.02 @profile
@api.model
def create(self, vals):
# context: no_log, because subtype already handle this
1 0 0.01 context = dict(self.env.context, mail_create_nolog=True)
# for default stage
1 0 0.01 if vals.get('project_id') and not context.get('default_project_id'):
context['default_project_id'] = vals.get('project_id')
# user_id change: update date_assign
1 0 0.01 if vals.get('user_id'):
vals['date_assign'] = fields.Datetime.now()
# Stage change: Update date_end if folded stage
1 0 0.0 if vals.get('stage_id'):
vals.update(self.update_date_end(vals['stage_id']))
1 108 631.8 task = super(Task, self.with_context(context)).create(vals)
1 0 0.01 return task
Total:
1 108 631.85
Dump stack
==========
Sending the SIGQUIT signal to an Odoo process (only available on POSIX) makes
this process output the current stack trace to log, with info level. When an
odoo process seems stuck, sending this signal to the process permit to know
what the process is doing, and letting the process continue his job.
Tracing code execution
======================
Instead of sending the SIGQUIT signal to an Odoo process often enough, to check
where the processes are performing worse than expected, we can use the `py-spy`_ tool to
do it for us.
Install py-spy
--------------
.. code:: bash
python3 -m pip install py-spy
Record executed code
--------------------
As py-spy is installed, we now record the executed code lines.
This tool will record, multiple times a second, the stacktrace of the process.
.. code:: bash
# record to raw file
py-spy record -o profile.json -f speedscope --pid <PID>
# OR record directly to svg
py-spy record -o profile.svg --pid <PID>
where <PID> is the process ID of the odoo process you want to graph.
To open profile.json you can use online tool `speedscope.app`_.
To open profile.svg you should use browser, because other viewer may not
support interactive part.
.. image:: profilecode/flamegraph.svg
.. _py-spy: https://github.com/benfred/py-spy
.. _speedscope.app: https://www.speedscope.app/

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 110 KiB

View File

@@ -4,6 +4,8 @@
Advanced B: ACL and Record Rules
================================
ACL stands for "Access Control List"
.. warning::
This tutorial assumes you have completed the :ref:`Core Training

View File

@@ -14,6 +14,7 @@ Python framework
backend/module
backend/reports
backend/security
backend/performance
backend/testing
backend/http
backend/mixins

View File

@@ -83,7 +83,6 @@ value::
.. autoattribute:: _parent_name
.. autoattribute:: _parent_store
.. autoattribute:: _date_name
.. autoattribute:: _fold_name
AbstractModel
@@ -651,50 +650,46 @@ Method decorators
Environment
===========
The :class:`~odoo.api.Environment` stores various contextual data used by
the ORM: the database cursor (for database queries), the current user
(for access rights checking) and the current context (storing arbitrary
metadata). The environment also stores caches.
.. currentmodule:: odoo.api
All recordsets have an environment, which is immutable, can be accessed
using :attr:`~odoo.models.Model.env` and gives access to:
* the current user (:attr:`~odoo.api.Environment.user`)
* the cursor (:attr:`~odoo.api.Environment.cr`)
* the superuser flag (:attr:`~odoo.api.Environment.su`)
* or the context (:attr:`~odoo.api.Environment.context`)
.. autoclass:: Environment
.. code-block:: bash
>>> records.env
<Environment object ...>
>>> records.env.uid
3
>>> records.env.user
res.user(3)
>>> records.env.cr
<Cursor object ...)
<Cursor object ...>
When creating a recordset from an other recordset, the environment is
inherited. The environment can be used to get an empty recordset in an
other model, and query that model::
other model, and query that model:
.. code-block:: bash
>>> self.env['res.partner']
res.partner()
>>> self.env['res.partner'].search([['is_company', '=', True], ['customer', '=', True]])
>>> self.env['res.partner'].search([('is_company', '=', True), ('customer', '=', True)])
res.partner(7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74)
.. currentmodule:: odoo.api
.. automethod:: Environment.ref
Some lazy properties are available to access the environment (contextual) data:
.. autoattribute:: Environment.lang
.. autoattribute:: Environment.user
.. autoattribute:: Environment.company
.. autoattribute:: Environment.companies
.. TODO cr, uid but not @property or methods of Environment class...
Useful environment methods
--------------------------
.. automethod:: Environment.ref
.. automethod:: Environment.is_superuser
.. automethod:: Environment.is_admin
.. automethod:: Environment.is_system
Altering the environment
------------------------
@@ -856,15 +851,11 @@ Search/Read
.. automethod:: Model.read_group
Fields/Views
''''''''''''
Fields
''''''
.. automethod:: Model.fields_get
.. automethod:: Model.get_view
.. automethod:: Model.fields_view_get
.. _reference/orm/domains:
Search domains

View File

@@ -0,0 +1,540 @@
:custom-css: performance.css
===========
Performance
===========
.. _performance/profiling:
Profiling
=========
.. currentmodule:: odoo.tools.profiler
Profiling is about analysing the execution of a program and measure aggregated data. These data can
be the elapsed time for each function, the executed SQL queries...
While profiling does not improve the performance of a program by itself, it can prove very helpful
in finding performance issues and identifying which part of the program is responsible for them.
Odoo provides an integrated profiling tool that allows recording all executed queries and stack
traces during execution. It can be used to profile either a set of requests of a user session, or a
specific portion of code. Profiling results can be either inspected with the integrated `speedscope
<https://github.com/jlfwong/speedscope>`_ :dfn:`open source app allowing to visualize a flamegraph`
view or analyzed with custom tools by first saving them in a JSON file or in the database.
.. _performance/profiling/enable:
Enable the profiler
-------------------
The profiler can either be enabled from the user interface, which is the easiest way to do so but
allows profiling only web requests, or from Python code, which allows profiling any piece of code
including tests.
.. tabs::
.. tab:: Enable from the user interface
#. :ref:`Enable the developer mode <developer-mode>`.
#. Before starting a profiling session, the profiler must be enabled globally on the database.
This can be done in two ways:
- Open the :ref:`developer mode tools <developer-mode/mode-tools>`, then toggle the
:guilabel:`Enable profiling` button. A wizard suggests a set of expiry times for the
profiling. Click on :guilabel:`ENABLE PROFILING` to enable the profiler globally.
.. image:: performance/enable_profiling_wizard.png
- Go to :guilabel:`Settings --> General Settings --> Performance` and set the desired time to
the field :guilabel:`Enable profiling until`.
#. After the profiler is enabled on the database, users can enable it on their session. To do
so, toggle the :guilabel:`Enable profiling` button in the :ref:`developer mode tools
<developer-mode/mode-tools>` again. By default, the recommended options :guilabel:`Record
sql` and :guilabel:`Record traces` are enabled. To learn more about the different options,
head over to :ref:`performance/profiling/collectors`.
.. image:: performance/profiling_debug_menu.png
When the profiler is enabled, all the requests made to the server are profiled and saved into
an `ir.profile` record. Such records are grouped into the current profiling session which
spans from when the profiler was enabled until it is disabled.
.. note::
Odoo Online (SaaS) databases cannot be profiled.
.. tab:: Enable from Python code
Starting the profiler manually can be convenient to profile a specific method or a part of the
code. This code can be a test, a compute method, the entire loading, etc.
To start the profiler from Python code, call it as a context manager. You may specify *what*
you want to record through the parameters. A shortcut is available for profiling test classes:
:code:`self.profile()`. See :ref:`performance/profiling/collectors` for more information on
the `collectors` parameter.
.. example::
.. code-block:: python
with Profiler():
do_stuff()
.. example::
.. code-block:: python
with Profiler(collectors=['sql', PeriodicCollector(interval=0.1)]):
do_stuff()
.. example::
.. code-block:: python
with self.profile():
with self.assertQueryCount(__system__=1211):
do_stuff()
.. note::
The profiler is called outside of the `assertQueryCount` in order to catch queries made
when exiting the context manager (e.g., flush).
.. autoclass:: Profiler()
:special-members: __init__
When the profiler is enabled, all executions of a test method are profiled and saved into an
`ir.profile` record. Such records are grouped into a single profiling session. This is
especially useful when using the :code:`@warmup` and :code:`@users` decorators.
.. tip::
It can be complicated to analyze profiling results of a method that is called several times
because all the calls are grouped together in the stack trace. Add an **execution context**
as a context manager to break down the results into multiple frames.
.. example::
.. code-block:: python
for index in range(max_index):
with ExecutionContext(current_index=index): # Identify each call in speedscope results.
do_stuff()
.. _performance/profiling/analyse:
Analyse the results
-------------------
To browse the profiling results, make sure that the :ref:`profiler is enabled globally on the
database <performance/profiling/enable>`, then open the :ref:`developer mode tools
<developer-mode/mode-tools>` and click on the button in the top-right corner of the profiling
section. A list view of the `ir.profile` records grouped by profiling session opens.
.. image:: performance/profiling_web.png
:align: center
Each record has a clickable link that opens the speedscope results in a new tab.
.. image:: performance/flamegraph_example.png
:align: center
Speedscope falls out of the scope of this documentation but there are a lot of tools to try: search,
highlight of similar frames, zoom on frame, timeline, left heavy, sandwich view...
Depending on the profiling options that were activated, Odoo generates different view modes that you
can access from the top menu.
.. image:: performance/speedscope_modes.png
:align: center
- The :guilabel:`Combined` view shows all the SQL queries and traces merged togethers.
- The :guilabel:`Combined no context` view shows the same result but ignores the saved execution
context <performance/profiling/enable>`.
- The :guilabel:`sql (no gap)` view shows all the SQL queries as if they were executed one after
another, without any Python logic. This is useful for optimizing SQL only.
- The :guilabel:`sql (density)` view shows only all the SQL queries, leaving gap between them. This
can be useful to spot if eiter SQL or Python code is the problem, and to identify zones in where
many small queries could be batched.
- The :guilabel:`frames` view shows the results of only the :ref:`periodic collector
<performance/profiling/collectors/periodic>`.
.. important::
Even though the profiler has been designed to be as light as possible, it can still impact
performance, especially when using the :ref:`Sync collector
<performance/profiling/collectors/sync>`. Keep that in mind when analyzing speedscope results.
.. _performance/profiling/collectors:
Collectors
----------
Whereas the profiler is about the *when* of profiling, the collectors take care of the *what*.
Each collector specializes in collecting profiling data in its own format and manner. They can be
individually enabled from the user interface through their dedicated toggle button in the
:ref:`developer mode tools <developer-mode/mode-tools>`, or from Python code through their key or
class.
There are currently four collectors available in Odoo:
.. list-table::
:header-rows: 1
* - Name
- Toggle button
- Python key
- Python class
* - :ref:`SQL collector <performance/profiling/collectors/sql>`
- :guilabel:`Record sql`
- `sql`
- `SqlCollector`
* - :ref:`Periodic collector <performance/profiling/collectors/periodic>`
- :guilabel:`Record traces`
- `traces_async`
- `PeriodicCollector`
* - :ref:`QWeb collector <performance/profiling/collectors/qweb>`
- :guilabel:`Record qweb`
- `qweb`
- `QwebCollector`
* - :ref:`Sync collector <performance/profiling/collectors/sync>`
- No
- `traces_sync`
- `SyncCollector`
By default, the profiler enables the SQL and the Periodic collectors. Both when it is enabled from
the user interface or Python code.
.. _performance/profiling/collectors/sql:
SQL collector
~~~~~~~~~~~~~
The SQL collector saves all the SQL queries made to the database in the current thread (for all
cursors), as well as the stack trace. The overhead of the collector is added to the analysed thread
for each query, which means that using it on a lot of small queries may impact execution time and
other profilers.
It is especially useful to debug query counts, or to add information to the :ref:`Periodic collector
<performance/profiling/collectors/periodic>` in the combined speedscope view.
.. autoclass:: SQLCollector
.. _performance/profiling/collectors/periodic:
Periodic collector
~~~~~~~~~~~~~~~~~~
This collector runs in a separate thread and saves the stack trace of the analysed thread at every
interval. The interval (by default 10 ms) can be defined through the :guilabel:`Interval` option in
the user interface, or the `interval` parameter in Python code.
.. warning::
If the interval is set at a very low value, profiling long requests will generate memory issues.
If the interval is set at a very high value, information on short function executions will be
lost.
It is one of the best way to analyse performance as it should have a very low impact on the
execution time thanks to its separate thread.
.. autoclass:: PeriodicCollector
.. _performance/profiling/collectors/qweb:
QWeb collector
~~~~~~~~~~~~~~
This collector saves the Python execution time and queries of all directives. As for the :ref:`SQL
collector <performance/profiling/collectors/sql>`, the overhead can be important when executing a
lot of small directives. The results are different from other collectors in terms of collected data,
and can be analysed from the `ir.profile` form view using a custom widget.
It is mainly useful for optimizing views.
.. autoclass:: QwebCollector
.. _performance/profiling/collectors/sync:
Sync collector
~~~~~~~~~~~~~~
This collector saves the stack for every function's call and return and runs on the same thread,
which greatly impacts performance.
It can be useful to debug and understand complex flows, and follow their execution in the code. It
is however not recommended for performance analysis because the overhead is high.
.. autoclass:: SyncCollector
.. _performance/profiling/pitfalls:
Performance pitfalls
--------------------
- Be careful with randomness. Multiple executions may lead to different results. E.g., a garbage
collector being triggered during execution.
- Be careful with blocking calls. In some cases, external `c_call` may take some time before
releasing the GIL, thus leading to unexpected long frames with the :ref:`Periodic collector
<performance/profiling/collectors/periodic>`. This should be detected by the profiler and give a
warning. It is possible to trigger the profiler manually before such calls if needed.
- Pay attention to the cache. Profiling before that the `view`/`assets`/... are in cache can lead to
different results.
- Be aware of the profiler's overhead. The :ref:`SQL collector
<performance/profiling/collectors/sql>`'s overhead can be important when a lot of small queries
are executed. Profiling is practical to spot a problem but you may want to disable the profiler in
order to measure the real impact of a code change.
- Profiling results can be memory intensive. In some cases (e.g., profiling an install or a long
request), it is possible that you reach memory limit, especially when rendering the speedscope
results, which can lead to an HTTP 500 error. In this case, you may need to start the server with
a higher memory limit: `--limit-memory-hard $((8*1024**3))`.
.. _reference/performance/populate:
Database population
===================
Odoo CLI offers a :ref:`database population <reference/cmdline/populate>` feature through the CLI
command :command:`odoo-bin populate`.
Instead of the tedious manual, or programmatic, specification of test data, one can use this feature
to fill a database on demand with the desired number of test data. This can be used to detect
diverse bugs or performance issues in tested flows.
.. _reference/performance/populate/methods:
To populate a given model, the following methods and attributes can be defined.
.. currentmodule:: odoo.models
.. autoattribute:: Model._populate_sizes
.. autoattribute:: Model._populate_dependencies
.. automethod:: Model._populate
.. automethod:: Model._populate_factories
.. note::
You have to define at least :meth:`~odoo.models.Model._populate` or
:meth:`~odoo.models.Model._populate_factories` on the model to enable database population.
.. example::
.. code-block:: python
from odoo.tools import populate
class CustomModel(models.Model)
_inherit = "custom.some_model"
_populate_sizes = {"small": 100, "medium": 2000, "large": 10000}
_populate_dependencies = ["custom.some_other_model"]
def _populate_factories(self):
# Record ids of previously populated models are accessible in the registry
some_other_ids = self.env.registry.populated_models["custom.some_other_model"]
def get_some_field(values=None, random=None, **kwargs):
""" Choose a value for some_field depending on other fields values.
:param dict values:
:param random: seeded :class:`random.Random` object
"""
field_1 = values['field_1']
if field_1 in [value2, value3]:
return random.choice(some_field_values)
return False
return [
("field_1", populate.randomize([value1, value2, value3])),
("field_2", populate.randomize([value_a, value_b], [0.5, 0.5])),
("some_other_id", populate.randomize(some_other_ids)),
("some_field", populate.compute(get_some_field, seed="some_field")),
('active', populate.cartesian([True, False])),
]
def _populate(self, size):
records = super()._populate(size)
# If you want to update the generated records
# E.g setting the parent-child relationships
records.do_something()
return records
Population tools
----------------
Multiple population tools are available to easily create the needed data generators.
.. automodule:: odoo.tools.populate
:members: cartesian, compute, constant, iterate, randint, randomize
.. _performance/good_practices:
Good practices
==============
.. _performance/good_practices/batch:
Batch operations
----------------
When working with recordsets, it is almost always better to batch operations.
.. example::
Don't call a method that runs SQL queries while looping over a recordset because it will do so
for each record of the set.
.. rst-class:: bad-example
.. code-block:: python
def _compute_count(self):
for record in self:
domain = [('related_id', '=', record.id)]
record.count = other_model.search_count(domain)
Instead, replace the `search_count` with a `read_group` to execute one SQL query for the entire
batch of records.
.. rst-class:: good-example
.. code-block:: python
def _compute_count(self):
if self.ids:
domain = [('related_id', 'in', self.ids)]
counts_data = other_model.read_group(domain, ['related_id'], ['related_id'])
mapped_data = {
count['related_id'][0]: count['related_id_count'] for count in counts_data
}
else:
mapped_data = {}
for record in self:
record.count = mapped_data.get(record.id, 0)
.. note::
This example is not optimal nor correct in all cases. It is only a substitute for a
`search_count`. Another solution could be to prefetch and count the inverse `One2many` field.
.. example::
Don't create records one after another.
.. rst-class:: bad-example
.. code-block:: python
for name in ['foo', 'bar']:
model.create({'name': name})
Instead, accumulate the create values and call the `create` method on the batch. Doing so has
mostly no impact and helps the framework optimize fields computation.
.. rst-class:: good-example
.. code-block:: python
create_values = []
for name in ['foo', 'bar']:
create_values.append({'name': name})
records = model.create(create_values)
.. example::
Fail to prefetch the fields of a recordset while browsing a single record inside a loop.
.. rst-class:: bad-example
.. code-block:: python
for record_id in record_ids:
model.browse(record_id)
record.foo # One query is executed per record.
Instead, browse the entire recordset first.
.. rst-class:: good-example
.. code-block:: python
records = model.browse(record_ids)
for record in records:
record.foo # One query is executed for the entire recordset.
We can verify that the records are prefetched in batch by reading the field `prefetch_ids` which
includes each of the record ids.browsing all records together is unpractical,
If needed, the `with_prefetch` method can be used to disable batch prefetching:
.. code-block:: python
for values in values_list:
message = self.browse(values['id']).with_prefetch(self.ids)
.. _performance/good_practices/algorithmic_complexity:
Reduce the algorithmic complexity
---------------------------------
Algorithmic complexity is a measure of how long an algorithm would take to complete in regard to the
size `n` of the input. When the complexity is high, the execution time can grow quickly as the input
becomes larger. In some cases, the algorithmic complexity can be reduced by preparing the input's
data correctly.
.. example::
For a given problem, let's consider a naive algorithm crafted with two nested loops for which the
complexity in in O(n²).
.. rst-class:: bad-example
.. code-block:: python
for record in self:
for result in results:
if results['id'] == record.id:
record.foo = results['foo']
break
Assuming that all results have a different id, we can prepare the data to reduce the complexity.
.. rst-class:: good-example
.. code-block:: python
mapped_result = {result['id']: result['foo'] for result in results}
for record in self:
record.foo = mapped_result.get(record.id)
.. example::
Choosing the bad data structure to hold the input can lead to quadratic complexity.
.. rst-class:: bad-example
.. code-block:: python
invalid_ids = self.search(domain).ids
for record in self:
if record.id in invalid_ids:
...
If `invalid_ids` is a list-like data structure, the complexity of the algorithm may be quadratic.
Instead, prefer using set operations like casting `invalid_ids` to a set.
.. rst-class:: good-example
.. code-block:: python
invalid_ids = set(invalid_ids)
for record in self:
if record.id in invalid_ids:
...
Depending on the input, recordset operations can also be used.
.. rst-class:: good-example
.. code-block:: python
invalid_ids = self.search(domain)
for record in self - invalid_ids:
...
.. _performance/good_practices/index:
Use indexes
-----------
Database indexes can help fasten search operations, be it from a search in the or through the user
interface.
.. code-block:: python
name = fields.Char(string="Name", index=True)
.. warning::
Be careful not to index every field as indexes consume space and impact on performance when
executing one of `INSERT`, `UPDATE`, and `DELETE`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -864,90 +864,6 @@ you can use the :meth:`~odoo.tests.common.BaseCase.assertQueryCount` method, int
with self.assertQueryCount(11):
do_something()
.. _reference/testing/populate:
Database population
-------------------
Odoo CLI offers a :ref:`database population<reference/cmdline/populate>` feature.
.. code-block:: console
odoo-bin populate
Instead of the tedious manual, or programmatic, specification of test data,
one can use this feature to fill a database on demand with the desired number of test data.
This can be used to detect diverse bugs or performance issues in tested flows.
.. _reference/testing/populate/methods:
To specify this feature for a given model, the following methods and attributes can be defined.
.. currentmodule:: odoo.models
.. autoattribute:: Model._populate_sizes
.. autoattribute:: Model._populate_dependencies
.. automethod:: Model._populate
.. automethod:: Model._populate_factories
.. note::
You have to define at least :meth:`~odoo.models.Model._populate` or :meth:`~odoo.models.Model._populate_factories`
on the model to enable database population.
Example model
~~~~~~~~~~~~~
.. code-block:: python
from odoo.tools import populate
class CustomModel(models.Model)
_inherit = "custom.some_model"
_populate_sizes = {"small": 100, "medium": 2000, "large": 10000}
_populate_dependencies = ["custom.some_other_model"]
def _populate_factories(self):
# Record ids of previously populated models are accessible in the registry
some_other_ids = self.env.registry.populated_models["custom.some_other_model"]
def get_some_field(values=None, random=None, **kwargs):
""" Choose a value for some_field depending on other fields values.
:param dict values:
:param random: seeded :class:`random.Random` object
"""
field_1 = values['field_1']
if field_1 in [value2, value3]:
return random.choice(some_field_values)
return False
return [
("field_1", populate.randomize([value1, value2, value3])),
("field_2", populate.randomize([value_a, value_b], [0.5, 0.5])),
("some_other_id", populate.randomize(some_other_ids)),
("some_field", populate.compute(get_some_field, seed="some_field")),
('active', populate.cartesian([True, False])),
]
def _populate(self, size):
records = super()._populate(size)
# If you want to update the generated records
# E.g setting the parent-child relationships
records.do_something()
return records
Population tools
~~~~~~~~~~~~~~~~
Multiple population tools are available to easily create
the needed data generators.
.. automodule:: odoo.tools.populate
:members: cartesian, compute, constant, iterate, randint, randomize
.. _qunit: https://qunitjs.com/
.. _qunit_config.js: https://github.com/odoo/odoo/blob/51ee0c3cb59810449a60dae0b086b49b1ed6f946/addons/web/static/tests/helpers/qunit_config.js#L49
.. _web.tests_assets: https://github.com/odoo/odoo/blob/51ee0c3cb59810449a60dae0b086b49b1ed6f946/addons/web/views/webclient_templates.xml#L594

View File

@@ -336,6 +336,21 @@ A view's specs are applied sequentially.
views: ``hasclass(*classes)`` matches if the context node has
all the specified classes
Model Commons
====================
.. currentmodule:: odoo.addons.base.models.ir_ui_view
Attributes
----------
.. autoattribute:: Model._date_name
Methods
-------
.. automethod:: Model.get_views
.. automethod:: Model.get_view
.. _reference/views/types:
View types

View File

@@ -8,3 +8,4 @@ Standard modules
:titlesonly:
standard_modules/account
standard_modules/payment

View File

@@ -0,0 +1,12 @@
:hide-page-toc:
=======
Payment
=======
.. toctree::
:titlesonly:
payment/payment_provider
payment/payment_token
payment/payment_transaction

View File

@@ -0,0 +1,18 @@
:hide-page-toc:
================
Payment Provider
================
.. autoclass:: odoo.addons.payment.models.payment_provider.PaymentProvider()
.. automethod:: _compute_feature_support_fields
.. automethod:: _compute_fees
.. automethod:: _compute_view_configuration_fields
.. automethod:: _get_compatible_providers
.. automethod:: _get_redirect_form_view
.. automethod:: _get_validation_amount
.. automethod:: _get_validation_currency
.. automethod:: _is_tokenization_required
.. automethod:: _should_build_inline_form
.. automethod:: _get_removal_values

View File

@@ -0,0 +1,12 @@
:hide-page-toc:
=============
Payment Token
=============
.. autoclass:: odoo.addons.payment.models.payment_token::PaymentToken()
.. automethod:: _build_display_name
.. automethod:: _get_specific_create_values
.. automethod:: _handle_archiving
.. automethod:: get_linked_records_info

View File

@@ -0,0 +1,26 @@
:hide-page-toc:
===================
Payment Transaction
===================
.. autoclass:: odoo.addons.payment.models.payment_transaction::PaymentTransaction()
.. automethod:: _compute_reference
.. automethod:: _compute_reference_prefix
.. automethod:: _get_post_processing_values
.. automethod:: _get_specific_create_values
.. automethod:: _get_specific_processing_values
.. automethod:: _get_specific_rendering_values
.. automethod:: _get_tx_from_notification_data
.. automethod:: _handle_notification_data
.. automethod:: _process_notification_data
.. automethod:: _send_capture_request
.. automethod:: _send_payment_request
.. automethod:: _send_refund_request
.. automethod:: _send_void_request
.. automethod:: _set_authorized
.. automethod:: _set_canceled
.. automethod:: _set_done
.. automethod:: _set_error
.. automethod:: _set_pending

View File

@@ -0,0 +1,7 @@
.bad-example {
border-left: 3px solid red;
}
.good-example {
border-left: 3px solid green;
}