Wednesday, October 29, 2025
20 changes · saas-18.4
Enhancements to existing features
VoIP searches now find phone numbers even when they include spaces, hyphens, parentheses, or other formatting characters. This makes it easier for users to locate contacts and call history entries using only the digits they remember, while also improving safe handling of search terms on the server side.
Original PR description
Introduces the `matchPhoneNumber` function, a new utility designed to match search terms against fully formatted phone numbers. The function converts a digit string like "123" into a flexible regex (e.g., /1\D*2\D*3/i) that matches digits regardless of any non-digit characters (spaces, hyphens, parentheses) between them. **Example:** * **SearchTerms**: "123" * **Target**: "+1 (2)-345" * **Match**: "1 (2)-3" Task-5160296 Forward-Port-Of: odoo/enterprise#97711
The Italian localization now removes obsolete tax exemption reason codes that are no longer accepted by the Italian Tax Agency. This helps businesses avoid invalid electronic invoices by relying on the newer, more detailed Natura codes already available in Odoo.
Original PR description
There are old Natura (l10n_it_tax_exemption_reason) that are deprecated in favour of more detailed ones. We already have the detailed ones, but we allow the old values, but the Tax Agency considers them invalid already. ref: https://fex-app.com/FatturaElettronica/FatturaElettronicaBody/DatiBeniServizi/DatiRiepilogo/Natura Forward-Port-Of: odoo/odoo#233440 Forward-Port-Of: odoo/odoo#226939
The GSTR2B late bill matching process now uses invoice reference and IRN details more accurately when available. This helps reduce duplicate or incorrect matches during bill reconciliation, improving confidence in GST reporting.
Original PR description
- Adjusted domain construction in GSTR2B late bill matching logic. - Split condition to handle the presence or absence of IRN separately: - If IRN exists, match on both `ref` and `l10n_in_irn_number`. - If IRN is missing, match only on `ref`. - Improves the accuracy of bill reconciliation and avoids redundant matches. Forward-Port-Of: odoo/enterprise#97469
Resolved issues and error corrections
Third-party checks are now identified by their most recent action, even when multiple actions happen on the same date. This prevents checks that have already been passed on from incorrectly appearing as still on hand, improving accuracy in check tracking and payment workflows.
Original PR description
**Steps to reproduce:** 1. Install the modules: `accounting`, `l10n_ar`, and `l10n_latam_check`. 2. Create a third-party check journal: * Add payment methods: *New Third Party Checks* (inbound) and…
**Steps to reproduce:** 1. Install the modules: `accounting`, `l10n_ar`, and `l10n_latam_check`. 2. Create a third-party check journal: * Add payment methods: *New Third Party Checks* (inbound) and *Existing Third Party Checks* (outbound). * Configure outstanding accounts for both methods. 3. Create a vendor payment: * Use the third-party check journal. * Select the *Existing Third Party Checks* method. * Leave the check list empty. * Keep the payment in *Draft*. 4. Create a customer payment: * Use the same journal and select the *New Third Party Checks* method. * Add a new check under the *Checks* tab. * Post the payment. 5. Return to the draft vendor payment created in step 3: * Add the newly created check to it (via *Add a line*). * Post the payment. 6. Go to **Customers → Third Party Checks**. **Observed behavior:** - The check still shows a `current_journal_id` even though it has both inbound and outbound operations. - As a result, the check incorrectly appears in the 'On Hand' filter. **Root cause:** - `_get_last_operation` was sorting operations by `date`. - In some scenarios or flows where multiple operations share the same `date`, the wrong operation could be selected as the "last one", leading `_compute_current_journal` to assign a journal incorrectly. **Solution:** - Sort operations by `write_date` to always pick the true last operation. - This ensures `_compute_current_journal` correctly clears `current_journal_id` whenever both inbound and outbound operations exist. opw-5012903 Forward-Port-Of: odoo/odoo#225556
This fixes an error that could appear when users opened the Project list after all projects had been archived and project stages were enabled. The list now loads sample entries correctly, so users can continue navigating the Project app without hitting a traceback.
Original PR description
Step to reproduce: - open projects - go to -> configuration -> settings -> enable "project stages" - archive all projects - go to home page and reopen project app - open list view Observation: - we…
Step to reproduce: - open projects - go to -> configuration -> settings -> enable "project stages" - archive all projects - go to home page and reopen project app - open list view Observation: - we receive a traceback Cause: - when loading sample records for list view, `_mockFormattedReadGroup` is used which do not have record key. - but for unfolded groups, we need records. - this happens after this [commit](https://github.com/odoo/odoo/commit/26c37c9c070107f8bd753cb8a6d8343384fdd7bf), previously , load data for each group from here https://github.com/odoo/odoo/blob/7843db3c4576c80e48fc42bea86134212add3589/addons/web/static/src/model/relational_model/relational_model.js#L476-L483 - but this part is removed in above mentioned commit as part of revamp, and a corner case lived i.e list view, in which, group is unfolded, never gets any records. Fix: - we add records to list view based on if the group is folded or not opw-5122678 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Bank synchronization now avoids importing transactions on dates that are locked for accounting, preventing entries from being created or shifted to incorrect dates. Opening balances are also aligned correctly so bank statements remain consistent and easier to reconcile.
Original PR description
If you have a company with a lock date set, and you connect a bank that has transactions dated to the day of the lock date, these transactions will be fetched, which do not make sense because nothing…
If you have a company with a lock date set, and you connect a bank that has transactions dated to the day of the lock date, these transactions will be fetched, which do not make sense because nothing should be created in a period covered by a lock date. As a result, these transactions would be created at a wrong date (if the current month is the first after the lock date or if the sequence has a monthly reset, then they would be appended to the current month, else if the sequence reset annually, then they would be created at the current date). Additionally, the potential opening balance would be created at a wrong date too, since it would try to create it one day prior to the oldest transaction. The date which the opening balance is created would not be the same as the transactions above, which adds a layer to the mess created. To prevent this, at initialization, we set the last sync date one day after the lock date, not the same day. As for the opening balance, we do not try to set it one day prior to the oldest transaction, but the same day. The `internal_index` computed will ensure it is displayed as the first transaction of that journal. Finally, the test related to statement creation were adapted to this new behavior. Some ordering based on `date` in other tests were changed to `internal_index` to unify the test file with these changes. opw-4890538 Forward-Port-Of: odoo/enterprise#95138 Forward-Port-Of: odoo/enterprise#93543
The report editor now handles conditional table headers more reliably when users add columns. This prevents cases where a new column is added only to the header instead of the full report table, improving accuracy when customizing delivery slip layouts.
Original PR description
The TableSizeComputer.compute() method can return cells with incorrect cell indexes. This can result in the _addColumn function only adding a column to some rows in the report editor.…
The TableSizeComputer.compute() method can return cells with incorrect cell indexes. This can result in the _addColumn function only adding a column to some rows in the report editor. TableSizeComputer.compute() does not handle cases where a conditional is used inside of a th element but the corresponding td element does not have a conditional. Steps to reproduce ----- 1. Open the Delivery Slip in the report editor. 2. Click the header to show the dropdown and select elif: o.move_line_ids and o.state=='done'. 3. Hover over the last th element to select the column button. 4. Click Insert right and see that only the header row has an additional column. Cause ----- TableSizeComputer.compute() calculates how many possible cells can be in a row which can be more than the total number of columns you have if you have th or td elements with a conditional inside of them. In the Delivery Slip report, a th element is present when using serial numbers and a different th element is present when not using serial numbers. The corresponding t-body has two different tr elements for these conditions. The compute method will have one less cell in these rows because the corresponding conditional is handled outside of the row. Solution ----- Only count mutually exclusive th or td elements once. This prevents the cellIndex from being larger than the total possible columns. opw-ticket 5173345 Forward-Port-Of: odoo/enterprise#98207
This fix stops the Point of Sale loyalty system from adding an unintended extra product when shoppers use quantity shortcuts in promotions such as "Buy X Get Y." It also restores the correct reward behavior so eligible free items are applied as configured, improving checkout accuracy and customer trust.
Original PR description
After commit https://github.com/odoo/odoo/commit/b86dd8f0674f02a14f4aaa10db39bd4a1e8270f1, an extra order line could be added unintentionally. For example, in a "Buy X Get Y" loyalty program, if you add the product and press 3x on the numpad, the system would incorrectly add 3x + 1 products to the order. Moreover, the fix introduced in the above commit was not correct according to the program logic. For instance, if the configuration is set to "Grant: 1 credit per order" with a minimum quantity of 2, and the reward is for one point, then when ordering 2 products, one of them should indeed be free. The previous fix changed this intended behavior, resulting in incorrect reward application. opw-5151979 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#232192 Forward-Port-Of: odoo/odoo#231704
This fixes Swedish POS receipt controls so receipts can only be reprinted once as intended. It also improves blackbox error handling, preventing stalled loading screens and making issues easier to identify when the device is disconnected or returns unexpected errors.
Original PR description
Before this commit, the receipt reprint check logic (which only allows a receipt to be reprinted once) was not working. There were two issues preventing it from working: - The name of the function had changed but not been updated in this module, so the override was not applied. - The ID being used to check the order was incorrect. A few smaller issues were also fixed: - A logging issue in the IoT driver, which prevented the error severity from being printed. - An infinite loading UI if the blackbox was disconnected. - The blackbox error handler swallowing up some errors due to only expecting one specific format. Forward-Port-Of: odoo/enterprise#98271 Forward-Port-Of: odoo/enterprise#98076
DHL pallet package defaults were corrected so their dimensions match the units DHL expects. This prevents validation failures when creating DHL shipping labels with the default pallet settings, though existing installations may need the module reinstalled for the new defaults to apply.
Original PR description
## Short functional explanation of the error When setting the 'DHLxw Package Type' of a DHL delivery method to 'DHL pallets' without changing default values, trying to validate an order delivery…
## Short functional explanation of the error When setting the 'DHLxw Package Type' of a DHL delivery method to 'DHL pallets' without changing default values, trying to validate an order delivery causes an error. ## Reproduction Steps 1. Type 'Delivery method' in the dashboard. Select DHL BE, set the region to Europe and the 'DHLxw Package Type' to 'DHL pallets'. Click on the arrow at the right of 'DHL pallets'. You should see the default values set to 1200, 1600 and 1200. These correspond to millimeters, while DHL expects centimeters. 2. Make sure you're using a company located in Belgium. 3. In the inventory settings, make sure that either 'multi-step route' is unchecked or that for your warehouse, the outgoing shipments are set to '1 step'. 3. Create a new quotation. Select a Customer with a Belgian address. Add a product for which there's at least 1 copy in stock. 4. Click on add shipping and select DHL BE. Then click add and ok. 5. Click on confirm. A smart button at the top of the page called "delivery" should appear. Click on it and set the scheduled date to a future day. Finally, click validate. ### Expected behavior New labels should generate without issue. ### Unexpected behavior An error occurs: ```Bad request Multiple problems found, see Additional Details 1001: The requested product(s) (N) not available based on your search criteria.(687662d08999745d3df3783068fcca24) 410107: The piece height exceeds max, N/- 410304: No products available ``` ## Origin of the issue The default values for DHL are set to 1200, 1600 and 1200, which correspond to millimeters. However, DHL expects centimeters, for which the default value is thus too high. Note: because the issue stems from default values, after implementing the fix, the module should be reinstalled. __ opw-4804639 Forward-Port-Of: odoo/enterprise#90272
This fixes a Safari-specific issue where the link editor could close before Apply, Dismiss, or link type selections took effect. Users editing emails or other rich text content in Safari can now create or cancel links reliably without confusing partial results.
Original PR description
## Issue: On Safari, the Apply and Dismiss buttons of the LinkPopover did not trigger their actions In some cases, it seemed to work only because a temporary link was not properly cleared The Link…
## Issue: On Safari, the Apply and Dismiss buttons of the LinkPopover did not trigger their actions In some cases, it seemed to work only because a temporary link was not properly cleared The Link Type Selection was also broken by the same bug ## Cause: Safari triggers a `pointerdown` event through the `LinkPopover`, which changes the `selection` and calls the `handleSelectionChange()` method https://github.com/odoo/odoo/blob/e43135e94bf22bc2f7a115c37e8a082f96871ed0/addons/html_editor/static/src/main/link/link_plugin.js#L672-L678 At that point, `documentSelection` is `null`, causing the overlay to close before the `onClickApply()` on the Apply button It's the same issue with the Dismiss button and the Link Type Selection ## Steps to reproduce: - Install mail to get access to an html_editor - Enable debug mode - Go in Email Templates and open one of them - Select a text and open link tools - Add Odoo.com and click on Apply - The link may seems to be created (if it's the case, there is no preview) - You can confirm that with the link type selector that closed the popover before the fix opw-5115887 Forward-Port-Of: odoo/odoo#233401 Forward-Port-Of: odoo/odoo#233241
Assets created from vendor bills with partially deductible lines now use only the deductible amount as their original value. This prevents overstating asset values and helps keep depreciation and accounting figures accurate.
Original PR description
We allow the user to create an asset from a bill with lines which are not fully deductible but the created asset's original value is the based on the entire balance of the journal item. It should be only the deductible part. task-5156256 Forward-Port-Of: odoo/enterprise#97505
Cancelled restaurant POS orders are now removed from the ticket list instead of appearing as paid orders. This keeps staff views accurate and reduces confusion when reviewing completed or cancelled sales.
Original PR description
pos*: point_of_sale, pos_restaurant Steps to reproduce: - Open the Restaurant POS and place an order. - Send it to the preparation screen by clicking Order. - Reopen the order and cancel it via the Action button. Issue: - The cancelled order still appears under the Paid section on the Ticket Screen. Fix: - Cancelled orders are now excluded from the Ticket Screen display. - Remove canceled orders from local records. Task: 4936636 Forward-Port-Of: odoo/odoo#232114 Forward-Port-Of: odoo/odoo#219402
This fix prevents employees from starting manufacturing work orders that are waiting on a prior dependent work order. It keeps shop floor activity aligned with the planned production sequence and reduces the risk of process errors.
Original PR description
**Issue** A work order that is blocked by another work order can still be started. **Steps to reproduce** 1. Go to Settings > Activate Work Order Dependencies. 2. Create a Bill of Material for a…
**Issue** A work order that is blocked by another work order can still be started. **Steps to reproduce** 1. Go to Settings > Activate Work Order Dependencies. 2. Create a Bill of Material for a product: - In the Miscellaneous tab, activate Work Order Dependency. - Create two work orders in different work centers where the second depends on the first. 3. Create a manufacturing order for the same product. 4. In the 'Operations' tab, observe that the start button is active for the blocked work order. 5. Click the Shop Floor smart button and observe that the blocked work order can still be started. **Cause** The [`state` of the work order](https://github.com/odoo/odoo/blob/dae9b0a906e86a9e26cd1b37bd9b9385804c8e55/addons/mrp/models/mrp_workorder.py#L65C1-L72C49) was not consistently checked before allowing a work order to start. **Solution** Follow the existing behaviour for blocked work centers: - Hide the start button on the manufacturing order if the work order is blocked. - Trigger an error message if the start button on the Shop Floor is clicked for a blocked work order. opw-5167644
This fixes an issue in Point of Sale where customer information chosen after adding an online payment was not saved when the payment was completed. It helps ensure orders paid online are linked to the correct customer, improving order records and follow-up accuracy.
Original PR description
Before this commit, if a partner was selected after adding an online payment line, the partner was not synced after completing the online payment. opw-5098127 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#233405 Forward-Port-Of: odoo/odoo#232455
Payslips for Lithuanian employees participating in the pension accumulation system no longer apply the pension contribution twice. This prevents inflated social security deductions and helps payroll amounts match expected Lithuanian tax rules.
Original PR description
**Issue**
When generating a payslip for an employee with the `l10n_lt_pension` setting enabled on the contract ("Participate to pension accumulation system"):
- the SSC is raised from 19.5% to 22.5%
- a 3% pension contribution ("Pension Scheme") is added This effectively doubles the expected contribution.
Various sources (e.g. https://taxsummaries.pwc.com/lithuania/individual/other-taxes) seem to show this is not correct.
opw-5067664
Forward-Port-Of: odoo/enterprise#98177
Forward-Port-Of: odoo/enterprise#95880Fixed an issue where translating the full text of a website mega menu item could fail to save. The editor now only marks truly translatable website content as editable, helping preserve translation references and prevent lost work.
Original PR description
Scenario: - install second language on website - add mega menu item to menu - translate full span (from first to last letter) - save Result: nothing is saved Cause: The mega menu is in a node with…
Scenario: - install second language on website - add mega menu item to menu - translate full span (from first to last letter) - save Result: nothing is saved Cause: The mega menu is in a node with [data-oe-model] attribute that receives the o_editable class from SetupEditorPlugin. Its content is in a `section > .container` that receives contenteditable="true" from BuilderContentEditablePlugin. Because the container zone is contenteditable, the editor allows to select outside of <span data-oe-translation-…/> elements and when we replace the whole content, the node is removed because it is an empty SPAN and we lose the translation reference, so the translation are lost when saved. Fix: There is already a code that disable wrapping editable since d4f8aebea8cc7eba1517575302e072e0d5e2e406. This was not taking this case where the content is not in '.o_editable' but in '.o_editable section > .container'. With this fix, we only add o_editable class to nodes that matches [data-oe-model][data-oe-translation-source-sha]. opw-5045798 opw-5159026
This fix ensures Spanish Facturae e-invoicing tax information is loaded correctly for mainland Spain and the Canary Islands. It also prevents unrelated taxes from receiving an incorrect default e-invoicing tax type, reducing configuration errors in Spanish electronic invoices.
Original PR description
Currently the tax data defined in l10n_es_edi_facturae is incomplete and never loaded. This commit makes sure that the l10n_es_edi_facturae_tax_type is loaded correctly and adds the appropriate templates for es_common_mainland and es_canary_common. The default is also removed on the field l10n_es_edi_facturae_tax_type to avoid the value being assigned for unrelated taxes. task-4981325 Forward-Port-Of: odoo/odoo#232432 Forward-Port-Of: odoo/odoo#231277
This fix ensures French POS certification checks ignore orders that do not have a secure sequence number when identifying the previous order. This prevents false duplicate matches that could block database upgrades or certification-related computations for affected customers.
Original PR description
## Description of the issue/feature this PR addresses: When obtaining the previous order for pos.order records, all orders with l10n_fr_secure_sequence_number == NULL will be recognised as the…
## Description of the issue/feature this PR addresses:
When obtaining the previous order for pos.order records, all orders with l10n_fr_secure_sequence_number == NULL will be recognised as the previous order for those where l10n_fr_secure_sequence_number == 1, as if their sequence value was zero.
## Current behavior before PR:
Since there can be more than one orders without sequence number, this behaviour will trigger an UserError exception, as the ORM will mistakenly deduce that there are multiple previous orders for a single one, which is not necessarily correct.
### Examples:
upg-3170341
```sql
lare_3170341=> SELECT count(id) FROM pos_order WHERE l10n_fr_secure_sequence_number IS NULL;
count
-------
67281
(1 row)
```
```python
# Debugging standard codebase with a Python debugger
...
match = prev_map.get(order.l10n_fr_secure_sequence_number - 1, []) # len(match) == 67281
if len(match) > 1:
raise UserError(_('An error occurred when computing the inalterability...'))
...
```
upg-3170341
```sql
lare_3167621=> SELECT count(id) FROM pos_order WHERE l10n_fr_secure_sequence_number IS NULL;
count
-------
294
(1 row)
```
```python
# Debugging standard codebase with a Python debugger
...
match = prev_map.get(order.l10n_fr_secure_sequence_number - 1, []) # len(match) == 294
if len(match) > 1:
raise UserError(_('An error occurred when computing the inalterability...'))
...
```
---
Traceback group: https://upgrade.odoo.com/odoo/tbg/1869
```
2025-09-30 07:48:30,945 329 INFO db_3167621 odoo.modules.loading: Loading module l10n_fr_pos_cert (110/131)
2025-09-30 07:48:31,375 329 INFO db_3167621 odoo.modules.registry: module l10n_fr_pos_cert: creating or updating database tables
2025-09-30 07:48:31,432 329 INFO db_3167621 odoo.models: Prepare computation of pos.order.previous_order_id
2025-09-30 07:48:31,597 329 WARNING db_3167621 odoo.modules.loading: Transient module states were reset
2025-09-30 07:48:31,597 329 ERROR db_3167621 odoo.modules.registry: Failed to load registry
2025-09-30 07:48:31,597 329 CRITICAL db_3167621 odoo.service.server: Failed to initialize database `db_3167621`.
Traceback (most recent call last):
File "/home/odoo/src/odoo/18.0/odoo/service/server.py", line 1361, in preload_registries
registry = Registry.new(dbname, update_module=update_module)
File "<decorator-gen-13>", line 2, in new
File "/home/odoo/src/odoo/18.0/odoo/tools/func.py", line 97, in locked
return func(inst, *args, **kwargs)
File "/home/odoo/src/odoo/18.0/odoo/modules/registry.py", line 129, in new
odoo.modules.load_modules(registry, force_demo, status, update_module)
File "/home/odoo/src/odoo/18.0/odoo/modules/loading.py", line 485, in load_modules
processed_modules += load_marked_modules(env, graph,
File "/home/odoo/src/odoo/18.0/odoo/modules/loading.py", line 365, in load_marked_modules
loaded, processed = load_module_graph(
File "/home/odoo/src/odoo/18.0/odoo/modules/loading.py", line 206, in load_module_graph
registry.init_models(env.cr, model_names, {'module': package.name}, new_install)
File "/home/odoo/src/odoo/18.0/odoo/modules/registry.py", line 618, in init_models
func()
File "/home/odoo/src/odoo/18.0/odoo/addons/base/models/ir_model.py", line 2007, in _reflect_relation
self.env.invalidate_all()
File "/home/odoo/src/odoo/18.0/odoo/api.py", line 839, in invalidate_all
self.flush_all()
File "/home/odoo/src/odoo/18.0/odoo/api.py", line 857, in flush_all
self._recompute_all()
File "/home/odoo/src/odoo/18.0/odoo/api.py", line 850, in _recompute_all
self[field.model_name]._recompute_field(field)
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 7359, in _recompute_field
field.recompute(records)
File "/home/odoo/src/odoo/18.0/odoo/fields.py", line 1463, in recompute
apply_except_missing(self.compute_value, recs)
File "/home/odoo/src/odoo/18.0/odoo/fields.py", line 1436, in apply_except_missing
func(records)
File "/home/odoo/src/odoo/18.0/odoo/fields.py", line 1485, in compute_value
records._compute_field_value(self)
File "/home/odoo/src/odoo/18.0/addons/mail/models/mail_thread.py", line 427, in _compute_field_value
return super()._compute_field_value(field)
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 5296, in _compute_field_value
fields.determine(field.compute, self)
File "/home/odoo/src/odoo/18.0/odoo/fields.py", line 110, in determine
return needle(*args)
File "/home/odoo/src/odoo/18.0/addons/l10n_fr_pos_cert/models/pos.py", line 79, in _compute_previous_order
raise UserError(_('An error occurred when computing the inalterability. Impossible to get the unique previous posted point of sale order.'))
odoo.exceptions.UserError: Une erreur s'est produite lors de la vérification de l'inaltérabilité. Impossible de récupérer la dernière commande de caisse unique et comptabilisée.
```
## Desired behavior after PR is merged:
The method `pos.order._compute_previous_order` already only checks orders with a sequence number != NULL, so to address this issue, we will use the same condition to retrieve only orders with a valid sequence. This will result in no more exceptions created by incorrect data.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#229585Batch payments now show a clear warning when SEPA Credit Transfer partners are missing required city or country information for structured addresses. This helps users correct partner records before generating payment files that would become invalid under the upcoming 2026 SEPA rules.
Original PR description
Starting from November 15th, 2026, SEPA Credit Transfer (SCT) payments require both the partner's country and city to be defined when using structured addresses. If missing, the generated XML file will be invalid. This change adds a non-blocking red banner on the batch payment form to warn users and provide a link to review the affected partners. task-5156613 Forward-Port-Of: odoo/enterprise#97598