Daily updates from Odoo
Wednesday, July 15, 2026
273 changes
13 changes
Resolved issues and error corrections
Since #198829, a `t-att-class` has been added to the `loadOlder` template that relies on `mountedAndLoaded` of thread state to control the visibility of the `Load More` button. But it doesn't read the value from the state properly. As a result, the button is always transparent. This change fixes this by reading the value from the state. Forward-Port-Of: odoo/odoo#275934 Forward-Port-Of: odoo/odoo#275253
Original PR description
Since #198829, a `t-att-class` has been added to the `loadOlder` template that relies on `mountedAndLoaded` of thread state to control the visibility of the `Load More` button. But it doesn't read the value from the state properly. As a result, the button is always transparent. This change fixes this by reading the value from the state. Forward-Port-Of: odoo/odoo#275934 Forward-Port-Of: odoo/odoo#275253
…nding When cash rounding is enabled with "Only for cash payment methods", an order partially paid in cash and completed with an online payment could neither request the correct online amount nor be marked as paid. Steps to reproduce: - Enable cash rounding (e.g. 0.05, HALF-UP) with "Only for cash payment methods" - Create an order with a total of 15.28 - Add a cash payment of 10.00, then an online payment for the remainder The frontend requests 5.28 for the online payment, but as so
Original PR description
…nding When cash rounding is enabled with "Only for cash payment methods", an order partially paid in cash and completed with an online payment could neither request the correct online amount nor be…
…nding When cash rounding is enabled with "Only for cash payment methods", an order partially paid in cash and completed with an online payment could neither request the correct online amount nor be marked as paid. Steps to reproduce: - Enable cash rounding (e.g. 0.05, HALF-UP) with "Only for cash payment methods" - Create an order with a total of 15.28 - Add a cash payment of 10.00, then an online payment for the remainder The frontend requests 5.28 for the online payment, but as soon as the order contained a cash payment the server rounded the whole order total: get_and_set_online_payments_data() returned an unpaid amount of 5.30 (15.30 - 10.00), so the validation failed with "Invalid online payments". Even once the online payment of 5.28 was processed, the order remained stuck in draft with the money captured: _is_pos_order_paid() compared the paid amount (15.28) against the rounded total (15.30). Only the part of the order actually settled in cash must be rounded: non-cash payments (card, online, ...) always pay their exact share. - get_amount_unpaid() now returns the exact residual of the order when the rounding only applies to cash payment methods. - _get_rounded_amount() now only rounds the amount not covered by non-cash payments, resolving its old TODO. Cash-only orders and orders where the cash payment settles the rounded remainder are unaffected. opw-6314690 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275472 Forward-Port-Of: odoo/odoo#275305
When an order is validated, the state is set to "paid" and a sync to the server is attempted. If the network dropped during that sync, the order could be permanently lost: the 300ms IndexedDB debounce had not yet fired, so the paid order lived only in memory, and no guard prevented the cashier from accidentally closing or refreshing the tab in that window. opw-6237823 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#27515
Original PR description
When an order is validated, the state is set to "paid" and a sync to the server is attempted. If the network dropped during that sync, the order could be permanently lost: the 300ms IndexedDB debounce had not yet fired, so the paid order lived only in memory, and no guard prevented the cashier from accidentally closing or refreshing the tab in that window. opw-6237823 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275159 Forward-Port-Of: odoo/odoo#267799
Description of the issue/feature this PR addresses: When reversing or replacing an invoice with a C-symbol (tax code requiring approval), the reverse_moves method used an undefined `_l10n_vn_edi_lookup_invoice`, which is an old artifact from 19.2. This commit replaces it by a call to the SInvoiceService `lookup_invoice`, following the same pattern used throughout the rest of the module. Steps to reproduce: 1- Install `l10n_vn_edi_viettel` 2- Use credentials to put in Account settings
Original PR description
Description of the issue/feature this PR addresses: When reversing or replacing an invoice with a C-symbol (tax code requiring approval), the reverse_moves method used an undefined…
Description of the issue/feature this PR addresses: When reversing or replacing an invoice with a C-symbol (tax code requiring approval), the reverse_moves method used an undefined `_l10n_vn_edi_lookup_invoice`, which is an old artifact from 19.2. This commit replaces it by a call to the SInvoiceService `lookup_invoice`, following the same pattern used throughout the rest of the module. Steps to reproduce: 1- Install `l10n_vn_edi_viettel` 2- Use credentials to put in Account settings 3- Fill the TIN under res.company 4- Go to symbols under configuration, fetch and select a symbol with a 'C' in the name 5- Create invoice, use symbol for VN e-invoice. Click Send 6- Create Credit note, click confirm on wizard Current behavior before PR: Validating the Credit Note would raise a Traceback. ``` AttributeError: 'account.move' object has no attribute '_l10n_vn_edi_lookup_invoice' ``` Desired behavior after PR is merged: Validating the Credit Note should process as expected, without errors. opw-6348241 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
With 8f25ed0bf363, the case of a comodel with active_test set was handled differently for the False value. Align to the previous behaviour. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
With 8f25ed0bf363, the case of a comodel with active_test set was handled differently for the False value. Align to the previous behaviour. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When registering a payment for multiple bills from different partners, the `source_currency_id` becomes empty/evaluates differently in the wizard. Because of this, the `currency_conversion_div` `invisible` condition failed, causing the UI to redundantly display the exchange rate even when the currencies were identical (e.g., showing '1 EUR = 1 EUR'). This commit simplifies the invisible condition to only check if the `currency_id` matches the `company_currency_id`, keeping the UI clean. se
Original PR description
When registering a payment for multiple bills from different partners, the `source_currency_id` becomes empty/evaluates differently in the wizard. Because of this, the `currency_conversion_div` `invisible` condition failed, causing the UI to redundantly display the exchange rate even when the currencies were identical (e.g., showing '1 EUR = 1 EUR'). This commit simplifies the invisible condition to only check if the `currency_id` matches the `company_currency_id`, keeping the UI clean. see ent pr- https://github.com/odoo/enterprise/pull/118183 task- 6237870
**Steps to reproduce:** 1. Install Sales and EasyPost modules and enable delivery methods in the Settings. 2. Configure a new delivery method in [Sales -> Configuration -> Delivery Methods], choose provider as EasyPost and set the API keys. 3. Set any margin % on the delivery method. 4. Add the shipping line to a sale order via "Add shipping". **Issue:** Unit Price displays at a 4dp precision while Subtotal correctly displays at a 2dp precision **Why this happens:** `_apply_margins(
Original PR description
**Steps to reproduce:** 1. Install Sales and EasyPost modules and enable delivery methods in the Settings. 2. Configure a new delivery method in [Sales -> Configuration -> Delivery Methods], choose provider as EasyPost and set the API keys. 3. Set any margin % on the delivery method. 4. Add the shipping line to a sale order via "Add shipping". **Issue:** Unit Price displays at a 4dp precision while Subtotal correctly displays at a 2dp precision **Why this happens:** `_apply_margins()` returns a float from margin arithmetic calculation with no currency rounding applied. `rate_shipment()` writes this unrounded value directly to res['price'], which becomes the delivery line's price_unit. opw-6355318 Forward-Port-Of: odoo/odoo#275233
Typing in an HTML field (e.g. a contact's Internal Notes) and validating a URL-like token with Enter or Space can crash the editor with "IndexSizeError: The index is not in the allowed range", leaving the user unable to continue typing. It happens on Safari (not Chromium). The trigger is a URL-like token that the editor auto-converts into a link. The splitText calls in prepareConvertToLink, run during beforeinput, leave Safari's native selection anchored on an empty text node with an out-of-ran
Original PR description
Typing in an HTML field (e.g. a contact's Internal Notes) and validating a URL-like token with Enter or Space can crash the editor with "IndexSizeError: The index is not in the allowed range",…
Typing in an HTML field (e.g. a contact's Internal Notes) and validating
a URL-like token with Enter or Space can crash the editor with
"IndexSizeError: The index is not in the allowed range", leaving the
user unable to continue typing. It happens on Safari (not Chromium).
The trigger is a URL-like token that the editor auto-converts into a
link. The splitText calls in prepareConvertToLink, run during
beforeinput, leave Safari's native selection anchored on an empty text
node with an out-of-range offset. Anything reading the selection
afterwards then works from a broken position: on Enter, splitBlock
reads it and makeActiveSelection ends up throwing in Range.setStart;
on Space, the browser inserts the character in the wrong node and the
selection is corrupted the same way.
```
UncaughtClientError > IndexSizeError
Uncaught Javascript Error > The index is not in the allowed range.
setStart@[native code]
createEditorSelection@.../web.assets_web.min.js:12239:15
getSelectionData@.../web.assets_web.min.js:12242:145
updateActiveSelection@.../web.assets_web.min.js:12230:92
@.../web.assets_web.min.js:12218:873
handler@.../web.assets_web.min.js:14366:121
```
Steps to reproduce:
1. Use Safari (Chromium-based browsers work fine)
2. Open any record with an HTML field (e.g. Contacts -> a contact ->
Internal Notes).
3. Type a URL-like token such as KF.16D2.0204.CG (.CG is a valid TLD,
so the editor auto-links it). Do not paste it.
4. Place the caret at the end of that token and press Enter or Space.
5. IndexSizeError is raised and the editor stops accepting input.
Fix it at the source: re-anchor the selection right after the splits in
prepareConvertToLink, so every consumer sees a valid caret position.
Since moving the selection during beforeinput makes WebKit cancel the
pending text insertion, the Space case now prevents the default and
performs the conversion, the space insertion and the caret placement
itself, in two history steps so that undo still reverts the link
conversion while keeping the typed space.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#275587
Forward-Port-Of: odoo/odoo#270910When multiple invoices were sent to MyInvois in a single batch and at least one document failed validation, the failure branch of _myinvois_submit_documents added self.invoice_ids (all invoices in the batch) to invoice_to_cancel instead of the current record's invoices. Every sibling in the batch was then cancelled locally, even those whose own MyInvois submission had been accepted and moved to in_progress. The account.move ended up in state 'cancel' while its myinvois.document stayed 'valid'
Original PR description
When multiple invoices were sent to MyInvois in a single batch and at least one document failed validation, the failure branch of _myinvois_submit_documents added self.invoice_ids (all invoices in the batch) to invoice_to_cancel instead of the current record's invoices. Every sibling in the batch was then cancelled locally, even those whose own MyInvois submission had been accepted and moved to in_progress. The account.move ended up in state 'cancel' while its myinvois.document stayed 'valid', which violates the intended synchronization between the two records and blocked users from posting the credit note. Scope the cancellation to record.invoice_ids so only the invoice tied to the failing document is cancelled. 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#274727
CertificateAdapter presents a client certificate stored in the database instead of on disk when opening an HTTPS connection (used by the l10n_es EDI modules verifactu, sii and tbai). It loaded that certificate on the connection path of requests 2.31, but requests >= 2.32 changed that path (no longer calls get_connection()), so the step was skipped and the call crashed with: "TypeError: expected str, bytes or os.PathLike object, not certificate" Odoo pins requests 2.31.0 (max depending on Pyth
Original PR description
CertificateAdapter presents a client certificate stored in the database instead of on disk when opening an HTTPS connection (used by the l10n_es EDI modules verifactu, sii and tbai). It loaded that…
CertificateAdapter presents a client certificate stored in the database instead of on disk when opening an HTTPS connection (used by the l10n_es EDI modules verifactu, sii and tbai). It loaded that certificate on the connection path of requests 2.31, but requests >= 2.32 changed that path (no longer calls get_connection()), so the step was skipped and the call crashed with: "TypeError: expected str, bytes or os.PathLike object, not certificate" Odoo pins requests 2.31.0 (max depending on Python version), but online databases can use the version shipped by the OS (2.32.x on recent Ubuntu 26). Set the certificate up when the adapter is created instead of on that connection call. That step runs the same on every requests version, so the fix works both before and after 2.32. Steps to reproduce: - Spanish company with Veri*Factu and a certificate, on a server running requests >= 2.32 (saas-19.3 database for exemple on ubuntu 26) - Post a customer invoice and send it to Veri*Factu. => TypeError Reference: https://github.com/psf/requests/blob/f361ead047be5cb873174218582f7d8b9fcd9f49/HISTORY.md?plain=1#L146 Ticket [link](https://www.odoo.com/odoo/project.task/6366028) opw-6366028 Forward-Port-Of: odoo/odoo#275324
The `retry` button shown after a failed initial fetch did nothing when clicked (it goes through `thread.fetchMoreMessages` which is for load older and load newer). This change routes the click through `fetchMessages` when the failure is an initial one. task-6223358 backport of #272153 Forward-Port-Of: odoo/odoo#276088 Forward-Port-Of: odoo/odoo#275300
Original PR description
The `retry` button shown after a failed initial fetch did nothing when clicked (it goes through `thread.fetchMoreMessages` which is for load older and load newer). This change routes the click through `fetchMessages` when the failure is an initial one. task-6223358 backport of #272153 Forward-Port-Of: odoo/odoo#276088 Forward-Port-Of: odoo/odoo#275300
**Steps to reproduce:** 1. Go to Website > Edit a page. 2. Add multiple Badges side by side. 3. Save the page. 4. Switch the website language, click on Edit/Translate and translate the badges. 5. Save. **Issue:** After saving in translate mode, all badge elements are merged into one. **Why this happens:** During save, `cleanForSave` triggers `mergeAdjacentInlines` on a detached clone of the dirty element. This clone lacks all the css styling, so `getComputedStyle` returns `""` f
Original PR description
**Steps to reproduce:** 1. Go to Website > Edit a page. 2. Add multiple Badges side by side. 3. Save the page. 4. Switch the website language, click on Edit/Translate and translate the badges. 5.…
**Steps to reproduce:** 1. Go to Website > Edit a page. 2. Add multiple Badges side by side. 3. Save the page. 4. Switch the website language, click on Edit/Translate and translate the badges. 5. Save. **Issue:** After saving in translate mode, all badge elements are merged into one. **Why this happens:** During save, `cleanForSave` triggers `mergeAdjacentInlines` on a detached clone of the dirty element. This clone lacks all the css styling, so `getComputedStyle` returns `""` for all padding/margin on detached nodes. Consequently, `areSimilarElements` incorrectly considers sibling `s_badge` spans as identical and merges them. A recent fix (https://github.com/odoo/odoo/commit/91972ec2bbd85f9cfd7a1af794bbb2385a312f30) applied to `BadgeOptionPlugin` registers `s_badge` as unsplittable via `unsplittable_node_predicates`, preventing the merge in normal edit mode. However, translate mode loads a separate plugin, `BadgeTranslationPlugin`, which was added in the commit https://github.com/odoo/odoo/commit/cbb2eb2edfeecbc21a70c1a3cba81ad0a7ac9c75 that lacks the same predicate. opw-6261146 Forward-Port-Of: odoo/odoo#276040 Forward-Port-Of: odoo/odoo#273986
This update resolves an issue where the customer list in the POS module was blank when using the Taiwan localization. The fix updates the Chart of Accounts to ensure all customers are displayed correctly, regardless of the company's localization setting. This ensures accurate sales reporting and customer management within the Taiwan market.
Original PR description
## Current behavior: Currently, when we go into POS using l10n_tw localization, none of the customers appear on the list. ## Expected behavior: All customers should be shown when using Taiwan localization ## Steps to reproduce: 1. Install l10n_tw and POS modules 2. Use the default US company, observe the customer list in POS. All of them are shown 3. Create and switch to a Taiwan company, go back to POS 4. Observe that no customers are shown ## Cause of the issue: Since 19.0, there is a check where if the default payable or receivable account set on the partner is non-trade, those accounts do not appear ## Fix: - Updated AR accounts in COA template file - Added migration script to version 1.1 opw-6298634 Forward-Port-Of: odoo/odoo#274150 Forward-Port-Of: odoo/odoo#270738
28 changes
Resolved issues and error corrections
[FIX] fleet: fix vendor bill vehicle association bug Bug reprod: Go to 19.2 or above 1 - Go to vendor bills. 2 - Create an invoice line add vehicle. 3 - Click to vehicle via the link 4 - You will see fleet model and try to press to some smart buttons, traceback will occur (Odometer, Services...) Bug cause: 1 - When we press to smart buttons for Odometer or Services we are going to return_action_to_open function. 2 - In this function corresponding action's
Original PR description
[FIX] fleet: fix vendor bill vehicle association bug Bug reprod: Go to 19.2 or above 1 - Go to vendor bills. 2 - Create an invoice line add vehicle. 3 - Click to vehicle via the link 4 - You will see…
[FIX] fleet: fix vendor bill vehicle association bug
Bug reprod: Go to 19.2 or above
1 - Go to vendor bills.
2 - Create an invoice line add vehicle.
3 - Click to vehicle via the link
4 - You will see fleet model and try to press to some smart buttons, traceback will occur (Odometer, Services...)
Bug cause:
1 - When we press to smart buttons for Odometer or Services we are going to return_action_to_open function.
2 - In this function corresponding action's xml id is calculated and we are calling that action and that will load some view.
3 - self.env.context is passed directly as a context
4 - In the view_move_form (That include invoice lines, account_id and vehicle_id fields), account_id has a context list_view_ref="account.view_account_list_from_entry"
5 - This context is passed in self.env.context and that's why it tries to load this list_view when we press to odometer,service smart buttons, which shouldn't be the case.
6 - In 19.1 this context is not in self.env.context because >=19.2 m2o_cell_with_extra_m2o_fields is used for account_id and account_id and vehicle_id fields are combined in the single cell.
7 - That's why the context of account_id is passed to the vehicle page as well.
Bug solution:
1 - In the return_action_to_open function I'm dropping the list_view_ref context and we can load the correct related views about odometer or service or other ones.
task - 6385611
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-prWe cannot assume in methods that the active_test is set. Therefore, we should always add active=True in search domains. 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
Original PR description
We cannot assume in methods that the active_test is set. Therefore, we should always add active=True in search domains. 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
`completeActiveField` crashes with "Cannot read properties of undefined (reading 'activeFields')" when the `extra` argument carries a `.related` object but the target `activeField` does not have one. This happens when a many2one field appears twice in the same view tree with different widget configurations — one plain, one with `relatedFields`. The concrete trigger: 1. `stock.picking.batch` has an x2many `picking_ids` whose inline list/kanban view contains `partner_id` as a plain many2one.
Original PR description
`completeActiveField` crashes with "Cannot read properties of undefined (reading 'activeFields')" when the `extra` argument carries a `.related` object but the target `activeField` does not have one.…
`completeActiveField` crashes with "Cannot read properties of undefined (reading 'activeFields')" when the `extra` argument carries a `.related` object but the target `activeField` does not have one.
This happens when a many2one field appears twice in the same view tree with different widget configurations — one plain, one with `relatedFields`. The concrete trigger:
1. `stock.picking.batch` has an x2many `picking_ids` whose inline list/kanban view contains `partner_id` as a plain many2one. `extractFieldsFromArchInfo` creates an activeField for `partner_id` with no `.related` property.
2. `website_sale_stock` inherits the `stock.picking` form view and adds a second `partner_id` node with `widget="pickup_location_many2one"`. That widget declares `relatedFields` (`pickup_location_data`), which `Field.parseFieldNode` converts into a synthetic `views.default`. When `extractFieldsFromArchInfo` processes the inline form view of `picking_ids`, the resulting activeField for `partner_id` gets a `.related` object from those fields.
3. `extractFieldsFromArchInfo` then merges the form view fields into the list view fields via `completeActiveFields`. For `partner_id` the field already exists in the list's activeFields (without `.related`), so `completeActiveField` is called. It checks `if (extra.related)` — true — then immediately accesses `activeField.related.activeFields`, which is undefined → crash.
The sibling function `patchActiveFields` already handles this exact scenario correctly:
activeField.related = activeField.related || { activeFields: {}, fields: {} };
Apply the same defensive initialisation in `completeActiveField`.
Part-of: odoo/odoo#160187
Related: odoo/enterprise#59935
Related: odoo/upgrade#6315
Backport-of odoo/odoo@03c0d6F
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-prIf we are in a case of a salary simulation, we don't care about future public holidays. The unlink done in _delete_future_public_holidays_timesheets was causing some cache invalidations which were messing up with the original offer.
Original PR description
If we are in a case of a salary simulation, we don't care about future public holidays. The unlink done in _delete_future_public_holidays_timesheets was causing some cache invalidations which were messing up with the original offer.
Backport of b667cacb (odoo/odoo#276156), currently on master. The guards of mark as read were only evaluated when requesting it, while the RPC itself goes through a sequential queue. A mark as read requested while another one was still in flight was thus executed later without any re-validation. Under CI load, the bus sync of a previous mark as read can lag enough for a focus-triggered mark as read to legitimately pass its guards on stale state and be queued. When the user then clicked "Ma
Original PR description
Backport of b667cacb (odoo/odoo#276156), currently on master. The guards of mark as read were only evaluated when requesting it, while the RPC itself goes through a sequential queue. A mark as read…
Backport of b667cacb (odoo/odoo#276156), currently on master.
The guards of mark as read were only evaluated when requesting it, while the RPC itself goes through a sequential queue. A mark as read requested while another one was still in flight was thus executed later without any re-validation.
Under CI load, the bus sync of a previous mark as read can lag enough for a focus-triggered mark as read to legitimately pass its guards on stale state and be queued. When the user then clicked "Mark as Unread", the queued mark as read executed right after and reverted that explicit action on the server, and through the resulting bus push, on the client as well. In the meeting view tour, the unread badge of the Chat action then never showed "1":
FAILED: [17/24] Tour discuss.meeting_view_public_tour
Step .o-mail-Meeting [title='Chat']:has(.badge:contains(1))
The state guards are now re-validated when the queued call actually executes: the member must still exist, the messages must not have been read in the meantime, and the channel must not have been marked as unread since the call was requested. The newest persistent message is still captured at request time as it is the payload of the intent: messages that arrived later have not been validated as read by the caller, their own triggers request another mark as read when appropriate.
https://runbot.odoo.com/odoo/error/941491Issue: ---------------------------------------- The units (day, year, etc.) aren't being translated in the Milestones view. Steps to reproduce: ---------------------------------------- - Switch the language to French - Go on an Accrual plan form view - In the milestones view, the units aren't translated Cause: ---------------------------------------- We input the key value of the selections fields `start_type` and `added_value_type`. These values aren't translated. Solution: --
Original PR description
Issue: ---------------------------------------- The units (day, year, etc.) aren't being translated in the Milestones view. Steps to reproduce: ---------------------------------------- - Switch the language to French - Go on an Accrual plan form view - In the milestones view, the units aren't translated Cause: ---------------------------------------- We input the key value of the selections fields `start_type` and `added_value_type`. These values aren't translated. Solution: ---------------------------------------- We create a dictionary with the same keys as the fields and a translated value as values. In the view, we read the values of the dictionary to get the translated units. opw-6367235 Forward-Port-Of: odoo/odoo#275575
Animated GIFs applied with an image shape freeze on Firefox and Safari when the shape's SVG is otherwise static. A dummy `<animateMotion dur="1ms" repeatCount="indefinite"/>` child on the <image> element keeps the animation running so the GIF plays. This hack was introduced in [1] but was missing from most shapes. This commit adds it to every <image> element that lacked it so any shape can be used with a GIF. task-5967171 [1]: https://github.com/odoo/odoo/commit/144e5ef799060da860a5fb1f
Original PR description
Animated GIFs applied with an image shape freeze on Firefox and Safari when the shape's SVG is otherwise static. A dummy `<animateMotion dur="1ms" repeatCount="indefinite"/>` child on the <image> element keeps the animation running so the GIF plays. This hack was introduced in [1] but was missing from most shapes. This commit adds it to every <image> element that lacked it so any shape can be used with a GIF. task-5967171 [1]: https://github.com/odoo/odoo/commit/144e5ef799060da860a5fb1fbe0fd009919afe79 Forward-Port-Of: odoo/odoo#275259
Problem: When posting expenses, if the expense domain is set as mandatory in any of the analytic plans, users can still submit expenses without entering an analytic distribution. This only happens when the expense is auto-approved on submission, which happens when the expense's employee is also the expense's manager or when the employee doesn't have an expense manager. Steps to reproduce: 1. Create an analytic plan with optional default applicability 2. Add an applicability rule with the d
Original PR description
Problem: When posting expenses, if the expense domain is set as mandatory in any of the analytic plans, users can still submit expenses without entering an analytic distribution. This only happens…
Problem: When posting expenses, if the expense domain is set as mandatory in any of the analytic plans, users can still submit expenses without entering an analytic distribution. This only happens when the expense is auto-approved on submission, which happens when the expense's employee is also the expense's manager or when the employee doesn't have an expense manager. Steps to reproduce: 1. Create an analytic plan with optional default applicability 2. Add an applicability rule with the domain set as Expense and set its applicability as mandatory. 3. Create a new expense 4. Set the expense's manager the same as the expense's employee. 5. Don't enter any analytic distribution. 6. Submit the expense 7. Notice how the expense is submitted and auto-approved without any error, even though no analytic distribution is entered and the analytic plan has a mandatory rule for expenses. Cause: The validation of the analytic distribution was only triggered on the approval of the expense, but when the expense is auto-approved on submission, the validation is not triggered at all. Solution: Move the validation of the analytic distribution to the do_approve method, which gets called both when an expense is approved and when it's auto-approved on submission. opw-6187340 Forward-Port-Of: odoo/odoo#270268
**Steps to reproduce:** - Install Contacts app - Open any record - Go to the chatter - Create an activity with a description - Duplicate the tab - Go back to the initial tab - Description doesn't appear anymore - Refreshing shows it but will remove it from the other tab **Issue:** Behavior comes from the broadcasting of activity changes between tabs `new browser.BroadcastChannel("mail.activity.channel");`. Computed fields are not recomputed on the receiver side after value inserti
Original PR description
**Steps to reproduce:** - Install Contacts app - Open any record - Go to the chatter - Create an activity with a description - Duplicate the tab - Go back to the initial tab - Description doesn't…
**Steps to reproduce:**
- Install Contacts app
- Open any record
- Go to the chatter
- Create an activity with a description
- Duplicate the tab
- Go back to the initial tab
- Description doesn't appear anymore
- Refreshing shows it but will remove it from the other tab
**Issue:**
Behavior comes from the broadcasting of activity changes between tabs `new browser.BroadcastChannel("mail.activity.channel");`.
Computed fields are not recomputed on the receiver side after value insertion in `_onActivityBroadcastChannelMessage` (also related components are not (re)mounted, e.g. when a new activity is created the other tab doesn't show it without a refresh).
This means that `isNoteEmpty` keeps its default value `true` (added by `this.toData()`) and the `note` stays hidden here [1]:
```xml
<div t-if="!props.activity.isNoteEmpty" class="o-mail-Activity-note text-break" t-out="props.activity.note"/>
```
**Fix:**
Remove computed fields in activity `serialize` before broadcasting them to ensure they don't force the default value.
(note installing `calendar` in 19.3+ removes this issue due to [2] which overrides the condition on `isNoteEmpty`)
[1] https://github.com/odoo/odoo/commit/eb9f0658c3da1a9fef69f1cc1117c2d44f9d61b1
[2] https://github.com/odoo/odoo/commit/44e2c2c5ca07849fd8964140f3ca61122c47f0c6
opw-6247412
Forward-Port-Of: odoo/odoo#276032
Forward-Port-Of: odoo/odoo#275528Modified `SampleServer._mockWebReadGroup` to intercept `groupby_read_specification`. It now dynamically fetches the requested related fields using `_mockWebSearchReadUnity` and safely injects them into the `__values` payload for each mock group, perfectly mirroring the standard ORM behavior. Task: [6307582](https://www.odoo.com/odoo/project/133/tasks/6307582) Forward-Port-Of: odoo/odoo#272135
Original PR description
Modified `SampleServer._mockWebReadGroup` to intercept `groupby_read_specification`. It now dynamically fetches the requested related fields using `_mockWebSearchReadUnity` and safely injects them into the `__values` payload for each mock group, perfectly mirroring the standard ORM behavior. Task: [6307582](https://www.odoo.com/odoo/project/133/tasks/6307582) Forward-Port-Of: odoo/odoo#272135
`_l10n_tr_nilvera_add_pdf_to_invoice` writes the response from `client.request('GET', '.../pdf')` directly into `ir.attachment.raw`. The Nilvera client sets `Accept: application/json` on the session and calls `response.json()` by default, so the returned value is a Python `str` holding the base64-encoded PDF body, not raw binary bytes. The previous code wrote to the base64-aware `datas` field, which auto-decoded its input. An earlier fix switched to `raw` to work around a `binascii.Error` fro
Original PR description
`_l10n_tr_nilvera_add_pdf_to_invoice` writes the response from `client.request('GET', '.../pdf')` directly into `ir.attachment.raw`. The Nilvera client sets `Accept: application/json` on the session…
`_l10n_tr_nilvera_add_pdf_to_invoice` writes the response from `client.request('GET', '.../pdf')` directly into `ir.attachment.raw`. The Nilvera client sets `Accept: application/json` on the session and calls `response.json()` by default, so the returned value is a Python `str` holding the base64-encoded PDF body, not raw binary bytes.
The previous code wrote to the base64-aware `datas` field, which auto-decoded its input. An earlier fix switched to `raw` to work around a `binascii.Error` from Python 3.14's stricter base64 validation in the `datas` auto-decode path. That switch silently changed what ends up on disk (`datas` decodes its input, `raw` does not)
Storing that string in the binary `raw` field encodes it as UTF-8, so the file on disk ends up as the literal ASCII of the base64 text. The attachment is served as `application/pdf` but the browser receives base64 ASCII and cannot preview or download the PDF.
Call `b64decode(response)` before storing so the attachment contains the actual PDF bytes.
OPW-6302803
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#274501
Forward-Port-Of: odoo/odoo#270759This fix is the same as this one https://github.com/odoo/odoo/pull/271577 but for the backend part of the code. After the fix, if you followed the same steps to reproduce and tried to close the session you would have an unbalanced entry for the session. Steps to reproduce: ------------------- * Create a 21% tax not included in price * Create a product with a price of 76.01 and the tax created above * Create a loyalty program with a 10% discount * Create a POS order with the product ab
Original PR description
This fix is the same as this one https://github.com/odoo/odoo/pull/271577 but for the backend part of the code. After the fix, if you followed the same steps to reproduce and tried to close the session you would have an unbalanced entry for the session. Steps to reproduce: ------------------- * Create a 21% tax not included in price * Create a product with a price of 76.01 and the tax created above * Create a loyalty program with a 10% discount * Create a POS order with the product above and apply the loyalty program * Validate the order and generate the invoice * Close the session > Observation: You need to force close the session because of unbalanced entry Why the fix: ------------ Apply the same fix for backend code. opw-6052112 Forward-Port-Of: odoo/odoo#276100 Forward-Port-Of: odoo/odoo#274985
**Steps to reproduce:** - Create a product A, tracked by lots - Create a kit product, include a component A - Change the UoM to 0.5 - Go to the PoS, order this kit product - Also order the component A, with a quantity of 2 - Pay for it, ask for an invoice - Go to the created picking - The Demand column is correctly computed and is 0.5 - The Quantity column is wrong and is 2 **Why the fix:** When getting the data from https://github.com/odoo/odoo/blob/e0d84c7fbb270d0d1f82572daefa
Original PR description
**Steps to reproduce:** - Create a product A, tracked by lots - Create a kit product, include a component A - Change the UoM to 0.5 - Go to the PoS, order this kit product - Also order the component…
**Steps to reproduce:** - Create a product A, tracked by lots - Create a kit product, include a component A - Change the UoM to 0.5 - Go to the PoS, order this kit product - Also order the component A, with a quantity of 2 - Pay for it, ask for an invoice - Go to the created picking - The Demand column is correctly computed and is 0.5 - The Quantity column is wrong and is 2 **Why the fix:** When getting the data from https://github.com/odoo/odoo/blob/e0d84c7fbb270d0d1f82572daefa96c2978d3785/addons/point_of_sale/models/stock_picking.py#L283 we always get the component's line, as the move's product is the component, even if it used to be the kit product's move. This is because when exploding a kit's moves, it gets the kit's component as a product instead of keeping the kit product. This was introducing a weird behavior because we took the quantity from the component line, and not from the kit line, meaning the kit would always have the same quantity as the component. We now check if the move is actually a kit product's move, and if it is we adapt the qty to correct one by fetching the correct line's qty, and adapting it with the correct UoM. Changing the line in itself would not work, as the kit itself is not tracked by lots, so we would not enter https://github.com/odoo/odoo/blob/e0d84c7fbb270d0d1f82572daefa96c2978d3785/addons/point_of_sale/models/stock_picking.py#L284 and the move line would not be correctly created. opw-6153000 Forward-Port-Of: odoo/odoo#276098 Forward-Port-Of: odoo/odoo#262551
**Steps to reproduce:** 1. Install Sales and EasyPost modules and enable delivery methods in the Settings. 2. Configure a new delivery method in [Sales -> Configuration -> Delivery Methods], choose provider as EasyPost and set the API keys. 3. Set any margin % on the delivery method. 4. Add the shipping line to a sale order via "Add shipping". **Issue:** Unit Price displays at a 4dp precision while Subtotal correctly displays at a 2dp precision **Why this happens:** `_apply_margins(
Original PR description
**Steps to reproduce:** 1. Install Sales and EasyPost modules and enable delivery methods in the Settings. 2. Configure a new delivery method in [Sales -> Configuration -> Delivery Methods], choose provider as EasyPost and set the API keys. 3. Set any margin % on the delivery method. 4. Add the shipping line to a sale order via "Add shipping". **Issue:** Unit Price displays at a 4dp precision while Subtotal correctly displays at a 2dp precision **Why this happens:** `_apply_margins()` returns a float from margin arithmetic calculation with no currency rounding applied. `rate_shipment()` writes this unrounded value directly to res['price'], which becomes the delivery line's price_unit. opw-6355318 Forward-Port-Of: odoo/odoo#275233
**Steps to reproduce:** - Enable 2FA - Change user language - Log in in another private window / device - Check the notification email of a login with another device - Email body/subject are not properly adapted to user language **Issue:** View manual rendering doesn't pass the user language. **Fix:** Add it to the context before `_render_template` and subject translation (reapply similar fix [1]). [1] https://github.com/odoo/odoo/commit/4d8d1736ca03a3d6b4e86cbc7463a79a284d1f3c
Original PR description
**Steps to reproduce:** - Enable 2FA - Change user language - Log in in another private window / device - Check the notification email of a login with another device - Email body/subject are not properly adapted to user language **Issue:** View manual rendering doesn't pass the user language. **Fix:** Add it to the context before `_render_template` and subject translation (reapply similar fix [1]). [1] https://github.com/odoo/odoo/commit/4d8d1736ca03a3d6b4e86cbc7463a79a284d1f3c opw-6042550 Forward-Port-Of: odoo/odoo#274333 Forward-Port-Of: odoo/odoo#261468
**Steps to reproduce:** 1. Go to Website > Edit a page. 2. Add multiple Badges side by side. 3. Save the page. 4. Switch the website language, click on Edit/Translate and translate the badges. 5. Save. **Issue:** After saving in translate mode, all badge elements are merged into one. **Why this happens:** During save, `cleanForSave` triggers `mergeAdjacentInlines` on a detached clone of the dirty element. This clone lacks all the css styling, so `getComputedStyle` returns `""` f
Original PR description
**Steps to reproduce:** 1. Go to Website > Edit a page. 2. Add multiple Badges side by side. 3. Save the page. 4. Switch the website language, click on Edit/Translate and translate the badges. 5.…
**Steps to reproduce:** 1. Go to Website > Edit a page. 2. Add multiple Badges side by side. 3. Save the page. 4. Switch the website language, click on Edit/Translate and translate the badges. 5. Save. **Issue:** After saving in translate mode, all badge elements are merged into one. **Why this happens:** During save, `cleanForSave` triggers `mergeAdjacentInlines` on a detached clone of the dirty element. This clone lacks all the css styling, so `getComputedStyle` returns `""` for all padding/margin on detached nodes. Consequently, `areSimilarElements` incorrectly considers sibling `s_badge` spans as identical and merges them. A recent fix (https://github.com/odoo/odoo/commit/91972ec2bbd85f9cfd7a1af794bbb2385a312f30) applied to `BadgeOptionPlugin` registers `s_badge` as unsplittable via `unsplittable_node_predicates`, preventing the merge in normal edit mode. However, translate mode loads a separate plugin, `BadgeTranslationPlugin`, which was added in the commit https://github.com/odoo/odoo/commit/cbb2eb2edfeecbc21a70c1a3cba81ad0a7ac9c75 that lacks the same predicate. opw-6261146 Forward-Port-Of: odoo/odoo#276040 Forward-Port-Of: odoo/odoo#273986
webhooks don't work because of it Forward-Port-Of: odoo/odoo#275845
Original PR description
webhooks don't work because of it Forward-Port-Of: odoo/odoo#275845
When multiple invoices were sent to MyInvois in a single batch and at least one document failed validation, the failure branch of _myinvois_submit_documents added self.invoice_ids (all invoices in the batch) to invoice_to_cancel instead of the current record's invoices. Every sibling in the batch was then cancelled locally, even those whose own MyInvois submission had been accepted and moved to in_progress. The account.move ended up in state 'cancel' while its myinvois.document stayed 'valid'
Original PR description
When multiple invoices were sent to MyInvois in a single batch and at least one document failed validation, the failure branch of _myinvois_submit_documents added self.invoice_ids (all invoices in the batch) to invoice_to_cancel instead of the current record's invoices. Every sibling in the batch was then cancelled locally, even those whose own MyInvois submission had been accepted and moved to in_progress. The account.move ended up in state 'cancel' while its myinvois.document stayed 'valid', which violates the intended synchronization between the two records and blocked users from posting the credit note. Scope the cancellation to record.invoice_ids so only the invoice tied to the failing document is cancelled. 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#274727
The "bus subscription is refreshed when channel is joined/left" tests were flaky: - `mockDate` needs 2 digit date/time parts. The format used here didn't always produce them, so it silently fell back to a past date. That was enough to make the "left" test pass even without actually leaving. - The "left" test never actually left the channel: a confirm dialog blocked it. - The "join" test never actually joined the channel. - The tests expected `runAllTimers` to guarantee that every initial sub
Original PR description
The "bus subscription is refreshed when channel is joined/left" tests were flaky: - `mockDate` needs 2 digit date/time parts. The format used here didn't always produce them, so it silently fell back…
The "bus subscription is refreshed when channel is joined/left" tests were flaky: - `mockDate` needs 2 digit date/time parts. The format used here didn't always produce them, so it silently fell back to a past date. That was enough to make the "left" test pass even without actually leaving. - The "left" test never actually left the channel: a confirm dialog blocked it. - The "join" test never actually joined the channel. - The tests expected `runAllTimers` to guarantee that every initial subscription was done, but thats not the case, making the number of `subscribe` calls non-deterministic (e.g. flushing calls to `bus_service.add` but not ensuring the worker received them through its message port, and triggered the debounced `updateChannels`). Fixing the tests exposed a real bug: `memberBusSubscription` is meant to trigger a refresh whenever membership changes relative to the bus start time. As a boolean, "member, no refresh needed" and "not a member" are indistinguishable (both `false`), so leaving a channel joined before the bus started never changed the value and never triggered a refresh. This PR add a third state so membership and non-membership stay distinguishable regardless of when the bus started. runbot-941462 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#276066 Forward-Port-Of: odoo/odoo#275938
# How to reproduce - In Settings, enable Variants & Product Reference Price - Create a published Product with a Sales Price - Add 2 variants to the Product - In the product's variant list, select the first one & set Base Unit Count to 0, - Set the second variant's Base Unit Count to a value > 0 - Go to the Product's page - Select the second variant # The issue The Reference Price is not displayed for the second variant, even though it should since it has a Base Unit Count > 0. Refresh
Original PR description
# How to reproduce - In Settings, enable Variants & Product Reference Price - Create a published Product with a Sales Price - Add 2 variants to the Product - In the product's variant list, select the…
# How to reproduce
- In Settings, enable Variants & Product Reference Price
- Create a published Product with a Sales Price
- Add 2 variants to the Product
- In the product's variant list, select the first one & set Base Unit Count to 0,
- Set the second variant's Base Unit Count to a value > 0
- Go to the Product's page
- Select the second variant
# The issue
The Reference Price is not displayed for the second variant, even though it should since it has a Base Unit Count > 0. Refreshing the page while being on the second variant will prevent the bug from happening.
# Cause
When loading the product's info, we call `_onChangeCombination`. This method is responsible for, among other things, updating the reference price and hiding it if Base Unit Count = 0 :
https://github.com/odoo/odoo/blob/68f258e99f42693131a5309b3606c3b95f93d824/addons/website_sale/static/src/js/variant_mixin.js#L277-L289
To do that, it will search for an html element with the `.o_base_unit_price` css class. If it does not find it, the reference price will not be updated. The issue is that this element is behind a condition in the template :
https://github.com/odoo/odoo/blob/68f258e99f42693131a5309b3606c3b95f93d824/addons/website_sale/views/templates.xml#L2083
When the first time the template is loaded, if
`combination_info.get('base_unit_price')` is False, then the Reference Price will never be added to the view and will never be found by `_onChangeCombination`.
Since our first variant has Base Unit Count = 0, then `base_unit_price` will equal 0, so `combination_info.get('base_unit_price')` will be evaluated to false.
opw-6367289
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#275699
Forward-Port-Of: odoo/odoo#274722Klipy requires attribution with "Search KLIPY" as the default placeholder [1]. This commit complies these guidelines. [1]: https://docs.klipy.com/attribution Forward-Port-Of: odoo/odoo#275995 Forward-Port-Of: odoo/odoo#275677
Original PR description
Klipy requires attribution with "Search KLIPY" as the default placeholder [1]. This commit complies these guidelines. [1]: https://docs.klipy.com/attribution Forward-Port-Of: odoo/odoo#275995 Forward-Port-Of: odoo/odoo#275677
**Steps to reproduce:** - Make a product with a category - In the category, make the inventory valuation to automated - Set the income and expense account - Set a cost for the product - Make a fiscal position and set it as default for the PoS - In the Account Mapping tab, map the income and expense to two other accounts - Go to the PoS - Make a sale for that product, without invoice - Close the session and in the backend check the session - Check the journal entries - The income acc
Original PR description
**Steps to reproduce:** - Make a product with a category - In the category, make the inventory valuation to automated - Set the income and expense account - Set a cost for the product - Make a fiscal…
**Steps to reproduce:** - Make a product with a category - In the category, make the inventory valuation to automated - Set the income and expense account - Set a cost for the product - Make a fiscal position and set it as default for the PoS - In the Account Mapping tab, map the income and expense to two other accounts - Go to the PoS - Make a sale for that product, without invoice - Close the session and in the backend check the session - Check the journal entries - The income account has been mapped to the fiscal position's - The outcome account stayed the same as in the category's **Why the fix:** When we invoice an order, the income and expense accounts are immediately updated, in a different place than if it has not been invoiced. At the session's closure, we update the accounts for every order that hasn't been invoiced. In this flow, the account mapping defined on the fiscal position was not applied, so we took the one defined on the product's category. The income account was already mapped as we need to do it earlier than the session closure, so it had already been set as the right one before our flow. For the expense account, we only need it at this specific time, so we can map it as the session's closure. We now map the account depending on the fiscal position if we are able to find one, otherwise, we use the category's default as we did before. opw-6171677 Forward-Port-Of: odoo/odoo#275114 Forward-Port-Of: odoo/odoo#266700
This update fixes an issue where online payments with cash rounding weren't calculating correctly. Now, when an order includes cash payments and cash rounding is enabled, the system accurately requests the correct online payment amount and properly marks the order as paid. This ensures accurate financial reporting and a smoother checkout experience for customers.
Original PR description
…nding When cash rounding is enabled with "Only for cash payment methods", an order partially paid in cash and completed with an online payment could neither request the correct online amount nor be…
…nding When cash rounding is enabled with "Only for cash payment methods", an order partially paid in cash and completed with an online payment could neither request the correct online amount nor be marked as paid. Steps to reproduce: - Enable cash rounding (e.g. 0.05, HALF-UP) with "Only for cash payment methods" - Create an order with a total of 15.28 - Add a cash payment of 10.00, then an online payment for the remainder The frontend requests 5.28 for the online payment, but as soon as the order contained a cash payment the server rounded the whole order total: get_and_set_online_payments_data() returned an unpaid amount of 5.30 (15.30 - 10.00), so the validation failed with "Invalid online payments". Even once the online payment of 5.28 was processed, the order remained stuck in draft with the money captured: _is_pos_order_paid() compared the paid amount (15.28) against the rounded total (15.30). Only the part of the order actually settled in cash must be rounded: non-cash payments (card, online, ...) always pay their exact share. - get_amount_unpaid() now returns the exact residual of the order when the rounding only applies to cash payment methods. - _get_rounded_amount() now only rounds the amount not covered by non-cash payments, resolving its old TODO. Cash-only orders and orders where the cash payment settles the rounded remainder are unaffected. opw-6314690 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275305
This update resolves a crash in Point of Sale (PoS) when settling sales orders after archiving product attributes. Previously, archiving a product attribute alongside a sale order could cause an error. This change ensures PoS settlement remains stable and reliable, even when product attributes are archived.
Original PR description
When a product attribute line is used in a confirmed sale order, Odoo archives it (active=False) instead of deleting it when removed from the product template. If the corresponding product.attribute record is also archived, settling that sale order in PoS crashes with: TypeError: Cannot read properties of undefined (reading 'create_variant') opw-6315766 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274484 Forward-Port-Of: odoo/odoo#271778
In [1], the need to build a registry for outgoing messages was removed, but `acquire_cursor` wasn't adapted. As a result, we might end up building more registries than needed, blocking the gevent server CPU. This commit fixes this issue. [1]: https://github.com/odoo/odoo/pull/235746 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
Original PR description
In [1], the need to build a registry for outgoing messages was removed, but `acquire_cursor` wasn't adapted. As a result, we might end up building more registries than needed, blocking the gevent server CPU. This commit fixes this issue. [1]: https://github.com/odoo/odoo/pull/235746 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
This update fixes a critical issue where paid orders could be lost if a network connection was interrupted during the order validation process. Previously, the system relied on a temporary memory storage, leaving no safeguards against accidental order closure. Now, the system ensures order data is reliably synchronized to the server, preventing data loss.
Original PR description
When an order is validated, the state is set to "paid" and a sync to the server is attempted. If the network dropped during that sync, the order could be permanently lost: the 300ms IndexedDB debounce had not yet fired, so the paid order lived only in memory, and no guard prevented the cashier from accidentally closing or refreshing the tab in that window. opw-6237823 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267799
This update resolves an issue where the 'Load More' button on the Odoo platform was consistently hidden. The fix ensures the button's visibility is correctly controlled based on the current state of the application, improving the user experience. This change was triggered by a recent update to the user interface.
Original PR description
Since #198829, a `t-att-class` has been added to the `loadOlder` template that relies on `mountedAndLoaded` of thread state to control the visibility of the `Load More` button. But it doesn't read the value from the state properly. As a result, the button is always transparent. This change fixes this by reading the value from the state. Forward-Port-Of: odoo/odoo#275828 Forward-Port-Of: odoo/odoo#275253
This update fixes an issue where the 'retry' button after a failed initial message load wouldn't work. Now, clicking the retry button correctly initiates a fresh attempt to fetch messages, ensuring users can reliably access their conversations. This improves the overall user experience and prevents data loss.
Original PR description
The `retry` button shown after a failed initial fetch did nothing when clicked (it goes through `thread.fetchMoreMessages` which is for load older and load newer). This change routes the click through `fetchMessages` when the failure is an initial one. task-6223358 backport of #272153 Forward-Port-Of: odoo/odoo#275300
12 changes
Resolved issues and error corrections
Remove the generic active 296 and 297 impairment accounts and make the existing French PCG 296/297 subaccounts active instead, because what we use in the balance sheet formulas are the subaccounts, and it's better to remove the generic ones to not give users the ability to post on these generic accounts, also adapt their translations to be aligned with PCG wording. Move pcg_2962 from the companies chart file to the base French chart file, as 2962 is a general PCG account and not a compa
Original PR description
Remove the generic active 296 and 297 impairment accounts and make the existing French PCG 296/297 subaccounts active instead, because what we use in the balance sheet formulas are the subaccounts, and it's better to remove the generic ones to not give users the ability to post on these generic accounts, also adapt their translations to be aligned with PCG wording. Move pcg_2962 from the companies chart file to the base French chart file, as 2962 is a general PCG account and not a company related one. Note: this is how things were already in 19.0 and this is how they should be, the changes happened by mistake as an unwanted side effect of commit 4f6068a6c88bf0530c19254df403e1194823b415 task-[6226138](https://www.odoo.com/odoo/project/967/tasks/6226138) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
v19 WIoT Boxes will be listening on localhost when updating to v19.1+, we need to ensure they use `http_interface = 0.0.0.0` after the update.
Original PR description
v19 WIoT Boxes will be listening on localhost when updating to v19.1+, we need to ensure they use `http_interface = 0.0.0.0` after the update.
Modified `SampleServer._mockWebReadGroup` to intercept `groupby_read_specification`. It now dynamically fetches the requested related fields using `_mockWebSearchReadUnity` and safely injects them into the `__values` payload for each mock group, perfectly mirroring the standard ORM behavior. Task: [6307582](https://www.odoo.com/odoo/project/133/tasks/6307582) Forward-Port-Of: odoo/odoo#272135
Original PR description
Modified `SampleServer._mockWebReadGroup` to intercept `groupby_read_specification`. It now dynamically fetches the requested related fields using `_mockWebSearchReadUnity` and safely injects them into the `__values` payload for each mock group, perfectly mirroring the standard ORM behavior. Task: [6307582](https://www.odoo.com/odoo/project/133/tasks/6307582) Forward-Port-Of: odoo/odoo#272135
**Steps to reproduce:** 1. Install Sales and EasyPost modules and enable delivery methods in the Settings. 2. Configure a new delivery method in [Sales -> Configuration -> Delivery Methods], choose provider as EasyPost and set the API keys. 3. Set any margin % on the delivery method. 4. Add the shipping line to a sale order via "Add shipping". **Issue:** Unit Price displays at a 4dp precision while Subtotal correctly displays at a 2dp precision **Why this happens:** `_apply_margins(
Original PR description
**Steps to reproduce:** 1. Install Sales and EasyPost modules and enable delivery methods in the Settings. 2. Configure a new delivery method in [Sales -> Configuration -> Delivery Methods], choose provider as EasyPost and set the API keys. 3. Set any margin % on the delivery method. 4. Add the shipping line to a sale order via "Add shipping". **Issue:** Unit Price displays at a 4dp precision while Subtotal correctly displays at a 2dp precision **Why this happens:** `_apply_margins()` returns a float from margin arithmetic calculation with no currency rounding applied. `rate_shipment()` writes this unrounded value directly to res['price'], which becomes the delivery line's price_unit. opw-6355318 Forward-Port-Of: odoo/odoo#275233
**Steps to reproduce:** - create storable avco product - set the cost to 10 - set an onhand quantity of 100 in WH/stock - create another warehouse (if you don't already have another one) - create an internal transfer from WH/Stock to WH2 - open the 'stock' view - click on inventory at date - confirm **Current behavior:** the total value is 11.000 **Expected behavior:** total value should be 10.000 **Cause of the issue:** To compute the total_value of the product, _co
Original PR description
**Steps to reproduce:** - create storable avco product - set the cost to 10 - set an onhand quantity of 100 in WH/stock - create another warehouse (if you don't already have another one) - create an…
**Steps to reproduce:** - create storable avco product - set the cost to 10 - set an onhand quantity of 100 in WH/stock - create another warehouse (if you don't already have another one) - create an internal transfer from WH/Stock to WH2 - open the 'stock' view - click on inventory at date - confirm **Current behavior:** the total value is 11.000 **Expected behavior:** total value should be 10.000 **Cause of the issue:** To compute the total_value of the product, _compute_value calls _run_average_batch https://github.com/odoo/odoo/blob/68f258e99f42693131a5309b3606c3b95f93d824/addons/stock_account/models/product.py#L260 Inside run_average_batch we need the qty_available at the time of last manual value (which is when we set the cost to 10 manually) in order to value all this quantity at the value of the manual value. https://github.com/odoo/odoo/blob/68f258e99f42693131a5309b3606c3b95f93d824/addons/stock_account/models/product.py#L435 This qty should be 0 cause we had no onhand quantity when we set the cost to 10. But it's actually going to be 10, here is why : Inside _compute_quantities_dict, because we're asking for a quantity in the past, the computation is current quantity - quantities that went in between the date in the past and now + quantities that went out between the date in the past and now. https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/stock/models/product.py#L255 So we should have : 100 - 100 (moves_in_res_past) + 0 (moves_out_res_past) = 0 because we have 100 now and between the date we're asking for (the time of the manual value) and now there is one move in (when we set a quantity of 100) and no move out. But moves_out_res_past will actually be 10 for our product instead of 0. That's because in the read_group, our internal move will be considered as a move out and be taken into account https://github.com/odoo/odoo/blob/60cf607d7148ebe389cc8513aa3b82e156cd4400/addons/stock/models/product.py#L233-L234 That's because: When we called _run_average_batch from _compute_value, we called it on 'products_to_value', which is based on 'products', which was computed calling with_valuation_context() https://github.com/odoo/odoo/blob/60cf607d7148ebe389cc8513aa3b82e156cd4400/addons/stock_account/models/product.py#L206 which passes the valued internal location in the context https://github.com/odoo/odoo/blob/60cf607d7148ebe389cc8513aa3b82e156cd4400/addons/stock_account/models/product.py#L366-L370 As wh2 is not internal (it's a view) it's not included in the locations from the context. strict is also set to True Therefore at the beginning of compute_quantities_dict, when we call _get_domain_location to compute domain_move_out_loc (on which domain_move_out_done will be based), https://github.com/odoo/odoo/blob/60cf607d7148ebe389cc8513aa3b82e156cd4400/addons/stock/models/product.py#L165 inside _get_domain_location, because a location is given in the context that's the one we're going to use. https://github.com/odoo/odoo/blob/60cf607d7148ebe389cc8513aa3b82e156cd4400/addons/stock/models/product.py#L365 and because strict is in the context, dest_location_domain_out will be "location_dest_id not in [the list of valued location which does not include wh2]". https://github.com/odoo/odoo/blob/7e95d32d669a7ee7c50b5e665697cb577be0af93/addons/stock/models/product.py#L402-L405 And back in compute_quantities_dict(), domain_move_out_loc will be "location_id in [the list of valued location] and location_dest_id not in [the list of valued location]". Our internal move will therefore be considered as an out move and taken into account in the computation mentioned above. Which explains why quantity will be 10 inside run_average_batch and why the computation of total_value is wrong **fix:** in 19.0 the fix is in the xml to take less risk with regards to stable policy, however starting from 19.1 the fix will be in python opw-6321636 Forward-Port-Of: odoo/odoo#273388
**Steps to reproduce:** 1. Go to Website > Edit a page. 2. Add multiple Badges side by side. 3. Save the page. 4. Switch the website language, click on Edit/Translate and translate the badges. 5. Save. **Issue:** After saving in translate mode, all badge elements are merged into one. **Why this happens:** During save, `cleanForSave` triggers `mergeAdjacentInlines` on a detached clone of the dirty element. This clone lacks all the css styling, so `getComputedStyle` returns `""` f
Original PR description
**Steps to reproduce:** 1. Go to Website > Edit a page. 2. Add multiple Badges side by side. 3. Save the page. 4. Switch the website language, click on Edit/Translate and translate the badges. 5.…
**Steps to reproduce:** 1. Go to Website > Edit a page. 2. Add multiple Badges side by side. 3. Save the page. 4. Switch the website language, click on Edit/Translate and translate the badges. 5. Save. **Issue:** After saving in translate mode, all badge elements are merged into one. **Why this happens:** During save, `cleanForSave` triggers `mergeAdjacentInlines` on a detached clone of the dirty element. This clone lacks all the css styling, so `getComputedStyle` returns `""` for all padding/margin on detached nodes. Consequently, `areSimilarElements` incorrectly considers sibling `s_badge` spans as identical and merges them. A recent fix (https://github.com/odoo/odoo/commit/91972ec2bbd85f9cfd7a1af794bbb2385a312f30) applied to `BadgeOptionPlugin` registers `s_badge` as unsplittable via `unsplittable_node_predicates`, preventing the merge in normal edit mode. However, translate mode loads a separate plugin, `BadgeTranslationPlugin`, which was added in the commit https://github.com/odoo/odoo/commit/cbb2eb2edfeecbc21a70c1a3cba81ad0a7ac9c75 that lacks the same predicate. opw-6261146 Forward-Port-Of: odoo/odoo#276040 Forward-Port-Of: odoo/odoo#273986
The "Opening thread with needaction messages should mark all messages of thread as read" test opens a channel that holds an inbox (needaction) message and asserts mark_all_as_read is sent. Two flows can mark that message as read: the channel messages fetch, through set_message_done, and mark_all_as_read, sent by markAsRead when the channel gets focused on open. When the self member's new_message_separator is 0, opening the channel fetches its messages around 0, and that fetch marks the messag
Original PR description
The "Opening thread with needaction messages should mark all messages of thread as read" test opens a channel that holds an inbox (needaction) message and asserts mark_all_as_read is sent. Two flows can mark that message as read: the channel messages fetch, through set_message_done, and mark_all_as_read, sent by markAsRead when the channel gets focused on open. When the self member's new_message_separator is 0, opening the channel fetches its messages around 0, and that fetch marks the message as read and drops the needaction counter to 0 before markAsRead runs. mark_all_as_read is then skipped and the step assertion receives nothing. Give the member a non-zero separator (the pre-existing message is already read) so opening the channel no longer fetches around 0, leaving mark_all_as_read as the flow that marks the inbox message read. https://runbot.odoo.com/odoo/error/243651 Forward-Port-Of: odoo/odoo#276181
## Steps to reproduce: - Install sale_timesheet - Create a timesheet with a Sale order item linked to it - Change the sale order item on that timesheet - Change the project linked to the timesheet to a non-billable project - Notice the sale order item still linked to the timesheet ## Cause: When computing the so_line we filter out the records that has is_so_line_edited as true, so when changing the SOL before changing the project we don't reset so_line field when setting a non-bill
Original PR description
## Steps to reproduce: - Install sale_timesheet - Create a timesheet with a Sale order item linked to it - Change the sale order item on that timesheet - Change the project linked to the timesheet to a non-billable project - Notice the sale order item still linked to the timesheet ## Cause: When computing the so_line we filter out the records that has is_so_line_edited as true, so when changing the SOL before changing the project we don't reset so_line field when setting a non-billable project. ## Fix: We reset the is_so_line_edited field to false when changing the project to a non-billable one. opw-6311549 Forward-Port-Of: odoo/odoo#275919
Klipy requires attribution with "Search KLIPY" as the default placeholder [1]. This commit complies these guidelines. [1]: https://docs.klipy.com/attribution Forward-Port-Of: odoo/odoo#275995 Forward-Port-Of: odoo/odoo#275677
Original PR description
Klipy requires attribution with "Search KLIPY" as the default placeholder [1]. This commit complies these guidelines. [1]: https://docs.klipy.com/attribution Forward-Port-Of: odoo/odoo#275995 Forward-Port-Of: odoo/odoo#275677
When multiple invoices were sent to MyInvois in a single batch and at least one document failed validation, the failure branch of _myinvois_submit_documents added self.invoice_ids (all invoices in the batch) to invoice_to_cancel instead of the current record's invoices. Every sibling in the batch was then cancelled locally, even those whose own MyInvois submission had been accepted and moved to in_progress. The account.move ended up in state 'cancel' while its myinvois.document stayed 'valid'
Original PR description
When multiple invoices were sent to MyInvois in a single batch and at least one document failed validation, the failure branch of _myinvois_submit_documents added self.invoice_ids (all invoices in the batch) to invoice_to_cancel instead of the current record's invoices. Every sibling in the batch was then cancelled locally, even those whose own MyInvois submission had been accepted and moved to in_progress. The account.move ended up in state 'cancel' while its myinvois.document stayed 'valid', which violates the intended synchronization between the two records and blocked users from posting the credit note. Scope the cancellation to record.invoice_ids so only the invoice tied to the failing document is cancelled. 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#274727
When creating an event in Odoo and syncing it to Outlook, the event appeared in the correct slot on Outlook's calendar grid, but its detail panel showed start/end times labelled as UTC, causing a mismatch between the user's wall-clock time and what was displayed in Microsoft Outlook. The sync now sends the event in the organizer's local timezone with a matching timezone label, so Outlook displays the same wall-clock time and timezone that was entered. task-6167258 Description of the issue/
Original PR description
When creating an event in Odoo and syncing it to Outlook, the event appeared in the correct slot on Outlook's calendar grid, but its detail panel showed start/end times labelled as UTC, causing a mismatch between the user's wall-clock time and what was displayed in Microsoft Outlook. The sync now sends the event in the organizer's local timezone with a matching timezone label, so Outlook displays the same wall-clock time and timezone that was entered. task-6167258 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#262488
This update clarifies the terminology used in Odoo's overtime reporting by renaming confusing labels like 'Difference' and 'Balance' to 'Worked Extra Hours' and 'Validated Extra Hours'. This change ensures consistent and understandable reporting across all views, improving accuracy and ease of use for HR teams.
Original PR description
The reporting labels "Difference" and "Balance" are confusing because "Difference" tracks system-qualified overtime while "Balance" represents accepted overtime hours. There is also a lack of consistency across views. This commit renames these fields to "Worked Extra Hours" and "Validated Extra Hours" to harmonize the naming everywhere task-6352142 Description of the issue/feature this PR addresses: Confusing and inconsistent naming for extra hours Current behavior before PR: - Reporting uses "Difference" and "Balance". - Views use inconsistent labels. Desired behavior after PR is merged: Labels are consistently named "Worked Extra Hours" and "Validated Extra Hours" everywhere. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275944 Forward-Port-Of: odoo/odoo#273631
9 changes
Resolved issues and error corrections
**Purpose of this PR:** Before this PR, the Voice detection sensitivity indicator in call settings could get stuck showing the last detected level after clicking "Stop" right after "Test". The `AudioWorkletNode`'s port kept receiving tic messages briefly after `disconnect()`, since disconnecting only unroutes the audio graph and does not stop the worklet from posting pending messages. <img width="546" height="73" alt="voice_test_bug" src="https://github.com/user-attachments/assets/05a10d23
Original PR description
**Purpose of this PR:** Before this PR, the Voice detection sensitivity indicator in call settings could get stuck showing the last detected level after clicking "Stop" right after "Test". The…
**Purpose of this PR:** Before this PR, the Voice detection sensitivity indicator in call settings could get stuck showing the last detected level after clicking "Stop" right after "Test". The `AudioWorkletNode`'s port kept receiving tic messages briefly after `disconnect()`, since disconnecting only unroutes the audio graph and does not stop the worklet from posting pending messages. <img width="546" height="73" alt="voice_test_bug" src="https://github.com/user-attachments/assets/05a10d23-fe60-4a85-b906-bfec6d235ec5" /> Steps to reproduce: 1. Open Voice & Video Settings. 2. Start the Voice detection sensitivity test. 3. Quickly click Stop immediately after clicking Test. 4. It may take a few tries, but eventually the Voice detection sensitivity indicator remains stuck at the last detected level. > [!NOTE] > this is timing-dependent. A tic message must already be in-flight from the worklet thread when `disconnect()` runs, so it won't happen every attempt. This race condition existed in the `disconnect` callback of `_loadAudioWorkletProcessor` since #66611, but stayed silent until #183969 introduced the Voice detection sensitivity feature in call settings, exposing it. This PR clears `port.onmessage` before disconnecting so late tic messages can no longer update the Voice detection sensitivity indicator after monitoring has stopped.
Since 414e55cf7c397, we can assign multiple users to a user-defined filter but because it's now a many2many, any user that got archived won't be shown in the `user_ids` fields anymore, it could mislead the filter being a global filter; whereas it's not. This commit also display archived users so we can see all users effectively assigned to the user-defined filter. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Since 414e55cf7c397, we can assign multiple users to a user-defined filter but because it's now a many2many, any user that got archived won't be shown in the `user_ids` fields anymore, it could mislead the filter being a global filter; whereas it's not. This commit also display archived users so we can see all users effectively assigned to the user-defined filter. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Currently, overlays remain open when the POS screensaver is loaded [^1]. #### Steps to reproduce: - Open the POS interface. - Open a dropdown/popover menu (e.g., the navbar hamburger menu). - Wait for the screensaver (SaverScreen) to trigger due to inactivity. - The open dropdown menu remains visible on top of the screensaver. #### Issue Dropdowns and popovers are rendered as active overlays outside the main screen container. While the screensaver setup closes active dialogs, it doe
Original PR description
Currently, overlays remain open when the POS screensaver is loaded [^1]. #### Steps to reproduce: - Open the POS interface. - Open a dropdown/popover menu (e.g., the navbar hamburger menu). - Wait for the screensaver (SaverScreen) to trigger due to inactivity. - The open dropdown menu remains visible on top of the screensaver. #### Issue Dropdowns and popovers are rendered as active overlays outside the main screen container. While the screensaver setup closes active dialogs, it does not handle active overlays. #### Fix Retrieve the overlay service in SaverScreen and close all active overlays during its setup phase using a dedicated `closeAllOverlays` method. [^1]:  Forward-Port-Of: odoo/odoo#274716
In Multiwebsite settings, when the public user interactions needs email generation (appointment or event flow), the email links are generated with a base url that does not corresponds to the one from which the request started. - Have website A and website B - Create an event and assign it to website B - As public user, access the event and register to it - Check the generated email Issue: button links in the email will redirect to the wrong website, so users will encounter an issue when
Original PR description
In Multiwebsite settings, when the public user interactions needs email generation (appointment or event flow), the email links are generated with a base url that does not corresponds to the one from which the request started. - Have website A and website B - Create an event and assign it to website B - As public user, access the event and register to it - Check the generated email Issue: button links in the email will redirect to the wrong website, so users will encounter an issue when managing the event. This occurs because the record `event.registration` has no website_id field and the base url is taken from the company default website (website A) opw-4146760 opw-4336369 Forward-Port-Of: odoo/odoo#275557 Forward-Port-Of: odoo/odoo#274051
**Steps to reproduce:** - activate subcontracting in the settings - create a storable product 'comp' with categ avco auto - confirm a PO and validate receipt for 1 comp at 10 - create a storable product 'prod' with categ avco auto - in the purchase tab set a vendor with a price of 30 - create a subcontracting bom with the same vendor as as the subcontractor and 1 quantity of our comp products in the components - confirm a PO for 1 prod with the subcontractor as the vendor - on
Original PR description
**Steps to reproduce:** - activate subcontracting in the settings - create a storable product 'comp' with categ avco auto - confirm a PO and validate receipt for 1 comp at 10 - create a storable…
**Steps to reproduce:** - activate subcontracting in the settings - create a storable product 'comp' with categ avco auto - confirm a PO and validate receipt for 1 comp at 10 - create a storable product 'prod' with categ avco auto - in the purchase tab set a vendor with a price of 30 - create a subcontracting bom with the same vendor as as the subcontractor and 1 quantity of our comp products in the components - confirm a PO for 1 prod with the subcontractor as the vendor - on the receipt, click on 'record component and change the 'quantity' to 2 then click on record production (you might need to click anywhere on the form to have the 'record production' appear) - validate the receipt - create and confirm the Bill for the 2 quantity - open valuation view **Current behavior:** an extra stock valuation layer was created with no quantity, no reference and a total value of 20 **Expected behavior:** This extra layer is not needed, the two svl for the receipt are made with a quantity of 2 and so is the bill, so the amls created are as follow : - svl comp : - credit 20 stock valuation - debit 20 cost of production - svl prod : - debit 80 stock valuation - credit 60 stock interim received - credit 20 cost of production - amls from the bill : - 60 stock interim received - 60 account payable After all of this the result is : debit 60 in stock valuation credit 60 account payable which is what we want The extra layer is not needed and creates unbalance, its amls are : credit 20 stock interim received debit 20 stock valuation **Cause of the issue:** This extra svl comes from the _apply_price_difference() method https://github.com/odoo/odoo/blob/deeecf7cd02e7383b591835b0c6495e3ddead0ff/addons/purchase_stock/models/account_invoice.py#L131 This method creates svl and/or amls to compensate difference between the bill price and the PO price (see https://github.com/odoo/odoo/pull/126536 for more details) To check if there is a difference, we compute the layer_price_unit https://github.com/odoo/odoo/blob/deeecf7cd02e7383b591835b0c6495e3ddead0ff/addons/purchase_stock/models/account_move_line.py#L140 and pass it as parameter to _prepare_pdiff_vals() https://github.com/odoo/odoo/blob/deeecf7cd02e7383b591835b0c6495e3ddead0ff/addons/purchase_stock/models/account_move_line.py#L159 were it will be compared to the aml price https://github.com/odoo/odoo/blob/deeecf7cd02e7383b591835b0c6495e3ddead0ff/addons/purchase_stock/models/account_move_line.py#L239-L244 In the case of a subcontracted product, price unit of the bill (30 in our case) should be the price unit of the svl of the subcontracted product (40) - the price of the comps for one unit of the subcontracted product (10). That's why when we call _get_layer_price_unit, there is a mrp_subcontracting_purchase override to remove the component price from the svl of the subcontracted product. https://github.com/odoo/odoo/blob/deeecf7cd02e7383b591835b0c6495e3ddead0ff/addons/mrp_subcontracting_purchase/models/stock_valuation_layer.py#L18-L20 To get the price of the components for on unit of the subcontracted product, we divide the value of the components svls by production.product_uom_qty, but that is not necessarily the same number as the quantity of the svl of the subcontracted product (in most cases yes but not in the case of our steps to reproduce for instance). In terms of account move lines the quantity of the svl is the one that maters so that's the one that we should take into account also in this computation. opw-6191829 Forward-Port-Of: odoo/odoo#271467
From versions 18.3 to 19.3, company_id and siret refer to the same field. This caused an issue when connecting to the PDP using siret or siren could overwrite company_id. task-6327304
Original PR description
From versions 18.3 to 19.3, company_id and siret refer to the same field. This caused an issue when connecting to the PDP using siret or siren could overwrite company_id. task-6327304
Problem: When importing XML files to generate vendor bills, the system uses UBL parser and assumes that the PriceAmount node needs to be divided by the BaseQuantity node to obtain the exact price unit. However, in Colombia, the DIAN treats the PriceAmount node as the exact price unit. This was not flagged in the system so the parser incorrectly divides the PriceAmount by BaseQuantity, resulting in negative discounts to be added to match the subtotal. Solution: Extract the basis_qty logic into
Original PR description
Problem: When importing XML files to generate vendor bills, the system uses UBL parser and assumes that the PriceAmount node needs to be divided by the BaseQuantity node to obtain the exact price…
Problem: When importing XML files to generate vendor bills, the system uses UBL parser and assumes that the PriceAmount node needs to be divided by the BaseQuantity node to obtain the exact price unit. However, in Colombia, the DIAN treats the PriceAmount node as the exact price unit. This was not flagged in the system so the parser incorrectly divides the PriceAmount by BaseQuantity, resulting in negative discounts to be added to match the subtotal. Solution: Extract the basis_qty logic into a helper method so other localizations can override when needed. Current behavior: When importing a Colombian XML with a product that has a BaseQuantity greater than 1, the PriceAmount gets incorrectly divided, resulting in negative discounts on the vendor bill. Expected Behavior: When importing a Colombian XML with a product that has a BaseQuantity greater than 1, the PriceAmount gets parses as the exact unit price with no negative discounts applied. Task [link](https://www.odoo.com/odoo/project.task/6215466) task-6215466 Forward-Port-Of: odoo/odoo#273129
Before this commit, in the test `test_ticket_price_with_currency_conversion` the exchange rate was not correctly assigned because `rate_ids` was not initialized when running tests on app install. As a result the the rate was left empty and the currency conversion was not applied. This commit creates the rate_ids in the test to make sure the rates are correctly applied. Runbot error: https://runbot.odoo.com/odoo/error/242431 --- I confirm I have signed the CLA and read the PR guidelines
Original PR description
Before this commit, in the test `test_ticket_price_with_currency_conversion` the exchange rate was not correctly assigned because `rate_ids` was not initialized when running tests on app install. As a result the the rate was left empty and the currency conversion was not applied. This commit creates the rate_ids in the test to make sure the rates are correctly applied. Runbot error: https://runbot.odoo.com/odoo/error/242431 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#265503
### Steps to reproduce the issue: 1. Download Accounting 2. Go to one move type (ex. customer invoices, vendor bills, etc.) 3. Select some records, click the wheel button and then export ZIP 4. Error raised: Nothing to export ### Cause of the issue: Commit 438603ac forward-ported the zip export feature from v17 to v18, but failed to adapt the action_export_zip function and import the controller route. ### Reason to introduce the fix: It has been decided to completly remove the butto
Original PR description
### Steps to reproduce the issue: 1. Download Accounting 2. Go to one move type (ex. customer invoices, vendor bills, etc.) 3. Select some records, click the wheel button and then export ZIP 4. Error raised: Nothing to export ### Cause of the issue: Commit 438603ac forward-ported the zip export feature from v17 to v18, but failed to adapt the action_export_zip function and import the controller route. ### Reason to introduce the fix: It has been decided to completly remove the button EXPORT ZIP since we already have other buttons that download/export the PDFs in a zip file (ex. button Download PDF). opw-6313750 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273296
5 changes
Resolved issues and error corrections
### Steps to reproduce the issue: 1. Download Accounting 2. Go to one move type (ex. customer invoices, vendor bills, etc.) 3. Select some records, click the wheel button and then export ZIP 4. Error raised: Nothing to export ### Cause of the issue: Commit 438603ac forward-ported the zip export feature from v17 to v18, but failed to adapt the action_export_zip function and import the controller route. ### Reason to introduce the fix: It has been decided to completly remove the butto
Original PR description
### Steps to reproduce the issue: 1. Download Accounting 2. Go to one move type (ex. customer invoices, vendor bills, etc.) 3. Select some records, click the wheel button and then export ZIP 4. Error raised: Nothing to export ### Cause of the issue: Commit 438603ac forward-ported the zip export feature from v17 to v18, but failed to adapt the action_export_zip function and import the controller route. ### Reason to introduce the fix: It has been decided to completly remove the button EXPORT ZIP since we already have other buttons that download/export the PDFs in a zip file (ex. button Download PDF). opw-6313750 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps: - Enable `pos_hr` and configure employees - Open the POS - Log in as an employee - Open the burger menu in the navbar Issue: - The "Create Product" menu is not visible immediately after the employee logs in. - It only appears after refreshing the POS. Cause: - The visibility of the menu is determined when `Navbar` component is mounted. - Since the `Navbar` is mounted only once when the POS UI loads, the value is not updated after employee login. Fix: - Replace the asynch
Original PR description
Steps: - Enable `pos_hr` and configure employees - Open the POS - Log in as an employee - Open the burger menu in the navbar Issue: - The "Create Product" menu is not visible immediately after the employee logs in. - It only appears after refreshing the POS. Cause: - The visibility of the menu is determined when `Navbar` component is mounted. - Since the `Navbar` is mounted only once when the POS UI loads, the value is not updated after employee login. Fix: - Replace the asynchronous permission check with a getter that evaluates product creation rights. - Cache the group access information in `posService` and let the hr override use the getter. Task-6361787 Related PR: https://github.com/odoo/enterprise/pull/123073
Rather than assign `log_target` and blow up if the third branch is taken, use a `defaultdict` and just increment the count in each branch on hit. The continue in the third branch is not strictly necessary, but that way it protects us if anyone decides to add post-processing which also doesn't account for the third branch.
Original PR description
Rather than assign `log_target` and blow up if the third branch is taken, use a `defaultdict` and just increment the count in each branch on hit. The continue in the third branch is not strictly necessary, but that way it protects us if anyone decides to add post-processing which also doesn't account for the third branch.
This update resolves an issue where non-administrator users accessing the POS payment method form would encounter an error. The change grants read-only access to the `payment.provider` model for POS managers and restricts the form's visibility to authorized users, ensuring a smoother experience for POS staff.
Original PR description
Only admin users have read access to the `payment.provider` model. Opening the PoS payment method form as a non-admin would raise an access error because the `online_payment_provider_ids` many2many field tries to fetch `payment.provider` records on form load. Grant read-only access on `payment.provider` to `group_pos_manager` so POS admins can use the field. Restrict the field's group in the form view to `point_of_sale.group_pos_manager,base.group_system` so it is not rendered for users without either role. opw-6208656 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#263837
This update fixes an issue where vendor bills generated from Colombian XML imports incorrectly applied discounts due to a misinterpretation of price unit calculations. The change ensures that the PriceAmount is correctly parsed as the unit price, aligning with DIAN regulations and preventing negative discounts on invoices.
Original PR description
Problem: When importing XML files to generate vendor bills, the system uses UBL parser and assumes that the PriceAmount node needs to be divided by the BaseQuantity node to obtain the exact price…
Problem: When importing XML files to generate vendor bills, the system uses UBL parser and assumes that the PriceAmount node needs to be divided by the BaseQuantity node to obtain the exact price unit. However, in Colombia, the DIAN treats the PriceAmount node as the exact price unit. This was not flagged in the system so the parser incorrectly divides the PriceAmount by BaseQuantity, resulting in negative discounts to be added to match the subtotal. Solution: Extract the basis_qty logic into a helper method so other localizations can override when needed. Current behavior: When importing a Colombian XML with a product that has a BaseQuantity greater than 1, the PriceAmount gets incorrectly divided, resulting in negative discounts on the vendor bill. Expected Behavior: When importing a Colombian XML with a product that has a BaseQuantity greater than 1, the PriceAmount gets parses as the exact unit price with no negative discounts applied. Task [link](https://www.odoo.com/odoo/project.task/6215466) task-6215466
6 changes
Resolved issues and error corrections
Steps to produce: 1) Install Manufacturing & enable "Work Order Dependencies" in the settings 2) Make a new BOM with 2 operations 3) Check "Operation Dependencies" in the miscellaneous tab on the BOM's form view. 4) Configure the first sequential operation to be blocked by the second 5) Make and confirm an MO using this BOM 6) Uncheck "Operation Dependencies" on the BOM 7) Press "Plan" on the MO, a validation error is thrown stating "You cannot create cyclic dependency." Issue occur
Original PR description
Steps to produce: 1) Install Manufacturing & enable "Work Order Dependencies" in the settings 2) Make a new BOM with 2 operations 3) Check "Operation Dependencies" in the miscellaneous tab on the…
Steps to produce: 1) Install Manufacturing & enable "Work Order Dependencies" in the settings 2) Make a new BOM with 2 operations 3) Check "Operation Dependencies" in the miscellaneous tab on the BOM's form view. 4) Configure the first sequential operation to be blocked by the second 5) Make and confirm an MO using this BOM 6) Uncheck "Operation Dependencies" on the BOM 7) Press "Plan" on the MO, a validation error is thrown stating "You cannot create cyclic dependency." Issue occurs because after the MO is confirmed the blocked_by_workorder_ids field for mrp.workorder records is set based on the order manually configured on the BOM (operation 1 is blocked by operation 2). After the BOM is edited to have allow_operation_dependencies = false, then Odoo uses the default sequential ordering when planning the operations (operation 2 is blocked by operation 1). Since the old ordering is never cleared, a cycle is created unintentionally. This PR resolves this issue by clearing the blocked_by_workorder_ids field on mrp.workorder records. [Ticket](https://www.odoo.com/odoo/project/49/tasks/6334271?debug=assets) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
hash_sign has become very used all over the place, so more and more tokens depend on `database.secret`, increasing the impact of that secret needing one day to be rotated or being compromised. To avoid making `database.secret` a single point of failure, we would like `hash_sign` to support a custom secret supplied by caller. task-6391264
Original PR description
hash_sign has become very used all over the place, so more and more tokens depend on `database.secret`, increasing the impact of that secret needing one day to be rotated or being compromised. To avoid making `database.secret` a single point of failure, we would like `hash_sign` to support a custom secret supplied by caller. task-6391264
Note: In odoo all date/datetime fields are stored and computed by default as UTC Before this commit, dates were called using local timezone getters. This caused the time returned from web to be shifted by the timezone as the dates returned would be treated as UTC. After this commit, dates are now called using UTC timzone getters. Now all web times are retrived as UTC and in sync with the rest of the odoo fields and computations. task-6271421
Original PR description
Note: In odoo all date/datetime fields are stored and computed by default as UTC Before this commit, dates were called using local timezone getters. This caused the time returned from web to be shifted by the timezone as the dates returned would be treated as UTC. After this commit, dates are now called using UTC timzone getters. Now all web times are retrived as UTC and in sync with the rest of the odoo fields and computations. task-6271421
When searching on the Website site, using the main search on the navbar, it opens a list view with the results (`website.list_hybrid`) which raises the warning on the logs (2 times): "Unknown directives or unused attributes: {'t-key'} in website.list_hybrid"  This happens after the attribute `t-key` was added to the template [\[1\]] because the template is only use
Original PR description
When searching on the Website site, using the main search on the navbar, it opens a list view with the results (`website.list_hybrid`) which raises the warning on the logs (2 times): "Unknown…
When searching on the Website site, using the main search on the navbar, it opens a list view with the results (`website.list_hybrid`) which raises the warning on the logs (2 times):
"Unknown directives or unused attributes: {'t-key'} in website.list_hybrid"

This happens after the attribute `t-key` was added to the template [\[1\]] because the template is only used in QWeb. The validation for them doesn't include the `t-key` [\[2\]] as one of the "iter_directives" nor has a `_compile_directive_*` method to check and remove it from the validation as it's done with the `t-as` and `t-foreach`.
This also causes the raise of the warnings on tours that use the tour method `searchProduct` (of the module `website_sale`) because it uses the first input with the name of search and happens to be the search on the navbar.

[\[1\]]: https://github.com/odoo/odoo/commit/7b1d82aa
[\[2\]]: https://github.com/odoo/odoo/blob/f52cfb09/odoo/addons/base/models/ir_qweb.py#L1400
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prTranslatable rows that are identified by a stable key rather than by their text (e.g. selection option labels in ir.model.fields.selection, and other module-reflected metadata written through upsert_en()) can have their English source text changed by a module upgrade while keeping the same key. For example product.template's selection value 'consu' went from meaning "Consumable" to meaning "Goods" between 17.0 and 18.0, without the stored value itself changing. In that situation, upsert
Original PR description
Translatable rows that are identified by a stable key rather than by their text (e.g. selection option labels in ir.model.fields.selection, and other module-reflected metadata written through…
Translatable rows that are identified by a stable key rather than by their text (e.g. selection option labels in ir.model.fields.selection, and other module-reflected metadata written through upsert_en()) can have their English source text changed by a module upgrade while keeping the same key. For example product.template's selection value 'consu' went from meaning "Consumable" to meaning "Goods" between 17.0 and 18.0, without the stored value itself changing. In that situation, upsert_en() always refreshes the 'en_US' entry from the current code, so English is never wrong. But every other language keeps whatever value it had, since upsert_en() blindly merges the new 'en_US' entry into the existing jsonb without checking whether the previous 'en_US' value actually changed. When the module's .po file is later reloaded, TranslationImporter.save() finds a non-empty value already there for each language and, by design, does not overwrite it unless explicitly asked to (`overwrite`) on a record that isn't `noupdate`. That protection is correct when the English text hasn't changed (it keeps manual translation customizations across upgrades), but here it ends up protecting a translation of a source string that no longer exists. As a result, a value whose meaning changes across versions keeps showing its old label in every language except English, forever, unless someone forces a translation overwrite. Fix this in upsert_en() itself: when the incoming 'en_US' value differs from the one currently stored, drop every other language already stored for that row instead of merging into it. Those translations were made for a source string that no longer exists, so there is nothing worth protecting. Once dropped, they are simply missing from the jsonb, so TranslationImporter.save() naturally lets the freshly (re)loaded translations in on its next run, without needing to know anything about source drift, and `overwrite`/`noupdate` keep their exact original meaning for every other case. Task-6333080 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
### Issue: The 'Schedule an appointment' and 'Next Events' CTA buttons were not updated even when their conditions were satisfied. ### Steps to reproduce: - Install only Website. - In the configurator, choose 'Schedule Appointments' as the main objective. - Complete the setup and create the website. - The CTA button remains 'Contact Us' instead of 'Schedule an appointment'. ### Reason: The `get_cta_data()` method is overridden in specific modules to update the CTA button base
Original PR description
### Issue: The 'Schedule an appointment' and 'Next Events' CTA buttons were not updated even when their conditions were satisfied. ### Steps to reproduce: - Install only Website. - In the configurator, choose 'Schedule Appointments' as the main objective. - Complete the setup and create the website. - The CTA button remains 'Contact Us' instead of 'Schedule an appointment'. ### Reason: The `get_cta_data()` method is overridden in specific modules to update the CTA button based on conditions. However, it is called before those modules are installed, so the overridden logic is never executed. ### Fix: Ensure that `get_cta_data()` is called and the CTA button is updated after the required modules are installed. task-[6383681](https://www.odoo.com/odoo/project/974/tasks/6383681) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr