Daily updates from Odoo
Friday, July 31, 2026
330 changes
21 changes
Enhancements to existing features
Since IAP now gives us multiple additional_identifiers. We get the DUNS directly from IAP. No need to process it on client. Backport of f184d1643ad50274004c0667aebfe615832dcb33 Task-5367705
Original PR description
Since IAP now gives us multiple additional_identifiers. We get the DUNS directly from IAP. No need to process it on client. Backport of f184d1643ad50274004c0667aebfe615832dcb33 Task-5367705
Resolved issues and error corrections
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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/su
Original PR description
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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#279418
Follow-up to #247929, which limited `forever` recurrences to a 15-year horizon (`calendar.max_recurrence_years`) for *yearly* and *monthly* frequencies but left *weekly* and *daily* on the hard cap `MAX_RECURRENT_EVENT` (720), ignoring the parameter. A weekly `forever` event therefore always materializes 720 occurrences (~14 years) regardless of `calendar.max_recurrence_years`, and a daily one ignores the parameter too. This applies the year limit to weekly and daily as well, accounting for th
Original PR description
Follow-up to #247929, which limited `forever` recurrences to a 15-year horizon (`calendar.max_recurrence_years`) for *yearly* and *monthly* frequencies but left *weekly* and *daily* on the hard cap `MAX_RECURRENT_EVENT` (720), ignoring the parameter. A weekly `forever` event therefore always materializes 720 occurrences (~14 years) regardless of `calendar.max_recurrence_years`, and a daily one ignores the parameter too. This applies the year limit to weekly and daily as well, accounting for the number of selected weekdays and the interval, while still capping at `MAX_RECURRENT_EVENT`. Steps to reproduce: 1. Set `calendar.max_recurrence_years` to e.g. 2. 2. Create a weekly event repeating "forever". 3. Before: 720 occurrences (~14 years). After: ~106 (2 years). task / context: extends #247929. Forward-Port-Of: odoo/odoo#272615 Forward-Port-Of: odoo/odoo#270348
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 Forward-Port-Of: odoo/odoo#278256 Forward-Port-Of: odoo/odoo#276474
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 Forward-Port-Of: odoo/odoo#278256 Forward-Port-Of: odoo/odoo#276474
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back
Original PR description
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is…
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back to the planned "days to receive" when nothing has been received yet according to [task](https://www.odoo.com/odoo/project/809/tasks/3691573). The query instead computes age(date_planned, COALESCE(date_done, date_order)), so once a receipt exists it returns date_planned - date_done (the gap between the scheduled date and the receipt) rather than date_done - date_order. https://github.com/odoo/odoo/blob/c06be48ce7277a667719fd756e0a1f63e91cda27/addons/purchase_stock/report/purchase_report.py#L20-L28 opw-6226523 Forward-Port-Of: odoo/odoo#279267 Forward-Port-Of: odoo/odoo#268843
Problem: Clicking an image padding option in Studio reports closes the dropdown, but the selected option is not applied. Cause: When editing inside an `iframe`, `unFocusEditable` is triggered on `focusin`, which runs `selection_leave_handlers` and closes the dropdown before the `click` event can propagate. Solution: Add `data-prevent-closing-overlay="true"` to the image padding dropdown, as done for other dropdowns, so it remains open until the click event is handled. Steps to reprod
Original PR description
Problem: Clicking an image padding option in Studio reports closes the dropdown, but the selected option is not applied. Cause: When editing inside an `iframe`, `unFocusEditable` is triggered on `focusin`, which runs `selection_leave_handlers` and closes the dropdown before the `click` event can propagate. Solution: Add `data-prevent-closing-overlay="true"` to the image padding dropdown, as done for other dropdowns, so it remains open until the click event is handled. Steps to reproduce: - Open a new report. - Add an image. - Select the image. - Open the padding dropdown. - Click a padding option. - Observe that the dropdown closes but the padding is not applied. task-6368964 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279408 Forward-Port-Of: odoo/odoo#276448
The test "show pulse effect on fullscreen mode only when another participant's camera is on" fails from time to time on runbot: the pulse never lands on the fullscreen button. The first rtc session of a channel posts a call notification message, whose new_message notification fetches channels_as_member. That response carries the rtc sessions with their server values, so when it lands after the mock remote turned the camera on, is_camera_on goes back to false. videoCountNotSelf drops to 0 and
Original PR description
The test "show pulse effect on fullscreen mode only when another participant's camera is on" fails from time to time on runbot: the pulse never lands on the fullscreen button. The first rtc session of a channel posts a call notification message, whose new_message notification fetches channels_as_member. That response carries the rtc sessions with their server values, so when it lands after the mock remote turned the camera on, is_camera_on goes back to false. videoCountNotSelf drops to 0 and its onUpdate sets promoteFullscreen to INACTIVE for good, as only a change of the count sets it back to ACTIVE. A real participant also stores is_camera_on on the server, so a fetch never brings outdated values back. Make the mock remote do the same. https://runbot.odoo.com/odoo/error/242050 Forward-Port-Of: odoo/odoo#279178
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Original PR description
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history
Original PR description
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history then opens on whichever product happens to carry that id, and stays empty when none does. Steps to reproduce: - Inventory > Reporting > Stock, click a Unit Cost -> the history of that product opens, as expected - go back, click "Inventory at Date" and confirm - click that same Unit Cost -> another product's history opens, or an empty list opw-6391778 Forward-Port-Of: odoo/odoo#279116
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready.
Original PR description
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready. runbot-223306 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278983 Forward-Port-Of: odoo/odoo#277954
Currently, when adding a line discount it does not reflect on the receipt. Steps to reproduce: ------------------- * Add items to the order * For one of them use a line discount (% button) * Pay the order * Generate the receipt > The mention x% discount off on y is not displayed Why the fix: ------------ On the product screen the mention is shown and the value is computed here: https://github.com/odoo/odoo/blob/fc2230fb44dc421fe280d49da9b2d8134e1a0702/addons/point_of_sale/static/s
Original PR description
Currently, when adding a line discount it does not reflect on the receipt. Steps to reproduce: ------------------- * Add items to the order * For one of them use a line discount (% button) * Pay the order * Generate the receipt > The mention x% discount off on y is not displayed Why the fix: ------------ On the product screen the mention is shown and the value is computed here: https://github.com/odoo/odoo/blob/fc2230fb44dc421fe280d49da9b2d8134e1a0702/addons/point_of_sale/static/src/app/models/accounting/pos_order_line_accounting.js#L54-L66 We can reuse this fonction for the frontend, in the backend we translate it. We don't show this mention for the chosen products of a combo product. opw-6290821 Forward-Port-Of: odoo/odoo#274717 Forward-Port-Of: odoo/odoo#270734
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category and add the route * Add the category to a product * use the repenish button -> the category route is not available on the replenishment Observation: ------------- When opening replenishment, it will open the view_product_replenish, in that view, it will use allowed_route_ids to allow us
Original PR description
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category…
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category and add the route * Add the category to a product * use the repenish button -> the category route is not available on the replenishment Observation: ------------- When opening replenishment, it will open the view_product_replenish, in that view, it will use allowed_route_ids to allow us to choose a route for this replenishment: https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/wizard/product_replenish_views.xml#L37 allowed_route_ids is compute in the mixin with the following domain: https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/models/stock_replenish_mixin.py#L18-L21 https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/models/stock_replenish_mixin.py#L25-L31 this only take into account route from the product and not the ones from the product category. https://github.com/odoo/odoo/blob/deeecf7cd02e7383b591835b0c6495e3ddead0ff/addons/stock/models/stock_location.py#L511 opw-6297308 Forward-Port-Of: odoo/odoo#271535
`onClickValidate`'s signature changed to `onClickValidate(args = {})`, so passing `true` directly from the Viva app callback made `isForceValidate` silently resolve to `false` instead of `true`. The previous `validateOrder` override was also dead code, since that method moved off `PaymentScreen` to `PosStore` and so we now override `onClickValidate` instead. Forward-Port-Of: odoo/odoo#278116
Original PR description
`onClickValidate`'s signature changed to `onClickValidate(args = {})`, so passing `true` directly from the Viva app callback made `isForceValidate` silently resolve to `false` instead of `true`.
The previous `validateOrder` override was also dead code, since that method moved off `PaymentScreen` to `PosStore` and so we now override `onClickValidate` instead.
Forward-Port-Of: odoo/odoo#278116Before this commit, the pointerup event when doing a drag'n'drop in kanban view was containing the kanban card placeholder. Now, this placeholder isn't considered anymore to prevent unwanted target in the event. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278324
Original PR description
Before this commit, the pointerup event when doing a drag'n'drop in kanban view was containing the kanban card placeholder. Now, this placeholder isn't considered anymore to prevent unwanted target in the event. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278324
Before this commit, starting a tour in test mode on the tours viewz wasn't triggering the redirect at the first step of the tour. Now, it redirect. TASK-6331071 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276531
Original PR description
Before this commit, starting a tour in test mode on the tours viewz wasn't triggering the redirect at the first step of the tour. Now, it redirect. TASK-6331071 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276531
The state_id field was not cleared when editing an address and switching to a country without states — the state selector reset visually, but the stale state_id was still saved to the backend. Steps to reproduce: 1. Add a product to the cart. 2. Go to checkout and edit the address, selecting a country that has states. 3. Edit the address again, now selecting a country without states. 4. Save and check the contact in the backend: state_id still holds the state from the previo
Original PR description
The state_id field was not cleared when editing an address and switching to a country without states — the state selector reset visually, but the stale state_id was still saved to the backend. Steps to reproduce: 1. Add a product to the cart. 2. Go to checkout and edit the address, selecting a country that has states. 3. Edit the address again, now selecting a country without states. 4. Save and check the contact in the backend: state_id still holds the state from the previous country. Solution: reset the state_id select options for the new country. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278660 Forward-Port-Of: odoo/odoo#278125
Steps to reproduce: - Edit a page. - Drop a carousel snippet like s_quotes_carousel - Click "Add Slide" with the browser console open(for concrete race condition) => Traceback: TypeError: Cannot read properties of null (reading 'classList') Cause: `slide()` used the editor window's `Carousel` instead of the iframe's. This created a second Carousel instance for the same element. Both instances updated the indicators at the same time, causing one to remove the active indicator before the
Original PR description
Steps to reproduce: - Edit a page. - Drop a carousel snippet like s_quotes_carousel - Click "Add Slide" with the browser console open(for concrete race condition) => Traceback: TypeError: Cannot read properties of null (reading 'classList') Cause: `slide()` used the editor window's `Carousel` instead of the iframe's. This created a second Carousel instance for the same element. Both instances updated the indicators at the same time, causing one to remove the active indicator before the other tried to use it, leading to the traceback. Fix: Use `this.window.Carousel` so the iframe's existing Carousel instance is reused instead of creating a second one. task-6084484 Forward-Port-Of: odoo/odoo#279117 Forward-Port-Of: odoo/odoo#275903
### Issue before this commit: 1. When generating a FatturaPA XML for a self-invoice (reverse charge / autofattura, e.g. TD17-TD19) with the "Reference" (ref) field filled in, the supplier's invoice number was placed under <DatiOrdineAcquisto> instead of <DatiFattureCollegate>. 2. When a credit note was generated from a vendor bill, the <IdDocumento> in <DatiFattureCollegate> contained Odoo's internal document number (e.g. BILL/2026/07/0002) instead of the actual reference of the invoice rece
Original PR description
### Issue before this commit: 1. When generating a FatturaPA XML for a self-invoice (reverse charge / autofattura, e.g. TD17-TD19) with the "Reference" (ref) field filled in, the supplier's invoice…
### Issue before this commit: 1. When generating a FatturaPA XML for a self-invoice (reverse charge / autofattura, e.g. TD17-TD19) with the "Reference" (ref) field filled in, the supplier's invoice number was placed under <DatiOrdineAcquisto> instead of <DatiFattureCollegate>. 2. When a credit note was generated from a vendor bill, the <IdDocumento> in <DatiFattureCollegate> contained Odoo's internal document number (e.g. BILL/2026/07/0002) instead of the actual reference of the invoice received from the supplier (ref). ### Steps to reproduce the issue: ISSUE 1: 1. Download Accounting and l10n_it 2. Go to Vendor -> Bills 3. Create a bill with: 1. Italian company as vendor 2. Product with tax 22% S RC 3. Bill reference filled (ex. FT00001) 4. Send it to SDI, open the XML and see that the tag <IdDocumento> is inside the tag <DatiOrdineAcquisto> while it sohuld be inside <Datifatturecollegate> ISSUE 2: 1. From a bill created click Credit Note 2. Send to SDI again, open the XML and see that the tag <IdDocumento> contains the bill reference created in Odoo while it should take the reference of the original invoice SENT by the vendor ### Cause of the issue: 1. The template's t-elif chain did not distinguish between self-invoices and regular documents, so any value in record.ref was routed to DatiOrdineAcquisto regardless of context. 2. Separately, the linked_moves loop always used linked_move.name to populate <IdDocumento>, which for vendor bills/refunds is Odoo's own sequential number, not the supplier's original invoice number. ### Reason to introduce the fix: 1. For the official FatturaPA Technical Specifications, DatiOrdineAcquisto must only reference a purchase order, while DatiFattureCollegate must reference a related invoice — which is the correct category for the supplier document being integrated in a self-invoice. This is confirmed by the Agenzia delle Entrate documentation: https://www.agenziaentrate.gov.it/portale/documents/d/guest/allegato-a-specifiche-tecniche-vers-1-9 (p.107, chapter Compilazione del documento XML con codice TD17) 2. For credit/debit notes, <IdDocumento> inside <DatiFattureCollegate> must contain the number of the original invoice being referenced/varied, not an internally generated document number, as clarified here: https://www.pa.sm/ticket/kb/faq.php?id=46 opw-6117968 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276523
Portal subscribe task can create tb because the task was archived before unsubscribing. opw-6397850 Forward-Port-Of: odoo/odoo#279071 Forward-Port-Of: odoo/odoo#278667
Original PR description
Portal subscribe task can create tb because the task was archived before unsubscribing. opw-6397850 Forward-Port-Of: odoo/odoo#279071 Forward-Port-Of: odoo/odoo#278667
When an image is start-aligned, if a list is defined after it, its bullets/numbers/checkboxes are rendered on top of the image. This commit makes the bullets rendered after the image. Steps to reproduce: - Edit a website page - Drop a text page - Insert an image with `/image` - Align image to the left - Insert a bullet list or a numbered list or a checkbox list with some indented entries => Some bullets were rendered on top of the image Additionally, the start-align is neutral
Original PR description
When an image is start-aligned, if a list is defined after it, its bullets/numbers/checkboxes are rendered on top of the image. This commit makes the bullets rendered after the image. Steps to reproduce: - Edit a website page - Drop a text page - Insert an image with `/image` - Align image to the left - Insert a bullet list or a numbered list or a checkbox list with some indented entries => Some bullets were rendered on top of the image Additionally, the start-align is neutralized inside list lines because other approaches do not provide a satisfactory layout - and break further situations. task-6116437 Forward-Port-Of: odoo/odoo#260325
Miscellaneous changes
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
Original PR description
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
26 changes
Resolved issues and error corrections
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simpl
Original PR description
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simply not decremented when no message has been seen yet. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279279 Forward-Port-Of: odoo/odoo#277417
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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/su
Original PR description
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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#279418
Follow-up to #247929, which limited `forever` recurrences to a 15-year horizon (`calendar.max_recurrence_years`) for *yearly* and *monthly* frequencies but left *weekly* and *daily* on the hard cap `MAX_RECURRENT_EVENT` (720), ignoring the parameter. A weekly `forever` event therefore always materializes 720 occurrences (~14 years) regardless of `calendar.max_recurrence_years`, and a daily one ignores the parameter too. This applies the year limit to weekly and daily as well, accounting for th
Original PR description
Follow-up to #247929, which limited `forever` recurrences to a 15-year horizon (`calendar.max_recurrence_years`) for *yearly* and *monthly* frequencies but left *weekly* and *daily* on the hard cap `MAX_RECURRENT_EVENT` (720), ignoring the parameter. A weekly `forever` event therefore always materializes 720 occurrences (~14 years) regardless of `calendar.max_recurrence_years`, and a daily one ignores the parameter too. This applies the year limit to weekly and daily as well, accounting for the number of selected weekdays and the interval, while still capping at `MAX_RECURRENT_EVENT`. Steps to reproduce: 1. Set `calendar.max_recurrence_years` to e.g. 2. 2. Create a weekly event repeating "forever". 3. Before: 720 occurrences (~14 years). After: ~106 (2 years). task / context: extends #247929. Forward-Port-Of: odoo/odoo#272615 Forward-Port-Of: odoo/odoo#270348
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used
Original PR description
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used while preserving the existing validation against empty or whitespace-only names. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279365 Forward-Port-Of: odoo/odoo#273593
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 Forward-Port-Of: odoo/odoo#278256 Forward-Port-Of: odoo/odoo#276474
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 Forward-Port-Of: odoo/odoo#278256 Forward-Port-Of: odoo/odoo#276474
Steps: - Install marketing_card & website_event_track - Create a marketing card campaign for "Event Track" - Create an event with tracks - Click on "Send Cards" in event form - Choose your campaign for the mailing - Update X cards for the mailing Actual result: - Recipients is "Event Track" - Card Campaign Mailing should target model Event Track - Mailing model is still the default one during the validation Expected result: - No error - Card are updated - User will be able to s
Original PR description
Steps: - Install marketing_card & website_event_track - Create a marketing card campaign for "Event Track" - Create an event with tracks - Click on "Send Cards" in event form - Choose your campaign for the mailing - Update X cards for the mailing Actual result: - Recipients is "Event Track" - Card Campaign Mailing should target model Event Track - Mailing model is still the default one during the validation Expected result: - No error - Card are updated - User will be able to send mailing after update
The discuss action's breadcrumb name is set asynchronously: a useEffect on the current thread's displayName calls setDisplayName after the OWL render. The tour clicked "Starred messages" then immediately clicked "View or join channels" (a sidebar category action that is always present, so there was no implicit wait). Under runbot load the starred render and its effect lagged, so the action was restored with the stale "Inbox" breadcrumb name and the ".breadcrumb-item:contains('Starred messages')"
Original PR description
The discuss action's breadcrumb name is set asynchronously: a useEffect on the current thread's displayName calls setDisplayName after the OWL render. The tour clicked "Starred messages" then immediately clicked "View or join channels" (a sidebar category action that is always present, so there was no implicit wait). Under runbot load the starred render and its effect lagged, so the action was restored with the stale "Inbox" breadcrumb name and the ".breadcrumb-item:contains('Starred messages')" step timed out.
This is a test-timing artifact: a real user always sees the starred view render before navigating away, so the breadcrumb is correct for them.
Wait for the starred thread to be displayed before opening the channels list, and assert the channels view opened via its "Public Channels" breadcrumb. Also use :text instead of :contains for the text selectors.
https://runbot.odoo.com/odoo/error/242893
Forward-Port-Of: odoo/odoo#279342
Forward-Port-Of: odoo/odoo#278909The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead.
Original PR description
The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead. 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#279322
The test "show pulse effect on fullscreen mode only when another participant's camera is on" fails from time to time on runbot: the pulse never lands on the fullscreen button. The first rtc session of a channel posts a call notification message, whose new_message notification fetches channels_as_member. That response carries the rtc sessions with their server values, so when it lands after the mock remote turned the camera on, is_camera_on goes back to false. videoCountNotSelf drops to 0 and
Original PR description
The test "show pulse effect on fullscreen mode only when another participant's camera is on" fails from time to time on runbot: the pulse never lands on the fullscreen button. The first rtc session of a channel posts a call notification message, whose new_message notification fetches channels_as_member. That response carries the rtc sessions with their server values, so when it lands after the mock remote turned the camera on, is_camera_on goes back to false. videoCountNotSelf drops to 0 and its onUpdate sets promoteFullscreen to INACTIVE for good, as only a change of the count sets it back to ACTIVE. A real participant also stores is_camera_on on the server, so a fetch never brings outdated values back. Make the mock remote do the same. https://runbot.odoo.com/odoo/error/242050 Forward-Port-Of: odoo/odoo#279178
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Original PR description
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history
Original PR description
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history then opens on whichever product happens to carry that id, and stays empty when none does. Steps to reproduce: - Inventory > Reporting > Stock, click a Unit Cost -> the history of that product opens, as expected - go back, click "Inventory at Date" and confirm - click that same Unit Cost -> another product's history opens, or an empty list opw-6391778 Forward-Port-Of: odoo/odoo#279116
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready.
Original PR description
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready. runbot-223306 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278983 Forward-Port-Of: odoo/odoo#277954
### Steps to reproduce: - Create 2 companies: c1, c2 - Create 2 storable products: P, Comp - In c1 update the available qty of P to 10 units and its cost to 50 - In c2 create a kit bom for P: 1 x Comp - With c1 > Accounting > Review > inventory > Inventory Valuation #### > The total value of Super product is 0 instead of 500 ### Cause of the issue: The total value of the product will be set to 0 since the `qty_available` of the product is incorrectly computed to be 0: https://gith
Original PR description
### Steps to reproduce: - Create 2 companies: c1, c2 - Create 2 storable products: P, Comp - In c1 update the available qty of P to 10 units and its cost to 50 - In c2 create a kit bom for P: 1 x…
### Steps to reproduce: - Create 2 companies: c1, c2 - Create 2 storable products: P, Comp - In c1 update the available qty of P to 10 units and its cost to 50 - In c2 create a kit bom for P: 1 x Comp - With c1 > Accounting > Review > inventory > Inventory Valuation #### > The total value of Super product is 0 instead of 500 ### Cause of the issue: The total value of the product will be set to 0 since the `qty_available` of the product is incorrectly computed to be 0: https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_account/models/product.py#L240-L243 This happens because the `_find_bom` used in the override of the `_compute_quantities_dict` in mrp does not consider take the contextual company into account: https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/mrp/models/product.py#L271-L289 and hence considers incorrectly that the product is a kit. ### Note: We make the same company dependency as in the `is_kits` computation: https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/mrp/models/product.py#L41-L47 opw-6361690 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278759 Forward-Port-Of: odoo/odoo#276306
Issue: When clicking "Send & Print" on an Ecuadorian invoice and sending the email with both the PDF and XML attachments visible in the wizard, only the PDF attachment is sent Steps to reproduce: 1. Install l10n_ec_edi and enter EC Company 2. Create and post an invoice 3. Click "Send & Print" on the invoice 4. Notice that both the XML and PDF attachments show up on the wizard, but when clicking "Send", only the PDF attachment is attached to the email that gets sent out Cause: Before
Original PR description
Issue: When clicking "Send & Print" on an Ecuadorian invoice and sending the email with both the PDF and XML attachments visible in the wizard, only the PDF attachment is sent Steps to reproduce: 1.…
Issue: When clicking "Send & Print" on an Ecuadorian invoice and sending the email with both the PDF and XML attachments visible in the wizard, only the PDF attachment is sent Steps to reproduce: 1. Install l10n_ec_edi and enter EC Company 2. Create and post an invoice 3. Click "Send & Print" on the invoice 4. Notice that both the XML and PDF attachments show up on the wizard, but when clicking "Send", only the PDF attachment is attached to the email that gets sent out Cause: Before the "Send & Print" wizard opens, the XML is already created. When opening the "Send & Print" wizard, the XML is added to the wizard with a "skip: True" flag. This is used for the wizard dropdown to add already existing attachments on the invoice. When the attachment is not selected, it makes sense to not be sent. However, when the "Send & Print" wizard opens, the attachment is added by default and the attachments in the dropdown does not consider the attachments already attached to the wizard at the start. The duplicated attachment in the dropdown has the "skip: True" flag still so it will wrongly signal later on that the attachment should not need to be sent Solution: When loading invoice attachments into the wizard, skip any attachment that is already present in the wizard's attachment list, so that default send attachments are not accidentally duplicated with the skip flag opw-6351635
# How to reproduce - Create a product with a tag that is not visible to customers - Go to the website shop page - Search for the tag's name # The issue The product & the tag are displayed even though they should be invisible to customers # Cause This commit introduced the search on tags : https://github.com/odoo/odoo/commit/9394e17a07cb125914fba137405c152bee2d7618 It did by simply adding `product_tag` to the fields searched by the autocomplete : https://github.com/odoo/odoo/blo
Original PR description
# How to reproduce - Create a product with a tag that is not visible to customers - Go to the website shop page - Search for the tag's name # The issue The product & the tag are displayed even though…
# How to reproduce - Create a product with a tag that is not visible to customers - Go to the website shop page - Search for the tag's name # The issue The product & the tag are displayed even though they should be invisible to customers # Cause This commit introduced the search on tags : https://github.com/odoo/odoo/commit/9394e17a07cb125914fba137405c152bee2d7618 It did by simply adding `product_tag` to the fields searched by the autocomplete : https://github.com/odoo/odoo/blob/9394e17a07cb125914fba137405c152bee2d7618/addons/website_sale/models/product_template.py#L901 The issue is that when building the domain to do the actual search, we simply do a big OR with an ilike search for all the searched fields : https://github.com/odoo/odoo/blob/f8d82f481b575a7a009234d9628fc8c604d0cf22/addons/website/models/mixins.py#L680-L686 # Proposed solution Move the domain creation for search fields in a new function. This allows us to override the simple ilike domain creation and create a custom domain based on the `visible_to_customers` field of tags Furthermore, we also need to prevent the invisible tags from being rendered because a product may contain visible & invisible tags opw-6357064
When an image is start-aligned, if a list is defined after it, its bullets/numbers/checkboxes are rendered on top of the image. This commit makes the bullets rendered after the image. Steps to reproduce: - Edit a website page - Drop a text page - Insert an image with `/image` - Align image to the left - Insert a bullet list or a numbered list or a checkbox list with some indented entries => Some bullets were rendered on top of the image Additionally, the start-align is neutral
Original PR description
When an image is start-aligned, if a list is defined after it, its bullets/numbers/checkboxes are rendered on top of the image. This commit makes the bullets rendered after the image. Steps to reproduce: - Edit a website page - Drop a text page - Insert an image with `/image` - Align image to the left - Insert a bullet list or a numbered list or a checkbox list with some indented entries => Some bullets were rendered on top of the image Additionally, the start-align is neutralized inside list lines because other approaches do not provide a satisfactory layout - and break further situations. task-6116437 Forward-Port-Of: odoo/odoo#260325
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category and add the route * Add the category to a product * use the repenish button -> the category route is not available on the replenishment Observation: ------------- When opening replenishment, it will open the view_product_replenish, in that view, it will use allowed_route_ids to allow us
Original PR description
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category…
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category and add the route * Add the category to a product * use the repenish button -> the category route is not available on the replenishment Observation: ------------- When opening replenishment, it will open the view_product_replenish, in that view, it will use allowed_route_ids to allow us to choose a route for this replenishment: https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/wizard/product_replenish_views.xml#L37 allowed_route_ids is compute in the mixin with the following domain: https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/models/stock_replenish_mixin.py#L18-L21 https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/models/stock_replenish_mixin.py#L25-L31 this only take into account route from the product and not the ones from the product category. https://github.com/odoo/odoo/blob/deeecf7cd02e7383b591835b0c6495e3ddead0ff/addons/stock/models/stock_location.py#L511 opw-6297308 Forward-Port-Of: odoo/odoo#271535
Before this commit, the pointerup event when doing a drag'n'drop in kanban view was containing the kanban card placeholder. Now, this placeholder isn't considered anymore to prevent unwanted target in the event. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278324
Original PR description
Before this commit, the pointerup event when doing a drag'n'drop in kanban view was containing the kanban card placeholder. Now, this placeholder isn't considered anymore to prevent unwanted target in the event. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278324
account/tests/test_audit_trail.py::TestAuditTrail.test_content was failing whenever l10n_fr_pdp was installed: posting/resetting a move produced an extra "E-Reporting Status" tracking value on top of the expected name/state ones. l10n_fr_pdp_status and l10n_fr_pdp_last_flow_id are tracked fields but are meant to be excluded from generic tracking and reported via a dedicated chatter message instead. The exclusion was implemented by overriding _message_track(), a method that no longer exi
Original PR description
account/tests/test_audit_trail.py::TestAuditTrail.test_content was failing whenever l10n_fr_pdp was installed: posting/resetting a move produced an extra "E-Reporting Status" tracking value on top of the expected name/state ones. l10n_fr_pdp_status and l10n_fr_pdp_last_flow_id are tracked fields but are meant to be excluded from generic tracking and reported via a dedicated chatter message instead. The exclusion was implemented by overriding _message_track(), a method that no longer exists in the mail tracking API (replaced by _track_get_fields()/_track_prepare() some time ago), so the override was dead code and never ran. Override _track_get_fields() instead, which is the actual hook the framework uses to build the set of auto-tracked fields. runbot error - 941346
The state_id field was not cleared when editing an address and switching to a country without states — the state selector reset visually, but the stale state_id was still saved to the backend. Steps to reproduce: 1. Add a product to the cart. 2. Go to checkout and edit the address, selecting a country that has states. 3. Edit the address again, now selecting a country without states. 4. Save and check the contact in the backend: state_id still holds the state from the previo
Original PR description
The state_id field was not cleared when editing an address and switching to a country without states — the state selector reset visually, but the stale state_id was still saved to the backend. Steps to reproduce: 1. Add a product to the cart. 2. Go to checkout and edit the address, selecting a country that has states. 3. Edit the address again, now selecting a country without states. 4. Save and check the contact in the backend: state_id still holds the state from the previous country. Solution: reset the state_id select options for the new country. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278660 Forward-Port-Of: odoo/odoo#278125
Steps to reproduce: - Edit a page. - Drop a carousel snippet like s_quotes_carousel - Click "Add Slide" with the browser console open(for concrete race condition) => Traceback: TypeError: Cannot read properties of null (reading 'classList') Cause: `slide()` used the editor window's `Carousel` instead of the iframe's. This created a second Carousel instance for the same element. Both instances updated the indicators at the same time, causing one to remove the active indicator before the
Original PR description
Steps to reproduce: - Edit a page. - Drop a carousel snippet like s_quotes_carousel - Click "Add Slide" with the browser console open(for concrete race condition) => Traceback: TypeError: Cannot read properties of null (reading 'classList') Cause: `slide()` used the editor window's `Carousel` instead of the iframe's. This created a second Carousel instance for the same element. Both instances updated the indicators at the same time, causing one to remove the active indicator before the other tried to use it, leading to the traceback. Fix: Use `this.window.Carousel` so the iframe's existing Carousel instance is reused instead of creating a second one. task-6084484 Forward-Port-Of: odoo/odoo#279117 Forward-Port-Of: odoo/odoo#275903
### Issue before this commit: 1. When generating a FatturaPA XML for a self-invoice (reverse charge / autofattura, e.g. TD17-TD19) with the "Reference" (ref) field filled in, the supplier's invoice number was placed under <DatiOrdineAcquisto> instead of <DatiFattureCollegate>. 2. When a credit note was generated from a vendor bill, the <IdDocumento> in <DatiFattureCollegate> contained Odoo's internal document number (e.g. BILL/2026/07/0002) instead of the actual reference of the invoice rece
Original PR description
### Issue before this commit: 1. When generating a FatturaPA XML for a self-invoice (reverse charge / autofattura, e.g. TD17-TD19) with the "Reference" (ref) field filled in, the supplier's invoice…
### Issue before this commit: 1. When generating a FatturaPA XML for a self-invoice (reverse charge / autofattura, e.g. TD17-TD19) with the "Reference" (ref) field filled in, the supplier's invoice number was placed under <DatiOrdineAcquisto> instead of <DatiFattureCollegate>. 2. When a credit note was generated from a vendor bill, the <IdDocumento> in <DatiFattureCollegate> contained Odoo's internal document number (e.g. BILL/2026/07/0002) instead of the actual reference of the invoice received from the supplier (ref). ### Steps to reproduce the issue: ISSUE 1: 1. Download Accounting and l10n_it 2. Go to Vendor -> Bills 3. Create a bill with: 1. Italian company as vendor 2. Product with tax 22% S RC 3. Bill reference filled (ex. FT00001) 4. Send it to SDI, open the XML and see that the tag <IdDocumento> is inside the tag <DatiOrdineAcquisto> while it sohuld be inside <Datifatturecollegate> ISSUE 2: 1. From a bill created click Credit Note 2. Send to SDI again, open the XML and see that the tag <IdDocumento> contains the bill reference created in Odoo while it should take the reference of the original invoice SENT by the vendor ### Cause of the issue: 1. The template's t-elif chain did not distinguish between self-invoices and regular documents, so any value in record.ref was routed to DatiOrdineAcquisto regardless of context. 2. Separately, the linked_moves loop always used linked_move.name to populate <IdDocumento>, which for vendor bills/refunds is Odoo's own sequential number, not the supplier's original invoice number. ### Reason to introduce the fix: 1. For the official FatturaPA Technical Specifications, DatiOrdineAcquisto must only reference a purchase order, while DatiFattureCollegate must reference a related invoice — which is the correct category for the supplier document being integrated in a self-invoice. This is confirmed by the Agenzia delle Entrate documentation: https://www.agenziaentrate.gov.it/portale/documents/d/guest/allegato-a-specifiche-tecniche-vers-1-9 (p.107, chapter Compilazione del documento XML con codice TD17) 2. For credit/debit notes, <IdDocumento> inside <DatiFattureCollegate> must contain the number of the original invoice being referenced/varied, not an internally generated document number, as clarified here: https://www.pa.sm/ticket/kb/faq.php?id=46 opw-6117968 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276523
Portal subscribe task can create tb because the task was archived before unsubscribing. opw-6397850 Forward-Port-Of: odoo/odoo#279071 Forward-Port-Of: odoo/odoo#278667
Original PR description
Portal subscribe task can create tb because the task was archived before unsubscribing. opw-6397850 Forward-Port-Of: odoo/odoo#279071 Forward-Port-Of: odoo/odoo#278667
Miscellaneous changes
Optimize search_paid_order_ids to reduce ORM overhead and resolve a database bottleneck during POS synchronization. - Move currency validation from a Python post-filter into the SQL domain via config_id.currency_id. - Split the costly OR query on pos.order.line into two targeted index scans combined via UNION, dropping execution time from ~627ms to ~16ms (~40x speedup) and reducing shared read blocks from 650k+ to zero. - Align totalCount with the exact same domain and simplify state exclus
Original PR description
Optimize search_paid_order_ids to reduce ORM overhead and resolve a database bottleneck during POS synchronization. - Move currency validation from a Python post-filter into the SQL domain via config_id.currency_id. - Split the costly OR query on pos.order.line into two targeted index scans combined via UNION, dropping execution time from ~627ms to ~16ms (~40x speedup) and reducing shared read blocks from 650k+ to zero. - Align totalCount with the exact same domain and simplify state exclusions from multiple != operators to a single not in. Explain Before: https://explain.dalibo.com/plan/84095dcgfdc158a2 Explain After: https://explain.dalibo.com/plan/ag2abcdf4ge5d5e5 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278739
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
Original PR description
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
When generating the Sales Report or Session Report with a large number of orders (1000+), the report computation could take several minutes or fail entirely with cursor closed errors. This was mainly caused by multiple inefficient ORM patterns, such as repeated searches inside nested loops and unnecessary recordset instantiations. This commit optimizes the report generation logic by: - Avoiding repeated searches inside loops (e.g. account payments per session) - Using `_search` instead of `
Original PR description
When generating the Sales Report or Session Report with a large number of orders (1000+), the report computation could take several minutes or fail entirely with cursor closed errors. This was mainly…
When generating the Sales Report or Session Report with a large number of orders (1000+), the report computation could take several minutes or fail entirely with cursor closed errors. This was mainly caused by multiple inefficient ORM patterns, such as repeated searches inside nested loops and unnecessary recordset instantiations. This commit optimizes the report generation logic by: - Avoiding repeated searches inside loops (e.g. account payments per session) - Using `_search` instead of `search` where only record ids are required - Grouping and caching session-related records (payments, moves, cash moves) - Reducing redundant ORM calls and Python-level iterations - Preserving the exact report output structure and values The returned data remains unchanged; only record ordering may differ due to optimized iteration and grouping. As a result, report generation time is significantly reduced and the report can be generated reliably even with very large order counts. task-5452734 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278843 Forward-Port-Of: odoo/odoo#241828
21 changes
Resolved issues and error corrections
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#26751
Original PR description
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#267510
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simpl
Original PR description
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simply not decremented when no message has been seen yet. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279279 Forward-Port-Of: odoo/odoo#277417
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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/su
Original PR description
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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#279418
The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead.
Original PR description
The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead. 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#279322
Problem: When adding a caption to an image, typing text, then undoing and redoing does not restore the caption content. Cause: The caption used a native `<input>` element whose content is managed by the browser, not the editor's history stack. While redo could restore the input element itself, its content was lost since the editor never tracked it. Solution: Replace the `<input>` with a `contenteditable` `<span>` so the editor manages its content as part of the DOM history, enabling ful
Original PR description
Problem: When adding a caption to an image, typing text, then undoing and redoing does not restore the caption content. Cause: The caption used a native `<input>` element whose content is managed by the browser, not the editor's history stack. While redo could restore the input element itself, its content was lost since the editor never tracked it. Solution: Replace the `<input>` with a `contenteditable` `<span>` so the editor manages its content as part of the DOM history, enabling full undo/redo. Changes: - Use a contenteditable `<span>` instead of `<input>` for caption editing - Prevent pasting HTML inside the span (plain text only) - Limit caption content to 100 characters - Disable power box, toolbar, and paragraph insertion inside the span task-6219868 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278901 Forward-Port-Of: odoo/odoo#267211
Issue: --- Adding a rating with a message on website is causing TB as the portal user doesn't have the access to send rating message. opw-6316142 Forward-Port-Of: odoo/odoo#279171 Forward-Port-Of: odoo/odoo#271833
Original PR description
Issue: --- Adding a rating with a message on website is causing TB as the portal user doesn't have the access to send rating message. opw-6316142 Forward-Port-Of: odoo/odoo#279171 Forward-Port-Of: odoo/odoo#271833
Before this commit, the composer suggestion list could re-open right after the user closed it with Escape, and the next press of Escape would then close the list again instead of being handled by the composer (e.g. discarding a reply). This happened because NavigableList was re-opened on every patch: the useEffect opening the list had `[this.props]` as dependency, and props are a new object on every render. Any unrelated re-render of the composer (e.g. triggered by a late store update) would
Original PR description
Before this commit, the composer suggestion list could re-open right after the user closed it with Escape, and the next press of Escape would then close the list again instead of being handled by the composer (e.g. discarding a reply). This happened because NavigableList was re-opened on every patch: the useEffect opening the list had `[this.props]` as dependency, and props are a new object on every render. Any unrelated re-render of the composer (e.g. triggered by a late store update) would therefore re-open the list, which would then steal the next Escape from the composer. Fix by narrowing the dependency to the content of the options, so the list only opens on mount and when a new set of options arrives. https://runbot.odoo.com/odoo/error/944571 Forward-Port-Of: odoo/odoo#279275 Forward-Port-Of: odoo/odoo#278929
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Original PR description
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history
Original PR description
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history then opens on whichever product happens to carry that id, and stays empty when none does. Steps to reproduce: - Inventory > Reporting > Stock, click a Unit Cost -> the history of that product opens, as expected - go back, click "Inventory at Date" and confirm - click that same Unit Cost -> another product's history opens, or an empty list opw-6391778 Forward-Port-Of: odoo/odoo#279116
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users & Companies > Companies and create two companies c1 and c2 3. Go to Website > Configuration > Websites and create two websites w1 with company c1 and w2 with company c2 4. Change the order of the websites so that w1 is at the top 5. Go to Website > eCommerce > Pricelists and create a pricelist pl
Original PR description
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users &…
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users & Companies > Companies and create two companies c1 and c2 3. Go to Website > Configuration > Websites and create two websites w1 with company c1 and w2 with company c2 4. Change the order of the websites so that w1 is at the top 5. Go to Website > eCommerce > Pricelists and create a pricelist pl1 in c1 assigned to w1 and pl2 in c2 assigned to w2 6. In an incognito tab, go to w1 and create a new account 7. As admin, go to Website > Configuration > Websites and change the order of the websites so that w2 is at the top 8. In an incognito tab, connect with the previously created account and go to the shop 9. An error is thrown (This error only happens when geoip works, i.e. when `_get_geoip_country_code` returns something) Issue: When geoip returns a country code, we search through all the pricelists available for that country code but some of them can be restricted to a company which raises an access error. We need to be able to access them in order to filter the ones that are not available on the current website Solution: Access all pricelists with sudo, they will be filtered out with `_is_available_on_website` opw-3574089 Forward-Port-Of: odoo/odoo#268863
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready.
Original PR description
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready. runbot-223306 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278983 Forward-Port-Of: odoo/odoo#277954
When an image is start-aligned, if a list is defined after it, its bullets/numbers/checkboxes are rendered on top of the image. This commit makes the bullets rendered after the image. Steps to reproduce: - Edit a website page - Drop a text page - Insert an image with `/image` - Align image to the left - Insert a bullet list or a numbered list or a checkbox list with some indented entries => Some bullets were rendered on top of the image Additionally, the start-align is neutral
Original PR description
When an image is start-aligned, if a list is defined after it, its bullets/numbers/checkboxes are rendered on top of the image. This commit makes the bullets rendered after the image. Steps to reproduce: - Edit a website page - Drop a text page - Insert an image with `/image` - Align image to the left - Insert a bullet list or a numbered list or a checkbox list with some indented entries => Some bullets were rendered on top of the image Additionally, the start-align is neutralized inside list lines because other approaches do not provide a satisfactory layout - and break further situations. task-6116437 Forward-Port-Of: odoo/odoo#260325
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category and add the route * Add the category to a product * use the repenish button -> the category route is not available on the replenishment Observation: ------------- When opening replenishment, it will open the view_product_replenish, in that view, it will use allowed_route_ids to allow us
Original PR description
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category…
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category and add the route * Add the category to a product * use the repenish button -> the category route is not available on the replenishment Observation: ------------- When opening replenishment, it will open the view_product_replenish, in that view, it will use allowed_route_ids to allow us to choose a route for this replenishment: https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/wizard/product_replenish_views.xml#L37 allowed_route_ids is compute in the mixin with the following domain: https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/models/stock_replenish_mixin.py#L18-L21 https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/models/stock_replenish_mixin.py#L25-L31 this only take into account route from the product and not the ones from the product category. https://github.com/odoo/odoo/blob/deeecf7cd02e7383b591835b0c6495e3ddead0ff/addons/stock/models/stock_location.py#L511 opw-6297308 Forward-Port-Of: odoo/odoo#271535
Before this commit, the pointerup event when doing a drag'n'drop in kanban view was containing the kanban card placeholder. Now, this placeholder isn't considered anymore to prevent unwanted target in the event. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278324
Original PR description
Before this commit, the pointerup event when doing a drag'n'drop in kanban view was containing the kanban card placeholder. Now, this placeholder isn't considered anymore to prevent unwanted target in the event. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278324
The state_id field was not cleared when editing an address and switching to a country without states — the state selector reset visually, but the stale state_id was still saved to the backend. Steps to reproduce: 1. Add a product to the cart. 2. Go to checkout and edit the address, selecting a country that has states. 3. Edit the address again, now selecting a country without states. 4. Save and check the contact in the backend: state_id still holds the state from the previo
Original PR description
The state_id field was not cleared when editing an address and switching to a country without states — the state selector reset visually, but the stale state_id was still saved to the backend. Steps to reproduce: 1. Add a product to the cart. 2. Go to checkout and edit the address, selecting a country that has states. 3. Edit the address again, now selecting a country without states. 4. Save and check the contact in the backend: state_id still holds the state from the previous country. Solution: reset the state_id select options for the new country. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278660 Forward-Port-Of: odoo/odoo#278125
Steps to reproduce: - Edit a page. - Drop a carousel snippet like s_quotes_carousel - Click "Add Slide" with the browser console open(for concrete race condition) => Traceback: TypeError: Cannot read properties of null (reading 'classList') Cause: `slide()` used the editor window's `Carousel` instead of the iframe's. This created a second Carousel instance for the same element. Both instances updated the indicators at the same time, causing one to remove the active indicator before the
Original PR description
Steps to reproduce: - Edit a page. - Drop a carousel snippet like s_quotes_carousel - Click "Add Slide" with the browser console open(for concrete race condition) => Traceback: TypeError: Cannot read properties of null (reading 'classList') Cause: `slide()` used the editor window's `Carousel` instead of the iframe's. This created a second Carousel instance for the same element. Both instances updated the indicators at the same time, causing one to remove the active indicator before the other tried to use it, leading to the traceback. Fix: Use `this.window.Carousel` so the iframe's existing Carousel instance is reused instead of creating a second one. task-6084484 Forward-Port-Of: odoo/odoo#279117 Forward-Port-Of: odoo/odoo#275903
### Issue before this commit: 1. When generating a FatturaPA XML for a self-invoice (reverse charge / autofattura, e.g. TD17-TD19) with the "Reference" (ref) field filled in, the supplier's invoice number was placed under <DatiOrdineAcquisto> instead of <DatiFattureCollegate>. 2. When a credit note was generated from a vendor bill, the <IdDocumento> in <DatiFattureCollegate> contained Odoo's internal document number (e.g. BILL/2026/07/0002) instead of the actual reference of the invoice rece
Original PR description
### Issue before this commit: 1. When generating a FatturaPA XML for a self-invoice (reverse charge / autofattura, e.g. TD17-TD19) with the "Reference" (ref) field filled in, the supplier's invoice…
### Issue before this commit: 1. When generating a FatturaPA XML for a self-invoice (reverse charge / autofattura, e.g. TD17-TD19) with the "Reference" (ref) field filled in, the supplier's invoice number was placed under <DatiOrdineAcquisto> instead of <DatiFattureCollegate>. 2. When a credit note was generated from a vendor bill, the <IdDocumento> in <DatiFattureCollegate> contained Odoo's internal document number (e.g. BILL/2026/07/0002) instead of the actual reference of the invoice received from the supplier (ref). ### Steps to reproduce the issue: ISSUE 1: 1. Download Accounting and l10n_it 2. Go to Vendor -> Bills 3. Create a bill with: 1. Italian company as vendor 2. Product with tax 22% S RC 3. Bill reference filled (ex. FT00001) 4. Send it to SDI, open the XML and see that the tag <IdDocumento> is inside the tag <DatiOrdineAcquisto> while it sohuld be inside <Datifatturecollegate> ISSUE 2: 1. From a bill created click Credit Note 2. Send to SDI again, open the XML and see that the tag <IdDocumento> contains the bill reference created in Odoo while it should take the reference of the original invoice SENT by the vendor ### Cause of the issue: 1. The template's t-elif chain did not distinguish between self-invoices and regular documents, so any value in record.ref was routed to DatiOrdineAcquisto regardless of context. 2. Separately, the linked_moves loop always used linked_move.name to populate <IdDocumento>, which for vendor bills/refunds is Odoo's own sequential number, not the supplier's original invoice number. ### Reason to introduce the fix: 1. For the official FatturaPA Technical Specifications, DatiOrdineAcquisto must only reference a purchase order, while DatiFattureCollegate must reference a related invoice — which is the correct category for the supplier document being integrated in a self-invoice. This is confirmed by the Agenzia delle Entrate documentation: https://www.agenziaentrate.gov.it/portale/documents/d/guest/allegato-a-specifiche-tecniche-vers-1-9 (p.107, chapter Compilazione del documento XML con codice TD17) 2. For credit/debit notes, <IdDocumento> inside <DatiFattureCollegate> must contain the number of the original invoice being referenced/varied, not an internally generated document number, as clarified here: https://www.pa.sm/ticket/kb/faq.php?id=46 opw-6117968 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276523
Portal subscribe task can create tb because the task was archived before unsubscribing. opw-6397850 Forward-Port-Of: odoo/odoo#279071 Forward-Port-Of: odoo/odoo#278667
Original PR description
Portal subscribe task can create tb because the task was archived before unsubscribing. opw-6397850 Forward-Port-Of: odoo/odoo#279071 Forward-Port-Of: odoo/odoo#278667
Description of the issue this commit addresses: The settlement tour expects an invoice named with the year 2026. On time-shifted test instances, invoices use a later year, so the tour cannot find the invoice and fails at the settlement selection step. --- Desired behavior after this commit is merged: This commit matches settlement invoices using the stable journal prefix, so the tour works regardless of the year in which it runs. --- runbot-[242206](https://runbot.odoo.com/odoo
Original PR description
Description of the issue this commit addresses: The settlement tour expects an invoice named with the year 2026. On time-shifted test instances, invoices use a later year, so the tour cannot find the invoice and fails at the settlement selection step. --- Desired behavior after this commit is merged: This commit matches settlement invoices using the stable journal prefix, so the tour works regardless of the year in which it runs. --- runbot-[242206](https://runbot.odoo.com/odoo/error/242206) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278573
Miscellaneous changes
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
Original PR description
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
Steps to reproduce: ------------------------- 1. Install hr_holidays. 2. Create a time off type with "Custom Hours" as the duration type and "Considered as" set to "Working Time". 3. Create a multi-day time off request for an employee with a standard working schedule. 4. Check the computed duration. Issue: -------- The duration is 32 hours instead of the expected 16 hours. Cause: ---------- https://github.com/odoo/odoo/blob/c0d737142f3a0a385163eb8d075ca71d63913b68/addons/hr_holid
Original PR description
Steps to reproduce: ------------------------- 1. Install hr_holidays. 2. Create a time off type with "Custom Hours" as the duration type and "Considered as" set to "Working Time". 3. Create a…
Steps to reproduce: ------------------------- 1. Install hr_holidays. 2. Create a time off type with "Custom Hours" as the duration type and "Considered as" set to "Working Time". 3. Create a multi-day time off request for an employee with a standard working schedule. 4. Check the computed duration. Issue: -------- The duration is 32 hours instead of the expected 16 hours. Cause: ---------- https://github.com/odoo/odoo/blob/c0d737142f3a0a385163eb8d075ca71d63913b68/addons/hr_holidays/models/hr_leave.py#L621-L623 For hourly time off types considered as working time, the duration was computed from the raw datetime difference between `date_from` and `date_to`. This bypassed the existing working schedule computation and included hours outside the employee's working schedule. Solution: ------------ Remove this logic and let the duration fall back to the working schedule-based computation. **NOTE:** This issue has been resolved in saas-19.4 with this [commit](https://github.com/odoo/odoo/commit/53672fdca597644a2b675ce887042ef640073d4f) opw-6385683 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
22 changes
Resolved issues and error corrections
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used
Original PR description
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used while preserving the existing validation against empty or whitespace-only names. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279365 Forward-Port-Of: odoo/odoo#273593
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired Connection
Original PR description
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired ConnectionToken. Move reader discovery to `connectReader()` so Odoo connects using fresh discovery results, and stop discovering readers eagerly when creating the Stripe Terminal instance. opw-6311626 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277765 Forward-Port-Of: odoo/odoo#276875
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Inventory > Configuration > Warehouse Management > Warehouses - Set your warehouse deliveries in two steps - Inventory > Operations > Tranfers > Internal > New - Set the operation type as Pick, set a partner and add Partner: Bob - In the sales & Purchase tab of the partner form set a customer location to be a child of the Customers location: Customers/Bob'Stock - Confirm and validate the Pick for 1 unit of a product
Original PR description
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Inventory > Configuration > Warehouse Management > Warehouses - Set your warehouse deliveries in two steps - Inventory >…
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Inventory > Configuration > Warehouse Management > Warehouses - Set your warehouse deliveries in two steps - Inventory > Operations > Tranfers > Internal > New - Set the operation type as Pick, set a partner and add Partner: Bob - In the sales & Purchase tab of the partner form set a customer location to be a child of the Customers location: Customers/Bob'Stock - Confirm and validate the Pick for 1 unit of a product P #### > A ship picking is created but the destination of the related move is still set to the default customer location. ### Note: If the flow is performed by a sale order, the `property_stock_customer` location will appropriately be used as `location_final_id`: https://github.com/odoo/odoo/blob/7609b5805c3704034b4d7813e2f356381ed18771/addons/sale_stock/models/sale_order_line.py#L297 https://github.com/odoo/odoo/blob/7609b5805c3704034b4d7813e2f356381ed18771/addons/sale_stock/models/sale_order_line.py#L306-L309 https://github.com/odoo/odoo/blob/720598d0315dbb91628441078febfd43ffefb431/addons/stock/models/stock_rule.py#L263-L264 So that the bug does not occur in that case. By contrast if the pick move is created manually, we do not set its `location_final_id` and hence do not propagate the info. Even though it looks expected to be set set as location_dest_id of the ship move sas suggested by the `stock.picking.location_dest_id` compute method : https://github.com/odoo/odoo/blob/fe3aea07a1964cd24f4c8ebf2bc93e483eca6b0b/addons/stock/models/stock_picking.py#L990-L1002 opw-6402483 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278838
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#26751
Original PR description
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#267510
Once the cron is called to update current_version_id, the new employee calendar is applied to the previous version as well, due to the inverse on resource.resource def _inverse_calendar_id(self): for resource in self: if resource.calendar_id != resource.employee_id.resource_calendar_id: resource.employee_id.resource_calendar_id = resource.calendar_id All that because the introduced piece of code was called before super if 'current_versi
Original PR description
Once the cron is called to update current_version_id, the new employee calendar is applied to the previous version as well, due to the inverse on resource.resource
def _inverse_calendar_id(self):
for resource in self:
if resource.calendar_id != resource.employee_id.resource_calendar_id:
resource.employee_id.resource_calendar_id = resource.calendar_id
All that because the introduced piece of code was called before super
if 'current_version_id' in vals:
new_version = self.env['hr.version'].browse(vals.get('current_version_id'))
self.resource_id.calendar_id = new_version.resource_calendar_id
And this the inverse method was called on the previous version (not yet updated), not the new one.
Forward-Port-Of: odoo/odoo#279048Issue: --- Adding a rating with a message on website is causing TB as the portal user doesn't have the access to send rating message. opw-6316142 Forward-Port-Of: odoo/odoo#279171 Forward-Port-Of: odoo/odoo#271833
Original PR description
Issue: --- Adding a rating with a message on website is causing TB as the portal user doesn't have the access to send rating message. opw-6316142 Forward-Port-Of: odoo/odoo#279171 Forward-Port-Of: odoo/odoo#271833
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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/su
Original PR description
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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#279418
Allow to add the district node for the peruvian electronic invoicing. opw-6282314 Forward-Port-Of: odoo/odoo#271364
Original PR description
Allow to add the district node for the peruvian electronic invoicing. opw-6282314 Forward-Port-Of: odoo/odoo#271364
The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead.
Original PR description
The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead. 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#279322
to reproduce: ============= - Have a database with a large number of kit BoMs (e.g. ~160k phantom mrp.bom records). - Open Inventory Valuation. - The request never returns and hangs forever. problem: ======== Commit 11e9c1297439 started searching the valued products with `('qty_available', '!=', 0)`. On `product.product` this triggers the mrp override `_search_qty_available_new`, which loads every phantom BoM in the database and computes `qty_available` (via BoM explode) for each
Original PR description
to reproduce: ============= - Have a database with a large number of kit BoMs (e.g. ~160k phantom mrp.bom records). - Open Inventory Valuation. - The request never returns and hangs forever. problem:…
to reproduce:
=============
- Have a database with a large number of kit BoMs (e.g. ~160k phantom
mrp.bom records).
- Open Inventory Valuation.
- The request never returns and hangs forever.
problem:
========
Commit 11e9c1297439 started searching the valued products with
`('qty_available', '!=', 0)`. On `product.product` this triggers the mrp
override `_search_qty_available_new`, which loads every phantom BoM in the
database and computes `qty_available` (via BoM explode) for each kit. On top
of that, the override builds the kit products recordset with repeated
`kit_products |= ...` unions, which is O(n^2). With a large catalog of kits
the combination of O(n) heavy explodes and O(n^2) unions never returns.
On top of the performance issue, the new search dropped the kit exclusion
that `_get_accounts_by_product` previously applied through
`_get_valuation_product_domain` (`('is_kits', '=', False)` in mrp_account),
so phantom products - which are never valued on their own - were wrongly
pulled into the valuation.
solution:
=========
Restore the kit exclusion: search the valued products through
`_get_valuation_product_domain()` (which adds `('is_kits', '=', False)` in
mrp_account) instead of the ad-hoc `('is_storable', '=', True)` domain, so
phantom products are no longer valued.
Add a `skip_kit_qty_available` context key on `_search_qty_available_new` so
callers that intentionally exclude kits can skip the costly kit BoM expansion
and return the base (quant-based) result directly. The key is set in
mrp_account (via `_get_valuation_product_context`), alongside the domain that
already excludes kits, so the optimization and its precondition stay in the
same layer.
Also make the remaining kit path in `_search_qty_available_new` scale: build
the kit products recordset in a single pass instead of O(n^2) recordset
unions, and use a set for membership checks.
Benchmark:
==========
for `_get_report_data()` (averaged over 5 runs):
| # Input data (phantom kits) | Before PR | After PR |
| :---: | :---: | :---: |
| 1,000 | 2.558 s | 35.5 ms |
| 5,000 | 10.991 s | 41.6 ms |
| 10,000 | 20.869 s | 66.0 ms |
| 25,000 | 61.807 s | 80.7 ms |
| 50,000 | 195.382 s | 87.9 ms |
the improvement is **~99% faster**
opw-6312168
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273982In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Original PR description
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Issue: Hourly Time Off requests can keep the hours computed for the previous request date after the user changes the date when using custom working hours. Steps to reproduce: - Configure an employee schedule with Wednesday 07:30-16:15 and Thursday 07:30-16:30. - Create an hourly Time Off request on Wednesday (extra hours), Observe the hours are from 07:30-16:15. - Change the request date to Monday, Observe the hours will still be from 07:30-16:15 not 07:30-16:30. Cause: This was intro
Original PR description
Issue: Hourly Time Off requests can keep the hours computed for the previous request date after the user changes the date when using custom working hours. Steps to reproduce: - Configure an employee…
Issue: Hourly Time Off requests can keep the hours computed for the previous request date after the user changes the date when using custom working hours. Steps to reproduce: - Configure an employee schedule with Wednesday 07:30-16:15 and Thursday 07:30-16:30. - Create an hourly Time Off request on Wednesday (extra hours), Observe the hours are from 07:30-16:15. - Change the request date to Monday, Observe the hours will still be from 07:30-16:15 not 07:30-16:30. Cause: This was introduced by this commit https://github.com/odoo/odoo/commit/acc03a1d890d2e8bd39e1506475df4c917697111 https://github.com/odoo/odoo/blob/3592b7826ca0c7c30511705e3282dd2c39a901ac/addons/hr_holidays/models/hr_leave.py#L255-L273 preserves non-empty `request_hour_from/request_hour_to` on hourly requests, but no date onchange refreshes those values when they were calendar defaults for the previous date, so it skipped recomputing `request_hour_from/request_hour_to` whenever `request_unit_hours` was set and both hour fields already had values, treating auto filled schedule hours as manual values. Solution: Add a request date onchange to recompute hourly defaults from the new date schedule, while preserving manually selected hours when they differ from the previous calendar default. opw-6259899 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271582
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history
Original PR description
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history then opens on whichever product happens to carry that id, and stays empty when none does. Steps to reproduce: - Inventory > Reporting > Stock, click a Unit Cost -> the history of that product opens, as expected - go back, click "Inventory at Date" and confirm - click that same Unit Cost -> another product's history opens, or an empty list opw-6391778 Forward-Port-Of: odoo/odoo#279116
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users & Companies > Companies and create two companies c1 and c2 3. Go to Website > Configuration > Websites and create two websites w1 with company c1 and w2 with company c2 4. Change the order of the websites so that w1 is at the top 5. Go to Website > eCommerce > Pricelists and create a pricelist pl
Original PR description
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users &…
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users & Companies > Companies and create two companies c1 and c2 3. Go to Website > Configuration > Websites and create two websites w1 with company c1 and w2 with company c2 4. Change the order of the websites so that w1 is at the top 5. Go to Website > eCommerce > Pricelists and create a pricelist pl1 in c1 assigned to w1 and pl2 in c2 assigned to w2 6. In an incognito tab, go to w1 and create a new account 7. As admin, go to Website > Configuration > Websites and change the order of the websites so that w2 is at the top 8. In an incognito tab, connect with the previously created account and go to the shop 9. An error is thrown (This error only happens when geoip works, i.e. when `_get_geoip_country_code` returns something) Issue: When geoip returns a country code, we search through all the pricelists available for that country code but some of them can be restricted to a company which raises an access error. We need to be able to access them in order to filter the ones that are not available on the current website Solution: Access all pricelists with sudo, they will be filtered out with `_is_available_on_website` opw-3574089 Forward-Port-Of: odoo/odoo#268863
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready.
Original PR description
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready. runbot-223306 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278983 Forward-Port-Of: odoo/odoo#277954
Preparation printing from mobile self ordering was made by sending a notification in the bus to the PoS. This logic was removed in odoo/odoo#265569, we reintroduce it to allow printing again.
Original PR description
Preparation printing from mobile self ordering was made by sending a notification in the bus to the PoS. This logic was removed in odoo/odoo#265569, we reintroduce it to allow printing again.
Steps to reproduce: - Open any PoS session - Click on Orders and filter by "Paid" orders - Select an order and click on "Details" - Open the "Payments" tab and click on the "View" button of a payment - Click on the payment method link Traceback: OwlError: The following error occurred in onWillStart: "Cannot find key "pos_payment_provider_cards" in the "view_widgets" registry" Backend views opened from within the PoS UI (order details dialog, drill-down on many2one links, ...) share t
Original PR description
Steps to reproduce: - Open any PoS session - Click on Orders and filter by "Paid" orders - Select an order and click on "Details" - Open the "Payments" tab and click on the "View" button of a payment…
Steps to reproduce: - Open any PoS session - Click on Orders and filter by "Paid" orders - Select an order and click on "Details" - Open the "Payments" tab and click on the "View" button of a payment - Click on the payment method link Traceback: OwlError: The following error occurred in onWillStart: "Cannot find key "pos_payment_provider_cards" in the "view_widgets" registry" Backend views opened from within the PoS UI (order details dialog, drill-down on many2one links, ...) share their arch with the backend, but `point_of_sale._assets_pos` excludes everything under `static/src/backend/`, so widgets defined there (e.g. `pos_payment_provider_cards`, `lna_checklist`, `point_of_sale_test_epos`) are never registered in the PoS UI. Unlike missing field widgets, which fall back to the default widget with a warning, an unknown `<widget>` node makes the whole view crash since `Widget.parseWidgetNode` reads the registry without a fallback. Those widgets are backend configuration helpers that are irrelevant in a PoS session, so instead of bundling each of them (and any future one) in the PoS assets, patch `Widget.parseWidgetNode` in the PoS bundle to skip unknown widgets with a warning, like missing field widgets do. This covers the form, list and kanban arch parsers at once. opw-6382156 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276912
In a MO for a product tracked by serial number, when changing the serial number after confirming the mo, it will silently assign a serial number. **Steps to reproduce** * Create three products: - "Component" - "Final" with a bom containing "Component" and tracked by Serial number - "Setup" with a bom containing "Final" * Create and confirm a MO for "Setup" - assign the serial number "PROD" to "Final" * Produce "Setup" * Create and confirm a MO for "Final" * Generate a seria
Original PR description
In a MO for a product tracked by serial number, when changing the serial number after confirming the mo, it will silently assign a serial number. **Steps to reproduce** * Create three products: -…
In a MO for a product tracked by serial number, when changing the serial number after confirming the mo, it will silently assign a serial number. **Steps to reproduce** * Create three products: - "Component" - "Final" with a bom containing "Component" and tracked by Serial number - "Setup" with a bom containing "Final" * Create and confirm a MO for "Setup" - assign the serial number "PROD" to "Final" * Produce "Setup" * Create and confirm a MO for "Final" * Generate a serial number * Clear the serial number * Generate a new serial number * Produce "Final" -> In Product Moves you can see that the serial number assign was "PROD" **Observation** First when creating the MO, it will create a stock move for "final" and create a stock move line without assigning any quant. action_confirm -> _action_assign https://github.com/odoo/odoo/blob/ff0dd8fcc8dfbb5e5cb798c90d68be41d56b7b4c/addons/stock/models/stock_move.py#L1643-L1646 In _action_assign it will bypass_reservation since the location is "production": https://github.com/odoo/odoo/blob/ff0dd8fcc8dfbb5e5cb798c90d68be41d56b7b4c/addons/stock/models/stock_move.py#L1948 https://github.com/odoo/odoo/blob/ff0dd8fcc8dfbb5e5cb798c90d68be41d56b7b4c/addons/stock/models/stock_location.py#L411-L413 and create the sml: https://github.com/odoo/odoo/blob/e8aa9219e3c72a987f431e47a1534f9ccb0028b2/addons/stock/models/stock_move.py#L2048 When adding the Serial number it will be added to lot_producing_ids, set qty_producing and call set_qty_producing ->_set_quantity_done -> _set_quantity_done_prepare_vals: https://github.com/odoo/odoo/blob/e8aa9219e3c72a987f431e47a1534f9ccb0028b2/addons/mrp/models/mrp_production.py#L1593-L1597 In set_qty_producing->_set_quantity_done ->_set_quantity_done_prepare_vals nothing will be done since there already is a stock move line with the right quantity: https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/stock/models/stock_move.py#L2368-L2371 Second when clearing the Serial number it will call action_clear_lot_producing_ids, where it will - Erase the lot from lot_producing_ids - Set qty_producing to 0 - and call _set_qty_producing _set_qty_producing -> _set_quantity_done -> _set_quantity_done_prepare_vals: where it will erase the stock move line since it's new quantity is 0: https://github.com/odoo/odoo/blob/e8aa9219e3c72a987f431e47a1534f9ccb0028b2/addons/stock/models/stock_move.py#L2353-L2355 Lastly this means that when add in the new lot, it will not already have a stock move line, and it will create a new stock move line based on available quants: https://github.com/odoo/odoo/blob/3a088e23d3e563c39cdcb252edc8c7cc74981de4/addons/stock/models/stock_move.py#L2392-L2402 The lot_ids on the moves is supposed the get assigned when we produce the product: https://github.com/odoo/odoo/blob/e8aa9219e3c72a987f431e47a1534f9ccb0028b2/addons/mrp/models/mrp_production.py#L1911-L1913 opw-6240857 Forward-Port-Of: odoo/odoo#268542
When an image is start-aligned, if a list is defined after it, its bullets/numbers/checkboxes are rendered on top of the image. This commit makes the bullets rendered after the image. Steps to reproduce: - Edit a website page - Drop a text page - Insert an image with `/image` - Align image to the left - Insert a bullet list or a numbered list or a checkbox list with some indented entries => Some bullets were rendered on top of the image Additionally, the start-align is neutral
Original PR description
When an image is start-aligned, if a list is defined after it, its bullets/numbers/checkboxes are rendered on top of the image. This commit makes the bullets rendered after the image. Steps to reproduce: - Edit a website page - Drop a text page - Insert an image with `/image` - Align image to the left - Insert a bullet list or a numbered list or a checkbox list with some indented entries => Some bullets were rendered on top of the image Additionally, the start-align is neutralized inside list lines because other approaches do not provide a satisfactory layout - and break further situations. task-6116437 Forward-Port-Of: odoo/odoo#260325
Description of the issue this commit addresses: The settlement tour expects an invoice named with the year 2026. On time-shifted test instances, invoices use a later year, so the tour cannot find the invoice and fails at the settlement selection step. --- Desired behavior after this commit is merged: This commit matches settlement invoices using the stable journal prefix, so the tour works regardless of the year in which it runs. --- runbot-[242206](https://runbot.odoo.com/odoo
Original PR description
Description of the issue this commit addresses: The settlement tour expects an invoice named with the year 2026. On time-shifted test instances, invoices use a later year, so the tour cannot find the invoice and fails at the settlement selection step. --- Desired behavior after this commit is merged: This commit matches settlement invoices using the stable journal prefix, so the tour works regardless of the year in which it runs. --- runbot-[242206](https://runbot.odoo.com/odoo/error/242206) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278573
Miscellaneous changes
Backport of [1]. Builder image tests were flaky in full-suite runs because earlier tests left slow requests pending. Bogus snippet thumbnails, obsolete modify_image mock data, and made-up attachment URLs triggered expensive website 404 rendering and starved the browser connection pool. Avoid rendering missing thumbnails, use data URIs or existing static images in fixtures, return the current modify_image response shape, and give the CORS test image explicit dimensions. [1]: https://gith
Original PR description
Backport of [1]. Builder image tests were flaky in full-suite runs because earlier tests left slow requests pending. Bogus snippet thumbnails, obsolete modify_image mock data, and made-up attachment URLs triggered expensive website 404 rendering and starved the browser connection pool. Avoid rendering missing thumbnails, use data URIs or existing static images in fixtures, return the current modify_image response shape, and give the CORS test image explicit dimensions. [1]: https://github.com/odoo/odoo/pull/277424 Forward-Port-Of: odoo/odoo#279314
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
Original PR description
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
6 changes
Resolved issues and error corrections
This commit fix the regex used in `street_split` to be more complient. Before: address format was "street_name street_number - street_number2" Now, street_number can be in front of street_name. Format is also less strict, allowing multiple numbers in the street_name without skipping the building number. Linked: https://github.com/odoo/enterprise/pull/121674 task-6317758 Forward-Port-Of: odoo/odoo#271855
Original PR description
This commit fix the regex used in `street_split` to be more complient. Before: address format was "street_name street_number - street_number2" Now, street_number can be in front of street_name. Format is also less strict, allowing multiple numbers in the street_name without skipping the building number. Linked: https://github.com/odoo/enterprise/pull/121674 task-6317758 Forward-Port-Of: odoo/odoo#271855
- `s_three_columns` cards could end up with mismatched heights: `equalizeCardHeights` now measures header height directly instead of deriving it from the already-stretched card container. - Links appeared with a black background: exclude `btn-link` from background-color application. - Background images didn't stretch: pass `preserve_comments` so the DPI-scaling fix comment isn't stripped from the sent email. opw-6044725 --- I confirm I have signed the CLA and read the PR guidelines at w
Original PR description
- `s_three_columns` cards could end up with mismatched heights: `equalizeCardHeights` now measures header height directly instead of deriving it from the already-stretched card container. - Links appeared with a black background: exclude `btn-link` from background-color application. - Background images didn't stretch: pass `preserve_comments` so the DPI-scaling fix comment isn't stripped from the sent email. opw-6044725 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279196 Forward-Port-Of: odoo/odoo#278862
**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088
Original PR description
**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088642d7699b3e033c1fcc2564, so this is essentially a backport for that fix. opw-6344750 Forward-Port-Of: odoo/odoo#276536
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, an
Original PR description
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the…
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, and stock.picking.group_id is a stored related on move_ids.group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/stock/models/stock_picking.py#L186). A single picking can therefore only resolve to one SO. _create_picking (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order.py#L290) builds one picking per PO and _prepare_stock_moves assigns every move the merged PO's group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order_line.py#L307), so when a merged dropship PO carries lines from multiple SOs every move lands in one picking under the PO group. Only one SO gets linked and the others stay "not fully delivered" even after validation. Solution Override PurchaseOrderLine._prepare_stock_moves to set group_id to the SO's procurement_group_id when sale_line_id is set, so each dropship move is created in its originating SO's procurement group. Override PurchaseOrder._create_picking to detect dropship POs whose order lines span more than one SO and create one picking per SO group by calling _prepare_picking and _create_stock_moves per group. picking.group_id then resolves to the SO group via the stored related field, picking.sale_id points to the right SO, and delivery_status updates correctly on validation. opw-6094608 Forward-Port-Of: odoo/odoo#257823
Before this commit, the unread banner could stop showing in a channel until it was left and opened again: - open a channel with unread messages - click "Mark as Read" - read the same channel from another device - receive a new message: the server counter increases, still no banner This happens because an implicit mark as read freezes the local unread state, so the banner stays in place while the user reads. The problem is that it stays frozen even after the banner is gone, and never fol
Original PR description
Before this commit, the unread banner could stop showing in a channel until it was left and opened again: - open a channel with unread messages - click "Mark as Read" - read the same channel from another device - receive a new message: the server counter increases, still no banner This happens because an implicit mark as read freezes the local unread state, so the banner stays in place while the user reads. The problem is that it stays frozen even after the banner is gone, and never follows the server counter again. This commit freezes that state only while something is still unread locally. This also fixes the flaky test "no unread message banner after message is deleted". https://runbot.odoo.com/odoo/error/242776 Forward-Port-Of: odoo/odoo#279195
## Problem `pttExtensionHookService` registers a global `window.addEventListener("message", ...)` handler that reads `data.from` without checking that `data` is defined first: ```js browser.addEventListener("message", ({ data, origin, source }) => { const rtc = env.services["discuss.rtc"]; if ( source !== window || origin !== location.origin || data.from !== "discuss-push-to-talk" || // <- crashes if data is undefined (!rtc && data.type !== "answer-is-
Original PR description
## Problem `pttExtensionHookService` registers a global `window.addEventListener("message", ...)` handler that reads `data.from` without checking that `data` is defined first: ```js…
## Problem
`pttExtensionHookService` registers a global `window.addEventListener("message", ...)`
handler that reads `data.from` without checking that `data` is defined first:
```js
browser.addEventListener("message", ({ data, origin, source }) => {
const rtc = env.services["discuss.rtc"];
if (
source !== window ||
origin !== location.origin ||
data.from !== "discuss-push-to-talk" || // <- crashes if data is undefined
(!rtc && data.type !== "answer-is-enabled")
) {
return;
}
...
```
Any same-window, same-origin `postMessage` sent by an unrelated browser
extension (a common content-script <-> injected-script pattern) can carry
`data === undefined`. The `source !== window` and `origin !== location.origin`
checks only filter out cross-window/cross-origin messages, so a same-origin
message from any other extension reaches this handler and crashes with:
```
TypeError: Cannot read properties of undefined (reading 'from')
```
This surfaces as an uncaught client error on any page with Discuss loaded,
after some time, unrelated to what the user is doing. The Discuss
push-to-talk extension itself does not need to be installed to trigger it,
since the crash happens before checking whether the message actually
originated from that extension.
## Solution
Use optional chaining (`data?.from`) so unrelated same-origin messages with
no `data` are safely ignored instead of crashing.
## Verification
- Reproduced against the live production `web.assets_web.min.js` bundle
(traceback matches exactly).
- Confirmed the bug is still present in the latest `18.0` of both `OCA/OCB`
and `odoo/odoo` (no newer commit touches this file since
`dc58ef1ad904`, which fixes an unrelated issue).
Forward-Port-Of: odoo/odoo#2794761 change
Resolved issues and error corrections
Use "VAT" instead of "TAX" for the default UK tax groups. Also set "Subtotal" as their preceding subtotal label so that it replaces "Untaxed Amount". task-[6413495](https://www.odoo.com/odoo/project/967/tasks/6413495) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Use "VAT" instead of "TAX" for the default UK tax groups. Also set "Subtotal" as their preceding subtotal label so that it replaces "Untaxed Amount". task-[6413495](https://www.odoo.com/odoo/project/967/tasks/6413495) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
3 changes
Resolved issues and error corrections
When we create a database with `-i web --skip-auto-install`, we run into CSS compilation errors due to undefined variables `$black` and `$gray-200`. This commit adds these two definitions. opw-6398398
Original PR description
When we create a database with `-i web --skip-auto-install`, we run into CSS compilation errors due to undefined variables `$black` and `$gray-200`. This commit adds these two definitions. opw-6398398
Currently, users encounter a traceback when attempting to print the traceability report for a manufacturing order. ## Steps to produce: - Install Manufacturing without demo data. - Enable Lots & Serial Numbers in Settings. - Create two products: Car and Engine. - Configure Engine to use Unique Serial Number tracking (Inventory →Traceability). - Set the on-hand quantity of Engine to 1 with serial number 0001. - Create a BoM for Car using Engine as a component. - Create and confirm a man
Original PR description
Currently, users encounter a traceback when attempting to print the traceability report for a manufacturing order. ## Steps to produce: - Install Manufacturing without demo data. - Enable Lots &…
Currently, users encounter a traceback when attempting to print the traceability report for a manufacturing order. ## Steps to produce: - Install Manufacturing without demo data. - Enable Lots & Serial Numbers in Settings. - Create two products: Car and Engine. - Configure Engine to use Unique Serial Number tracking (Inventory →Traceability). - Set the on-hand quantity of Engine to 1 with serial number 0001. - Create a BoM for Car using Engine as a component. - Create and confirm a manufacturing order for Car. - Click `Consumed` for the component and click Produce All. - Navigate to Lots & Serial Numbers → Engine → 0001 → Traceability. - Click the arrow next to the manufacturing order reference, then click Print. ## Observed Behavior: An `Arbitrary Uncaught Python Exception` traceback is raised, resulting in a 404 error. ## Root Cause: This issue occurs because, when the user clicks the arrow button in the traceability report, the template [1] invokes the `onClickUpDownStream` function. This function adds the URL `/stock/output_format/stock/active_id` to the context , as shown in [2]. Later, when the user clicks the Print button, `onClickPrint()` [3] constructs the print URL using the `controllerUrl` value by replacing the active model and active ID placeholders with values from the context. However, the URL stored in the context contains `/active_id` instead of `:active_id`. As a result, the placeholder replacement does not occur, leaving the URL unchanged. This causes the print action to use an invalid URL, ultimately resulting in a 404 error. As shown in [4], `controllerUrl` is assigned directly from the context. [1]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.xml#L52-L56 [2]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.js#L105-L118 [3]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.js#L120-L131 [4]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.js#L53-L55 ## Solution: Pass the correct URL in the context so that the active ID placeholder can be replaced correctly during the print action. This ensures that the generated print URL is valid, allowing the user to print the report without encountering any errors. opw-6372834
Current behaviour: In the Calendar view (day/week/month scale), when the user's timezone observes a DST transition that starts exactly at local midnight (e.g. Africa/Cairo, since 2023), the day column right after the transition gets the wrong weekday name, duplicating the previous day's name. For ex. it renders "... THU THU FRI ..." instead of "... THU FRI SAT ...", for the week surrounding April 30th 2027. To fix this we add 1 hour to the Date before reading its weekday/day from it, mirrori
Original PR description
Current behaviour: In the Calendar view (day/week/month scale), when the user's timezone observes a DST transition that starts exactly at local midnight (e.g. Africa/Cairo, since 2023), the day…
Current behaviour: In the Calendar view (day/week/month scale), when the user's timezone observes a DST transition that starts exactly at local midnight (e.g. Africa/Cairo, since 2023), the day column right after the transition gets the wrong weekday name, duplicating the previous day's name. For ex. it renders "... THU THU FRI ..." instead of "... THU FRI SAT ...", for the week surrounding April 30th 2027. To fix this we add 1 hour to the Date before reading its weekday/day from it, mirroring the workaround FullCalendar itself adopted for this same bug. It has no effect on any ordinary day (adding 1h to a correct local midnight stays within the same calendar day), and it cannot overshoot into the next day since no real-world DST gap exceeds that margin. Note: This is a known bug (https://github.com/fullcalendar/fullcalendar/issues/7633), fixed in FullCalendar v6.1.17, a major version ahead of the v4.4.0, so the fix can't be applied directly without a full library upgrade. opw-6370140