Compare commits
15 Commits
fix/doc/di
...
master-rel
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bac0f08299 |
[IMP] supported_version: release 16.0 and deprecate 13.0
X-original-commit:
|
||
|
|
d41a66758f |
[IMP] sale_amazon: support all marketplaces
task-2939972
closes odoo/documentation#2806
X-original-commit:
|
||
|
|
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:
|
||
|
|
c8ab0c1535 |
[FIX] developer/iap: wrong :class: element
X-original-commit:
|
||
|
|
0e567a08de |
[IMP] reference/payment: auto-document the method _get_removal_values
Task - 3002532
closes odoo/documentation#2802
X-original-commit:
|
||
|
|
9baab389c9 |
[ADD] reference/standard_modules: API reference for the payment engine
task-2804999
closes odoo/documentation#2797
X-original-commit:
|
||
|
|
46a80f60c5 |
[ADD] developer/reference: add a reference page on performance
closes odoo/documentation#2794
X-original-commit:
|
||
|
|
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:
|
||
|
|
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:
|
||
|
|
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> |
||
|
|
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:
|
||
|
|
7424e4176c |
[IMP] website: register domain name menu path
closes odoo/documentation#2766
X-original-commit:
|
||
|
|
8287c88bd4 |
[IMP] MRP: updated Variants BOM Management rst content
closes odoo/documentation#2764
X-original-commit:
|
||
|
|
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:
|
||
|
|
2c7d61f938 |
[FIX] accounting: grammar fix in ponto
closes odoo/documentation#2759
X-original-commit:
|
4
conf.py
|
|
@@ -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",
|
||||
|
|
|
|||
|
|
@@ -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
|
||||
|
||||
|
|
|
|||
BIN
content/administration/maintain/domain_names/register-menu.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
|
@@ -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 | |
|
||||
+-----------------+-------------+----------+-------------+----------------+------------------------+
|
||||
|
|
|
|||
|
|
@@ -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
|
||||
---------------------------------------
|
||||
|
|
|
|||
|
|
@@ -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
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 7.7 KiB |
|
|
@@ -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
|
||||
=====================
|
||||
|
||||
|
|
|
|||
|
|
@@ -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 provider’s 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.
|
||||
|
|
|
|||
|
|
@@ -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.
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
|
@@ -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`
|
||||
|
|
|
|||
|
|
@@ -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`
|
||||
|
|
|
|||
|
|
@@ -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
|
||||
|
|
|
|||
|
|
@@ -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
|
||||
|
|
|
|||
|
|
@@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@@ -12,7 +12,6 @@ Tutorials
|
|||
howtos/website
|
||||
howtos/backend
|
||||
howtos/web_services
|
||||
howtos/profilecode
|
||||
howtos/company
|
||||
howtos/accounting_localization
|
||||
howtos/translations
|
||||
|
|
|
|||
|
|
@@ -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/
|
||||
|
Before Width: | Height: | Size: 110 KiB |
|
|
@@ -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
|
||||
|
|
|
|||
|
|
@@ -14,6 +14,7 @@ Python framework
|
|||
backend/module
|
||||
backend/reports
|
||||
backend/security
|
||||
backend/performance
|
||||
backend/testing
|
||||
backend/http
|
||||
backend/mixins
|
||||
|
|
|
|||
|
|
@@ -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
|
||||
|
|
|
|||
540
content/developer/reference/backend/performance.rst
Normal 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`.
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
|
@@ -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
|
||||
|
|
|
|||
|
|
@@ -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
|
||||
|
|
|
|||
|
|
@@ -8,3 +8,4 @@ Standard modules
|
|||
:titlesonly:
|
||||
|
||||
standard_modules/account
|
||||
standard_modules/payment
|
||||
|
|
|
|||
12
content/developer/reference/standard_modules/payment.rst
Normal file
|
|
@@ -0,0 +1,12 @@
|
|||
:hide-page-toc:
|
||||
|
||||
=======
|
||||
Payment
|
||||
=======
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
payment/payment_provider
|
||||
payment/payment_token
|
||||
payment/payment_transaction
|
||||
|
|
@@ -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
|
||||
|
|
@@ -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
|
||||
|
|
@@ -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
|
||||
7
static/css/performance.css
Normal file
|
|
@@ -0,0 +1,7 @@
|
|||
.bad-example {
|
||||
border-left: 3px solid red;
|
||||
}
|
||||
|
||||
.good-example {
|
||||
border-left: 3px solid green;
|
||||
}
|
||||