Tuesday, August 4, 2026
266 changes
10 changes
New functionality added to Odoo
Slovak entities are identified by three separate numbers: IČO, IČ DPH and DIČ. The first two are already on res.partner as `company_registry` and `vat`. The DIČ was only defined on res.company by `l10n_sk`, so it could not be recorded for customers and vendors. It identifies Slovak companies on business documents, and Peppol EAS 0245 designates it. With mandatory B2B e-invoicing in Slovakia from January 2027 and Peppol support coming in #275798, it has to live on res.partner. `income_tax_id`
Original PR description
Slovak entities are identified by three separate numbers: IČO, IČ DPH and DIČ. The first two are already on res.partner as `company_registry` and `vat`. The DIČ was only defined on res.company by `l10n_sk`, so it could not be recorded for customers and vendors. It identifies Slovak companies on business documents, and Peppol EAS 0245 designates it. With mandatory B2B e-invoicing in Slovakia from January 2027 and Peppol support coming in #275798, it has to live on res.partner. `income_tax_id` on res.company becomes related to it, mirroring vat and company_registry since they are related as well. Existing values are moved by a post init hook. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280178
Enhancements to existing features
Pycups has an issue where it can raise an error (1280) meanwhile the status is a success. We don't want to see a traceback in such case, so we skip logging in this case.
Original PR description
Pycups has an issue where it can raise an error (1280) meanwhile the status is a success. We don't want to see a traceback in such case, so we skip logging in this case.
Resolved issues and error corrections
We don’t need the onchange hack anymore after the orm fix: odoo/pull/273404
Original PR description
We don’t need the onchange hack anymore after the orm fix: odoo/pull/273404
Miscellaneous changes
Simplified version of https://github.com/odoo/odoo/pull/276689 Forward-Port-Of: odoo/odoo#280175 Forward-Port-Of: odoo/odoo#276696
Original PR description
Simplified version of https://github.com/odoo/odoo/pull/276689 Forward-Port-Of: odoo/odoo#280175 Forward-Port-Of: odoo/odoo#276696
9 changes
Enhancements to existing features
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
24 changes
Enhancements to existing features
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification
Original PR description
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification ) task-6171251 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262801
6 changes
Enhancements to existing features
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HT
Original PR description
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries…
8 changes
Enhancements to existing features
This PR handles 2 cases : ===== PART 1 ===== Self-billing bill sequences should be unique per partner, as implemented in v19+. This PR backports that behavior to 17.0. ===== PART 2 ===== Previously, the `is_self_billing` option on `account.journal` was available only for purchase journals. This caused an issue when importing a self-billing invoice into a regular sales journal with quick edit mode (accounting firm) enabled. In such cases, the newly created invoices would use the self-
Original PR description
This PR handles 2 cases : ===== PART 1 ===== Self-billing bill sequences should be unique per partner, as implemented in v19+. This PR backports that behavior to 17.0. ===== PART 2 ===== Previously, the `is_self_billing` option on `account.journal` was available only for purchase journals. This caused an issue when importing a self-billing invoice into a regular sales journal with quick edit mode (accounting firm) enabled. In such cases, the newly created invoices would use the self-billing sequence pattern, leading to traceability issues. This PR allows the creation of self-billing sales journals to prevent this issue. task-6103142 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276028 Forward-Port-Of: odoo/odoo#259935
6 changes
Enhancements to existing features
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649
Original PR description
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649
3 changes
Resolved issues and error corrections
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except Exception: pass if i: pass ``` Traceback: ```py ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT ``` https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L10
Original PR description
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues. Forward-Port-Of: odoo/odoo#279984
When selecting a new microphone or camera in the `Voice & Video settings` outside an active meeting, the browser was not asking for permission immediately. This caused Firefox (which enforces per device permissions) to reprompt when the meeting started. This fix pre-authorizes the selected device, so Firefox prompts at selection time rather than when starting a meeting. task-6175062 Forward-Port-Of: odoo/odoo#280201 Forward-Port-Of: odoo/odoo#277730
Original PR description
When selecting a new microphone or camera in the `Voice & Video settings` outside an active meeting, the browser was not asking for permission immediately. This caused Firefox (which enforces per device permissions) to reprompt when the meeting started. This fix pre-authorizes the selected device, so Firefox prompts at selection time rather than when starting a meeting. task-6175062 Forward-Port-Of: odoo/odoo#280201 Forward-Port-Of: odoo/odoo#277730
The fw-ports of https://github.com/odoo/odoo/pull/269465 incorrectly use _get_peppol_error_message, which is depreciated from 19.0 and even removed in subsequent versions (at least 19.4 and master). It now uses the correct get_peppol_error_message static method. Forward-Port-Of: odoo/odoo#278057
Original PR description
The fw-ports of https://github.com/odoo/odoo/pull/269465 incorrectly use _get_peppol_error_message, which is depreciated from 19.0 and even removed in subsequent versions (at least 19.4 and master). It now uses the correct get_peppol_error_message static method. Forward-Port-Of: odoo/odoo#278057
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative.
Original PR description
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with…
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative. **CAUSE** Fixed tax not affecting the base of other tax are dispatched into new base lines and then merged into one line per fixed tax. The new base lines they are dispatched to are created as a copy of the line they originated from. It means we copy the discount from the original lines. The fixed tax amount is the unit price of each new base lines. When reducing the base lines into one line, we take the unit prices of the line, and apply the discount to the unit price. But, since the unit price is the fixed tax amount, and fixed tax are not affected by discounts, we shouldn't apply discount. **PROBLEM 2** fixed division by 0 traceback when the aggregation of invoice lines is 0 **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create the following invoice: - qty: 1, unit_price: 100, tax:0% + fixed tax 1€, set an analytic distribution account - qty: -1, unit_price: 50, tax:0% + fixed tax 1€, set the same analytic distribution account 3. Send the invoice to peppol. 4. A division by 0 should occur. opw-6388219 Forward-Port-Of: odoo/odoo#276945
When 2 workers try to load at the same time a registry that needs to be updated, one of them will deadlock while waiting on the exclusive lock. In such a case, instead of logging and error, we want to log a warning and retry. The retry will block at the shared lock and avoid additional deadlocks. We cannot just raise ConcurrencyError because the HTTP server instantiates the registry before calling `retrying`. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/su
Original PR description
When 2 workers try to load at the same time a registry that needs to be updated, one of them will deadlock while waiting on the exclusive lock. In such a case, instead of logging and error, we want to log a warning and retry. The retry will block at the shared lock and avoid additional deadlocks. We cannot just raise ConcurrencyError because the HTTP server instantiates the registry before calling `retrying`. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277154
The field `website_description` is empty for many partners (or empty html `<p><br></p>`). But for real partners published on the website, it can be huge, including base64 images. With this commit, we avoid prefetching the field when manipulating partners. It can lead to memory errors when looking for parnters on the website, where they all have (possibly heavy) values for this field. It's only really needed when displaying a single partner. --- I confirm I have signed the CLA and read
Original PR description
The field `website_description` is empty for many partners (or empty html `<p><br></p>`). But for real partners published on the website, it can be huge, including base64 images. With this commit, we avoid prefetching the field when manipulating partners. It can lead to memory errors when looking for parnters on the website, where they all have (possibly heavy) values for this field. It's only really needed when displaying a single partner. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274746
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues. Forward-Port-Of: odoo/odoo#279984
Resolved issues and error corrections
Before this commit, the user's presence was not sent to the server when another device reported this user as away/offline while this device was online. `ImStatusMixin` reacts to `presence_status` and correct the user's presence on the server when needed (e.g. locally online while away was received). Since [1], the check on the presence being the one of the current user is wrong (comparing `store.self` to the presence user record). The tests only pass because of the initial presence upda
Original PR description
Before this commit, the user's presence was not sent to the server when another device reported this user as away/offline while this device was online. `ImStatusMixin` reacts to `presence_status` and correct the user's presence on the server when needed (e.g. locally online while away was received). Since [1], the check on the presence being the one of the current user is wrong (comparing `store.self` to the presence user record). The tests only pass because of the initial presence update. This commit fixes the issue and ensures the initial update is not confused by the correction. [1]: https://github.com/odoo/odoo/pull/248168 runbot-944282 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
### Steps to reproduce: - Open CRM app (or any model with chatter) - Open any record (e.g., an Opportunity) - Click "Log note" - Type some text into the input box - Click the "Full composer" icon to open the mail composition wizard - Log the note - Click "Log Note" again > The note is logged successfully, but the text remains visible inside the small inline chatter input box as if it was never sent. (Doesn't happen everytime) ### Cause of Issue: Composer drafts are auto-saved to I
Original PR description
### Steps to reproduce: - Open CRM app (or any model with chatter) - Open any record (e.g., an Opportunity) - Click "Log note" - Type some text into the input box - Click the "Full composer" icon to…
### Steps to reproduce: - Open CRM app (or any model with chatter) - Open any record (e.g., an Opportunity) - Click "Log note" - Type some text into the input box - Click the "Full composer" icon to open the mail composition wizard - Log the note - Click "Log Note" again > The note is logged successfully, but the text remains visible inside the small inline chatter input box as if it was never sent. (Doesn't happen everytime) ### Cause of Issue: Composer drafts are auto-saved to IndexedDB via the debounced saveContent() https://github.com/odoo/odoo/blob/ac2d15c1132af16f00f8955d1be9b43a8626d9bd/addons/mail/static/src/core/common/composer.js#L986-L1003 `clear()`, called from the Full Composer's `onClose` handler after logging a note, only resets in-memory composer state and removes a `localStorage` key — it never deletes the corresponding `IndexedDB` entry. ### Fix: Have `clear()` also delete the persisted IndexedDB draft via the helper used after a normal chatter post in `_sendMessage()`, so `clear()` fully tears down both in-memory and persisted state. opw-6354149
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company currency, posting that reversal move could fail with "The entry is not balanced.", making it impossible to invoice the order. Steps to reproduce: - company in currency A, PoS config in currency B, with a conversion rate producing rounding drift (e.g. 0.4007) - sell a product of 20.0 B + 15% t
Original PR description
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company…
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company currency, posting that reversal move could fail with "The entry is not balanced.", making it impossible to invoice the order. Steps to reproduce: - company in currency A, PoS config in currency B, with a conversion rate producing rounding drift (e.g. 0.4007) - sell a product of 20.0 B + 15% tax (23.0 B), paid by bank, without invoicing - close the session - set a partner on the order and invoice it => UserError: "The entry is not balanced." Cause: in `_prepare_aml_values_list_per_nature`, the product and tax lines each get their balance converted and rounded individually (20.0 * 0.4007 -> 8.01, 3.0 * 0.4007 -> 1.20), while the payment term line was converted from the payment total, without rounding (23.0 * 0.4007 -> 9.2161). Per-line rounding does not distribute over the sum, so the balances could differ by a few cents (8.01 + 1.20 != 9.22) and the move could not be posted. The closing entry has the balancing-account wizard as an escape valve for such differences; the reversal move had none. Fix, following what is done for regular invoices (see `account.move._compute_needed_terms`, where the payment term balance is derived from the sum of the already rounded lines): - round the payment term conversions - put the conversion residual on the last payment term line so the payment terms exactly counterbalance the other lines, but only when the amounts in currency are balanced, so it can only absorb rounding drift - include the cash rounding amounts in the accumulated totals - fix the swapped `amount_currency`/`balance` values when merging two non-split payments on the same receivable account opw-6375309 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275673
The fw-ports of https://github.com/odoo/odoo/pull/269465 incorrectly use _get_peppol_error_message, which is depreciated from 19.0 and even removed in subsequent versions (at least 19.4 and master). It now uses the correct get_peppol_error_message static method. Forward-Port-Of: odoo/odoo#278057
Original PR description
The fw-ports of https://github.com/odoo/odoo/pull/269465 incorrectly use _get_peppol_error_message, which is depreciated from 19.0 and even removed in subsequent versions (at least 19.4 and master). It now uses the correct get_peppol_error_message static method. Forward-Port-Of: odoo/odoo#278057
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative.
Original PR description
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with…
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative. **CAUSE** Fixed tax not affecting the base of other tax are dispatched into new base lines and then merged into one line per fixed tax. The new base lines they are dispatched to are created as a copy of the line they originated from. It means we copy the discount from the original lines. The fixed tax amount is the unit price of each new base lines. When reducing the base lines into one line, we take the unit prices of the line, and apply the discount to the unit price. But, since the unit price is the fixed tax amount, and fixed tax are not affected by discounts, we shouldn't apply discount. **PROBLEM 2** fixed division by 0 traceback when the aggregation of invoice lines is 0 **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create the following invoice: - qty: 1, unit_price: 100, tax:0% + fixed tax 1€, set an analytic distribution account - qty: -1, unit_price: 50, tax:0% + fixed tax 1€, set the same analytic distribution account 3. Send the invoice to peppol. 4. A division by 0 should occur. opw-6388219 Forward-Port-Of: odoo/odoo#276945
Before this commit, opening a live chat in Discuss crashes as soon as the visitor is a contact with an open lead, and the agent can no longer post in that conversation: TypeError: can't access property "length", ctx.templateParams.info_records is undefined This happens because the "Open leads" block reads the visitor member on the channel to decide whether to show itself, and on the thread, which holds none, to pass the leads. It therefore calls info_links with no record, and info
Original PR description
Before this commit, opening a live chat in Discuss crashes as soon as the visitor is a contact with an open lead, and the agent can no longer post in that conversation:
TypeError: can't access property "length",
ctx.templateParams.info_records is undefined
This happens because the "Open leads" block reads the visitor member on the channel to decide whether to show itself, and on the thread, which holds none, to pass the leads. It therefore calls info_links with no record, and info_links reads their length. The panel opens by default in Discuss, so the crash takes the composer with it.
This commit reads the visitor member on the channel to pass the leads, and drops the condition of the caller, so that info_links alone decides whether it has something to show.
https://github.com/odoo/enterprise/pull/126715Miscellaneous changes
This is in preparation for forcefully recommending the use of `execute_query` and `SQL` as early as 19.0. While `execute_query` is the primary recommendation, `execute(SQL(...))` is an OK alternative, but static checking limitations mean queries constructed in function calls, or callers (that includes the implementation of `execute_query` itself), or using conditionals, will be flagged. In that case the easiest pattern is execute(SQL("%s", query)) which we do not want to penalize overl
Original PR description
This is in preparation for forcefully recommending the use of `execute_query` and `SQL` as early as 19.0. While `execute_query` is the primary recommendation, `execute(SQL(...))` is an OK alternative, but static checking limitations mean queries constructed in function calls, or callers (that includes the implementation of `execute_query` itself), or using conditionals, will be flagged. In that case the easiest pattern is
execute(SQL("%s", query))
which we do not want to penalize overly.
- Add fast path for `SQL("%s", arg: SQL)`.
- Improve fast-path for `SQL(SQL())` to do ~nothing when possible.
- Allow overriding `to_flush` in both case, fix site which needs that
- Update type dispatches to check for `Iterable` instead of `__iter__`. this both helps type checkers and is actually correct.
Forward-Port-Of: odoo/odoo#280108
Forward-Port-Of: odoo/odoo#258930The field `website_description` is empty for many partners (or empty html `<p><br></p>`). But for real partners published on the website, it can be huge, including base64 images. With this commit, we avoid prefetching the field when manipulating partners. It can lead to memory errors when looking for parnters on the website, where they all have (possibly heavy) values for this field. It's only really needed when displaying a single partner. --- I confirm I have signed the CLA and read
Original PR description
The field `website_description` is empty for many partners (or empty html `<p><br></p>`). But for real partners published on the website, it can be huge, including base64 images. With this commit, we avoid prefetching the field when manipulating partners. It can lead to memory errors when looking for parnters on the website, where they all have (possibly heavy) values for this field. It's only really needed when displaying a single partner. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274746
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues. Forward-Port-Of: odoo/odoo#279984
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HT
Original PR description
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries…
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HTTP workers were being recycled under normal load. Tracking usage -------------- Every request for a registry goes through the single lookup in the registry constructor, which stamps it with a monotonic timestamp; the stamp is also set when a registry is first built. Collecting idle registries -------------------------- A collection pass drops every registry whose last use is older than the configured idle timeout. It runs at the end of registry loading, so it fires periodically as databases come and go. Registries that are still loading are skipped, so a concurrent build is never collected. Dropping a registry only detaches it from the LRU: a request still holding a reference keeps working, and the next lookup rebuilds it. The timeout is read from ODOO_REGISTRY_MAX_IDLE_TIMEOUT, in seconds; a value of zero, the default, disables the mechanism so behaviour is unchanged unless it is opted into. Results ------- With a five-minute timeout on the same ~2500-database server, the HTTP workers settle at around 40 resident registries instead of saturating memory on the long run. The gevent worker, which sees every web client reconnect at startup and briefly fills the LRU with ~150 databases, releases most of them on the first pass, reclaiming the memory. On a real-life SaaS server with 64GB of RAM, that frees up to ~10GB which were previously taken by unused registries in the LRU. It comes at the expense of extra registry recomputes, but on the other hand workers do not reach their virtual memory limit anymore. closes odoo/odoo#276581 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278236
Resolved issues and error corrections
This commit fix the regex used in `street_split` to be more complient. Before: address format was "street_name street_number - street_number2" Now, street_number can be in front of street_name. Format is also less strict, allowing multiple numbers in the street_name without skipping the building number. Linked: https://github.com/odoo/enterprise/pull/121674 task-6317758 Forward-Port-Of: odoo/odoo#279934 Forward-Port-Of: odoo/odoo#271855
Original PR description
This commit fix the regex used in `street_split` to be more complient. Before: address format was "street_name street_number - street_number2" Now, street_number can be in front of street_name. Format is also less strict, allowing multiple numbers in the street_name without skipping the building number. Linked: https://github.com/odoo/enterprise/pull/121674 task-6317758 Forward-Port-Of: odoo/odoo#279934 Forward-Port-Of: odoo/odoo#271855
Restore the previous behavior by calling `checkAccessRight()` without awaiting it during `PosStore.setup()`. This prevents the POS startup from being blocked while the access check is running. This fixes PoS startup and offline fallback tours timing out while waiting for the "Continue with limited functionality" dialog. Runbot Error-[944421](https://runbot.odoo.com/odoo/error/944421) Forward-Port-Of: odoo/odoo#279792 Forward-Port-Of: odoo/odoo#278628
Original PR description
Restore the previous behavior by calling `checkAccessRight()` without awaiting it during `PosStore.setup()`. This prevents the POS startup from being blocked while the access check is running. This fixes PoS startup and offline fallback tours timing out while waiting for the "Continue with limited functionality" dialog. Runbot Error-[944421](https://runbot.odoo.com/odoo/error/944421) Forward-Port-Of: odoo/odoo#279792 Forward-Port-Of: odoo/odoo#278628
Use "VAT" instead of "TAX" for the default UK tax groups. Also set "Subtotal" as their preceding subtotal label so that it replaces "Untaxed Amount". task-[6413495](https://www.odoo.com/odoo/project/967/tasks/6413495) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279865 Forward-Port-Of: odoo/odoo#278351
Original PR description
Use "VAT" instead of "TAX" for the default UK tax groups. Also set "Subtotal" as their preceding subtotal label so that it replaces "Untaxed Amount". task-[6413495](https://www.odoo.com/odoo/project/967/tasks/6413495) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279865 Forward-Port-Of: odoo/odoo#278351
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, an
Original PR description
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the…
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, and stock.picking.group_id is a stored related on move_ids.group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/stock/models/stock_picking.py#L186). A single picking can therefore only resolve to one SO. _create_picking (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order.py#L290) builds one picking per PO and _prepare_stock_moves assigns every move the merged PO's group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order_line.py#L307), so when a merged dropship PO carries lines from multiple SOs every move lands in one picking under the PO group. Only one SO gets linked and the others stay "not fully delivered" even after validation. Solution Override PurchaseOrderLine._prepare_stock_moves to set group_id to the SO's procurement_group_id when sale_line_id is set, so each dropship move is created in its originating SO's procurement group. Override PurchaseOrder._create_picking to detect dropship POs whose order lines span more than one SO and create one picking per SO group by calling _prepare_picking and _create_stock_moves per group. picking.group_id then resolves to the SO group via the stored related field, picking.sale_id points to the right SO, and delivery_status updates correctly on validation. opw-6094608 Forward-Port-Of: odoo/odoo#279843 Forward-Port-Of: odoo/odoo#257823
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database. **Current behavior before PR:** ``` ERROR: TestRepair.test_search_date_category Traceback (most recent call last):
Original PR description
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of…
**Description of the issue/feature this PR addresses:**
`test_search_date_category` is failing across runbot builds
Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database.
**Current behavior before PR:**
```
ERROR: TestRepair.test_search_date_category
Traceback (most recent call last):
File "/data/build/odoo/addons/repair/tests/test_repair.py", line 915, in test_search_date_category
self.env['repair.order'].search([]).unlink()
File "/data/build/odoo/addons/rating/models/mail_thread.py", line 21, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/mail_thread.py", line 391, in unlink
res = super(MailThread, self).unlink()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/models.py", line 46, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/odoo/orm/models.py", line 4131, in unlink
func(self)
File "/data/build/odoo/addons/repair/models/repair.py", line 421, in _unlink_except_confirmed
repairs_to_cancel.action_repair_cancel()
File "/data/build/enterprise/quality_repair/models/repair.py", line 114, in action_repair_cancel
res = super().action_repair_cancel()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/repair/models/repair.py", line 475, in action_repair_cancel
raise UserError(_("You cannot cancel a Repair Order that's already been completed"))
odoo.exceptions.UserError: You cannot cancel a Repair Order that's already been completed
```
**Desired behavior after PR is merged:**
`test_search_date_category` passes
opw-[4998413](https://www.odoo.com/odoo/my-tasks/4998413)
runbot.build.error-[231146](https://runbot.odoo.com/odoo/runbot.build.error/231146)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#267852…F fetch Nilvera PDF retrieval (the manual "Get PDF" action and the scheduled "retrieve sale PDFs" cron) hardcoded the "Sale" document category. That is correct for e-invoices (/einvoice/Sale/{uuid}/pdf) but wrong for e-archive documents, whose resource is "Invoices". For e-archive invoices it produced GET /earchive/Sale/{uuid}/pdf, which Nilvera answers with 404, surfacing to the user as "Odoo could not perform this action at the moment... Not Found - 404" and making the cron raise on every
Original PR description
…F fetch
Nilvera PDF retrieval (the manual "Get PDF" action and the scheduled "retrieve sale PDFs" cron) hardcoded the "Sale" document category. That is correct for e-invoices (/einvoice/Sale/{uuid}/pdf) but wrong for e-archive documents, whose resource is "Invoices". For e-archive invoices it produced GET /earchive/Sale/{uuid}/pdf, which Nilvera answers with 404, surfacing to the user as "Odoo could not perform this action at the moment... Not Found - 404" and making the cron raise on every run.
Derive the document category from the invoice channel so e-archive resolves to /earchive/invoices/{uuid}/pdf while e-invoice keeps using /einvoice/sale/{uuid}/pdf.
OPW-6311661
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278796Before this commit, the chat window test "mark as read when opening chat window" failed at random on runbot, on the store fetches checked at teardown: 14. [step] unverified steps > Steps: [ "store fetch: /discuss/channel/messages", ] This happens because waitStoreFetch resolves as soon as the mock server serves the request, so the thread can still be loading when the test posts bob's message. As a result the scroll to unread, which only the loaded thread applies, is st
Original PR description
Before this commit, the chat window test "mark as read when opening chat window" failed at random on runbot, on the store fetches checked at teardown:
14. [step] unverified steps
> Steps: [
"store fetch: /discuss/channel/messages",
]
This happens because waitStoreFetch resolves as soon as the mock server serves the request, so the thread can still be loading when the test posts bob's message. As a result the scroll to unread, which only the loaded thread applies, is still pending when the chat window closes, and re-opening it loads around the new message separator: that second fetch is the one no assertion verifies.
This commit waits for the loaded thread before posting the message.
https://runbot.odoo.com/odoo/error/242447During the FWP, the inherit has been mistakingly inverted. PINT_EU should inherit PINT and EN16931 as dictated in the pint documentation. no-task --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
During the FWP, the inherit has been mistakingly inverted. PINT_EU should inherit PINT and EN16931 as dictated in the pint documentation. no-task --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088
Original PR description
**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088642d7699b3e033c1fcc2564, so this is essentially a backport for that fix. opw-6344750 Forward-Port-Of: odoo/odoo#279887 Forward-Port-Of: odoo/odoo#276536
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actuall
Original PR description
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actually finishes. runbot-941543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279826 Forward-Port-Of: odoo/odoo#278025
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught Promise > Invalid props for component 'CopyButton': 'content' is not a string or object or function ``` Cause: - The 'CopyButton' component expect content to be a string, object or function but receives false. It does not happen in previous versions because in the refector https:/
Original PR description
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught…
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught Promise > Invalid props for component 'CopyButton': 'content' is not a string or object or function ``` Cause: - The 'CopyButton' component expect content to be a string, object or function but receives false. It does not happen in previous versions because in the refector https://github.com/odoo/odoo/commit/c2f34517b2f9832a498981d0fa17ec39b9739cb6 set the `videocall_location` to false instead of empty string like before https://github.com/odoo/odoo/blob/499420f7062ab467ff6f50b30c547e54c35ae1e9/addons/web/static/src/core/copy_button/copy_button.js#L14 - but any field using the `CopyClipboardChar/CopyClipboardURL` widget passes its raw field value straight through as content. An empty char/text field is represented as false, so whenever such a field becomes empty, CopyClipboardField hands `false` to CopyButton, which fails prop validation (debug mode). Solution: - Fix it at the source: CopyClipboardField's template now falls back to an empty string when the field value is falsy, so CopyButton never receives false but a valid string. opw-6360936 Forward-Port-Of: odoo/odoo#275236
[FIX] html_builder: prevent crash on legacy image shapes When the Website Editor encounters an image shape that does not exist in the registry, it fatally crashes upon saving (`TypeError: Cannot read properties of undefined`), blocking the user from saving the page. While an upgrade script exists to remap these shapes ([commit https://github.com/odoo/odoo/commit/f348be018f5740a31754494c905ea2b61bb718be](https://github.com/odoo/upgrade/commit/f348be0dcbc63c1f74f742b562509f81767564c0)), ti
Original PR description
[FIX] html_builder: prevent crash on legacy image shapes When the Website Editor encounters an image shape that does not exist in the registry, it fatally crashes upon saving (`TypeError: Cannot read…
[FIX] html_builder: prevent crash on legacy image shapes When the Website Editor encounters an image shape that does not exist in the registry, it fatally crashes upon saving (`TypeError: Cannot read properties of undefined`), blocking the user from saving the page. While an upgrade script exists to remap these shapes ([commit https://github.com/odoo/odoo/commit/f348be018f5740a31754494c905ea2b61bb718be](https://github.com/odoo/upgrade/commit/f348be0dcbc63c1f74f742b562509f81767564c0)), timeline gaps leave SaaS databases vulnerable. For example, if a client upgraded their database to 17.0 in Feb 2024, they bypassed the migration script merged in Dec 2024. This leaves the legacy shape permanently orphaned inside their modern views. This commit adds a `getImageShape` fallback. Instead of crashing,the editor now defaults to standard values and renders "None" in the UI, allowing the user to select a new shape and save their work. Steps to Reproduce: 1. Install Website. 2. Go to Site -> HTML / CSS Editor. 3. Add `data-shape="web_editor/basic/bsc_organic_2"` to an <img> tag. 4. Click "Edit" to open the Website Builder. 5. Click the image, OR click "Save". 6. JS traceback. [opw-6286044](https://www.odoo.com/odoo/my-support-tasks/6286044?debug=assets) [opw-6291591](https://www.odoo.com/odoo/my-support-tasks/6291591?debug=assets) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270356
## Problem `pttExtensionHookService` registers a global `window.addEventListener("message", ...)` handler that reads `data.from` without checking that `data` is defined first: ```js browser.addEventListener("message", ({ data, origin, source }) => { const rtc = env.services["discuss.rtc"]; if ( source !== window || origin !== location.origin || data.from !== "discuss-push-to-talk" || // <- crashes if data is undefined (!rtc && data.type !== "answer-is-
Original PR description
## Problem `pttExtensionHookService` registers a global `window.addEventListener("message", ...)` handler that reads `data.from` without checking that `data` is defined first: ```js…
## Problem
`pttExtensionHookService` registers a global `window.addEventListener("message", ...)`
handler that reads `data.from` without checking that `data` is defined first:
```js
browser.addEventListener("message", ({ data, origin, source }) => {
const rtc = env.services["discuss.rtc"];
if (
source !== window ||
origin !== location.origin ||
data.from !== "discuss-push-to-talk" || // <- crashes if data is undefined
(!rtc && data.type !== "answer-is-enabled")
) {
return;
}
...
```
Any same-window, same-origin `postMessage` sent by an unrelated browser
extension (a common content-script <-> injected-script pattern) can carry
`data === undefined`. The `source !== window` and `origin !== location.origin`
checks only filter out cross-window/cross-origin messages, so a same-origin
message from any other extension reaches this handler and crashes with:
```
TypeError: Cannot read properties of undefined (reading 'from')
```
This surfaces as an uncaught client error on any page with Discuss loaded,
after some time, unrelated to what the user is doing. The Discuss
push-to-talk extension itself does not need to be installed to trigger it,
since the crash happens before checking whether the message actually
originated from that extension.
## Solution
Use optional chaining (`data?.from`) so unrelated same-origin messages with
no `data` are safely ignored instead of crashing.
## Verification
- Reproduced against the live production `web.assets_web.min.js` bundle
(traceback matches exactly).
- Confirmed the bug is still present in the latest `18.0` of both `OCA/OCB`
and `odoo/odoo` (no newer commit touches this file since
`dc58ef1ad904`, which fixes an unrelated issue).
Forward-Port-Of: odoo/odoo#279920
Forward-Port-Of: odoo/odoo#279476The test for `hr_leave_attendance_report` failed Runbot's faketime tests for two reasons: * The report's view use SQL's reserved syntax `CURRENT_DATE` which always resolves to real system clock, and ignores Odoo's faketime mechanism. * The three tests used hardcoded dates. Since the report is exclusively concerned with the window of last 13 months. Faking the time in a future date further than this led to wrong results. This commit fixes both issues by: 1. Using `now()::date`
Original PR description
The test for `hr_leave_attendance_report` failed Runbot's faketime tests for two reasons: * The report's view use SQL's reserved syntax `CURRENT_DATE` which always resolves to real system clock, and ignores Odoo's faketime mechanism. * The three tests used hardcoded dates. Since the report is exclusively concerned with the window of last 13 months. Faking the time in a future date further than this led to wrong results. This commit fixes both issues by: 1. Using `now()::date` in the view instead of `CURRENT_DATE`. 2. Replacing the hardcoded dates in the tests by dates computed relative to `fields.Date.today()`. Runbot Errors: [1](https://runbot.odoo.com/odoo/runbot.build.error/944585), [2](https://runbot.odoo.com/odoo/runbot.build.error/944585/runbot.build.error/runbot.build.error/944584) Forward-Port-Of: odoo/odoo#280110 Forward-Port-Of: odoo/odoo#279337
The fw-ports of https://github.com/odoo/odoo/pull/269465 incorrectly use _get_peppol_error_message, which is depreciated from 19.0 and even removed in subsequent versions (at least 19.4 and master). It now uses the correct get_peppol_error_message static method. Forward-Port-Of: odoo/odoo#278057
Original PR description
The fw-ports of https://github.com/odoo/odoo/pull/269465 incorrectly use _get_peppol_error_message, which is depreciated from 19.0 and even removed in subsequent versions (at least 19.4 and master). It now uses the correct get_peppol_error_message static method. Forward-Port-Of: odoo/odoo#278057
Steps to reproduce: - Open any PoS session - Click on Orders and filter by "Paid" orders - Select an order and click on "Details" - Open the "Payments" tab and click on the "View" button of a payment - Click on the payment method link Traceback: OwlError: The following error occurred in onWillStart: "Cannot find key "pos_payment_provider_cards" in the "view_widgets" registry" Backend views opened from within the PoS UI (order details dialog, drill-down on many2one links, ...) share t
Original PR description
Steps to reproduce: - Open any PoS session - Click on Orders and filter by "Paid" orders - Select an order and click on "Details" - Open the "Payments" tab and click on the "View" button of a payment…
Steps to reproduce: - Open any PoS session - Click on Orders and filter by "Paid" orders - Select an order and click on "Details" - Open the "Payments" tab and click on the "View" button of a payment - Click on the payment method link Traceback: OwlError: The following error occurred in onWillStart: "Cannot find key "pos_payment_provider_cards" in the "view_widgets" registry" Backend views opened from within the PoS UI (order details dialog, drill-down on many2one links, ...) share their arch with the backend, but `point_of_sale._assets_pos` excludes everything under `static/src/backend/`, so widgets defined there (e.g. `pos_payment_provider_cards`, `lna_checklist`, `point_of_sale_test_epos`) are never registered in the PoS UI. Unlike missing field widgets, which fall back to the default widget with a warning, an unknown `<widget>` node makes the whole view crash since `Widget.parseWidgetNode` reads the registry without a fallback. Those widgets are backend configuration helpers that are irrelevant in a PoS session, so instead of bundling each of them (and any future one) in the PoS assets, patch `Widget.parseWidgetNode` in the PoS bundle to skip unknown widgets with a warning, like missing field widgets do. This covers the form, list and kanban arch parsers at once. opw-6382156 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279255 Forward-Port-Of: odoo/odoo#276912
Normalize client IPv6 addresses to their /64 network prefix when generating device keys. This prevents the same IPv6 user from being tracked as multiple devices due to changing interface identifiers while preserving IPv4 behavior. This reduces the number of devices in the session while maintaining reliability. The original IP address will be used to determine device location. Task-6397512
Original PR description
Normalize client IPv6 addresses to their /64 network prefix when generating device keys. This prevents the same IPv6 user from being tracked as multiple devices due to changing interface identifiers while preserving IPv4 behavior. This reduces the number of devices in the session while maintaining reliability. The original IP address will be used to determine device location. Task-6397512
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative.
Original PR description
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with…
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative. **CAUSE** Fixed tax not affecting the base of other tax are dispatched into new base lines and then merged into one line per fixed tax. The new base lines they are dispatched to are created as a copy of the line they originated from. It means we copy the discount from the original lines. The fixed tax amount is the unit price of each new base lines. When reducing the base lines into one line, we take the unit prices of the line, and apply the discount to the unit price. But, since the unit price is the fixed tax amount, and fixed tax are not affected by discounts, we shouldn't apply discount. **PROBLEM 2** fixed division by 0 traceback when the aggregation of invoice lines is 0 **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create the following invoice: - qty: 1, unit_price: 100, tax:0% + fixed tax 1€, set an analytic distribution account - qty: -1, unit_price: 50, tax:0% + fixed tax 1€, set the same analytic distribution account 3. Send the invoice to peppol. 4. A division by 0 should occur. opw-6388219 Forward-Port-Of: odoo/odoo#276945
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280257 Forward-Port-Of: odoo/odoo#280094
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280257 Forward-Port-Of: odoo/odoo#280094
Miscellaneous changes
This is in preparation for forcefully recommending the use of `execute_query` and `SQL` as early as 19.0. While `execute_query` is the primary recommendation, `execute(SQL(...))` is an OK alternative, but static checking limitations mean queries constructed in function calls, or callers (that includes the implementation of `execute_query` itself), or using conditionals, will be flagged. In that case the easiest pattern is execute(SQL("%s", query)) which we do not want to penalize overl
Original PR description
This is in preparation for forcefully recommending the use of `execute_query` and `SQL` as early as 19.0. While `execute_query` is the primary recommendation, `execute(SQL(...))` is an OK alternative, but static checking limitations mean queries constructed in function calls, or callers (that includes the implementation of `execute_query` itself), or using conditionals, will be flagged. In that case the easiest pattern is
execute(SQL("%s", query))
which we do not want to penalize overly.
- Add fast path for `SQL("%s", arg: SQL)`.
- Improve fast-path for `SQL(SQL())` to do ~nothing when possible.
- Allow overriding `to_flush` in both case, fix site which needs that
- Update type dispatches to check for `Iterable` instead of `__iter__`. this both helps type checkers and is actually correct.
Forward-Port-Of: odoo/odoo#280108
Forward-Port-Of: odoo/odoo#258930Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HTTP workers were being recycled under normal load. Tracking usage -------------- Every request for a registry goes through the single lookup in the registry constructor, which stamps it with a monotonic timestamp; the stamp is also set when a registry is first built. Collecting idle registries -------------------------- A collection pass drops every registry whose last use is older than the configured idle timeout. It runs at the end of registry loading, so it fires periodically as databases come and go. Registries that are still loading are skipped, so a concurrent build is never collected. Dropping a registry only detaches it from the LRU: a request still holding a reference keeps working, and the next lookup rebuilds it. The timeout is read from ODOO_REGISTRY_MAX_IDLE_TIMEOUT, in seconds; a value of zero, the default, disables the mechanism so behaviour is unchanged unless it is opted into. Results ------- With a five-minute timeout on the same ~2500-database server, the HTTP workers settle at around 40 resident registries instead of saturating memory on the long run. The gevent worker, which sees every web client reconnect at startup and briefly fills the LRU with ~150 databases, releases most of them on the first pass, reclaiming the memory. On a real-life SaaS server with 64GB of RAM, that frees up to ~10GB which were previously taken by unused registries in the LRU. It comes at the expense of extra registry recomputes, but on the other hand workers do not reach their virtual memory limit anymore. closes odoo/odoo#276581 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278236
Resolved issues and error corrections
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught Promise > Invalid props for component 'CopyButton': 'content' is not a string or object or function ``` Cause: - The 'CopyButton' component expect content to be a string, object or function but receives false. It does not happen in previous versions because in the refector https:/
Original PR description
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught…
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught Promise > Invalid props for component 'CopyButton': 'content' is not a string or object or function ``` Cause: - The 'CopyButton' component expect content to be a string, object or function but receives false. It does not happen in previous versions because in the refector https://github.com/odoo/odoo/commit/c2f34517b2f9832a498981d0fa17ec39b9739cb6 set the `videocall_location` to false instead of empty string like before https://github.com/odoo/odoo/blob/499420f7062ab467ff6f50b30c547e54c35ae1e9/addons/web/static/src/core/copy_button/copy_button.js#L14 - but any field using the `CopyClipboardChar/CopyClipboardURL` widget passes its raw field value straight through as content. An empty char/text field is represented as false, so whenever such a field becomes empty, CopyClipboardField hands `false` to CopyButton, which fails prop validation (debug mode). Solution: - Fix it at the source: CopyClipboardField's template now falls back to an empty string when the field value is falsy, so CopyButton never receives false but a valid string. opw-6360936 Forward-Port-Of: odoo/odoo#275236
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280094
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280094
Before this commit, test_01_invite_by_email_flow could fail right after a tour that succeeded, on a loaded runbot: ``` AssertionError: res.partner(2417,) not found in res.partner(2416,) ``` This happens because the tour ends on the click on "Invite to Group Chat", which only starts the add_members and invite_by_email calls. The test closes the browser and reads the channel members right after, so under load the calls never reach the server. Note that the tour did wait for the invite p
Original PR description
Before this commit, test_01_invite_by_email_flow could fail right after a tour that succeeded, on a loaded runbot: ``` AssertionError: res.partner(2417,) not found in res.partner(2416,) ``` This happens because the tour ends on the click on "Invite to Group Chat", which only starts the add_members and invite_by_email calls. The test closes the browser and reads the channel members right after, so under load the calls never reach the server. Note that the tour did wait for the invite panel to close, until that panel became a dialog: the step waited for any panel to be gone, and the member list stays open. This commit waits for the invited member in the member list and for the dialog to close, which only happens once both calls are done. https://runbot.odoo.com/odoo/error/944291
The fw-ports of https://github.com/odoo/odoo/pull/269465 incorrectly use _get_peppol_error_message, which is depreciated from 19.0 and even removed in subsequent versions (at least 19.4 and master). It now uses the correct get_peppol_error_message static method. Forward-Port-Of: odoo/odoo#278057
Original PR description
The fw-ports of https://github.com/odoo/odoo/pull/269465 incorrectly use _get_peppol_error_message, which is depreciated from 19.0 and even removed in subsequent versions (at least 19.4 and master). It now uses the correct get_peppol_error_message static method. Forward-Port-Of: odoo/odoo#278057
Miscellaneous changes
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior was previously introduced to match the content of the composer body/subject to the recipient language. If there was only one language among the recipients it automatically adapted the template and changed the rendered language (which also refreshed the content). This logic was trigge
Original PR description
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior…
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior was previously introduced to match the content of the composer body/subject to the recipient language. If there was only one language among the recipients it automatically adapted the template and changed the rendered language (which also refreshed the content). This logic was triggered by a depends on `partner_ids` and triggered the compute on every recipient changes which led to the subject/body reset. **Fix:** Revert commit: https://github.com/odoo/odoo/commit/b7bbb7b21f4848323666230b518cad9459726f67 in 18.0+ Also adapt commit: https://github.com/odoo/odoo/commit/c6f19e89cb6019e7dbaadbc7427fbb6ddd5661ed to avoid mixed language in resulting mail when the composer was modified We could also try to prevent the compute when the subject or body is already modified instead of removing its logic. opw-6020245 Forward-Port-Of: odoo/odoo#279669 Forward-Port-Of: odoo/odoo#254090
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues. Forward-Port-Of: odoo/odoo#279984
Resolved issues and error corrections
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#274701 Forward-Port-Of: odoo/odoo#268284
Original PR description
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#274701 Forward-Port-Of: odoo/odoo#268284
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' Th
Original PR description
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' The '/' case was not excluded, causing it to be treated as a valid VAT number ### Steps to reproduce: - Install `account` - Create two fiscal positions with auto-apply: -- Name: FP VAT, VAT required: True, sequence: 1 -- Name: FP no VAT, VAT required: False, sequence: 2 - Create a partner with VAT: '/' - Create an Invoice for that partner and check the Fiscal Position Before the fix, `FP VAT` is selected instead of `FP no VAT` opw-6204531 Forward-Port-Of: odoo/odoo#280065
Before this commit, turning the camera on during a call could leave the camera off in every member's UI, including the local user's own tile, while the video was already being sent. This happens because toggleVideo awaits network.updateUpload before updateAndBroadcast, and updateUpload waits on the ready promise of every peer. A single member whose handshake never completes holds isCameraOn and isScreenSharingOn for everyone. This commit fixes the issue by broadcasting the state first and
Original PR description
Before this commit, turning the camera on during a call could leave the camera off in every member's UI, including the local user's own tile, while the video was already being sent. This happens because toggleVideo awaits network.updateUpload before updateAndBroadcast, and updateUpload waits on the ready promise of every peer. A single member whose handshake never completes holds isCameraOn and isScreenSharingOn for everyone. This commit fixes the issue by broadcasting the state first and awaiting the upload after. Note that updateUpload sends its info snapshot to the peers synchronously, so they still learn the new track. Back-port of https://github.com/odoo/odoo/pull/279106 Forward-Port-Of: odoo/odoo#280014
Steps to reproduce ------------------ 1. Set the company document layout to DIN5008 2. Open a delivery and print the delivery slip The title is missing on the DIN5008 layout, we only have the reference `WH/OUT/00001`. What happens ------------ The DIN5008 layout hides the body title with css and prints its own `h2` instead, from the `din5008_document_title` variable, and uses `o.name` (the picking number) when this variable is not set. The commit 0058d1cf7655 added the title on the
Original PR description
Steps to reproduce ------------------ 1. Set the company document layout to DIN5008 2. Open a delivery and print the delivery slip The title is missing on the DIN5008 layout, we only have the reference `WH/OUT/00001`. What happens ------------ The DIN5008 layout hides the body title with css and prints its own `h2` instead, from the `din5008_document_title` variable, and uses `o.name` (the picking number) when this variable is not set. The commit 0058d1cf7655 added the title on the standard delivery report with `picking_type_id._get_code_report_name()`, but `l10n_din5008_stock` was not updated to set `din5008_document_title`, so on DIN5008 we only get the number. The fix ------- We set it the same way as the other layouts, hence we get back the full title `Delivery Note WH/OUT/00001`. opw-6299248
This RST syntax fix prevents warnings during system update. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274770
Original PR description
This RST syntax fix prevents warnings during system update. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274770
This commit is a backport of the extra timeout added in the forward port in commit 75e9ec3e9ae041d5509bd0f6c62128d1075b0135 The previous step trigger a reload of the iframe because the template for the header is changed, which takes some time. This causes non-deterministic failure due timeout. Thus, the timeout is increased. runbot-234060 Forward-Port-Of: odoo/odoo#280247
Original PR description
This commit is a backport of the extra timeout added in the forward port in commit 75e9ec3e9ae041d5509bd0f6c62128d1075b0135 The previous step trigger a reload of the iframe because the template for the header is changed, which takes some time. This causes non-deterministic failure due timeout. Thus, the timeout is increased. runbot-234060 Forward-Port-Of: odoo/odoo#280247
Resolved issues and error corrections
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` el
Original PR description
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon`…
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` element. Our guess is that we may sometimes early return in `isVideoReady`, because the component has been destroyed (a new rendering might be on the way). To ensure that we don't take that as the ready signal in the test, we now only consider that we're ready if isVideoReady returned true (i.e. no early return). runbot error-241798 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
## Issue When generating an invoice for a service product with an invoicing policy based on timesheets, the amount of hours invoiced is wrong if there exists a credit note linked to that SO. ## Steps to reproduce 1. Install *Sales Timesheet* (`sale_timesheet`) 2. Create a Product P - Product Type: Service - Create on Order: Task - Project: Any project - Invoicing Policy: Based on Timesheets 3. Create a SO - Any Customer - Product P (any quantity) - Confi
Original PR description
## Issue When generating an invoice for a service product with an invoicing policy based on timesheets, the amount of hours invoiced is wrong if there exists a credit note linked to that SO. ## Steps…
## Issue
When generating an invoice for a service product with an invoicing policy based on timesheets, the amount of hours invoiced is wrong if there exists a credit note linked to that SO.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P
- Product Type: Service
- Create on Order: Task
- Project: Any project
- Invoicing Policy: Based on Timesheets
3. Create a SO
- Any Customer
- Product P (any quantity)
- Confirm the SO
4. In the created task, add a timesheet entry
- Date: Today
- Time Spent: 10:00 (10 hours)
5. Create and confirm the invoice for the SO
6. Create a Credit Note from the invoice, set the quantity to 4 hours, and confirm it
7. From the created task, add a second timesheet entry
- Date: Any future date (e.g., today + 7)
- Time Spent: 15:00 (15 hours)
8. Create a second invoice, but set a Timesheets Period that only covers the second timesheet entry
9. **The quantity on the newly created invoice is 9 hours, even though we're clearly trying to invoice the 15 hours from the second timesheet entry.**
## Cause
The second invoice is impacted by the credit note generated from the first one. When generating that second invoice, the [`_recompute_qty_to_invoice`](https://github.com/odoo/odoo/blob/0512ebd4c8cc277fdb4fbe0f57619a0bd61192c2/addons/sale_timesheet/models/sale_order_line.py#L149) method incorrectly computes the amount to invoice by taking into account `account.analytic.line` from outside the provided range.
The delivered quantity is correctly calculated by taking into account the provided range (through the `start_date` and `end_date` added to the domain passed to `_get_delivered_quantity_by_analytic`:
https://github.com/odoo/odoo/blob/0512ebd4c8cc277fdb4fbe0f57619a0bd61192c2/addons/sale_timesheet/models/sale_order_line.py#L176-L180
But then, for each `sale.order.line`, we look at the related `account.analytic.line` without taking into account the provided dates, which leads to lines outside of the range impacting the invoice.
https://github.com/odoo/odoo/blob/0512ebd4c8cc277fdb4fbe0f57619a0bd61192c2/addons/sale_timesheet/models/sale_order_line.py#L182-L193
In the example described in the *Steps to reproduce*, we start with a (correct) amount delivered of 15.0, we find two `invoice_lines_to_calculate` (the invoice of 10 hours, and the credit note of 4 hours), which leads to the quantity to invoice being set to `15 - (-4 + 10) = 9`. This seems like an odd behavior as it:
- doesn't invoice all the hours within the provided range (15 hours within the range, and we're only invoicing 9)
- doesn't invoice **all** the hours left to be invoiced (6 hours are already invoiced, 25 should be in total, and we're invoicing 9)
opw-6373870Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail
Original PR description
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail deterministically. This commit avoids the issue by emptying the many2one without validation, so it basically only set the input value to the empty string, but doesn't tab/enter or anything else, hence it never selects an unwanted value. runbot error-941430 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps to reproduce: - From the website editor, open the Theme tab. - Upload a custom font. - Open the media dialog and go to the "Documents" tab. Issue: The uploaded font files appeared in the Documents tab. When a zip file was uploaded, every font it contained appeared individually, along with the generated "CSS font face" attachment. Cause: Fonts uploaded through `/website/theme_upload_font` are created as public attachments. The Documents tab of the media dialog lists every public
Original PR description
Steps to reproduce: - From the website editor, open the Theme tab. - Upload a custom font. - Open the media dialog and go to the "Documents" tab. Issue: The uploaded font files appeared in the…
Steps to reproduce: - From the website editor, open the Theme tab. - Upload a custom font. - Open the media dialog and go to the "Documents" tab. Issue: The uploaded font files appeared in the Documents tab. When a zip file was uploaded, every font it contained appeared individually, along with the generated "CSS font face" attachment. Cause: Fonts uploaded through `/website/theme_upload_font` are created as public attachments. The Documents tab of the media dialog lists every public attachment that is not an image or an asset, so the font files (mimetype `font/...`), their font face declaration (mimetype `text/css`) and googleFontMetadata (server caches it as public attachment) were listed. Fix: Exclude those attachments from the Documents tab domain: - whose mimetype starts with `font/`, - whose description matches the font face declarations created in `snippets.options.js`. - whose name equals "googleFontMetadata". task-[4771523](https://www.odoo.com/odoo/project/974/tasks/4771523)
Description of the issue this commit addresses: Some existing demo databases lack the tax XML IDs introduced by ae4da50e5f246. Mandatory references to these IDs prevent the l10n_ar demo invoices from loading. --- Desired behavior after this commit is merged: This commit makes the new taxes optional in demo data, allowing invoices to load when the tax XML IDs are absent while preserving them when available. --- runbot-[234672](https://runbot.odoo.com/odoo/error/234672) ---
Original PR description
Description of the issue this commit addresses: Some existing demo databases lack the tax XML IDs introduced by ae4da50e5f246. Mandatory references to these IDs prevent the l10n_ar demo invoices from loading. --- Desired behavior after this commit is merged: This commit makes the new taxes optional in demo data, allowing invoices to load when the tax XML IDs are absent while preserving them when available. --- runbot-[234672](https://runbot.odoo.com/odoo/error/234672) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps to reproduce the error: (Python Version: 3.14.X)
- Install ``accounting_firm`` industry with demo data
Code for server action to generate the error:
```py
for i in [1]:
try:
pass
except Exception:
pass
if i:
pass
```
Traceback:
```py
ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT
```
https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L108
The server action contains a ``for`` loop with a ``try/except`` block followed by additional statements in the loop body,
this combination generates the ``JUMP_BACKWARD_NO_INTERRUPT`` opcode, which is not included in ``_SAFE_OPCODES`` at [1].
When the server action is evaluated by ``safe_eval``, it calls the ``assert_valid_codeobj`` method, which validates the compiled bytecode against ``_SAFE_OPCODES``. Since ``JUMP_BACKWARD_NO_INTERRUPT`` is not present in the allowed opcodes, ``assert_valid_codeobj()`` raises a ``ValueError`` at [2] before the server action is executed .
Solution:
``JUMP_BACKWARD_NO_INTERRUPT`` opcode is added in the ``_SAFE_OPCODES`` and it is also added in the ``_SAFE_QWEB_OPCODES``.
It was added in Python 3.11: https://docs.python.org/3/whatsnew/3.11.html#new-opcodes
``JUMP_BACKWARD_NO_INTERRUPT`` is a control-flow opcode that only changes
the interpreter's execution flow by jumping back to a previous instruction.
It is the equivalent to ``JUMP_BACKWARD`` opcode. Its only semantic difference is
that the interpreter does not perform an interrupt check at that instruction.
It does not introduce any new capabilities or perform operations such as
attribute access, imports, function calls, or object creation.
Ref: https://docs.python.org/3.12/library/dis.html#opcode-JUMP_BACKWARD_NO_INTERRUPT
Similar commit that adds some necessary opcodes:
https://github.com/odoo/odoo/commit/86498d24946e510025add5d24ef0d4bcce8ad05f
[1]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L135
[2]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L244-L246
sentry-7614026125
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prIt makes no sense to mention (Production) on pdp registration wizard when you are in prod mode
Original PR description
It makes no sense to mention (Production) on pdp registration wizard when you are in prod mode
Miscellaneous changes
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the surrounding table remains rendered and appears empty. Only display the tags table when at least one tag is visible on ecommerce. @Tecnativa TT63855 **Description of the issue/feature this PR addresses:** The condition used to display the product tags table considers all tags associate
Original PR description
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the…
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the surrounding table remains rendered and appears empty. Only display the tags table when at least one tag is visible on ecommerce. @Tecnativa TT63855 **Description of the issue/feature this PR addresses:** The condition used to display the product tags table considers all tags associated with the product, including those that are not visible on ecommerce. **Current behavior before PR:** When a product only has non-visible tags, the tags table is displayed without any content. <img width="669" height="350" alt="image" src="https://github.com/user-attachments/assets/4758ea76-5186-4035-a065-aa4c71ce7053" /> **Desired behavior after PR is merged:** The tags table is only displayed when the product has at least one tag visible on ecommerce. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr