Thursday, August 21, 2025
21 changes · saas-18.4
Enhancements to existing features
Stock pickings with many serial-numbered items are now processed more efficiently during reservation and validation. This reduces timeouts and significantly improves performance for large warehouse operations.
Original PR description
### Description: When using serial numbers, pickings with many move lines can cause performance issues during validation. This is due to `_update_reserved_quantity` updating quantities and creating move lines individually. By moving the creation outside `_update_reserved_quantity`, we can batch create move lines per move, significantly improving performances. ### Benchmark: | N° of mls | Before | After | |-----------|---------|-------| | 500 | 1:37 | 1:34 | | 15000 | Timeout | 3:30 | | 30000 | Timeout | 4:29 | ### Reference: opw-4889581 Forward-Port-Of: odoo/odoo#223420 Forward-Port-Of: odoo/odoo#219471
Resolved issues and error corrections
This fixes cases where messages or comments with attachments could behave incorrectly if a file was still uploading. Users are less likely to accidentally delete attachments or send incomplete messages in chat, mail, live chat, and course review flows.
Original PR description
\* = im_livechat, website_slides Not waiting for the uploading state to be resolved can lead to unexpected behavior, such as deleting the attachment immediately when clicking on the delete button rather than showing the confirm dialog. This might also prevent the composer from being sent if the attachment is still uploading. This is checked when checking the enabled state of the send button when clicking on it, but it is not checked when pressing enter directly. Some tests also checked uploading was finished but didn't target the correct attachment. https://runbot.odoo.com/odoo/error/230901 https://github.com/odoo/enterprise/pull/92620 Forward-Port-Of: odoo/odoo#223464 Forward-Port-Of: odoo/odoo#223367
This update brings the spreadsheet component to the latest version and fixes several user-facing issues. Users should see more reliable chart exports, cleaner copy-paste behavior, safer table row moves, and correct pivot refresh after undoing deletions.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/d5eb3a626 [REL] 18.4.7 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/d5eb3a626 [REL] 18.4.7 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/c25b8c6cb [FIX] xlsx: correctly export aggregated charts [Task: 4954426](https://www.odoo.com/odoo/2328/tasks/4954426) https://github.com/odoo/o-spreadsheet/commit/1c099dc42 [FIX] clipboard: don't paste both image and text content [Task: 4876682](https://www.odoo.com/odoo/2328/tasks/4876682) https://github.com/odoo/o-spreadsheet/commit/a593cb80a [FIX] selection: prevent partial move of table rows with headers [Task: 4862731](https://www.odoo.com/odoo/2328/tasks/4862731) https://github.com/odoo/o-spreadsheet/commit/a74b221a4 [FIX] pivot: reload when delete is undone [Task: 5001153](https://www.odoo.com/odoo/2328/tasks/5001153) Co-authored-by: Anthony Hendrickx (anhe) <anhe@odoo.com> Co-authored-by: Alexis Lacroix (laa) <laa@odoo.com> Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com> Co-authored-by: Dhrutik Patel (dhrp) <dhrp@odoo.com> Co-authored-by: Adrien Minne (adrm) <adrm@odoo.com> Co-authored-by: Ronak Mukeshbhai Bharadiya <rmbh@odoo.com> Co-authored-by: Florian Damhaut (flda) <flda@odoo.com> Co-authored-by: Rémi Rahir (rar) <rar@odoo.com> Co-authored-by: Pierre Rousseau (pro) <pro@odoo.com> Co-authored-by: Vincent Schippefilt (vsc) <vsc@odoo.com>
Restaurant point-of-sale orders are now reliably saved and synchronized when staff return to the floor screen after making edits. This prevents changes such as notes, customer details, quantities, prices, discounts, or pricelists from being missed across devices or sessions.
Original PR description
Previously, changes made to an order did not trigger synchronization when navigating back to the floor screen. These changes include: • Adding a note or customer note to a line or order • Setting a customer • Modifying quantity, price, or discount via the numpad • Setting a pricelist This commit ensures the order is marked as dirty, which triggers the sync when returning to the floor screen. task.4946929 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#221292 Forward-Port-Of: odoo/odoo#220724
This fixes an issue where the online shop page could fail to load if all variants of a product template had been deleted. Customers and staff can now browse the shop without encountering an error caused by incomplete product variant data.
Original PR description
When a product template's variants are deleted, accessing the shop page raises an traceback. Steps to reproduce the error: - Install ``website_sale`` module - Enable Product Variants From Settings - Go to Website > eCommerce > Attributes > Open Color > On Product Cards: Visible > Add 2 Attribute values - Create a new Product Template > Attributes & Variants > Add Color attribute with 2 values - Delete the variants of this Product Template - Go to Website > Shop Traceback: ``IndexError: tuple index out of range`` https://github.com/odoo/odoo/blob/c7bedc25c9702956aab73cb6a0c0c544c062a3dd/addons/website_sale/models/product_template.py#L298 When a product template's variants are deleted, ``ptav.ptav_product_variant_ids`` becomes empty. The code tries to access the first element by index, causing the traceback. sentry-6801851377 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Selecting a record from the "Search more" dialog now correctly fills the field instead of unexpectedly opening the record form. This prevents confusion when choosing items such as purchase order lines and keeps the selection flow focused on completing the field.
Original PR description
Example of steps: - install web, purchase and studio - add a many2one with studio anywhere and choose purchase.order.line - close studio - try to use this new field, select "Search more" - select a random record - It opens the form view record instead of select It This is because purchase order line has an openAction that forces the opening of a form view. However, for a select_create_dialog, we must bypass this action to allow nothing except selection. To do this, a new prop has been added, “allowOpenAction,” in the list_controller, which will be true by default, but will be false for select_create_dialog. opw-4958121 Forward-Port-Of: odoo/odoo#223253 Forward-Port-Of: odoo/odoo#222602
Combo products now show the correct pricelist discount on product pages and during checkout. This prevents customers from seeing misleading crossed-out prices such as $0.00 and helps ensure discount information remains consistent through the buying flow.
Original PR description
Versions -------- - 18.0+ Steps ----- 1. Have a combo product; 2. create a pricelist that gives a 10% discount on the product; 3. go to product's website page; 4. observe the displayed discount; 5. add product to cart; 6. go to checkout. Issue ----- The discount has disappeared, instead it displays the original price next to a stricken-through "$ 0.00" Cause ----- The `_compute_discount` method does not get the correct `pricelist_item_id` for the combo items. Additionally, on checkout, it shows the `price_unit` of the combo line in the strike-through, which is always 0. Solution -------- When computing the discount of a combo item, retrieve the discount of its linked line, which has the correct value. Additionally, when displaying a combo product in eCommerce, use `_get_display_price_ignore_combo` instead of the `price_unit`. opw-4968848 Forward-Port-Of: odoo/odoo#223436 Forward-Port-Of: odoo/odoo#222472
This fixes incorrect duration calculations for employees on flexible schedules when attendance is recorded on a public holiday. Work entries now reflect the actual time gaps instead of incorrectly assigning a full 8-hour duration, improving payroll and time-off accuracy.
Original PR description
### Steps to reproduce: - Set Marc Demo's contract work entry source to attendances and working schedule to flexible hours. - Create a public holiday with generic time off work entry type. - Create…
### Steps to reproduce: - Set Marc Demo's contract work entry source to attendances and working schedule to flexible hours. - Create a public holiday with generic time off work entry type. - Create one or multiple attendances for marc demo on the public holiday. - Regenerate work entries for marc demo for that day, the gaps in between the attendances created and the working hours will be filled with work entries with the right start/end time but duration will always be 8h. ### Cause: This is happening because when getting the duration batch for the work entry we get the attendance intervals the employee should work in that period and if the employee is flexible we will get a fake attendance with the number of hours required per day ignoring if the period is just a small period of the day ### Fix: We are checking now since the start date not monday so we don't set a fixed week start. We check if the period is less than the remaining hours we get it as it mostly means that it is less than one day opw-4887933 Forward-Port-Of: odoo/odoo#222646 Forward-Port-Of: odoo/odoo#218823
Editing the quantity on a validated receipt for products valued by lot no longer causes an unexpected crash. The system now guides users with an error when the lot information is ambiguous, helping prevent incorrect inventory valuation changes.
Original PR description
Steps to reproduce: 1) Create a product tracked by lot and with valuation by lot. 2) Create a Purchase Order with this product and Confirm it. 3) Go to Receipt 4) Add a Lot number and validate 3) Unlock the receipt and modify the `quantity`. Current behavior - Get a traceback. Expected behavior: - If there is only one lot: - update the lot quantity - Else : - raise an error The fix should be applied before the `web_save` call to prevent the creation of a new `stock.move.line`. Therefore it's done on the `onchange` call. opw-4841162 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#221620 Forward-Port-Of: odoo/odoo#213534
This fixes the Spanish VAT Model 303 report so operations covered by articles 22, 23, and 24 are included in box 60. Businesses using Spanish localization will get more accurate tax reporting and reduce manual correction needs.
Original PR description
Operations included in articles 22, 23 and 24 should be included in section 60 of the model 303 report: source: https://declarando.es/modelo-303/casillas-59-60-y-61? opw-4954870 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#222549 Forward-Port-Of: odoo/odoo#221686
Event tickets sold through Point of Sale now keep their ticket-specific price when a customer is added or the pricelist changes. This prevents accidental price reductions to the base product price and helps ensure customers are charged the intended event ticket amount.
Original PR description
Before this commit: ========== - When selling event tickets through the Point of Sale (PoS), if an orderline was created with the ticket-specific price (higher than the base product price), the price would reset to the base product price when a customer (partner) was added or the pricelist was changed. After this commit: ========== - The event ticket orderline now retains its original ticket price even after a partner is selected or the pricelist is updated. This ensures pricing consistency and prevents unintended overrides for event-specific products. task-4862687 Forward-Port-Of: odoo/odoo#223549 Forward-Port-Of: odoo/odoo#214109
Time Off now uses the employee's active running contract when calculating working schedules and holiday days. This prevents incorrect balances when an employee has multiple contracts for the same period, such as a part-time active contract and a future full-time contract.
Original PR description
Steps: -Install the hr_holidays_contract module - Create two contracts for the same employee: - Contract A (Part-time) starting from 01/01/2025 and set to Running - Contract B (Full-time) also…
Steps: -Install the hr_holidays_contract module - Create two contracts for the same employee: - Contract A (Part-time) starting from 01/01/2025 and set to Running - Contract B (Full-time) also starting from 01/01/2025 and set to New - open holiday dashboard for that employee Description of the issue/feature this PR addresses: The Time Off dashboard incorrectly considers the full-time contract instead of the part-time one, even though the part-time contract is in the running state. Cause: The contract selection logic did not correctly prioritize the running contract when multiple contracts existed for the same period. Fix: This PR updates the logic to ensure that: - If a contract is in the running state at a given time, it is used to determine the working schedule and time off calculations. - If no contract is running during that time and multiple contracts exist, the contract with the latest creation_id will be considered. task-4724155 Forward-Port-Of: odoo/odoo#212959
Self-order prices now correctly include extra charges from all selected product options, including checkbox-style choices. This prevents customers from seeing or paying the wrong amount when ordering configurable items such as pizzas with size and topping options.
Original PR description
Currently, there is inconsistent behavior in price calculation when a user places a self order for a product containing attributes. **Pre-requisites:** - POS module installed and configured. -…
Currently, there is inconsistent behavior in price calculation when a user places a self order for a product containing attributes. **Pre-requisites:** - POS module installed and configured. - Variant enabled in settings. - Self-ordering is enabled in the POS configuration. - Two product attributes created in the settings/attributes: - One of type radio with variant creation set to Instantly. - Another of type multi-checkbox with variant creation set to Never. - Create attribute lines for both attributes with default extra prices. **Steps to reproduce:** 1) Create a product template linking the above attributes 2) Ensure the product is available in POS and self ordering 3) Open a POS session in one browser tab and the self-ordering in another. 4) Select the product in the self-ordering interface, first choosing an option for the radio attribute, then selecting one or more options for the multi-checkbox attribute. **Error:** You will see the difference between the expected price and the displayed price **Example for Clarity:** Consider a product called Pizza with 2 attributes. The base price of the pizza is $10. | Attribute | Option | Extra Price | | ----------------------------------- | ---------------- | --------------------- | | **Size** (radio) | Small (S) | \$0 (no extra charge) | | | Medium (M) | \$5 | | | Large (L) | \$10 | | **Extra Toppings** (multi-checkbox) | Veggies | \$3 | | | Extra Cheese | \$3 | | | Veggies & Cheese | \$5 | If the user selects a medium-sized pizza with veggie toppings, The expected price is: ``` $10 (base) + $5 (Medium size) + $3 (Veggies) = $18. However, the price shown is only $13. ``` **Root Cause:** For attributes of the multi-checkbox type, variant creation is set to Never by default. This means no product variants are generated for such attributes. Because of this, when calculating the price, the extra price associated with the multi-checkbox attribute is added directly to the base price of the product template instead of the price of the selected variant. This happens because the variant information is not properly passed to the price calculation method: https://github.com/odoo/odoo/blob/9df334c0aca8a57dcbed4c87b43b18403f3a7c6e/addons/pos_self_order/static/src/app/services/card_utils.js#L187-L196 https://github.com/odoo/odoo/blob/9df334c0aca8a57dcbed4c87b43b18403f3a7c6e/addons/point_of_sale/static/src/app/models/product_template.js#L185-L189 As a result, the extra price for the multi-checkbox attribute is incorrectly added to the product template’s base price rather than the variant’s price. **Solution:** Pass the product_variant derived from the selected product.product to the price calculation method. This ensures that if a variant exists based on the user’s selection, the extra price is added to the variant’s price rather than the base product template price, resulting in the correct total price. opw-4963537 Forward-Port-Of: odoo/odoo#221375
Creating a draft journal entry from a payslip list filtered by pay run now keeps the correct company context. This prevents empty entries from being created in the wrong company and ensures payroll accounting entries are populated as expected.
Original PR description
Problem ---------- When you create a draft entry from the payslip list view filtered by payrun, it creates a empty journal entry in Company US instead of the current one. Objective ---------- Create a filled journal entry in the good company Solution ---------- The context of the payrun card component was empty. The context of the list controller is now transmitted to the Record Component to keep the same context task-4932712
This fixes an issue where Odoo Studio treated behind-the-scenes fields as editable items in views. Studio now keeps those fields available for data loading without showing them or letting them interfere with view editing, helping avoid incorrect layout changes.
Original PR description
…lly added since commit odoo/odoo@6f06420e4a9443c52dc0cb427f8f55eb4aecabce, fields that are present in expression but not in the arch are automatically added. This caused problems in Studio, where those were considered normal nodes, while they should only be there to tell the model what to fetch. This commit aims at not rendering those nodes in a way that prevent them from parasiting the computation of xpaths. opw-4981741 Forward-Port-Of: odoo/enterprise#92789 Forward-Port-Of: odoo/enterprise#92602
The accounting payment widget now correctly shows remaining bank statement amounts after partial reconciliation and applies the right currency conversion. This helps accountants match invoices to bank statement lines accurately and prevents unrelated invoice payments from being undone when one partial match is removed.
Original PR description
[FIX] account_accountant: fix multi_currency payment_widget To reproduce: - Make a statement line for partner_a for 200 $ - Make an invoice for same partner for 100 $ - Reconcile it with the…
[FIX] account_accountant: fix multi_currency payment_widget To reproduce: - Make a statement line for partner_a for 200 $ - Make an invoice for same partner for 100 $ - Reconcile it with the statement line - Duplicate the invoice and post it => First issue, you don't see the 100$ left on the statement line It's still reconciliable To fix that, we only remove fully reconciled statement lines. Second issue: - Have a bank journal in EUR with a rate of 2 - Make a statement line for 400€ in this journal - Create an invoice for the same partner of 100$ => The widget proposes a statement line of 400$ instead of a 200$ equivalent (with the rate conversion) The issue is that we convert with a foreign_currency_id that is not present in that case. To fix both, we change the way we compute the amount to always use the residual converted from the right currency [FIX] account_accountant: partial on statement line for invoice widget To reproduce: - Make a statement line for partner_a for 200 $ - Make 2 invoice for same partner for 100 $ - Reconcile them with the statement line (via the widget) - Unreconcile first invoice via the payment widget => The second invoice is also unreconciled To solve: Only unreconcile the lines that are part of the partial that we want to unlink Forward-Port-Of: odoo/enterprise#92005
Reloading the Point of Sale with the booking view selected no longer leaves users on a blank screen. The booking screen now opens automatically as expected, helping staff continue managing restaurant appointments without interruption.
Original PR description
**Before this commit**: When reload data in pos then booking tab is display blank. It is action method so need to call when component is called. **After this commit**: Booking view now correctly and automatically opens when the POS is loaded or reloaded with the `actionName=manage-booking` parameter. Task - 4873055
Fixed an issue where employees on flexible schedules could receive incorrect 8-hour work entry durations for short gaps on public holidays. Work entries now calculate durations from the actual period being regenerated, improving payroll and attendance accuracy.
Original PR description
### Steps to reproduce: - Set Marc Demo's contract work entry source to attendances and working schedule to flexible hours. - Create a public holiday with generic time off work entry type. - Create…
### Steps to reproduce: - Set Marc Demo's contract work entry source to attendances and working schedule to flexible hours. - Create a public holiday with generic time off work entry type. - Create one or multiple attendances for marc demo on the public holiday. - Regenerate work entries for marc demo for that day, the gaps in between the attendances created and the working hours will be filled with work entries with the right start/end time but duration will always be 8h. ### Cause: This is happening because when getting the duration batch for the work entry we get the attendance intervals the employee should work in that period and if the employee is flexible we will get a fake attendance with the number of hours required per day ignoring if the period is just a small period of the day ### Fix: We are checking now since the start date not monday so we don't set a fixed week start. We check if the period is less than the remaining hours we get it as it mostly means that it is less than one day opw-4887933 Forward-Port-Of: odoo/enterprise#92193 Forward-Port-Of: odoo/enterprise#90163
Updating a company's address now also clears outdated map coordinates for related child contacts, preventing old or incorrect pins from staying visible. This helps users trust that Map View reflects the latest contact address information, with a known limitation for some import scenarios that can be corrected by resyncing the parent contact.
Original PR description
**Issue:** When adding contacts with incorrect address data, the Map View could display outdated or incorrect markers **Cause:** The `partner_latitude` and `partner_longitude` fields were not reset…
**Issue:** When adding contacts with incorrect address data, the Map View could display outdated or incorrect markers **Cause:** The `partner_latitude` and `partner_longitude` fields were not reset for child contacts when the parent’s address changed **Fix:** We added a `partner_latitude` and `partner_longitude` reset when changing address in write We added `partner_latitude` and `partner_longitude` in the _address_fields to update the value each time it can be required, like on address change or contact creation The extension in the _address_fields is there to detect the changes on children synchronization, because it only replace the value that where present in vals for the fields in that list In that way, it will detect more address changes and trigger the write for the children with the corresponding parent `partner_latitude` and `partner_longitude` We also make sure that those extra _address_fields will not be displayed in the formatted address by removing them from `_formatting_address_fields` **Limitations:** One issue remains during import: the parent-child address synchronization is disabled on contact creation This means children may be created with addresses different from the parent’s and have mismatch positions on Map This can be corrected by updating or re-importing the parent to trigger synchronization **Steps to reproduce:** With Form: - Add a parent contact company with a valid address - Add a child contact related to company, with a valid address - Open the Map View, both address must appear on Map - Modify the parent address to remove street (make it invalid) - Check that the child address match the parent one - Check the Map View, before the fix the child should remain with a wrong position With import: Create an import file (an example is in on the ticket) - Add a sheet for the Parent contact with an valid address - Add a sheet to add the Child contact with a parent_Id, with a valid address - Add a sheet to break the address on the parent, removing the street - Open the contacts app - Import the valid Parent and Child sheets (you need to select Related Company / External ID) - Add a filter to get your created contacts - Check the Map View (You should see both parent and child) - Import the Break parent sheet - Check that the child address match the parent one in the Form - Check the Map View, before the fix the child should remain with a wrong position A file can be found on the ticket with pre-made data **Technical notes:** The reset logic is duplicated from the `base_geolocalize` module, because this module is optional and may not be installed in all cases Since `base_geolocalize` is not always present, its `write` override will not be triggered consistently On the other hand, `web_map` is automatically installed with the Enterprise version of Odoo Therefore, it is necessary to implement this fix in at least one of the two modules to ensure the behavior is active when Enterprise is used We chose to keep the override in both `base_geolocalize` and `web_map` to cover both Community and Enterprise cases reliably An alternative approach would be to move the reset logic directly into `res.partner` in the `base` module, making it always available regardless of installed addons and avoiding the duplication opw-4842910 Forward-Port-Of: odoo/enterprise#92658 Forward-Port-Of: odoo/enterprise#90392
The kitchen preparation display no longer crashes when an order is marked done in a setup with only one preparation stage. This improves reliability for restaurants using simplified kitchen workflows and avoids interruptions during service.
Original PR description
Currently, an IndexError traceback occurs when changing the order state in the preparation display if it contains only one stage. **Steps to reproduce this issue:** 1) Install POS, Kitchen Display 2)…
Currently, an IndexError traceback occurs when changing the order state in the preparation display if it contains only one stage. **Steps to reproduce this issue:** 1) Install POS, Kitchen Display 2) Create a preparation display by removing all but one stage in the prep settings. 3) Open a restaurant session and create an order. 4) Open the preparation display and mark the created order as DONE. 5) A traceback will occur **Error:** ``` IndexError: tuple index out of range ``` **Cause:** When the Done button is clicked in a preparation display with only one stage, an ORM call to `change_state_status` is triggered. This then calls `_record_status_change_prep_time`, followed by `is_stage_position`. https://github.com/odoo/enterprise/blob/39810b5b7df01f381a08582ddc0c5218e99c964c/pos_enterprise/models/pos_prep_state.py#L31-L40 https://github.com/odoo/enterprise/blob/39810b5b7df01f381a08582ddc0c5218e99c964c/pos_enterprise/models/pos_prep_stage.py#L21-L22 In `is_stage_position`, static positions [0, -1, -2] are used to access items in the `stage_ids`. If only one stage exists, accessing indices -2 results in an IndexError. **Solution:** Before accessing a stage by position, check that the length of stage_ids is greater than or equal to the absolute value of the position. This prevents attempts to access out-of-range indices. opw-4985306 Forward-Port-Of: odoo/enterprise#91918
Users editing spreadsheet global filters now see the selected filter panel replace the existing side panel instead of piling up a second panel. This prevents broken Cancel or Remove actions and makes filter management more reliable.
Original PR description
Steps to reproduce: - Open the global filter side panel (list of all filters) - Pin the panel - Click on a specific filter to view/edit it Current behavior before PR: - A second side panel was opened instead of replacing the current one - Clicking 'Cancel' on the new panel had no effect - Clicking 'Remove' caused a traceback Desired behavior after PR is merged: - The new side panel replaces the current one (main or secondary) - The previous panel is restored correctly on 'Cancel' or 'Remove' - If the new panel is already open, we simply close the current one Task: [4911603](https://www.odoo.com/odoo/2328/tasks/4911603)