[IMP] developer/howtos: proofread adv topics

- Cleaned up the language a tiny bit
- Fixed small errors/typos
- Add some missing info for dashboard topic
- Updated unit test exercise to match what's in the solutions repo

Part-of: odoo/documentation#1146
This commit is contained in:
Tiffany Chang (tic) 2021-09-14 14:18:40 +00:00 committed by Antoine Vandevenne (anv)
parent 85410bd8dc
commit b3845ae0d8
4 changed files with 78 additions and 65 deletions

View File

@ -33,7 +33,7 @@ However:
* Real-estate agents don't need or get to decide what property types or tags are
*available*.
* Real-estate agents can have *exclusive* properties, we do not want one agent
to be able to manage another's exclusivities.
to be able to manage another's exclusives.
* All real-estate agents should be able to confirm the sale of a property they
can manage, but we do not want them to be able to validate or mark as paid
any invoice in the system.
@ -44,7 +44,7 @@ However:
Because it's easier for users to disable unnecessary security rules than it
is to create them from nothing, it's better to err on the side of caution
and limiting access: users can relax that access if necessary or convenient.
and limit access: users can relax that access if necessary or convenient.
Groups
======
@ -294,7 +294,7 @@ do so.
There are two main ways to bypass existing security checks in Odoo, either
wilfully or as a side-effect:
* The ``sudo()`` method will create a new recorset in "sudo mode", this ignores
* The ``sudo()`` method will create a new recordset in "sudo mode", this ignores
all access rules and access rights (although hard-coded group and user checks
may still apply).
* Performing raw SQL queries will bypass access rules and access rights as a
@ -366,9 +366,9 @@ Explicit security checks can be performed by:
specific models or records.
* Checking that the current user has specific groups hard-coded to allow or deny
an operation (``self.env.user.has_group``).
* Calling the ``check_access_rights(operation)`` method on a recorset, this
* Calling the ``check_access_rights(operation)`` method on a recordset, this
verifies whether the current user has access to the model itself.
* Calling ``check_access_rule(operations)`` on a non-empty recorset, this
* Calling ``check_access_rule(operations)`` on a non-empty recordset, this
verifies that the current user is allowed to perform the operation on *every*
record of the set.
@ -380,7 +380,7 @@ Explicit security checks can be performed by:
Before creating the invoice, use ``check_access_rights`` and
``check_access_rule`` to ensure that the current user can update properties
in general, and this specific property in particular.
in general as well as the specific property the invoice is for.
Re-run the bypass script, check that the error occurs before the print.
@ -393,7 +393,7 @@ Multi-company security
:ref:`reference/howtos/company` for an overview of multi-company facilities
in general, and :ref:`multi-company security rules <howto/company/security>`
this in particular.
in particular.
Documentation on rules in general can, again, be found at
:ref:`reference/security/rules`.
@ -403,15 +403,15 @@ Multi-company security
At the end of this section, agents should only have access to properties
of their agency (or agencies).
For one reason or an other we might need to manage our real-estate business
as multiple companies e.g. we might have largely autonomous agencies, or a
For one reason or another we might need to manage our real-estate business
as multiple companies e.g. we might have largely autonomous agencies, a
franchise setup, or multiple brands (possibly from having acquired other
real-estate businesses) which remain legally or financially separate from one
another.
Odoo can be used to manage multiple companies inside the same system, however
the actual handling is up to individual modules: Odoo itself provides the tools
to manage the issue like company-dependent fields and *multi-company rules*,
to manage the issue of company-dependent fields and *multi-company rules*,
which is what we're going to concern ourselves with.
We want different agencies to be "siloed" from one another, with properties
@ -447,7 +447,7 @@ associated with *one* of the companies the user has access to:
Multi-company rules are usually :ref:`global <reference/security/rules/global>`,
otherwise there is a high risk that additional rules would allow bypassing
the muti-company rules.
the multi-company rules.
.. exercise::
@ -472,7 +472,7 @@ Visibility != security
.. admonition:: **Goal**
At the end of this section, real-estate agents should not see the Settings
menu of the rea-estate application, but should still be able to set the
menu of the real-estate application, but should still be able to set the
property type or tags.
Specific Odoo models can be associated directly with groups (or companies, or
@ -480,7 +480,7 @@ users). It is important to figure out whether this association is a *security*
or a *visibility* feature before using it:
* *Visibility* features mean a user can still access the model or record
otherwise, either through an other part of the interface or by :doc:`perform
otherwise, either through another part of the interface or by :doc:`performing
operations remotely using RPC <../../misc/api/odoo>`, things might just not be
visible in the web interface in some contexts.
* *Security* features mean a user can not access records, fields or operations.
@ -507,10 +507,10 @@ Here are some examples:
.. exercise::
Real Estate agents can not add property types or tags, and can see their
Real Estate agents can not add property types or tags, but can see their
options from the Property form view when creating it.
The Settings menu just adds noise to their interface, it should only be
The Settings menu just adds noise to their interface, make it only
visible to managers.
Despite not having access to the Property Types and Property Tags menus anymore,

View File

@ -23,23 +23,23 @@ We already met technical data previously since we have defined
:ref:`security rules<howto/rdtraining/N_security>`, :ref:`views<reference/views>` and
:ref:`actions<reference/actions>`. Those are one kind of master data.
On top of technical data, business data can be defined: countries, currencies, units of measure but
also complete country localization (legal reports, tax definitions, chart of account), and much
On top of technical data, business data can be defined, e.g. countries, currencies, units of measure,
as well as complete country localization (legal reports, tax definitions, chart of account), and much
more...
Demo Data
---------
Next to master data which are requirements for the modules to work properly, we also like having
data for demonstration purpose setups:
In additional to master data, which are requirements for a module to work properly, we also like
having data for demonstration purposes:
* Help the sales representatives to make their demos quickly.
* Have a set of working data for developers to test the new features and see what it looks like
with something they might not have created without it.
* Help the sales representatives make their demos quickly.
* Have a set of working data for developers to test new features and see how these new features look
with data they might not have added themselves.
* Test that the data is loaded correctly, without raising an error.
* Be ready to use most of the features quickly when creating a new database.
* Setup most of the features to be used quickly when creating a new database.
Demo data is automatically loaded when you start the server if you didn't say explicitly you don't
Demo data is automatically loaded when you start the server if you don't explicitly say you don't
want it. This can be done in the database manager or with the command line.
.. code-block:: console
@ -70,15 +70,15 @@ Manifest
**Reference**: the documentation related to this topic can be found in
:ref:`Module Manifests<reference/module/manifest>`.
The data is declared either in CSV either in XML.
Data is declared either in CSV or in XML.
Each file containing data must be added in the manifest for them to be loaded.
The keys to use in the manifest to add new data are ``data`` for the master data and ``demo`` for
the demo data. Both values should be a list of strings representing the relative path to the files
the demo data. Both values should be a list of strings representing the relative paths to the files
declaring the data.
Usually, the demo data is set in a ``demo`` folder, the views and actions are put in a ``views``
folder, the security related data is put in a ``security`` folder, and the other data is set in a
Usually, demo data is in a ``demo`` folder, views and actions are in a ``views``
folder, security related data is in a ``security`` folder, and other data is in a
``data`` folder.
If your work tree looks like this:
@ -129,7 +129,7 @@ CSV
:ref:`CSV data files<reference/data/csvdatafiles>`.
The easiest way to declare simple data is by using the CSV format. This is however limited in terms
of features: use it for long lists of simple models, but prefer XML in the other cases.
of features: use it for long lists of simple models, but prefer XML otherwise.
.. code-block:: text
@ -153,7 +153,7 @@ XML
**Reference**: the documentation related to this topic can be found in
:ref:`Data Files<reference/data>`.
When the data to create is a bit more complex it can be useful, or even needed, to do it in XML.
When the data to create is more complex it can be useful, or even necessary, to do it in XML.
.. code-block:: xml
@ -243,7 +243,7 @@ works too if you are in the module declaring it).
Deco Addict Big Villa 1500001 14
============== ========= ======= ========
.. exercise:: Both properties should be Residential properties.
.. exercise:: Ensure both of your demo properties are created with their Property Type set to Residential.
``eval``
~~~~~~~~
@ -279,13 +279,13 @@ Sometimes, you need to call the ORM to do a ``search``. This is not feasible wit
</record>
</odoo>
In this code snippet, it is needed because the master data actually depends on the localization
In this code snippet, it is needed because the master data depends on the localization
installed.
``function``
~~~~~~~~~~~~
You might also need to execute python code when loading the data.
You might also need to execute python code when loading data.
.. code-block:: xml
@ -324,15 +324,8 @@ common ORM methods.
</record>
</odoo>
.. code-block:: text
id,parent_id:id,name
"child1","module.parent","Name1"
"child2","module.parent","Name2"
"child3","module.parent","Name3"
.. exercise:: Create one new Property, but this time with some offers created directly inside the
One2many field linking to the Offers.
One2many field linked to the Offers.
Accessing the data
==================

View File

@ -15,11 +15,11 @@ Advanced E: Python Unit Tests
Writing tests is a necessity for multiple reasons. Here is a non exhaustive list:
* Ensure it will not be broken in the future
* Ensure code will not be broken in the future
* Define the scope of your code
* Give examples of use cases
* It is one way to technically document the code
* Help you develop by defining your goal before working towards it
* Help your coding by defining your goal before working towards it
Running Tests
=============
@ -79,7 +79,7 @@ Integration Bots
================
.. note:: This section is only for Odoo employees and people that are contributing to
`github.com/odoo`. We highly recommend having your own CI if it is not the case.
`github.com/odoo`. We highly recommend having your own CI otherwise.
When a test is written, it is important to make sure it always passes when modifications are
applied to the source code. To automate this task, we use a development practice called
@ -100,7 +100,7 @@ GitHub.
You can see the state of a commit/branch by filtering on the runbot dashboard.
A **bundle** is created for each branch. A bundle consists of a configuration and contains the
A **bundle** is created for each branch. A bundle consists of a configuration and
batches.
A **batch** is a set of builds, depending on the parameters of the bundle.
@ -116,17 +116,17 @@ process. Generally it is used to split the post install tests in 4 parallel inst
A sub-build is green if all the tests are passing and there are no errors/warnings logged.
.. note::
* All tests are run whatever the modifications done. Correcting a typo in an error message or
refactoring a whole module triggers the same tests. It will install all the modules. This means
something might not work if Runbot green but your changes depend on something you don't depend
on.
* All tests are run regardless of the modifications done. Correcting a typo in an error message or
refactoring a whole module triggers the same tests. All modules will be installed as well. This means
something might not work even if the Runbot is green, i.e. your changes depend on a module that the
module the changes are in doesn't depend on.
* The localization modules (i.e. country-specific modules) are not installed on Runbot (except
the generic one), some modules with external dependencies can be excluded also.
* There is a nightly build running additional tests, like module operations, localization, single
the generic one). Some modules with external dependencies can also be excluded.
* There is a nightly build running additional tests: module operations, localization, single
module installs, multi-builds for nondeterministic bugs, etc.
These are not kept in the standard CI to shorten the time of execution.
You can also login on a build built by Runbot. There are 3 users usable: `admin`, `demo` and
You can also login to a build built by Runbot. There are 3 users usable: `admin`, `demo` and
`portal`. The password is the same as the login. This is useful to quickly test things on different
versions without having to build it locally. The full logs are also available; these are used for
monitoring.
@ -138,9 +138,9 @@ You will most likely have to gain a little bit more experience before having the
robodoo, but here are a few remarks anyways.
Robodoo is the guy spamming the CI status as tags on your PRs, but he is also the guy that kindly
integrates your commits on the main repositories.
integrates your commits into the main repositories.
When the last batch is green, the reviewer can ask robodoo to merge your PR (actually it is more
When the last batch is green, the reviewer can ask robodoo to merge your PR (it is more
a `rebase` than a `merge`). It will then go to the mergebot.
Mergebot
@ -166,8 +166,8 @@ your branch on the target and rerun the tests locally.
Modules
=======
Because Odoo is modular, the tests need to be modular also. This means the modules are defined in
the module that adds the functionality you add; and that tests cannot depend on functionality
Because Odoo is modular, the tests need to be also modular. This means tests are defined in
the module that adds the functionality you are adding in and tests cannot depend on functionality
coming from modules your module doesn't depend on.
**Reference**: the documentation related to this topic can be found in
@ -193,7 +193,7 @@ coming from modules your module doesn't depend on.
If the behavior you want to test can be changed by the installation of another module, you need to
ensure that the tag `at_install` is set; otherwise you can use the tag `post_install` to speed up
the CI, and ensure it is not changed if it shouldn't.
the CI and ensure it is not changed if it shouldn't.
Writing a test
==============
@ -233,13 +233,13 @@ import the test folder/module in the ``__init__.py`` of the module.
├── __init__.py
└── __manifest__.py
.. note:: Some older tests are extending ``odoo.tests.common.TransactionCase``, but they are less
.. note:: Some older tests extend ``odoo.tests.common.TransactionCase``, but they are less
scalable. The difference is that the setup is done per test method and not per test class.
The data changed are rollbacked between each test in `SavepointCase` to have the same behavior as
in `TransactionCase`.
Changed data is rolled back between each test in `SavepointCase` to have the same behavior as
`TransactionCase`.
All the tests should extend ``odoo.tests.common.SavepointCase``. You usually define a
``setUpClass``, and the tests. After doing the `setUpClass`, you have an `env` available on the
``setUpClass`` and the tests. After writing the `setUpClass`, you have an `env` available in the
class and can start interacting with the ORM.
These test classes are built on top of the ``unittest`` python module.
@ -285,12 +285,18 @@ These test classes are built on top of the ``unittest`` python module.
with self.assertRaises(UserError):
self.properties.forbidden_action_on_sold_property()
.. note:: For more readability, split your tests into multiple files depending on the scope of the
tests. You can also have a Common class that most of the tests should inherit from; that common
.. note:: For better readability, split your tests into multiple files depending on the scope of the
tests. You can also have a Common class that most of the tests should inherit from; this common
class can define the whole set up for the module. For instance in
`account <https://github.com/odoo/odoo/blob/14.0/addons/account/tests/common.py>`__.
.. exercise:: Ensure no one can create an offer for a sold Property, and create a test for it.
.. exercise:: Update the code so no one can:
- Create an offer for a sold property
- Sell a property with no accepted offers on it
and create tests for both of these cases. Additionally check that selling a property that can
be sold is correctly marked as sold after selling it.
.. exercise:: Someone keeps breaking the reset of Garden Area and Orientation when you uncheck the

