Wednesday, May 14, 2025
7 changes · master
Enhancements to existing features
Credit note references are now generated in the invoice customer's language rather than the language of the employee creating them. This helps customers receive clearer, localized accounting documents and reduces confusion in multilingual business contexts.
Original PR description
This commit makes the credit note reference use the invoice customer's language instead of the user's language. task-4657801 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Odoo can now deliberately retry a request when a concurrency conflict is detected but not automatically recognized. This helps reduce avoidable failures in high-traffic situations where two processes try to create or update the same information at the same time.
Original PR description
The `retrying` function automatically retries to call its function if it catches errors related to concurrent databases operations (e.g. serialization failures). However, there are other cases where…
The `retrying` function automatically retries to call its function if it catches errors related to concurrent databases operations (e.g. serialization failures).
However, there are other cases where an error is due to concurrency but can't be automatically caught by the retry mechanism.
For example, in a context where we search for a record before creating it, it can occur that two concurrent requests create the same record. If there is a uniqueness constraint, it will raise a `UniqueViolation` error that won't be caught by the retry mechanism. In this case, it can be useful to be able to manually trigger a retry.
Example of usage for this situation:
```py
class MyModel(models.Model):
_name = 'my.model'
name = fields.Char()
value = fields.Integer()
_uniq_name = models.Constraint('UNIQUE(name)', 'Name is unique')
def update_value(name, value):
record = self.search([('name', '=', name)])
if not record:
try:
record = self.create({'name': name})
except UniqueViolation as e:
raise ConcurrencyError(
"Concurrent 'my.model' creation"
) from e
record.value = value
```
Note: as of now, there are no usage for this (yet) in Odoo main repositories, but there are some in IAP servers (which are running on regular Odoo instances) as concurrency issues are much more frequent there.
task-none
Co-authored-by: @Julien00859This update streamlines an internal evaluation mechanism used across Odoo so it behaves more consistently and is easier for developers to use correctly. It reduces legacy complexity and helps lower the risk of confusion when maintaining business logic, reports, and automated actions.
Original PR description
This PR simplifies `safe_eval` which, up until now, allowed passing global and local namespaces. There is no usecase for this anymore. We want safe_eval exec mode to behave like a top-level module scope. `nocopy` is not needed anymore either. It's a relic of when the context could be dynamic (e.g. for already deleted `RecordDictWrapper` or `QWebContext`). Passed in context is always a dict. It will always be mutated with the local eval namespace dict after evaluation. This all makes `safe_eval` API less confusing. See: https://github.com/odoo/enterprise/pull/83818 See: https://github.com/odoo/upgrade-util/pull/265 task-4378806
The color picker now includes a knob control for adjusting gradient angles more smoothly and intuitively. This improves the website or interface design experience by making gradient customization easier for users.
Original PR description
**Purpose:** Introduce a knob button to enhance the gradient color experience by providing smoother and more intuitive control for adjusting the angle. task:4745708
The underlying evaluation logic used by payroll calculations has been simplified to remove outdated options and make behavior more predictable. This reduces confusion for developers maintaining payroll rules while keeping business functionality unchanged.
Original PR description
This PR simplifies `safe_eval` which, up until now, allowed passing global and local namespaces. There is no usecase for this anymore. We want safe_eval exec mode to begave like a top-level module scope. `nocopy` is not needed anymore either. It's a relic of when the context could be dynamic (e.g. for already deleted `RecordDictWrapper` or `QWebContext`). Passed in context is always a dict. It will always be mutated with the local eval namespace dict after evaluation. This all makes `safe_eval` API less confusing. See: odoo/odoo#206846 See: odoo/upgrade-util#265 task-4378806
Menu syncing for UrbanPiper point-of-sale integrations now uses only active option values, reducing the chance of sync errors caused by outdated or inactive product options. This should make menu updates more reliable while simplifying the underlying process.
Original PR description
Before this commit: === - Iterated over each product and its attribute lines to fetch product template attribute values (PTAVs). - Risk of expected singleton error when multiple PTAVs (active/inactive) existed. After this commit: === - Fetch only active PTAVs directly using a filtered search. -Simplified the loop and removed redundant product-option search.
This update lets Odoo’s read-only route logic use values captured directly from the web address, such as an ID or keyword in the URL. It avoids duplicate processing and makes route behavior more accurate for document-related pages.
Original PR description
The signature of `collable` inside `@route(readonly=callable)` was:
class ...(http.Controller):
def callable(self) -> bool:
...
It was possible to access the path, query-string and body via the globalish `request` object:
request.httprequest.path
request.httprequest.args
request.httprequest.get_data()
But it was not possible up to this point to get the parameters extracted from the path.
Take for example the following endpoint:
@route('/endpoint/<word>', readonly=callable)
def endpoint(self, word):
....
The `callable` function has no way to get `word` unless we match the endpoint again.
With this PR we change the definition of those readonly callable once again, this time to include:
- `rule`: the endpoint that was matched along with its `routing` dictionnary (the `@route` extracted informations)
- `args`: a dict containing the arguments extracted from the path.
task-4572591