Tuesday, September 1, 2026
17 changes · saas-19.2
Resolved issues and error corrections
This change reverts a previous restaurant point-of-sale update that caused full orders to be reprinted when staff only intended to print newly added items. It restores the expected kitchen or preparation printing flow, reducing confusion and unnecessary duplicate tickets in restaurant operations.
Original PR description
This reverts commit a1ee5faa141af45e38879a448ce6bbd5ed58cc54 (https://github.com/odoo/odoo/pull/266070) which is causing issues (reprint whole order when I only want to print newly added order lines). task-id: 6230594 FW of https://github.com/odoo/odoo/pull/285993 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The timesheet screens now block repeated save actions while the first request is still processing. This avoids duplicate entries appearing in the list or being created when users click Add or Create multiple times on a slow connection.
Original PR description
Steps to reproduce: 1. Open the ActivityWatch timesheets view. 2. Throttle the network speed to simulate a slow connection. 3. Rapidly click "Add" on an ActivityWatch suggestion. 4. Click 'New', fill in the details, and rapidly click "Create" (or mash Ctrl+Enter). Issue: - Suggestion List: Multiple duplicate timesheets are created in the database. - Creation Form: The newly created timesheet appears multiple times in the UI list on the left side, even though only one might be created in the database. Cause: Both the `onTake` (ActivityWatch list) and `onSave` (Timesheet form) methods are asynchronous. Without a concurrency lock, rapid user interactions trigger these methods multiple times before the initial network request finishes, causing parallel ORM calls and duplicate UI array pushes. task-6462515 Forward-Port-Of: odoo/enterprise#127806
Fixed an accounting issue where bill references could disappear in the bank reconciliation widget when a foreign-currency payment also created an exchange difference entry. This helps users correctly identify matched bills after reconciliation, reducing confusion during financial review.
Original PR description
In the bank reconciliation widget, a reconciled transaction matched with a bill and a loss exchange entry no longer displays the bill reference next to the reconciled line. Steps to reproduce: - Have…
In the bank reconciliation widget, a reconciled transaction matched with a bill and a loss exchange entry no longer displays the bill reference next to the reconciled line. Steps to reproduce: - Have company currency USD and foreign currency EUR - Create a vendor bill in foreign currency (100 EUR, rate 1 USD = 1 EUR) - Create a bank transaction in the foreign currency for less than the bill total, at a rate making the amount higher in company currency (90 EUR, 108 USD at 1 EUR = 1.2 USD) - Open the bank reconciliation widget, reconcile transaction and bill - Unfold the reconciled transaction Issue: A bill reference is missing Analysis: The exchange difference line is reconciled with the transaction line. Being reconciled with two lines (bill and exch), the widget relies on `*_reconciled_lines_excluding_exchange_diff` to show the fields. However, `count_reconciled_lines_excluding_exchange_diff` has been defined as boolean instead of int, faulting the comparison. opw-6479015 Forward-Port-Of: odoo/odoo#283855
Odoo now records the correct outcome when a VoIP call is answered or rejected in another phone application, such as Linphone. This prevents calls from being incorrectly shown as missed or left in progress, giving users a more accurate call history when Odoo is open.
Original PR description
Steps to reproduce: - Have an external VoIP software configured (e.g. Linphone) - Have your Odoo configured and opened too - Call your VoIP number, using your smartphone => Both the softphone and…
Steps to reproduce: - Have an external VoIP software configured (e.g. Linphone) - Have your Odoo configured and opened too - Call your VoIP number, using your smartphone => Both the softphone and Linphone ring - Answer or reject using Linphone => The VoIP call record in Odoo immediately switches from "Trying to call" to "Missed". While there was no guarantee for our VoIP integration to work alongside Linphone in 19.0, we decided this should be an easy safe enough fix. Starting 19.2 (with [1]), the fix will be simplified and hopefully prettier thanks to the ameliorations that were made. After this fix, provided Odoo is open while Linphone is used, the call records will now switch to the right terminated / rejected status, still immediately once Linphone answers / rejects. In future versions and especially 20.0+, the system will be different and will allow way more features like this one to work better (e.g. here the call record only even exists if Odoo is opened while using Linphone and we won't have any information about the call duration). [1]: https://github.com/odoo/enterprise/commit/942f32316ab02d8c739fe7fdd5ec2bdde472a68e task-6449259 Forward-Port-Of: odoo/enterprise#128482 Forward-Port-Of: odoo/enterprise#127077
Customers are now prevented from continuing checkout when a pricing rule unexpectedly makes the cart total zero but zero-priced sales are not allowed. Instead of timing out during payment, they are sent back to the cart with a clear warning, reducing failed checkout experiences and support cases.
Original PR description
When 'Prevent Sale of Zero Priced Product' is enabled and a country-group pricelist prices a product at 0 once the customer's country becomes known during checkout, the cart total becomes 0. The 'free order' branch then validated the order at the payment step, which could hang and time out for a cart that is not actually sellable. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285439 Forward-Port-Of: odoo/odoo#284959
The web property editor no longer crashes when a saved relational property contains a filter the server cannot evaluate. Instead of blocking the editor, Odoo hides the matching-record count so users can still open, fix, or delete the property.
Original PR description
When a relational property has a domain the server cannot evaluate, opening its definition editor crashes. The editor calls search_count on that domain to show how many records match, both when it…
When a relational property has a domain the server cannot evaluate, opening its definition editor crashes. The editor calls search_count on that domain to show how many records match, both when it opens and on every later render. The server raises a ValueError and the call has no error handling, so the whole editor goes down. The bad domain stays saved on the property, so reopening the editor fails the same way and the property can no longer be edited or deleted. Wrap the search_count call in _updateMatchingRecordsCount (property_definition.js) in a try/catch and show no count when it fails. This is the only place the editor counts matching records, so guarding it here handles a bad domain from any source, the field selector or the code editor. The field selector still shows its warning on the invalid path, so the user can fix or delete the property. Steps to reproduce: 1. On a model that has a Properties field, add a Many2one property and set its Model to a model that itself has a Properties field. 2. Open the property Domain and click New Rule. 3. In the field selector pick the Properties entry, then close the selector. => An error dialog appears and the property can no longer be edited or deleted. Ticket [link](https://www.odoo.com/odoo/project.task/6101311) opw-6101311 Forward-Port-Of: odoo/odoo#283802 Forward-Port-Of: odoo/odoo#259886
Fixes an issue where timesheets could lose their connection to a replacement invoice after an invoice was reversed and recreated with a credit note. This helps ensure corrected invoices still show the right timesheet details, improving billing traceability and reducing manual follow-up.
Original PR description
### Description of the issue/feature this PR addresses: Fixes an issue where timesheets lose their invoice reference when reversing and re-creating an invoice via a credit note. ### Current behavior…
### Description of the issue/feature this PR addresses: Fixes an issue where timesheets lose their invoice reference when reversing and re-creating an invoice via a credit note. ### Current behavior before PR: When reversing an invoice tied to timesheets and creating a replacement via a credit note, the timesheets linked to the original invoice have their timesheet_invoice_id cleared. Because the modify_moves function builds the replacement invoice directly via copy_data()/create(), it bypasses the normal sale order invoicing flow. As a result, the unbilled timesheets are left permanently unlinked from the newly created invoice, leaving the new invoice with no reference to the timesheets linked to the original sale order. ### Desired behavior after PR is merged: When a replacement invoice is created, each timesheet is properly relinked to the corresponding line on the new invoice. This linkage matches on the sale order line (so_line) rather than line position, ensuring accuracy since line order and count are not guaranteed to be preserved between the original and modified invoices. opw-6449995 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283104
Colombian point-of-sale receipts now correctly show the required DIAN tax authority information. This helps businesses issue compliant customer receipts and avoids missing fiscal details at checkout.
Original PR description
Receipts are now generated in POS using the `generateReceiptData` function. This commit extends this function and adds all the data necessary to properly show the receipt in Colombian POS. opw-6414901
Odoo now recognizes five new response codes introduced by Chile's tax authority (SII) for supplier electronic documents. This prevents affected documents from getting stuck and restores the expected acceptance or claim processing flow.
Original PR description
**Before this PR:** After the implementation of Resolution 161 of November 13th 2025, SII responses included keys not supported by the current l10n_cl_edi implementation. This resulted in supplier DTEs not being processed as they were before the change, because the five new keys were not found in Odoo's current `l10n_cl_claim` field, causing that the documents with these responses, were kept in a loop not solved. **After this PR:** The five new values from the resolution, along with their translations, were added to the selector field, fixing the process flow. **SII Reference:** https://www.sii.cl/normativa_legislacion/resoluciones/2025/reso161.pdf (see Event Code, page 5) Forward-Port-Of: odoo/enterprise#121833
Clearing an internal note on a restaurant PoS order line now updates the existing preparation display item instead of cancelling and recreating it. This prevents kitchen staff from seeing the same quantity as a new order and accidentally preparing items twice.
Original PR description
Steps to reproduce ------------------ 1. Open a restaurant PoS with a preparation display. 2. Add a product, put the internal note "A" on the line, press Send. 3. Change the note from "A" to "B",…
Steps to reproduce ------------------ 1. Open a restaurant PoS with a preparation display. 2. Add a product, put the internal note "A" on the line, press Send. 3. Change the note from "A" to "B", then open the note again and click "discard", that will clear it. 4. Press Send. -> The line is fully cancelled on the preparation display and the same quantity is sent again as a new order. Expected Behavour ----------------- The existing line should be updated in-place instead of cancelling and re-creating a new one. Why it's happening ------------------ In `_process_preparation_changes` we calculate a key for every line and the `note` is inside this key. For the order lines we take `line.note or "[]"`, but for the note history we take `note['new'] or ''`, in that case, the keys don't match, so we cancel the current one and create a new line!! The fix ------- We use `"[]"` now, in many places (for completness), a follow up of 484ef2e8b2b. opw-6467346 Forward-Port-Of: odoo/enterprise#128601
This fixes an issue where partially received subcontracted products could incorrectly mark related receipt lines as ready to process. As a result, receipts with both subcontracted and regular products now create accurate backorders, reducing inventory and purchasing errors.
Original PR description
### Steps to reproduce: - Create a subcontracted product P1 - Create a storable product P2 - Buy 5 units of both products from your subcontractor - On the receipt set both moves quantity to 2 Units -…
### Steps to reproduce: - Create a subcontracted product P1 - Create a storable product P2 - Buy 5 units of both products from your subcontractor - On the receipt set both moves quantity to 2 Units - Validate the receipt and create a backorder #### > Only the subcontracted move has been kept on the receipt and a backorder was created for 3 units of P1 and 5 of P2. ### Cause of the issue: Setting the quantity of the subcontracted move will automatically record the quantities on the subcontracted MO: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/stock_move.py#L83 https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/stock_move.py#L123 https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/mrp_production.py#L91 However, the `_update_finished_move` method adds and update the related subcontracted move lines marking them as *picked* to adapt the related reservation: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/mrp_production.py#L118-L164 This is problematic since picking a move line will also pick the move: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/stock/models/stock_move.py#L261-L267 And only picked moves are considered to be processed at picking validation. ### Note: The exact same issue had already been fixed in 17.0: db8b33ebb9fe23507bcba30b12741e4d688ae549 However, the fix had an issue concerning the barcode behavior as it removed the picked computation for subcontracted moves which made hybrid pickings such as the above one (with one subcontracted and one non-subcontracted move) impossible to process in the barcode app. As such, the fix and test where reverted in cf2d18c92bee55ef79db1a338e9baf12f258ee5b The present commit provides an alternative fix of the original issue keeping subcontracted moves unpicked by quantity changes without affecting the picked computation of subcontracted moves (e.g. adding a picked move line on a subcontracted move will still pick that move). Enterprise: https://github.com/odoo/enterprise/pull/123884 opw-6330584 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283927 Forward-Port-Of: odoo/odoo#275304
Opening a page from the Website Pages list no longer sends users to the website's configured public domain when they are working from the Odoo-hosted address. This keeps users in their current session and prevents unexpected login prompts or lost context.
Original PR description
Steps to reproduce: =================== 1. Go to Website > Pages 2. Set a real domain on the default website 3. Open any page linked to that website => User is redirected to the real domain When clicking on a page linked to the default website from the Website > Pages list, if that website had a real domain configured, the action was redirecting the user to that domain instead of staying on the current host (e.g. <db>.odoo.com). since it's a different domain the user would then end up in the login page and lose the context of the page they wanted to open. Solution: ========= Now we change the behavior as requested by PO. On <domain>.odoo.com, in the Pages list view, if the page is linked to the default website, keep <domain>.odoo.com and don't redirect to the real domain => User should stay on the current host opw-6141457 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261698
This fixes an issue where Monday as the chosen first day of the week was ignored in some locales, causing one work week to be split across two week numbers. Businesses using weekly hour limits or planning reports will now see hours grouped consistently into the correct week.
Original PR description
**Description of the issue/feature this PR addresses:** `weeknumber` takes a `first_week_day` override, documented as `(0 = Monday, ..., 6 = Sunday). If None, derived from the locale.`, but tests it…
**Description of the issue/feature this PR addresses:** `weeknumber` takes a `first_week_day` override, documented as `(0 = Monday, ..., 6 = Sunday). If None, derived from the locale.`, but tests it with `if not first_week_day`, so Monday (`0`) is discarded and the locale's own day is used. `resource` passes `int(get_lang(self.env).week_start) - 1`, which is exactly `0` for Monday, at three call sites. #259600 added the parameter for the opposite case, a Monday locale with a Sunday-start user, and that direction works; this one never has. **Current behavior before PR:** With `en_US` (first day Sunday) and week start set to Monday, `resource_resource.py:299` builds `week_start_date` from Monday while `:303` buckets by Sunday. Monday 2026-08-24 to Sunday 2026-08-30 comes back as W35 for six days and W36 for the Sunday, so one week's hours are split across two buckets and the `hours_per_week` cap lands on the wrong days. **Desired behavior after PR is merged:** The override is honoured and those seven days are all W35. I checked this with a partition property: every day of a `first_week_day`-aligned week must share one `(year, week)`. Over 9 locales x 7 values of `first_week_day` x 12 years, 275940 combinations, 5 locales failed and every failure was in the `first_week_day=0` bucket. After the change there are none. I also diffed every output before and after, 315360 combinations of locale, `first_week_day` and date: 4460 rows change, all of them `first_week_day=0` on a non-Monday locale. `None` and values 1 to 6 are byte identical, so the change is contained to the broken case. Targeting 19.0 because that is the oldest branch carrying the parameter; 17.0 and 18.0 do not have it. AI-assisted: I used Claude to sweep the parameter space and write the tests. Forward-Port-Of: odoo/odoo#285706 Forward-Port-Of: odoo/odoo#285508
This fixes a point of sale issue where order lines could disappear from a restaurant order when the same table was handled across two devices before payment. Orders now keep their products correctly when paid, helping avoid inaccurate sales records and reconciliation issues.
Original PR description
Steps to reproduce: - Restaurant config with two POS devices on the same session - Device A: open a table, add two products, press Order (the order is synced as a draft, its lines get server ids) -…
Steps to reproduce:
- Restaurant config with two POS devices on the same session
- Device A: open a table, add two products, press Order (the order is synced as a draft, its lines get server ids)
- Device A: remove both lines, without syncing
- Device B: touch the same order, so device A re-reads it from the server through the synchronisation websocket
- Device A: pay and validate the order
Issue:
The order is saved as paid, with its total and its payment, but without any orderline. The lines are deleted on the server: odoo.models.unlink: deleted pos.order.line records with IDs: [...]
Cause:
Removing an orderline queues an unlink command in
models.commands['pos.order'].unlink['lines_<order id>'] (delete_ in related_models.js). That command is only discarded by clearCommands(), which syncAllOrders() calls after a successful sync, so it stays pending in between.
Any read of the order in that window puts the line back: a deleted record counts as missing in missingRecursive(), so it is fetched again and loadData() re-creates it with its server id.
serialize() then emits both the update of the live line and the still pending unlink, and sync_from_ui writes
lines: [[1, id, {...}], [3, id]]. The ORM applies commands in order, and pos.order.line.order_id is ondelete='cascade', so Command.UNLINK deletes the line right after writing it.
Fix:
Skip a removal command when the record is still linked to the parent at serialization time. A record cannot be both linked and removed in the same payload, so the pending command is stale and dropping it keeps the local state. Genuine removals, where the record is no longer linked, are still sent.
opw-6401146
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#285427
Forward-Port-Of: odoo/odoo#284695Fixed an issue where Argentine eCommerce product pages could show a tax-excluded price with the pricelist discount applied twice. This keeps prices consistent between the shop listing and product detail page, reducing customer confusion.
Original PR description
Steps to produce: --- - Create a company with `Argentina` as the country. - Switch to the newly created company. - Create a new website for the `Argentina company`. - Create a pricelist with a `23%`…
Steps to produce: --- - Create a company with `Argentina` as the country. - Switch to the newly created company. - Create a new website for the `Argentina company`. - Create a pricelist with a `23%` discount on the sales price for all products. - Create a new product, set the sale price to 100, remove all tax, and publish. - Go to the website and switch to the newly created Argentina company website. - Go to the Shop page and open the product. Issue: --- - The tax-excluded price (`Precio s/Imp. Nac.`) displayed on the shop catalog card differs from the tax-excluded price displayed on the product detail page. Root cause: --- - In `_get_additionnal_combination_info`, [1] returns the unit price with the pricelist discount already applied. However, when `combination_info['has_discounted_price']` [2] is `True`, the method applies the discount again manually, resulting in the pricelist discount being applied twice on the product detail page. Solution: --- - Remove the redundant discount calculation block. This ensures that the tax-excluded price displayed on the product detail page matches the price shown on the shop catalog card. [1]https://github.com/odoo/odoo/blob/7f9560bd0ff66882459593a2d043c0197ceec0bb/addons/l10n_ar_website_sale/models/product_template.py#L61-L62 [2]https://github.com/odoo/odoo/blob/7f9560bd0ff66882459593a2d043c0197ceec0bb/addons/l10n_ar_website_sale/models/product_template.py#L71-L74 opw-6480531 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283761
Polish electronic invoices now correctly treat K_12 taxes, such as the 0% EU reverse charge tax, as reverse charge transactions. This ensures the exported KSeF XML contains the proper reverse charge indicator and tax base, reducing reporting errors for affected invoices.
Original PR description
**PROBLEM** K_12 taxes needs to be reported as reverse charge tax. **STEP TO REPRODUCE** 1. Create an invoice with the tax 0% EU U. 2. Send the invoice the ksef. 3. Open the xml, an notice P_18 value is 2 (meaning no reverse charge), and there is no tag P_13_10. expected behavior: P_18 = 1, P_13_10 = base for the tax. opw-6460338 Forward-Port-Of: odoo/odoo#281934
Project updates now show the same profitability and invoicing amounts as the project dashboard. This prevents already invoiced sales or vendor bill amounts from appearing as still pending, giving managers more accurate project financial snapshots.
Original PR description
Steps to reproduce: ------------------- 1. Install sale_timesheet. 2. Create a service product with: - Invoicing Policy: Prepaid/Fixed Price - Create on Order: Project & Task 3. Create a sales order…
Steps to reproduce: ------------------- 1. Install sale_timesheet. 2. Create a service product with: - Invoicing Policy: Prepaid/Fixed Price - Create on Order: Project & Task 3. Create a sales order with this product. 4. Open the generated project > dashboard and verify that "To Invoice" shows $1. 5. Create a project update and observe that "To Invoice" also shows $1. 6. Return to the sales order, create and post the invoice. 7. Open the project dashboard again and verify that "To Invoice" is now $0. 8. Create another project update. Issue: ------ The project update margin still displays $1 under "To Invoice" even though the sales order has already been fully invoiced. Cause: ------ The project update template displays the aggregated profitability totals (`profitability['total']['revenues']` and `profitability['total']['costs']`) instead of the dedicated `to_bill_to_invoice` and `billed_invoiced` values, causing stale "to invoice" amounts to persist after invoicing. Solution: --------- Use the `to_bill_to_invoice` and `billed_invoiced` values when rendering the project update profitability report. opw-6323869 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278646 Forward-Port-Of: odoo/odoo#273605