View File

@ -319,7 +319,7 @@ View
Now that we have our model, we can make its dashboard view. There is no difference to how its made
except that its file is located in the ``report`` folder. Since it is a new model not linked to
any other model, we will also have to add a new menuitem to view our dashboard. Typically SQL views
are added under a first level menu called ``Reporting` (because it's a report, surprise!). Do you
are added under a first level menu called *Reporting* (because it's a report, surprise!). Do you
remember how to add a ``menuitem``? If not, revisit :ref:`howto/rdtraining/06_firstui`) again.
.. exercise:: Create report view.
@ -352,3 +352,17 @@ from this report.
**Tip 2** If you have a field that you do not want as a measure (i.e. in your pivot or
graph views), then you can add ``store=False`` to it and it will not show.
**Tip 3** If you have a SQL View that depends on context then instead of overriding
``BaseModel.init()`` set the ``_table_query`` property::
@property
def _table_query(self):
return 'SELECT %s FROM %s' % (self._select(), self._from())
The *select* and *from* methods remain the same.
`Here is an example <https://github.com/odoo/odoo/blob/14.0/addons/account/report/account_invoice_report.py>`__
of a report that depends on the currently selected companies (in a multi-company environment) context to
determine the currency exchange rates to use for accurately displaying amounts when the selected companies
have different currencies.