Commit Graph
919 Commits
Author SHA1 Message Date
Alvaro Fuentes ce3aac8672 [FIX] core: propagate update of modifiers attributes from base terms
When we update an inline translated element (like `<span>`) for the base
language `en_US` we should update the modifiers attributes for all
languages.

For example when updating from (16.0)
https://github.com/odoo/odoo/blob/7ecd9413/odoo/addons/base/views/ir_ui_view_views.xml#L127-L129
https://github.com/odoo/odoo/blob/7ecd9413/odoo/addons/base/i18n/fr.po#L7233-L7235
to (17.0)
https://github.com/odoo/odoo/blob/b1461d28/odoo/addons/base/views/ir_ui_view_views.xml#L126-L128
https://github.com/odoo/odoo/blob/b1461d28/odoo/addons/base/i18n/fr.po#L12087-L12089

The base term, `en_US`, is updated since the text matches but the
attributes of the translated terms, `fr_FR` for example, are not
updated. Later when the PO file is loaded in non-overwrite mode the
translated terms for `fr_FR` is not updated. This causes all sort of
issues during an upgrade for inline-translated terms -- like `<span>`.
More so since the recent change that converts domain-based attributes
into inline Python expressions.

In this patch we propagate modifiers attributes from inline-translated
items in the new base term into all translated terms when the base term
is updated. In that way we ensure the attributes are correct in all
languages even if later the loading of their corresponding PO file
doesn't update the term.

For a detailed example, let's see what happens when loading the view
above during an upgrade 16->17, right at the first load of the XML file
at https://github.com/odoo/odoo/blob/b1461d28/odoo/fields.py#L1864
```
(Pdb) p old_term
'<span attrs="{\'invisible\': [(\'reset_mode\', \'!=\', \'soft\')]}">This view has no previous version.</span>\n                        <span attrs="{\'invisible\': [(\'reset_mode\', \'!=\', \'hard\')]}">This view is not coming from a file.</span>\n                        <span attrs="{\'invisible\': [(\'reset_mode\', \'!=\', \'other_view\')]}">You need two views to compare.</span>'
(Pdb) p closest_term
'<span invisible="reset_mode != \'soft\'">This view has no previous version.</span>\n                        <span invisible="reset_mode != \'hard\'">This view is not coming from a file.</span>\n                        <span invisible="reset_mode != \'other_view\'">You need two views to compare.</span>'
(Pdb) p translation_dictionary[old_term]
defaultdict(<class 'dict'>, {'fr_FR': '<span attrs="{\'invisible\': [(\'reset_mode\', \'!=\', \'soft\')]}">Cette vue n\'a pas de version antérieure.</span>\n                        <span attrs="{\'invisible\': [(\'reset_mode\', \'!=\', \'hard\')]}">Cette vue ne provient pas d\'un fichier.</span>\n                        <span attrs="{\'invisible\': [(\'reset_mode\', \'!=\', \'other_view\')]}">Vous avez besoin de deux vues pour comparer.</span>'})
```
As we can see the new term will get an updated value for its `invisible`
attribute, while also removing `attrs`. The translated terms will be
still keep the old modifier though.
Now later when the fr_FR.po file is loaded we reach this point
https://github.com/odoo/odoo/blob/b1461d28/odoo/tools/translate.py#L1442
```
(Pdb) p term_en
'<span invisible="reset_mode != \'soft\'">This view has no previous version.</span>\n                        <span invisible="reset_mode != \'hard\'">This view is not coming from a file.</span>\n                        <span invisible="reset_mode != \'other_view\'">You need two views to compare.</span>'
(Pdb) p translation_dictionary[term_en]
defaultdict(<function DeepDefaultDict at 0x7fc9640cdfc0>, {'fr_FR': '<span attrs="{\'invisible\': [(\'reset_mode\', \'!=\', \'soft\')]}">Cette vue n\'a pas de version antérieure.</span>\n                        <span attrs="{\'invisible\': [(\'reset_mode\', \'!=\', \'hard\')]}">Cette vue ne provient pas d\'un fichier.</span>\n                        <span attrs="{\'invisible\': [(\'reset_mode\', \'!=\', \'other_view\')]}">Vous avez besoin de deux vues pour comparer.</span>'})
```
Thus the translated values are NOT updated, keeping the _wrong_
modifiers. This is later fixed during the upgrade in a clumsy way.
C.f. the warnings like this one in runbot:
```
Incomplete conversion for view(id=77, lang=fr_FR) at
<span attrs="{'invisible': [('reset_mode', '!=', 'soft')]}">Cette vue n'a pas de version ant&#233;rieure.</span>
```
Note that such warnings are gone in current PR CI.
The root issue here is that when the fr_FR translation is loaded the
terms are not updated due to a combination of factors:
1. The text content of the term didn't change
2. There is no override flag set for translations

Option 2 is not a valid option during upgrades because we want to keep
custom translations. We could instead of the current patch tweak how
option 1 works and perhaps make the closest term more restricted. This
would lead to the update of the whole translation though while the
actual issue here is _just_ the modifiers. Moreover if the translations
are out of sync the translated terms will still keep the wrong values
that could still be essential for the correct functioning of the record
they belong too (view archs -- for example).

