Friday, September 26, 2025
18 changes · saas-18.3
Enhancements to existing features
Point of Sale now avoids loading large lists of product option values until they are actually needed. This reduces startup delays for stores with complex product catalogs while keeping product options linked correctly.
Original PR description
Before this commit, when loading PoS, all product template attribute value (ptav) IDs linked to a product attribute were loaded. This caused performance issues when attributes had a large number of values, even though they were not needed at that stage. With this commit, the values are no longer preloaded, since the reverse fields in ptav and ptal are fetched when needed, ensuring they can still be linked correctly without degrading performance. opw-5006818 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#225600 Forward-Port-Of: odoo/odoo#224497
Restaurant point-of-sale users can now retry kitchen receipt printing when a printer issue causes a failure. The retry action only sends the receipt to printers that failed previously, avoiding duplicate prints on printers that already succeeded.
Original PR description
Before this commit: = - There was no option to retry printing kitchen receipts if a printer failed. After this commit: = - Users can now manually retry printing kitchen receipts that failed due to printer issues. - The `Retry` button targets only the printers that previously failed, ensuring other successful prints are not repeated. Task: 4717776
Resolved issues and error corrections
Fixed an issue in Brazilian electronic invoicing where confirming several invoices at the same time could cause the process to fail. This helps accounting teams process batches of invoices more reliably and reduces manual retries.
Original PR description
opw-5107516 Forward-Port-Of: odoo/enterprise#95511
This fixes paid order search in the Point of Sale so staff only see orders from the current register setup or its trusted related setups. It prevents unrelated paid orders from appearing, reducing confusion and helping teams keep sales data separated correctly.
Original PR description
Before this commit, when searching paid orders in the PoS UI, orders from other configs could appear even if they were not part of the trusted configs or the same PoS config. This commit ensures that only orders related to the current PoS configuration (or its trusted configs) are loaded and displayed. opw-5083747 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#227709
Barcode receipt users will now see quality checks only for items they have actually picked. This prevents unnecessary or confusing checks from appearing for products with zero processed quantity, making warehouse quality control more accurate.
Original PR description
_______________________________________ ## Short functional explanation of the error On barcode, when an item isn't picked, when clicking on quality checks, the quality check for the unpicked item…
_______________________________________ ## Short functional explanation of the error On barcode, when an item isn't picked, when clicking on quality checks, the quality check for the unpicked item will still show. ## Reproduction Steps 1. Go to Quality and create a Quality point by clicking on Quality Control. Click on new, set a title and put 2 products in the field Product. In operation, select Receipt. 2. Go to Inventory and click Receipts. 3. Click New. Fill the Receive From field, and add 2 products. Set the demand field to 2 for example. 4. Click on Mark as Todo. 6. Go to Barcode. Click on Operations, the Receipts, and click on the latest Receipt you created. 7. For one product, click on the +2 button. For the other one, leave it at 0. Then, click on Quality Check. ### Expected behavior Only the quality check for the item that has been picked should show. ### Unexpected behavior Both quality checks show. ## Origin of the issue The behavior of the code is different when we perform the operations in backend compared to when we perform them in barcode. Indeed, for the regular flow in Inventory, in ```check_quality()```, we also retrieve the checks linked to a move line that hasn't been picked: https://github.com/odoo/enterprise/blob/c09a5cbc2450ec32b0ad3985fa2d4e5e2fcd3d71/quality_control/models/stock_picking.py#L44-L58 Which isn't the intended flow for barcode. Thus, we have to change this behavior and take into account the environment. __ opw-5010764
Preparation ticket printing now handles order notes consistently, even when multiple kitchen printers are configured. This prevents printing failures caused by different note formats, helping restaurant staff receive complete kitchen tickets reliably.
Original PR description
Normalize getStrNotes() to handle multiple note formats (JSON array string, array, plain string) and avoid crashes when printing preparation tickets to multiple printers. Steps to reproduce:…
Normalize getStrNotes() to handle multiple note formats (JSON array string, array, plain string) and avoid crashes when printing preparation tickets to multiple printers.
Steps to reproduce:
-------------------
* Configure two preparation printers for a pos_restaurant with food categorie.
* Create an order with a note in that restaurant.
* Send the order to the kitchen.
> Observation:
The second printer fails to print the ticket with an (uncaught) JSON parse error (Unexpected token), while the first prints correctly.
Why the fix:
------------
`getStrNotes()` assumed notes were always JSON strings like [{"text":"...","colorIndex":0}]. In practice, notes can be plain strings or already-parsed arrays depending on the update path and last printed changes.
The function now:
- returns joined texts for arrays,
- tries to parse JSON strings and joins texts if it’s an array,
- falls back to the raw string if parsing fails. This makes note rendering stable across printers and prevents the error, ensuring tickets are printed consistently.
opw-5029870When no receipt printer is connected, online self-order payments now send orders to the preparation display before opening the browser print dialog. This prevents staff from missing or waiting on paid orders because an unattended print popup blocked the process.
Original PR description
Steps to reproduce: ------------------- 1. Enable self orderdering, and set an online payment method 2. Open 3 tabs: the main PoS one, the self order one, and the preparation display one (we have to…
Steps to reproduce: ------------------- 1. Enable self orderdering, and set an online payment method 2. Open 3 tabs: the main PoS one, the self order one, and the preparation display one (we have to setup the prep display too) 3. In the self order tab, make an order and pay for it Observe that in the main tab, a receipt modal (window.print) appears, and the order is not sent to the payment display (on the third tab) until we either dismiss or accept the printing popup on the main tab. Reason: ------- If there is no printing device connected, we fallback to printing the receipt with `window.print`; this operation blocks the execution of the code that follows it, in our case sending the order to the preparation display, until we either dismiss or confirm the printing popup. Now if the user is not paying attention to the main tab (only looking at the preparation display for instance), the order will not appear in the prep display. Fix: ---- In the case of fallbacking to web printing, we execute the print in a `setTimeout`, so to not block the code that comes after it. opw-5039685
This update prevents two users or sessions from creating separate invoices for the same Point of Sale order at the same time. If invoicing is already underway, the user sees an error, and if an invoice already exists, Odoo opens it instead of creating another one.
Original PR description
This fix prevents multiple users from generating separate invoices for the same POS order simultaneously. Steps to reproduce: 1. Create a new POS order. 2. Open two tabs (or two POS sessions). 3. Generate an invoice in the first tab. 4. Immediately try to generate an invoice in the second tab. 5. Two invoices will be generated. With this fix: - If a user attempts to generate an invoice while another is already in progress, an error message is shown. - If the invoice has already been generated, the existing invoice view is opened instead of creating a duplicate. opw-5004504 Forward-Port-Of: odoo/odoo#223845
Bill Matching now treats individual contacts and their parent companies consistently when matching purchase orders with vendor bills. This prevents an error that blocked users from matching bills when both documents used the same individual contact linked to a company.
Original PR description
**Issue** When both a Purchase Order and a Vendor Bill are created using the same individual contact linked to a company, Bill Matching fails with a traceback. **Steps to Reproduce** 1. Create an…
**Issue** When both a Purchase Order and a Vendor Bill are created using the same individual contact linked to a company, Bill Matching fails with a traceback. **Steps to Reproduce** 1. Create an individual contact and link it to a company. 2. Create a Purchase Order with the individual as a vendor. 3. Create a Vendor Bill with the same individual as the vendor. 4. Try to perform Bill Matching. 5. A `ValueError: Expected singleton: res.partner(...)` is raised. Video for reference: https://drive.google.com/file/d/1qVnPLpk8jyMTKz-6AVLSaN2nVVeWiF4y/view **Root Cause** Purchase Orders store the partner exactly as selected (the individual contact), while Vendor Bills are normalized internally to the parent company (`commercial_partner_id`). This creates a mismatch in the Bill Matching logic, where records reference both the individual and the company, leading to an invalid recordset and the singleton error. **Fix** Always normalize vendors to their `commercial_partner_id` during Bill Matching. This ensures that both Purchase Orders and Vendor Bills consistently reference the same partner, avoiding mismatches between individual contacts and their parent company. Opw-5050339 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#226130
The Belgian EC Sales List XML export now correctly includes the month or quarter when opened from the VAT Return page. This prevents incomplete XML files and helps businesses submit compliant tax reports without manually reselecting the period.
Original PR description
**Issue** When accessing the EC Sales List report via the smart button from the VAT Return page, downloading the XML without explicitly selecting a period omits the <Month> element—even though a…
**Issue** When accessing the EC Sales List report via the smart button from the VAT Return page, downloading the XML without explicitly selecting a period omits the <Month> element—even though a month is visibly preselected. **Steps to Reproduce** 1. Install the Accounting module and Belgium localization. 2. Go to the Accounting dashboard. 3. Open the VAT Return via the "Miscellaneous Operations" section. 4. Click the smart button to access the EC Sales List report. 5. Use the gear icon to export the XML. 6. Observe that the XML <Period> section only includes the <Year>—the <Month> is missing. **Root Cause** If no period is explicitly selected, the report uses a period_type of "tax_period". However, this value was not handled when generating the XML, so the logic to include the \<Month> or \<Quarter> elements skipped it. As a result, only the \<Year>, which is always included, was rendered. **Fix** Extend the handling of tax_period to derive the period from the company’s tax periodicity settings and adjust the filter accordingly. This ensures that the generated XML always includes the \<Month> or \<Quarter> element, in addition to \<Year>, whenever the report is based on a tax period. Opw-4702613 Forward-Port-Of: odoo/enterprise#89290
Scanning a package in the Barcode app now correctly converts quantities when the package and delivery line use different units of measure. This prevents under-recording delivered quantities, such as treating 10 kg as 10 g instead of 10,000 g.
Original PR description
Manual forward port of https://github.com/odoo/enterprise/pull/90878 **Problem:** When scanning a package with a different UoM than the barcode line, the conversion is not made. **Steps to…
Manual forward port of https://github.com/odoo/enterprise/pull/90878 **Problem:** When scanning a package with a different UoM than the barcode line, the conversion is not made. **Steps to reproduce:** - Enable the "Packages" setting; - Create a new storable product and set kg as its UoM; - In the inventory tab, add "g" in the packagings - Click on the on hand smart button and select update quantity - Add a new line; - In the package column create a new package; - Set a quantity of 10 kg; - Create a delivery and select your product; - Set a demand on 10000 and select g as the UoM; - Mark as todo; - Open the delivery in the Barcode app; - Scan the package. **Current behavior:** The quantity on the line is now 10 / 10000 g **Expected behavior:** It should be 10000 / 10000 g **Cause of the issue:** https://github.com/odoo/enterprise/blob/4c9fa9dc010958710d848fbcb3241b17ea7205ca/stock_barcode/static/src/models/barcode_picking_model.js#L1500-L1505 remaining_qty is expressed in the uom of the quant so it will be 10 but qty_needed is expressed in the uom of the line is it will be 10000. qty_used beeing the minimum of those two it will be 10. **Fix:** To define how much quantity to take from the package, we convert the line's quantity by using the package's UoM. Then, when we add this quantity to the line's quantity, we re-convert it by using the line's UoM. opw-4860064
Fixes an accounting display issue where cash basis journal item lines could show '/' instead of the actual posted journal entry name. This helps accountants see accurate journal entry references in transaction lists after payment-based tax entries are created.
Original PR description
### Issue: In the list view of Journal Items, cash basis lines show a `move_name` of '/' event if the move is posted and has a name. ### Steps to reproduce: - Activate Cash Basis in the accounting…
### Issue: In the list view of Journal Items, cash basis lines show a `move_name` of '/' event if the move is posted and has a name. ### Steps to reproduce: - Activate Cash Basis in the accounting settings - Create a tax with "Tax Exigibility" set "Based on Payment" - Set the "Cash Basis Transition Account" to "Current Assets" - Activate reconciliation on "Current Assets" - Create an invoice with this tax, confirm - In the dashboard, click on Bank and new - Set the name of the invoice as the label, and the amount of the invoice as amount - Save & Close - Go in Accounting > Transactions > Journal Items - The lines created for the cah basis entry display '/' in the column "Journal Entry" ### Cause: This issue is linked to the order in which things are done in `_set_next_sequence`: the fields triggered by the sequence field are added in `self.env.transaction.tocompute` then the sequence is computed and assigned. When `_set_next_sequence()` is called from [`_create_tax_cash_basis_moves()`](https://github.com/odoo/odoo/blob/849e4a87178d8c8588b75e3f7d9073d6a78326f9/addons/account/models/account_partial_reconcile.py#L649-L654) this order is problematic as `account.move.line.move_name` will be computed and removed from `self.env.transaction.tocompute`. So it will not be updated when the sequence is assigned in `account.move.name`. The callstack is something like this: - `_set_next_sequence()` calls `_locked_increment()` to compute the sequence - `_locked_increment()` calls `flush_recordset()` which will call `_recompute_recordset()` to recompute all fields - `_compute_invoice_date_due()` needs the field `needed_terms` triggering `_compute_needed_terms()` - `_compute_needed_terms()` needs `invoice_line_ids` - the fetch on `account.move.line` is ordered by `move_name` - So `_compute_related()` is triggered for `move_name` and `account.move.line.move_name` is removed from `self.env.transaction.tocompute` Then `_locked_increment()` returns the sequence, it gets assigned as the move name and `move_name` is never updated because it's not in `self.env.transaction.tocompute`. This doesn't occur in other flows (like calling `action_post()`) because the value of `needed_terms` is read from the cache. ### Solution: Swap the order in which things are done in `_set_next_sequence()`: first compute and assign the sequence and then add the triggered fields in `self.env.transaction.tocompute` so that they are computed afterwards. It seems more logic that way: we change the `_sequence_field` then mark all fields that will be impacted in `tocompute`. opw-5056938
This fix ensures cash basis journal item lines show the proper journal entry name instead of a placeholder slash. It protects accounting users from confusing entries in journal item lists and adds test coverage to prevent the issue from returning.
Original PR description
This commit adds a test for the [change made in community](https://github.com/odoo/odoo/pull/225558). ### Issue: In the list view of Journal Items, cash basis lines show a `move_name` of '/' event if…
This commit adds a test for the [change made in community](https://github.com/odoo/odoo/pull/225558). ### Issue: In the list view of Journal Items, cash basis lines show a `move_name` of '/' event if the move is posted and has a name. ### Steps to reproduce: - Activate Cash Basis in the accounting settings - Create a tax with "Tax Exigibility" set "Based on Payment" - Set the "Cash Basis Transition Account" to "Current Assets" - Activate reconciliation on "Current Assets" - Create an invoice with this tax, confirm - In the dashboard, click on Bank and new - Set the name of the invoice as the label, and the amount of the invoice as amount - Save & Close - Go in Accounting > Transactions > Journal Items - The lines created for the cah basis entry display '/' in the column "Journal Entry" ### Cause: This issue is linked to the order in which things are done in `_set_next_sequence`: the fields triggered by the sequence field are added in `self.env.transaction.tocompute` then the sequence is computed and assigned. When `_set_next_sequence()` is called from [`_create_tax_cash_basis_moves()`](https://github.com/odoo/odoo/blob/849e4a87178d8c8588b75e3f7d9073d6a78326f9/addons/account/models/account_partial_reconcile.py#L649-L654) this order is problematic as `account.move.line.move_name` will be computed and removed from `self.env.transaction.tocompute`. So it will not be updated when the sequence is assigned in `account.move.name`. The callstack is something like this: - `_set_next_sequence()` calls `_locked_increment()` to compute the sequence - `_locked_increment()` calls `flush_recordset()` which will call `_recompute_recordset()` to recompute all fields - `_compute_invoice_date_due()` needs the field `needed_terms` triggering `_compute_needed_terms()` - `_compute_needed_terms()` needs `invoice_line_ids` - the fetch on `account.move.line` is ordered by `move_name` - So `_compute_related()` is triggered for `move_name` and `account.move.line.move_name` is removed from `self.env.transaction.tocompute` Then `_locked_increment()` returns the sequence, it gets assigned as the move name and `move_name` is never updated because it's not in `self.env.transaction.tocompute`. This doesn't occur in other flows (like calling `action_post()`) because the value of `needed_terms` is read from the cache. ### Solution: Swap the order in which things are done in `_set_next_sequence()`: first compute and assign the sequence and then add the triggered fields in `self.env.transaction.tocompute` so that they are computed afterwards. It seems more logic that way: we change the `_sequence_field` then mark all fields that will be impacted in `tocompute`. opw-5056938
The Time Off calendar now shows the selected employee’s own working schedule instead of the schedule of the person viewing it. This prevents confusion when managers review employees with different days off or working patterns.
Original PR description
Steps to reproduce: - In the Employee app, select an employee with a different working schedule than yours - Click on the "Time Off" smartbutton - Switch from Kanban to Calendar view - The displayed working schedule is yours and not the employee's (easier to see if you and the employee have different days off) Reason: The employee_id field in the context used by the Python method was null instead of an ID, which caused the Python method to default to not use the employee's working schedule but the working schedule of the user viewing it. How it was fixed: By using a different field already present in the context, the employee's ID is correctly retrieved and used to display the calendar. Task ID: 4987732
Orders placed through self-order or kiosk flows with online payment now appear on the preparation display only after the payment is confirmed. This prevents staff from preparing unpaid orders while still ensuring paid orders reach the preparation display, including when customers leave through an alternate payment portal route.
Original PR description
pos_*= pos_online_payment_self_order_preparation_display, pos_self_order_iot Before this commit, if an online payment method was assigned to a self or a kiosk, the order was displayed on the preparation display before the payment was confirmed. After this commit, the order is no longer displayed on the preparation display until the payment confirmation. Community PR: https://github.com/odoo/enterprise/pull/87173 Backport of https://github.com/odoo/odoo/pull/87173, with additional logic to ensure the order is correctly sent to the preparation display even if an exit route is used in the payment portal Forward-Port-Of: odoo/enterprise#95312
Orders placed through self-order or kiosk flows with online payment are now held back from the preparation display until payment is confirmed. This prevents staff from preparing unpaid orders while still ensuring confirmed orders reach the kitchen display, including when customers exit through the payment portal.
Original PR description
pos_*= pos_online_payment, pos_online_payment_self_order, pos_self_order Before this commit, if an online payment method was assigned to a self or a kiosk, the order was displayed on the preparation display before the payment was confirmed. After this commit, the order is no longer displayed on the preparation display until the payment confirmation. Enterprise PR: https://github.com/odoo/enterprise/pull/95312 Backport of https://github.com/odoo/odoo/pull/213493, with additional logic to ensure the order is correctly sent to the preparation display even if an exit route is used in the payment portal --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#228189
Online shop stock availability now accounts for kit products already in the cart when they share components with other products. This prevents customers from seeing outdated available quantities or attempting to buy unavailable stock after adding either a kit or its component to the cart.
Original PR description
### Steps to reproduce: - In the settings website > Shop: - Disable `Out-of-Stock: Continue Selling`. - Enable `Show Available Qty` if below 5 units. - Create 2 storable products published on the…
### Steps to reproduce:
- In the settings website > Shop:
- Disable `Out-of-Stock: Continue Selling`.
- Enable `Show Available Qty` if below 5 units.
- Create 2 storable products published on the website:
- COMP, put 1 unit in stock.
- KIT with bom of type Kit using 1 x COMP.
- With a private window go to the shop.
- Add 1 x COMP or KIT to the chart.
#### > This is not reflected on the available quantity in stock of the other product
### Cause of the issue:
The availability on the website is computed from the product availability using the `free_qty` fetched because of this override: https://github.com/odoo/odoo/blob/d358542c9159f325b4e2ff184ed1f5cdb6b8c5a9/addons/website_sale_stock/controllers/variant.py#L10-L13 from which the cart quantity of the product itself is deduced before re-render:
https://github.com/odoo/odoo/blob/d358542c9159f325b4e2ff184ed1f5cdb6b8c5a9/addons/website_sale_stock/static/src/js/variant_mixin.js#L49-L51 https://github.com/odoo/odoo/blob/d358542c9159f325b4e2ff184ed1f5cdb6b8c5a9/addons/website_sale_stock/static/src/js/variant_mixin.js#L83-L86 While the `free_qty` is correctly computed from kit products based on the component availability:
https://github.com/odoo/odoo/blob/d358542c9159f325b4e2ff184ed1f5cdb6b8c5a9/addons/mrp/models/product.py#L211-L221 The qties in the virtual cart quantities are not recomputed base on kits.
opw-4889956
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#228537
Forward-Port-Of: odoo/odoo#222945This fix ensures the latest restaurant point-of-sale order changes are saved before sending them to the kitchen printer or preparation display. It prevents outdated-order errors when staff add items, leave a table, and later return to send the updated order.
Original PR description
Before this commit, if an order had no changes and no preparation display was active, adding items to the order in the restaurant PoS and then returning to the tables would sync the order to the server and mark it as not dirty. As a result, reopening the order and clicking the order button to send it to the preparation display or printer would not sync the updated changes. This caused inconsistencies and errors. Steps to reproduce: 1. Open a table, place an order, and send it to the kitchen printer 2. Add more products but instead of placing the order, go back 3. Re-enter the table, place the order, and send it 4. When placing another order, the error "Order Outdated" appears This commit fixes the syncing logic to ensure that last changes are properly synced, avoiding the "Order Outdated" error. opw-5097566 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#227824