Tuesday, March 17, 2026
7 changes · 17.0
Enhancements to existing features
This update ensures Odoo's SEPA XML transactions comply with the latest ISO 20022 standard by using a structured address format. Previously, addresses were unstructured, but now they utilize hybrid tags for country, city, and postal code, improving data accuracy and compatibility with SEPA regulations. Validation has also been added to guarantee country and city information is present.
Original PR description
According to the ISO 20022 XML standard, any address included in SEPA interbank messages must be in a structured or hybrid format. Before this commit: --- - `<PstlAdr>` generation in SEPA XML used unstructured `<AdrLine>` tags. In this commit: --- - Generate <PstlAdr> with hybrid tags `<PstCd>`, `<TwnNm>`, `<Ctry>` and `<AdrLine>` in compliance with ISO 20022 requirements. - Added validation to ensure both country and city are present for partners and employees. --- task-5003410
Resolved issues and error corrections
This update resolves a memory issue that occurred when running procurement crons with a large number of orderpoints. The change optimizes how orderpoint data is processed, preventing a MemoryError and ensuring these critical tasks complete successfully. This improves the reliability of our inventory management system.
Original PR description
When running the procurement crons with a lot of orderpoints in the database, typically tens of thousands, a MemoryError can get triggered in `_run_scheduler_tasks` thanks to the line `orderpoints_batch._compute_qty_to_order()`. The Orderpoints recordset here is the result of a search in the whole database and can contain thousands of records. This computation puts every prefetched fields and every computed fields into the cache, leading to a MemoryError. In this commit the explicit compute call is replaced by a context key that is used down the stack to call `add_to_compute`. Thanks to the commit at the end of the `_procure_orderpoint_confirm` the cache gets cleared after 1000 orderpoints so the memory is stable and no MemoryError is thrown. Before PR: MemoryError (more than 2GB of `self.env.cache._data`) After PR: Procurement cron terminates without memory error. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue preventing new employee creation when generating BVG-LLP reports with duplicate monthly data. The fix addresses a technical problem related to how Odoo processes recordsets, ensuring accurate employee creation in Swiss companies using the LPP reporting feature.
Original PR description
Steps to reproduce: ---------------------------------- 1. Install `l10n_ch_hr_payroll_elm_transmission` module 2. Switch to Swiss company 3. Navigate to Payroll > Transmission > BVG-LLP Basis…
Steps to reproduce:
----------------------------------
1. Install `l10n_ch_hr_payroll_elm_transmission` module
2. Switch to Swiss company
3. Navigate to Payroll > Transmission > BVG-LLP Basis Declaration
4. Create two Reports with same Year and Month
5. Now try to create new Employee from the employee app
Observation:
----------------------------------
Tracaback Occurs:
```
File '/home/odoo/src/enterprise/19.0/l10n_ch_hr_payroll/models/l10n_ch_employee_monthly_values.py', line 319, in _compute_bvg_lpp_annual_basis
existing_declaration = max(existing_declaration, key=lambda r: r.month) if existing_declaration else False
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File '/home/odoo/src/odoo/19.0/odoo/orm/models.py', line 5934, in ensure_one
raise ValueError('Expected singleton: %s' % self)
ValueError: Expected singleton: l10n.ch.lpp.basis.report(1, 2)
```
Issue:
----------------------------------
In the following code:
https://github.com/odoo/enterprise/blob/44a26539093f9313d9cd5f823c11866e3c98ec97/l10n_ch_hr_payroll_elm_transmission/models/l10n_ch_employee_monthly_values.py#L319-L320
Python's max() function doesn't just call the key function once per item. When there are ties (equal key values), it may need to compare the original objects, and during this process, Odoo's recordset operations combine records, causing the lambda receives `r` as a combined recordset. To access `.month` on a multi-record recordset it gives singleton error.
Solution:
----------------------------------
Creates tuples of (month, recordset) pairs and uses max() to compare month integers directly, avoiding the singleton error.
opw-5391742This update corrects a bug where public time off end dates were incorrectly calculated when start dates were set to midnight. The fix ensures the end date accurately reflects the intended duration, resolving a validation error and preventing incorrect scheduling. This improves the reliability of time off management.
Original PR description
## Short functional explanation of the error When creating a public Time off for a Working Schedule, the end date will automatically set to a moment earlier than the set start date if the start date…
## Short functional explanation of the error When creating a public Time off for a Working Schedule, the end date will automatically set to a moment earlier than the set start date if the start date hour is set to midnight sharp. ## Reproduction Steps 1. Go to Employees. 2. Click on Configuration tab > Working Schedules. 3. Select a Working Schedule. 4. A smart button Public Time Off should appear. Click on it. 5. Click New and select a Start Date with a random date but 00:00:00 as hours:minutes:seconds. ### Expected behavior The End date should automatically set 23 hours 59 minutes and 59 seconds later. ### Unexpected behavior A Validation error occurs and the end date is set 1 second before the start date. ## Origin of the issue When setting automatically the end date of a leave, it is set to 23:59:59. With our timezone, if we select midnight, this time will be converted to 23:00:00, the day before: https://github.com/odoo/odoo/blob/e85f1a182ee60a25905369c84ced05480c5a3360/addons/resource/models/resource_calendar_leaves.py#L69-L70 Thus, the resulting end date will be set to the day before, at 23:59:59. Additionally, we have to take into account the timezone of the user to set a consistent end date, and not the generic utc one. __ opw-5187977 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves a memory issue that occurred when propagating deliveries across multiple lots in the stock module. The fix addresses a situation where processing large delivery sets (containing thousands of picking IDs) caused the system to run out of memory, particularly when dealing with complex lot relationships. This ensures smoother and more reliable delivery processing for large inventory operations.
Original PR description
- Some lots were found to contain very large delivery sets (7k+ picking IDs) with multiple parents. - Updating parent sets in a single operation caused a MemoryError for large datasets. ```sql…
- Some lots were found to contain very large delivery sets (7k+ picking IDs) with multiple parents.
- Updating parent sets in a single operation caused a MemoryError for large datasets.
```sql
Traceback (most recent call last):
File "/tmp/tmpe5fq5baf/migrations/base/tests/test_mock_crawl.py", line 333, in crawl_menu
self.mock_action(action_vals)
File "/tmp/tmpe5fq5baf/migrations/base/tests/test_mock_crawl.py", line 346, in mock_action
return self.mock_act_window(action)
File "/tmp/tmpe5fq5baf/migrations/base/tests/test_mock_crawl.py", line 506, in mock_act_window
mock_method(model, view, fields_list, domain, group_by)
File "/tmp/tmpe5fq5baf/migrations/base/tests/test_mock_crawl.py", line 539, in mock_view_form
[data] = record.read(fields_list)
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 3858, in read
return self._read_format(fnames=fields, load=load)
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 4089, in _read_format
vals[name] = convert(record[name], record, use_display_name)
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 7078, in __getitem__
return self._fields[key].__get__(self)
File "/home/odoo/src/odoo/18.0/odoo/fields.py", line 1311, in __get__
self.compute_value(recs)
File "/home/odoo/src/odoo/18.0/odoo/fields.py", line 1493, in compute_value
records._compute_field_value(self)
File "/home/odoo/src/odoo/18.0/addons/mail/models/mail_thread.py", line 442, in _compute_field_value
return super()._compute_field_value(field)
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 5297, 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/stock/models/stock_lot.py", line 149, in _compute_delivery_ids
delivery_ids_by_lot = self._find_delivery_ids_by_lot_iterative()
File "/home/odoo/src/odoo/18.0/addons/stock/models/stock_lot.py", line 385, in _find_delivery_ids_by_lot_iterative
delivery_by_lot[parent_id].update(delivery_by_lot[lot_id])
MemoryError
(Pdb)len(all_lot_ids)
22166
(Pdb)len(barren_lines)
9682
(Pdb)len(lots_to_propagate)
9682
Lot_id 11412: delivery_by_lot size = 7420, parents = 3
Lot_id 11753: delivery_by_lot size = 0, parents = 7
Lot_id 12845: delivery_by_lot size = 11, parents = 5
Lot_id 14646: delivery_by_lot size = 12, parents = 2
Lot_id 15801: delivery_by_lot size = 1700, parents = 3
Lot_id 19817: delivery_by_lot size = 0, parents = 4
Lot_id 22370: delivery_by_lot size = 0, parents = 1
Lot_id 25072: delivery_by_lot size = 6827, parents = 2
Lot_id 25134: delivery_by_lot size = 3, parents = 2
Lot_id 25135: delivery_by_lot size = 1, parents = 2
```
- Previous fix adds all child deliveries, even if some already exist, but this new patch adds only the missing ones
UPG - 3869661
OPW - 5900313
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update enhances the security and performance of the calendar module by adding a required CSRF token to form submissions and streamlining data handling. The changes optimize how calendar actions are processed, improving overall system efficiency. This resolves a previous vulnerability and ensures smoother operation.
Original PR description
Add a csrf token in the form which is required for post requests. Additionally, post requests form values are stored on the form attribute of the request rather than args which makes the keep_query implementation janky, as the form is only filled if coming from a get url. Instead just keep using keep_query in the action, only including csrf in post values. Finally a couple action urls were missed in mail templates. related: 0e57ff9cbc87c83276bdb823c5fb08cd4d2806f9 task-4555579
This update corrects a validation error in the ZATCA XML generation for Saudi Arabia companies. The change ensures that invoice cash rounding is included in the payable amount calculation, resolving a mismatch that was causing validation failures. This ensures accurate tax reporting and compliance.
Original PR description
Currently the generated ZATCA XML is not accounting for invoice cash rounding, leading to an invoice validation issue due to a mismatch in the calculation of PayableAmount. Steps to reproduce: - Have a SA Company setup - Create a [cash rounding] with strategy 'Add invoice line' and rounding 1.00 (UP) - Create an invoice for 99.55 + 15% Tax - Set Cash Rounding Method to [cash rounding] - Confirm and send xml for validation Issue: Validation will issue the following warning `[202] BR-CO-16 : Amount due for payment (BT-115) = Invoice total amount with VAT (BT-112) -Pre-Paid amount (BT-113) + Rounding amount (BT-114).` Analysis: The ZATCA implementation was calculating the payable amount strictly as (TaxInclusiveAmount - PrepaidAmount). This change ensures the rounding amount is fetched and added to the total payable calculation opw-5939550