Finally this is a more extreme case (16.0):
https://github.com/odoo/enterprise/blob/1e63b4a8/sale_subscription/views/sale_order_views.xml#L142
In this case during the upgrade we fix the modifier value (refer to
runbot warning above -- it's the same script that fixes it) and set
```
invisible="(subscription_management == 'upsell') or (recurrence_id == False)"
```
for translations, which is wrong. The correct value is (17.0):
```
invisible="not plan_id or subscription_state == '7_upsell'"
```
https://github.com/odoo/enterprise/blob/530ba3ad/sale_subscription/views/sale_order_views.xml#L136

closes odoo/odoo#150152

Signed-off-by: Raphael Collet <rco@odoo.com>
2024-01-30 21:08:04 +00:00
Lucas Perais d8993d61e6 [FIX] base: can delete manual models with base fields
Create an ir.model custom (state = "manual" -- for example via studio) that has a mix
of manual fields (named x_...) and of base fields (originating from some mixin).

Unlink all linked views or object, and try to unlink that model eventually.

Before this commit, an error was raised because base fields couldn't be deleted, even though the table was empty.

After this commit, the deletion works.

Note that this commit is a fix of https://github.com/odoo/odoo/pull/130420/ , which added partial support for this
and a backport of 7550bcd61e which fixed the former PR in 17.0

opw-3558590

closes odoo/odoo#151282

X-original-commit: 3e84f3e9b0da397d82d5add0e37be58f0e30c7be
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
2024-01-26 21:08:00 +00:00
Julien Castiaux 05fd991389 [FIX] link_tracker: prevent links from linking themselves
It was technically possible to register a link that would loop on itself
by abusing the query and fragment parts of the URL. It was possible to
register a link targetting `#` and get the following HTTP exchange which
enter an infinite loop.

	GET /r/bAd HTTP/1.0

	HTTP/1.0 301 Redirect
	Location: #

	GET /r/bAd# HTTP/1.0

Prevent such links from being registered and highlight flaws inside the
`validate_url` method with unittests.

Part-of: odoo/odoo#150678
2024-01-24 10:44:40 +00:00
AH-Yussef ed95da37dc [FIX] base: translate partner display_name
Steps to reproduce:
- Install Contacts app
- Go to General Settings and add another language
- Add a new contact to a parent.
        - Don't add a specific contact name
        - Assign a contact type (delivery address, invoice address, other address)
- Go to the list or kanban view of the contancts and change the language
- The type of the contact listed next to the parent name is not translated from English.

Investigation:
- When the contact name is not set, the `display_name` displayed in both kanban and list views is set by concatinating the parent name with the contact type.
- The line https://github.com/odoo/odoo/blob/03b7e17faef4075dbbb805bca4e7f40f7fbcc988/odoo/addons/base/models/res_partner.py#L345 in the function `_compute_display_name`, `with_context({})` in particular basically enforce to compute the name in english language regardless of the active language. That actually makes sense as the `display_name` field has `store=True` https://github.com/odoo/odoo/blob/03b7e17faef4075dbbb805bca4e7f40f7fbcc988/odoo/addons/base/models/res_partner.py#L199

Solution:
- add a computed field that is not stored that gets recomputed on changing the language.

opw-3569171

closes odoo/odoo#147650

X-original-commit: 60b3ae846de59b1f6e71df68e99e29758ba734fe
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
Signed-off-by: Ali Hassan Youssef (alhy) <alhy@odoo.com>
2024-01-24 10:44:36 +00:00
Denis Ledoux ec0cd75328 [IMP] core: disable x2many manipulation as sudo for sensitive models
This revision adds a flag
`_allow_sudo_commands` to which models can opt-in
to protect themselves against malicious
manipulation of one2many or many2many fields
through an environment using `sudo` or a more priviledged user.

Flagging a model `_allow_sudo_commands = False`
disable `sudo` and `with_user(...)`
when manipulating a one2many or many2many
field targeting this model.

task-3695103
2023-11-01 08:05:16 +00:00
Ruben Gomes (rugo) a819d7190c [IMP] odoo.tools: add tests to formatLang()
Tests the method formatLang() to be able to do safe(r) refactoring in future versions.

closes odoo/odoo#149775

Signed-off-by: Brice Bartoletti (bib) <bib@odoo.com>
2024-01-19 19:10:54 +00:00
Iván Todorovich 9eaecfa062 [FIX] base: skip pdf rendering tests if pdfminer is not installed
The unit tests introduced in 4820be3c only work if pdfminer is installed.
As it's an optional dependency, it may not be installed in some environments.

This commit skips the tests if pdfminer is not installed.

See also: 6fa4dbf2

closes odoo/odoo#147720

Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2024-01-15 11:11:23 +00:00
Gaetan Vanden Bergh (gavb) 03f2ed8955 [FIX] base: Module category can reference itself as parent
Steps:
- Update a module category to reference itself as parent
OR
- Update multiple module categories to create a circular dependency (A -> B -> A)

Actual result:
- Upgrade a module is impossible
- Un/Install a module is impossible
- Infinite loop: https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/models/ir_module.py#L900

Expected result:
- Circular dependencies not possible
- Module can be upgrade and un/install

opw-3490162

closes odoo/odoo#149284

X-original-commit: 6932714200d158a21bf10b90b2f71fa5cae0b13f
Signed-off-by: Raphael Collet <rco@odoo.com>
2024-01-12 21:43:45 +00:00
sami odoo e096a210aa [FIX] base: prevent language deactivation
Before this commit user was able to archive the language used by superuser
Odoobot by activating different language. Because of which whenever odoobot was
in action then the user faced error.

Steps to produce:
 - Install `contacts`.
 - Settings > Translations > Languages > Choose a language eg: English (UK).
 - Activate that language and switch to it.
 - In `contacts` change the language of each contact in the contacts to the
   newly selected language.
 - Settings > Translations > Languages > Choose English (US) and archive it.
 - Settings > User & Companies > User, Apply the filter of Inactive Users.

After this commit user would not be able to archive the language used by
superuser or the language in which there db was installed.

Task-2896526

closes odoo/odoo#149215

X-original-commit: 681fc0a04c7ca625c7120ff2f7b537b75398b23d
Related: odoo/enterprise#54209
Signed-off-by: Raphael Collet <rco@odoo.com>
2024-01-12 16:12:49 +00:00
std-odoo 55a3a17090 [IMP] base: use the notification email by default for miss-configured database
Purpose
=======
When a database is miss-configured, we have no other choices to
potentially spoof the FROM. We decided that a better heuristic would
be to use the notification email instead of the user email.

Task-3645895

closes odoo/odoo#149189

X-original-commit: eae9214ade8487ac326fc83abe67af53d861e00a
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2024-01-12 16:12:47 +00:00
Yannick Tivisse a913272136 [FIX] base: Make tests demo data independent
Part-of: odoo/odoo#146649
2023-12-18 23:32:05 +00:00
Sven Fuehr 79c9a7741f [FIX] base: res_currency.rate cache issue
Currently there is the following issue with cached conversion rates
from the "from currency" to the "to currency".
When the rate of the res_currency_rate of the "to currency" changes the cache is not invalidated.
Thus the cached value may be used wrongly (leading to wrong results).

This commit simply invalidates all the cached rates in case we update or
create a res_currency_rate.

closes odoo/odoo#143847

Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
2023-12-12 23:08:47 +00:00
Eteil Djoumatchoua(etdj) etdj@odoo.com 870acffba6 [FIX] mail: well sanitize the mails coming from outlook desktop
Steps:
- Create a ticket with a customer ( it will the email)
- Answer to the mail with Outlook Desktop( a multiple lines break)
- Look at the response in the discuss frame.

Issue:
In the frame there is much more lines break than in the original mail

Cause:
The format of outlook desktop mail before sanitizing looks like this
```
<div class="WordSection1">
<p class="MsoNormal">Test<o:p></o:p></p>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal">Two break lines<o:p></o:p></p>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<div>
```
So when parsing it transforms the ``<o:p></o:p>`` in ``<p></p>``
which adds more lines break when displayed.

Solution:
Remove empty ``<o:...>`` and ``</o:...>`` tags which are specific to outlook desktop before.

opw-3089550

closes odoo/odoo#144931

X-original-commit: a3e9db87277771c9801f24a5f52aa73b98a0d879
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2023-12-05 10:54:59 +00:00
Youssef Bashandy 8b22980e25 [FIX] mail : HTML characters displayed in email
Current behavior before PR:
When you send an email at the receivers end you will see '&nbsp;' shown before you open the mail and it disappears once you open the email

Desired behavior after PR is merged:
Corrected and now the '&nbsp;' character doesn't appear where I replace it in the HTML template with its equivalent character

Test changes:
The test case that was there was comparing static strings with the HTML entities where my solution is removing those entities so I change the strings to be after escaping those HTML

opw-3481781

closes odoo/odoo#144648

X-original-commit: 1fcd45f19c2d6900ad5d1848a988ab0ae5f287a8
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
2023-12-04 07:16:06 +00:00
Xavier-Do ad993e673d [FIX] base: avoid no autoinstall propagation
A custom script is modifying the output of
load_information_from_description_file to disable the
auto-install of modules during local testing. It was naively adapted for
v16.0 by replacing the corresponding methods. Since a lru cache was added
(nice optimization in most cases) this is an issue because running lint
test afterward will get the cached value with an incorrect autoinstall
value. It makes sens to avoid reading the file on the filesystem each
time, but making a deepcopy looks like an acceptable safeguard to avoid
hard to debug behaviors.

closes odoo/odoo#143628

X-original-commit: ad10ff4410ccf7c38f6154480484495bb57c53ff
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
2023-11-28 06:19:55 +00:00
Thibault Delavallée 795091c69d [FIX] base: fix 'extract_rfc2822_addresses' in case of email-like name
Remove quotes when name of a formatted email is also an email, as indicated
in tests. We still get two emails being sent for a given outgoing email
when the name part is an email but that would be difficult to avoid.

Task-3566542

closes odoo/odoo#141856

X-original-commit: odoo/odoo@d3cdaa6c18
Related: odoo/enterprise#50892
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2023-11-17 16:11:51 +00:00
Thibault Delavallée cd5727c488 [IMP] base: add test cases for 'extract_rfc2822_addresses'
Add test cases related to an issue found during mail gateway testing. When
an email_to is formatted like '"robert@notgmail.com" <robert@notgmail.com>'
the tool finds two emails. As it is used in IrMailServer it sends two emails
insted of one. This may happen notably when partners are automatically created
based on an email only in which case it is put in both name and email.

Task-3566542

X-original-commit: odoo/odoo@312323e0d9
Part-of: odoo/odoo#141856
2023-11-17 16:11:51 +00:00
Thibault Delavallée a03ae3765e [IMP] base: fallback on 'email_re' when getadresses fails
When 'getadresses' fails at parsing some input and give us a result like
'gmail.com' (see previous commit adding test cases) we fallback on using
'email_re' which is better at finding email addresses in a global string.
We use it only in this specific case as fallback mechanism to rely on
'getadresses' when possible.

Task-3572208

X-original-commit: odoo/odoo@8e61a3b690
Part-of: odoo/odoo#141856
2023-11-17 16:11:51 +00:00
Thibault Delavallée d5b39338ff [IMP] base: add test cases for 'email_split'
Add test cases related to issues found in various leads management. All those
email inputs lead to an email found being '@gmail.com' (or equivalent) which
is not a valid email.

A consequence of that behavior is that 'email_normalized' for several leads
is the same ('@gmail.com') and they are considered as being the same email
identity. They could be included in a pack of leads to merge (see 'crm').

Task-3572208

X-original-commit: odoo/odoo@7498b9a0a1
Part-of: odoo/odoo#141856
2023-11-17 16:11:51 +00:00
MerlinGuillaume cdcdee40f4 [FIX] base: error when setting a too big default value for integer
Setting a default value for an integer that is greater than that allowed
by a 32-bit integer raises an error when we save a new record so it
isn't clear that the issue comes from the default value

Steps to reproduce:
1. Install Contacts and Studio
2. Go to Contacts and open any contact
3. Toggle Studio and add an integer field in the view
4. In the Studio sidebar, set the default value to 3 000 000 000
5. Save and close Studio
6. Create a new contact, give it a name and try to save the record
7. An error is thrown

Solution:
Raise an error if we set an integer field's default value out of the
bounds of a 32-bit integer

opw-3360160

closes odoo/odoo#141339

X-original-commit: 85978e4c6fb1199f5e6ec4dce5c45b9f09be9b77
Signed-off-by: Guillaume Merlin (megu) <megu@odoo.com>
2023-11-09 14:51:21 +00:00
Chong Wang (cwg) 1a7978e509 [FIX] base: fix update translations for base field
in #124402
`update_field_translations` will call `write` to trigger all override logics.
But for ir.model.fields, write will call init_model which may remove all
translations. This commit fix the issue by adding a bypass for translate_only
`write`.
(this commit is the merge of #141126 and #140695)

opw-3575512

closes odoo/odoo#141472

X-original-commit: 33f08c40c92429ada6c5b0387f36d32d4825fcb6
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Chong Wang (cwg) <cwg@odoo.com>
2023-11-08 04:09:54 +00:00
Rémy Voet (ryv) c1e8a32e7d [FIX] core,*: Fix display_name computations for new records.
As of https://github.com/odoo/odoo/pull/114024, `display_name` is
implicit in every form view (see the use of addFieldDependencies in the
Form controller). Therefore, when you create a new record for this
model, it calls the first `onchange`, which will compute display_name
for a new record (id without origin). Some `_compute_display_name` don't
handle new records correctly and raise a traceback. These models are
sometimes directly accessible:

- Accounting > Account Group > New => Traceback
- Contact > Contact Tags > New => Traceback

Other models are inaccessible by default (no view to access or create a
new record), but if someone creates a view for them with studio (or
modifies an existing one to allow creation):

- `crm.iap.lead.role`
- `crm.iap.lead.seniority`
- `chatbot.script.answer`
- `payment.token`

Change the code of `_compute_display_name` on these models to be more
defensive and avoid (potential) tracebacks. Similarly, change the
`convert_to_display_name` of `fields.Datetime` to take into account
`None` value.

closes odoo/odoo#139592

Related: odoo/enterprise#49721
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
2023-11-06 11:16:31 +00:00
Nicolas Lempereur 3aa1434164 [FIX] base: fallback on model_id to fill related field
Scenario:

- go to a model in technical
- create a new field and set "Related Field" to id

=> error "Unknown field name 'id' in related field 'id'" because we
get the field in self.model which is not present in the form view.

Fix:

Fallback to self.model_id.model as was the case before 16.0 commit:
76f699ca0b

Note: without the change, the added tests fails with:

  Warning Unknown field name 'id' in related field 'id'
  AssertionError: False != 'integer

opw-3138440
closes #112495

closes odoo/odoo#140583

X-original-commit: aa406352541abd8bbf188da84fc4e370029ffc12
Signed-off-by: Rémy Voet (ryv) <ryv@odoo.com>
Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
2023-11-02 15:11:00 +00:00
Christophe Simonis 35e22b8fe9 [IMP] core: reflect the model inherits in the database
This will help the upgrade process. Currently, there is an harcoded[^1]
inherit tree stored in the upgrade source. By storing this information
in the databases, we:
 - avoid this hardcoded list.
 - support more than the standard modules.

task-3504720

[^1]: hardcoded, but autogenerated.

closes odoo/odoo#140261

Signed-off-by: Raphael Collet <rco@odoo.com>
2023-10-31 13:26:44 +00:00
Chong Wang (cwg) 2d08f97c07 [IMP] core: support delay translation
Jsonb data structure of model_terms translated fields' columns
'{
	"en_US": "<div>Apple</div>"
	"fr_FR": "<div>Pomme</div><div>Banane</div>"
	"_fr_FR": "<div>Pomme</div>"
}'::jsonb

"column" IS NULL OR "column"->>'en_US' IS NOT NULL

"column"->>'lang'
1. stores last confirmed value
2. logically fallbacks to
    COALESCE(
        "column"->>'lang',
        "column"->>'en_US'
    )

"column"->>'_lang'
1. stores translations and the last written html/xml structure
2. shares the same html/xml structure with other "column"->>'_lang'
3. logically fallbacks to
    COALESCE(
        "column"->>'_lang',
        "column"->>'lang',
        "column"->>'_en_US',
        "column"->>'en_US'
    )

Context:
1. `delay_translations`(new) only write values to _langs while keeping
translations for langs when the written value has at least one translatable term
2. `check_translations`(new) read _langs values to create translation mapping
for the translation dialog
3. `edit_translations` read values whose translatable terms are wrapped by
`<span></span>` with term information for the TRANSLATE mode of website

Potential issue
since the record value of a model terms translated field is logical content
dependent (check_translations, edit_translations), all computed field computed
from any model terms translated field should also be marked.
@api.depends_context('lang', 'edit_translations', 'check_translations')

Data flow for column value, cache value and record value
(make sure the window is wide enough to see the graph)

                             +- - - - - - - - - - - - - - - - - - - - - - - - - - - -+
                             ' Record(str):                                          '
                             '                                                       '
                             ' +---------------------------------------------------+ '               +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
                             ' | "<div><span data-oe-model='model'                 | '               {            read fr_FR             {
                             ' | data-oe-id='id' ...>French</span></div>"          | ' <------------ } context.get('edit_translations')  } <+
                             ' +---------------------------------------------------+ '               +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+  |
                             ' +---------------------------------------------------+ '               +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+  |
                             ' | "<div>French</div>"                               | '               {            read fr_FR             {  |
                             ' |                                                   | ' <------------ } context.get('check_translations') } <+
                             ' +---------------------------------------------------+ '               +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+  |
+~~~~~~~~~~~~+               ' +---------------------------------------------------+ '                                                      |
{ read fr_FR { ------------> ' | "<a>French</a>"                                   | '                                                      |
+~~~~~~~~~~~~+               ' +---------------------------------------------------+ '                                                      |
  ^                          '                                                       '                                                      |
  |                          +- - - - - - - - - - - - - - - - - - - - - - - - - - - -+                                                      |
  |                                                                                                                                         |
  |                                                                                                                                         |
  |                                                                                                                                         |
  |                          +- - - - - - - - - - - - - - - - - - - - - - - - - - - -+                                                      |
  |                          ' Cache(dict):                                          '                                                      |
  |                          '                                                       '                                                      |
  |                          ' +---------------------------------------------------+ '                                                      |
  |                          ' |                                                   | ' -----------------------------------------------------+
  |                          ' | "_fr_FR": "<div>French</div>"                     | '
  |                          ' |                                                   | ' <----------------------------------------------------+
  |                          ' +---------------------------------------------------+ '                                                      |
  |                          ' +---------------------------------------------------+ '               +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
  +------------------------- ' |                                                   | '               {              fetch fr_FR               {
                             ' | "fr_FR": "<a>French</a>"                          | '               }    context.get('edit_translations')    }
  +------------------------> ' |                                                   | '               {  or context.get('check_translations')  {
  |                          ' +---------------------------------------------------+ '               +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
+~~~~~~~~~~~~~~~~~+          '                                                       '                                                      ^
{   fetch fr_FR   {          +- - - - - - - - - - - - - - - - - - - - - - - - - - - -+                              COALESCE(               |
+~~~~~~~~~~~~~~~~~+                                                                                                     "c"->>'_fr_FR',     |
  ^                                                                                                                     "c"->>'fr_FR',      |
  | COALESCE(                                                                                                           "c"->>'_en_US',     |
  |     "c"->>'fr_FR',       +- - - - - - - - - - - - - - - - - - - - - - - - - - - -+                                  "c"->>'en_US'       |
  |     "c"->>'en_US'        ' Database(jsonb):                                      '                              )                       |
  | )                        '                                                       '                                                      |
  |                          ' +---------------------------------------------------+ '                                                      |
  |                          ' | "_fr_FR": "<div>French</div>"                     | ' -----------------------------------------------------+
  |                          ' +---------------------------------------------------+ '                                                      |
  |                          ' +---------------------------------------------------+ '                                                      |
  +------------------------- ' | "fr_FR": "<a>French</a>"                          | ' -----------------------------------------------------+
  |                          ' +---------------------------------------------------+ '                                                      |
  |                          ' +---------------------------------------------------+ '                                                      |
  |                          ' | "_en_US": "<div>English</div>"                    | ' -----------------------------------------------------+
  |                          ' +---------------------------------------------------+ '                                                      |
  |                          ' +---------------------------------------------------+ '                                                      |
  +------------------------- ' | "en_US": "<div>English1</div><div>English2</div>" | ' -----------------------------------------------------+
                             ' +---------------------------------------------------+ '
                             '                                                       '
                             +- - - - - - - - - - - - - - - - - - - - - - - - - - - -+

Task: 3043340
Part-of: odoo/odoo#139819
2023-10-27 11:35:03 +00:00
Thibault Delavallée 43c6b5e7a8 [IMP] mail: add message_type for outgoing emails
Currently both incoming and outgoing emails are using the same 'email'
message_type. However both flows are not linked in any way.

Purpose of 'message_type' is to distinguish who generated the message.
In this case incoming emails are generated by the mailgateway while outgoing
emails are generated by mailins e.g. using the composer in mailing mode.

We now distinguish outgoing emails from incoming emails by using a specific
type for outgoing emails. Addons are updated accordingly.

Default 'message_type' value when removing sms/snailmail/whatsapp is now
'comment' instead of 'email', as default value of messages should be
comment as discuss is the main source of messages.

Task-3285720

closes odoo/odoo#139814

Related: odoo/enterprise#49597
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2023-10-27 11:35:01 +00:00
Damien Bouvy 05e5b48971 [IMP] base: improve UX for server actions that update a boolean field
Before this commit, updating a boolean field through a server action was
possible but unintuitive: if you wanted to set the field to `False`, you
had to leave the value empty - worse, writing down `False` would be
considered truth-y since it was evaluated as a string!

This commit introduces a simpler UX for these cases, where the user can
select Yes/No in a selection field if the field they're trying to update
is a boolean field.

Task-3450200

Part-of: odoo/odoo#138804
2023-10-26 13:41:07 +00:00
Damien Bouvy 37976ec5e1 [IMP] base,mail,sms,base_automation: auto-naming of server actions
Commit b05e7e4da0 rightfully removed the _compute_name dependency on
context keys (a bad idea for stored computed fields), but this change
could lead to UX frustrations (Server Action names getting reset all the
time despite what the user may have used as a name before) and UX issues
(e.g. triggering a recompute by accident at module removal that could
reset all 'code' action names to 'Execute Code').

This commit simply removes the automated naming feature from the base
module and moves the logic to the base_automation module - and only
computes automated names based on the link with an automation rule or
not (so 'standalone' server actions need a name given by the user at all
times).

Task-3450200

Part-of: odoo/odoo#138804
2023-10-26 13:41:07 +00:00
Damien Bouvy 3871ae2c6c [IMP] base_automation,base: support m2m operations in server actions
Before this commit, server actions of the 'Update Record' type could
only write on m2m fields entirely - meaning that there was no support
for commands like adding or removing records from the set without
writing it completely.

This commit introduces this possibility, along with some UI changes to
come from it regarding the display of such actions in automation rules.

Task-3450200

Part-of: odoo/odoo#138804
2023-10-26 13:41:07 +00:00
Damien Bouvy b3efb92f6b [IMP] base: add 'webhook'-type server actions
Webhook server actions allow users to send a POST request to an external
system, e.g. Slack, Github or even another Odoo instance.

This is a rather simple setup, as this feature does not include frequent
features of typical webhooks, such as the possibility to use headers for
authentication, or a retry-policy with exponential decay and all the
bells and whistles of that style.

However, this can be useful for simple actions and automations.

Task-3450200

Part-of: odoo/odoo#138804
2023-10-26 13:41:07 +00:00
Damien Bouvy 253c214b5b [IMP] base: allow server actions to update records across relations
Up until now, the 'Update record' server actions could only update the
record on which the action was triggered.

This is a rather serious limitations, especially in modules that
leverage server actions, like base automation - indeed, if you want a
server action run on e.g. Leads that will write changes on the leads'
customer, you *had* to use Python code.

This commit makes it possible to traverse relations when selecting the
field to update, and indeed to write across relations.

Task-3450200

Part-of: odoo/odoo#138804
2023-10-26 13:41:07 +00:00
Mathieu Duckerts-Antoine 998ef1f63a [IMP] tools: ignore set in view expressions
Now that some field attributes like invisible are given by Python expressions
and that those can involve some set operations, we have to ensure that
the views can be validated if they use such operations. We do that and
add a test.

closes odoo/odoo#139451

Signed-off-by: Géry Debongnie <ged@odoo.com>
2023-10-25 17:03:19 +00:00
william-andre 9353a6f9ba [IMP] base: cache currency convertion rate per transaction
Most of the time, rates are computed in a loop by using
`<res.currency>._convert`. This leads to a lot of round trips with the
database.

This PR is caching the value for a whole transaction.
In order to do that, the non stored field `rate` has new (missing)
contextual dependencies: the arguments of `_get_conversion_rate`.
This allows to move the actual computation of the rate to the computed
field, and `_get_conversion_rate` is now only a proxy to avoid playing
with the context manually; also kept for backward compatibility.

Other solutions were considered:
* `ormcache`, but we want to avoid creating multiple caches and reduce
  the possibility to have inter dependent caches.
* managing a local cache everywhere, which is cumbersome and error prone
* a helper for the previous option by using a converter factory, but it
  is still an issue when the convert function is called from multiple
  call functions because the cache isn't shared then.

Part-of: odoo/odoo#137609
2023-10-25 15:50:33 +00:00
Thibault Delavallée ab8c0e4c6f [REF] mail, various: remove now dead configuration parameters
PURPOSE

Allow alias domains to be multiple, notably to be used in a multi company
environment where each company has its own alias domain.

SPECIFICATIONS

Now that alias domains are used in Odoo codebase there is no usage anymore
for the old config parameters. So long and thanks for all the fish !

Task-36879 (Mail: Support Multi Domains Aliases)

Part-of: odoo/odoo#76734
2023-10-24 19:24:50 +00:00
Thibault Delavallée 9345060498 [IMP] mail: respect alias domains in 'mail.mail' and outgoing emails
PURPOSE

Allow alias domains to be multiple, notably to be used in a multi company
environment where each company has its own alias domain.

SPECIFICATIONS: MAIL.MAIL

Update MailMail to use alias domains. Notably "Return-Path" headers are
now computed based on alias domain when possible, using the recently added
fields on 'mail.message' model for that purpose. Fallback is to use current
company's bounce email when mail_mail creation is done outside of classic
mail flows or without that information.

SPECIFICATIONS: IR.MAIL.SERVER

Update IrMailServer and low-level stack to use alias domains. This has an
impact notably on default values computation for from and bounce emails

  * '_get_default_bounce_address' is called when there is no 'Return-Path'
    given. Most classic mail flows will set it according to current record
    company / alias domain. Fallback when not set is to fallback on current
    company's bounce email, computed based on its alias domain;
  * '_get_default_from_address' is used in two use cases
    * computing a default 'email_from' for outgoing emails when it is not set.
      In most classic mail flows it is set based on current user's email. If
      not set fallback on current company's notification emails is considered
      as a safe bet, replacing the global configuration parameter;
    * overriding the 'email_from' of emails that are considered spoofing the
      mail server, allowing to wrap the sending into a 'notifications@domain'
      generic sender. For those we should try to keep record's information as
      it may be called in classic mail flows;
  * '_get_default_from_filter' is added in base and overridden in mail to
    either use 'mail.default.from_filter' ICP, or use the one defined on
    the alias domain. Supporting both is still an option, as its behavior
    is implemented for basic email sending, without mail being available.

Those methods are updated to try to support multi domains / multi company
setup. However as those defaults are located ar ir.mail_server level it is
not always easy to have complete environment information, hence fallbacking
on current company's parameters when no better information is provided.

A test about 'mail.default.from' is removed, as it was testing a default_from
outside of catchall domain. It is not possible anymore as default_from is now
part of domain definition. As multi domains is supported, no need to support
exotic configuration like that.

SPECIFICATIONS: FROM MAIL.MAIL TO OUTGOING EMAILS

When sending emails based on MailMail, we now prepares sending groups based
on MailServer, email_from, but also alias domain to which the mail belongs to.
Information about alias domain (e.g. notifications email based on default_from
and bounce email) is propagated to low-level email preparation methods. It
uses the context as it is the easiest way to propagate information to that
level without hacking too much models or calls.

Task-36879 (Mail: Support Multi Domains Aliases)

Part-of: odoo/odoo#76734
2023-10-24 19:24:50 +00:00
Thibault Delavallée 3a0da2278f [IMP] mail: respect alias domains in mail gateway
PURPOSE

Allow alias domains to be multiple, notably to be used in a multi company
environment where each company has its own alias domain.

SPECIFICATIONS

Make mail gateway support alias domains instead of relying on configuration
parameters. This implies the following changes

  * destination alias check is now based on full email by default. Previously
    only left-part of aliases were checked. Optionally an allowed list of
    domains could be additionally checked. Default from now on is to check
    the complete email e.g. 'sales@mydomain.com' != 'sales@mydomain.in';
  * detection of direct write to catchall implies checking all domains
    catchall emails;
  * detection of write to bounce implies checking all domains bounce emails;
  * when having to send bounce emails using the bounce alias as mailer-daemon,
    find the bounce email from the relevant company;

However we have to ease transition from the old ICP-based model used since
ages to the new domain-based model. Notably a common usage of mail gateways
is to do mail forwarding e.g. forward mail from domainA to domainB without
rewriting destination. It means that e.g. sales@mail.domainA should be
considered as a valid alias equivalent to sales@mail.domainB. This was
working due to left-part only check of destination aliases. In order to
keep this setup working after migration a flag is added on aliases allowing
to keep the detection of those aliases based only on local parts.

In summary: When searching for aliases, mailgateway now either checks for
exact email, either for matching local parts when the flag is active. This
is not the default behavior, as we want a stricter comparison of emails by
default but it will be the default behavior at **migration time**.

The 'mail.catchall.domain.allowed' configuration parameter is kept. It is
used only for left-part check aliases, allowing to limit the scope of the
match.

Task-36879 (Mail: Support Multi Domains Aliases)

Part-of: odoo/odoo#76734
2023-10-24 19:24:50 +00:00
Thibault Delavallée b99d16670c [FIX] base: make ir_mail_server ordering deterministic
This may have an impact when trying to find an outgoing mail server based
on from and filter, as first match wins when checking matching filter on a
bunch of mail servers.

Prepares Task-36879 (Mail: Support Multi Domains Aliases)

Part-of: odoo/odoo#76734
2023-10-24 19:24:50 +00:00
Stephane Debauche 503508fb8e [FIX] base: fix mock of IrMailServer methods
Due to current implementation of mocks context is lost when accessing methods
'connect' and '_find_mail_server' of IrMailServer. Indeed self is replaced by
an instance of IrMailServer and code relying on context could not be called as
planned.

This commit aims at doing a custom mock so that we can correctly rely on self
and context in those methods. This is necessary for incoming changes in mail
notably to allow testing SMTP feature in multi domains environment.

Logged information when having failed SMTP check is improved: we now also
log found From in order to ease debugging failing tests due to invalid from.

Prepares Task-36879 (Mail: Support Multi Domains Aliases)

Part-of: odoo/odoo#76734
2023-10-24 19:24:50 +00:00
Raphael Collet c041919f1b [IMP] core: introduce _order_to_sql() to replace _generate_order_by()
The new method should be used to generate an SQL object that represents
how to order by a field in an SQL query.  We introduced the auxiliary
method _order_field_to_sql() so that one can specify some SQL for
ordering by a given field with a simple method override.

Part-of: odoo/odoo#138019
2023-10-20 09:35:18 +00:00
Raphael Collet 026993775f [IMP] core: use SQL wrapper in expression
We take advantage of SQL objects to discard the use of domain operators
'inselect and 'not inselect'.  Indeed, as we now support SQL objects at
the right-hand side of a condition, one can replace conditions like
(lhs, 'inselect', (query, params)) by (lhs, 'in', SQL(query, *params)).

This commit also adds tests that ensure the correct behavior of the
adaptation of the implementation.

Part-of: odoo/odoo#138019
2023-10-20 09:35:18 +00:00
Raphael Collet 31caff2834 [IMP] core: add named parameters to SQL wrapper
For very large bits of SQL code with potentially repeated terms, it is
useful to use named parameters instead of positional parameters:

    sql = SQL(
        "SELECT %(column)s FROM %(table)s WHERE %(column)s IS NOT NULL",
        table=SQL.identifier("foo"),
        column=SQL.identifier("foo", "bar"),
    )

Part-of: odoo/odoo#138019
2023-10-20 09:35:17 +00:00
Xavier-Do 4820be3cb7 [IMP] base: add test for wkhtmltopdf generation
The current used version of wkhtmltopdf manages is frozen to 0.12.5
because some features used by odoo are only available in this version
using a patched qt.

Anyway, it become difficult to keep this version up to date, especially
with Ubuntu Jammy and updates of the dependencies used by wkhtmltopdf.
More than that because of qt related issues, wkhtmltopdf maintenance
will end soon.

Adding a test to check some caracteristics of pdf reports may be usefull
to check that current version is still working, and eventually to find
an alternative solution.

This test checks that pdf reports contains the expected headers and
footers elements with the correct page number (2 record of 2 pages)
This also check that the pdf is in the expected A4 format.

Future test may check other formats, margins, layout,
page size/pagebreak combination, (table of content?), ...

This test may also check performances and existing limitations.

closes odoo/odoo#136626

Signed-off-by: Christophe Monniez (moc) <moc@odoo.com>
2023-10-19 13:20:28 +00:00
Dylan Kiss (dyki) f050ef335e [FIX] base,core: relax {child,parent}_of with related fields
In the context of branches, you need to be able to select taxes of
an ancestor company on an invoice/bill, even when you don't have access
to the ancestor company.

In order to do that, we relax the restriction when searching with a
`parent_of` or `child_of` on a related field, so that it also includes
ids of related field records you don't have access to. This should not
be a problem, since in the end the search will return records of a
model restricted by its own access rules.

task-3503204

closes odoo/odoo#138942

Signed-off-by: William André (wan) <wan@odoo.com>
Signed-off-by: Dylan Kiss (dyki) <dyki@odoo.com>
2023-10-18 12:05:25 +00:00
Thomas Lefebvre (thle) 7a33a52371 [FIX] google_calendar,microsoft_calendar: use ReadonlyDict
To avoid developers to update the dict of `_events`
in their overrides, to not alter by mistake
the default behavior.
Using a frozendict will force them to create a copy
of the dict.

closes odoo/odoo#123261

Signed-off-by: Arnaud Joset (arj) <arj@odoo.com>
2023-08-17 18:43:10 +00:00
Benoit Socias 1b8a1d97d6 [REF] base, website, *: rename snippets_list to configurator_snippets
*: theme_default

This commit renames the `snippets_list` manifest key to
`configurator_snippets`.

task-3381714

Part-of: odoo/odoo#126719
2023-10-14 03:27:03 +00:00
Benoit Socias a2f8e18b76 [IMP] website, base: generate distinct templates for new pages
This commit is a preparation for the new page from template feature.

In order to make it possible for new page templates to be customizable
at several levels from themes, it was decided to create several layers
of primary templates.
Those templates are build from the descriptions found in manifest files
under the new `new_page_templates` key.
The same principle is also applied for configurator pages (described in
manifest files under the `snippet_lists` key) because we noticed that
some of the changes that were made in themes for some blocks were not
supposed to impact the "drag'n'drop" version of the block, but only
the version used inside the pages generated by the configurator. (E.g.
connecting shapes between blocks)

The manifest entries now have the following structure:
```py
'snippet_lists': {
    'somepagename': ['s_block_name', ...],
},
'new_template_pages': {
    'somecategoryname': {
        'sometemplatename': ['s_block_name', ...],
    },
},
```

This commit finds those entries in the manifests and creates the
following primary templates:
- `s_block_name`: already exists, this is the block that is drag and
dropped using the website builder
- `configurator_s_block_name`: specialization of `s_block_name` used in
all pages generated by the configurator
- `configurator_somepagename_s_block_name`: specialization of
`configurator_s_block_name` for that specific page
- `new_page_template_s_block_name`: specialization of `s_block_name`
used in all new page templates
- `new_page_template_somecategoryname_s_block_name`: specialization of
`new_page_template_s_block_name` used in new page templates of that
specific category
- `new_page_template_somecategoryname_sometemplatename_s_block_name`:
specialization of `new_page_template_somecategoryname_s_block_name` for
that specific template

For the template pages defined in `website` it also creates primary
templates that assemble `t-snippet-call`s of the most specific block
templates. Those templates are named
`new_page_template_sections_somecategoryname_sometemplatename`.

task-3381714

Part-of: odoo/odoo#126719
2023-10-14 03:27:03 +00:00
Xavier-Do 3ee7cb6680 [FIX] invalidate t-cache in all cases
The issue with the t-cache (discribeds with a test in previous commit)
is that the key/value can be anything. It can be based on other t-cache
(assets in the example) but could be anything else.

The proposed solution will clear the t-cache when ANY other cache is
cleared. This is similar to the behaviour when the t-cache was
introduced (single ormcache)

Also sligly improve logging to precise what was cleared

closes odoo/odoo#138647

X-original-commit: aa69fa9f8efed0da45c601e5d57ce252446e376f
Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
2023-10-14 02:26:52 +00:00
Rémy Voet (ryv) b67df70b8a [REV] core: remove ORM display_name fallback
This reverts commit 4573ca0c83eb63785016f4389a5157efb21fa9a4.

Because now, `display_name` is implicitly on every form (last breadcrumb
item). Then it will be queried by `onchange` calls. When we create a
new record, `_rec_name` can be `False` and the display_name will be a
technical one: '<model_name>,<NewId0x...>' which is uglier than the
previous situation showing 'New'.

Part-of: odoo/odoo#138061
2023-10-10 12:35:01 +00:00
Martin Trigaux 22ab49e343 [IMP] *: use file_path and file_open
Replace all the calls to get_resource_path to the better file_path or
directly use file_open when not needed

Doing both a get_resource_path and file_open means checking twice that
the file exists.
Doing a simple path concatenation before a file_open is safe.
If given to another method (e.g. etree.parse), calling file_path is
the prefered method.

Note that get_resource_path used to return False when the file does
not exists while file_path/file_open raises a FileNotFoundException

closes odoo/odoo#135607

Related: odoo/upgrade#5187
Related: odoo/enterprise#47475
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2023-10-06 14:33:43 +00:00
Valeriya(vchu) d9c7ff69a4 [IMP] website_sale, base: use invoice address at checkout
at checkout use the invoice address as billing address instead of
main address if the invoice one is defined. Add the functionality to
add new billings addresses at checkout.

task-3258835

Part-of: odoo/odoo#118428
2023-10-06 13:08:53 +00:00