Daily updates from Odoo
Monday, June 8, 2026
15 changes · 18.0
Resolved issues and error corrections
This update resolves an error that occurred when generating payment reports for Swiss companies. The issue was triggered when the 'hr_payroll_account_iso20022' module wasn't installed. The fix ensures the system handles missing module configurations gracefully, preventing the report generation process from failing.
Original PR description
*=l10n_ch_hr_payroll,hr_payroll_account_iso20022 When clicking the create payment report button on a payslip for a Swiss company, a traceback occurs if the ``hr_payroll_account_iso20022`` module is…
*=l10n_ch_hr_payroll,hr_payroll_account_iso20022 When clicking the create payment report button on a payslip for a Swiss company, a traceback occurs if the ``hr_payroll_account_iso20022`` module is not installed. Steps to reproduce the error: - Install ``l10n_ch_hr_payroll`` module - Switch to CH Company - Create an Employee and running contract for it - Go to Payroll > Payslip > All payslips > Create a new payslip > Set the employee > Confirm > Create payment report Traceback: ```py ValueError: Wrong value for hr.payroll.payment.report.wizard.export_format: 'iso20022_ch' ``` https://github.com/odoo/enterprise/blob/7792926504a823590fbbe574a96994002a92fc17/l10n_ch_hr_payroll/models/hr_payslip.py#L383 https://github.com/odoo/enterprise/blob/7792926504a823590fbbe574a96994002a92fc17/l10n_ch_hr_payroll/models/hr_payslip_run.py#L13 Here, ``iso20022_ch`` is passed as ``export_format``, However, ``iso20022_ch`` is added to the selection field in the ``hr_payroll_account_iso20022`` module at [1]. When that module is not installed, the selection value does not exist, leading to the above error. [1]: https://github.com/odoo/enterprise/blob/7792926504a823590fbbe574a96994002a92fc17/hr_payroll_account_iso20022/wizard/hr_payroll_payment_report_wizard.py#L11 sentry-7391832811
This update corrects an issue in the l10n_lu_reports module that caused incorrect balance sheet reports due to incorrect data in XML fields. Specifically, fields 2955 and 2956 must be set to zero, as required by Luxembourg's eCDF reporting standards. Fixing this ensures reports are accepted by the eCDF, preventing data rejection and maintaining accurate financial reporting.
Original PR description
Before this commit, fields 2955 and 2956 in the balance sheet could be incorrect. 2955 must always be blank (not exist) and 2956 must always be 0 per: https://ecdf-developer.b2g.etat.lu/ecdf/forms/popup/CA_PLANCOMPTA/2020/en/2/rules page 116 + 117 If they are not these values specifically, submitting the XML to eCDF results in the report being rejected. Steps to reproduce: - Install l10n_lu_reports - Create a journal entry for a closed year (2025) that debits account 142000 and credits another account that starts with a 1 - Go to the balance sheet for 2025 - Download the XML for the report - 2955 is present and 2956 is either not present or is not 0 (behavior varies between versions) Ticket [link](https://www.odoo.com/odoo/project.task/6246564) opw-6246564 Forward-Port-Of: odoo/enterprise#119193
This update fixes a calculation error in the purchase order reporting, ensuring the 'Effective Days To Arrival' metric accurately reflects the time between order confirmation and receipt. Previously, the calculation was flawed, leading to incorrect lead time reporting. This change improves the accuracy of purchase data analysis.
Original PR description
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is…
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back to the planned "days to receive" when nothing has been received yet according to [task](https://www.odoo.com/odoo/project/809/tasks/3691573). The query instead computes age(date_planned, COALESCE(date_done, date_order)), so once a receipt exists it returns date_planned - date_done (the gap between the scheduled date and the receipt) rather than date_done - date_order. https://github.com/odoo/odoo/blob/c06be48ce7277a667719fd756e0a1f63e91cda27/addons/purchase_stock/report/purchase_report.py#L20-L28 opw-6226523 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes an issue where customer pricing on the website was sometimes incorrect due to cached data. The change ensures that pricing is always recalculated based on the current website context, guaranteeing accurate pricing for customers.
Original PR description
Steps to reproduce: - enable pricelists on a website - create a backend-only pricelist with no website, no code and not selectable - assign that pricelist to a customer - access the customer…
Steps to reproduce: - enable pricelists on a website - create a backend-only pricelist with no website, no code and not selectable - assign that pricelist to a customer - access the customer pricelist once outside the website flow so it is cached - create a cart as Public User on the website - log in as that customer Issue: when the cart is reassigned from Public User to the logged-in customer, the order pricelist can switch to the cached backend-only pricelist, even though that pricelist should not be available on the website. Cause: `website_sale` filters partner pricelists depending on the current website, but the cached value of `partner.property_product_pricelist` can come from a non-website context and be reused during cart repricing. Solution: invalidate the cached partner pricelist before recomputing website order pricelists, so the value is resolved again in the current website context. opw-6251887 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves a potential crash in Odoo's environment setup under Python 3.14. The fix ensures that environment data is accessed safely during initialization, preventing errors caused by concurrent modifications to the environment collection. This improves overall system stability.
Original PR description
- Type: ORM - Impact: stability / Python 3.14 compatibility _Note:_ This pattern is also present in **19.0** (`odoo/orm/environments.py`), so the fix should likely be forward-ported. ### Purpose This…
- Type: ORM - Impact: stability / Python 3.14 compatibility _Note:_ This pattern is also present in **19.0** (`odoo/orm/environments.py`), so the fix should likely be forward-ported. ### Purpose This fix prevents intermittent runtime errors occurring during registry initialization when iterating over `transaction.envs`. Under Python 3.14, `WeakSet` iteration may fail if the set is modified during traversal, leading to: `RuntimeError: dictionary changed size during iteration` - Relevant stack trace: ```bash File ".../odoo/api.py", line 586, in __new__ for env in transaction.envs: File ".../python3.14/_weakrefset.py", line 25, in __iter__ for itemref in self.data.copy(): File ".../odoo/tools/misc.py", line 1069, in __init__ self._map: dict[T, None] = dict.fromkeys(elems) RuntimeError: dictionary changed size during iteration ``` ### Root cause Unsafe snapshot creation and iteration over `transaction.envs` (`WeakSet`) while the collection may still be mutated during `Environment` lifecycle operations. `transaction.envs` is a `WeakSet` that can be modified during iteration due to: - `Environment` creation during ORM calls - `WeakRef` cleanup during registry bootstrap - re-entrant calls to `Environment.__new__` ### Additional issue in `OrderedSet.copy()` `WeakSet.__iter__()` internally relies on: ```python self.data.copy() ``` In Odoo, `self.data` may be backed by `OrderedSet`. Before this fix, `OrderedSet.copy()` rebuilt the collection from iteration: ```python return self.__class__(self) ``` This re-entered `OrderedSet.__iter__()` during copy construction itself, making the snapshot operation unsafe when weakref cleanup or recursive `Environment` creation mutated the collection during traversal. The fix copies the underlying mapping directly instead of rebuilding the collection from iteration, ensuring `copy()` remains iteration-safe and side-effect free. ### Why this is safe - `WeakSet` is not safe for concurrent mutation during iteration - `list(transaction.envs)` creates a stable snapshot before traversal - `OrderedSet.copy()` now copies the underlying mapping directly instead of rebuilding the collection from iteration - The new implementation preserves insertion order and shallow-copy semantics - No behavioral change in normal single-env execution --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves a crash in the Asset Depreciation Schedule report that occurred when generating reports with many assets grouped together. The fix ensures the report handles missing data gracefully, preventing errors and allowing users to accurately analyze their assets even with large groups.
Original PR description
#### Description of the issue/feature this PR addresses: Opening the Asset Depreciation Schedule report with a period comparison enabled crashes with KeyError: 'no_format' when prefix grouping is…
#### Description of the issue/feature this PR addresses:
Opening the Asset Depreciation Schedule report with a period comparison enabled crashes with KeyError: 'no_format' when prefix grouping is active (large number of assets in one account group). The report becomes unusable for affected customers.
#### Current behavior before PR:
_regroup_lines_by_name_prefix sums each subline column by indexing prefix_subline['columns'][i]['no_format'] directly. Empty columns are built as {} by _build_column_dict (both col_value and col_data are None), so they have no 'no_format' key. With a comparison period enabled, an asset that has no value in the comparison period produces an empty column for that period; once prefix grouping fires (len(lines) >= prefix_groups_threshold, default 4000), the direct lookup hits that empty dict and raises KeyError: 'no_format'.
#### Desired behavior after PR is merged:
The prefix group total treats a missing 'no_format' as 0, matching the sibling caller in account_asset/models/account_assets_report.py that already guards with .get('no_format', 0). The report builds without crashing and the empty comparison column contributes 0 to the prefix group total.
opw-6225639This update ensures that stock valuation account moves created from sales orders correctly inherit the analytic account specified on the SO line. Previously, these moves didn't utilize the SO's analytic distribution, leading to incorrect accounting. This change aligns the behavior with invoices, providing more accurate tracking of costs by analytic accounts.
Original PR description
PR very similar to https://github.com/odoo/odoo/pull/263236 but here on the SO side instead of PO **Problem:** account move created by stock valuation layer does not take analytic account from SO…
PR very similar to https://github.com/odoo/odoo/pull/263236 but here on the SO side instead of PO **Problem:** account move created by stock valuation layer does not take analytic account from SO **Steps to reproduce:** - make sure you have at least one analytic account - create a storable product with categ standard automated - set a positive cost and a positive on hand quantity - create a SO for 1 quantity - on the SO line of the product, in the analytic distribution column (might need to be unfiltered) set an analytic account - confirm SO and validate delivery - click on the valuation smart button and on the book widget of the stock valuation layer **Current behavior:** the account move lines have no analytic distribution **Expected behavior:** The account move lines should inherit the analytic account from the sale order line like it's the case for the invoice. For the analytic distribution of the Invoice, the selection is : 1) take analytic distribution from SO if one 2) if not, take from distribution model if there is one 3) empty Currently for the account move lines of the svl the selection is: 1) take from distribution model if there is one 2) empty But we should use same selection as for the invoice **Cause of the issue:** When setting the analytic distribution we first try to use the one from PO/SO by calling _related_analytic_distribution() https://github.com/odoo/odoo/blob/4cc1e6884be673523f768d5ec471a1ffa19c5fb4/addons/account/models/account_move_line.py#L1157 But since the account move lines have no sale_line_ids no analytic distribution will be returned https://github.com/odoo/odoo/blob/261b15953ca89657644f52d1cb9ecda6e3b686c5/addons/sale/models/account_move_line.py#L41-L46 opw-6022695
This update resolves an issue where timesheets were incorrectly added to invoices after a partial refund. The fix ensures that timesheets linked to previously fully invoiced orders are no longer considered when generating new invoices, preventing duplicate invoicing and maintaining accurate financial records. This improves invoice accuracy and reduces the risk of errors.
Original PR description
### Steps to reproduce: - Download 'Sales' and 'Timesheets' apps - Create 2 lines for the services product in the SO, invoicing policy = based on timesheets - Create 2 timesheets for both SO items - Invoice the SO - Create a credit note for line 1 => only line 2 is invoiced and line 1 is now released - Back to the SO > create invoice again > Line 2 is added to the invoice again. ### Cause of Issue: When generating the new invoice, `_recompute_qty_to_invoice` identifies timesheets linked to refunded invoices. Because the original invoice was partially refunded, all timesheets attached to that invoice match the domain used to locate timesheets—even the timesheets for line 2, which wasn't refunded. ### Fix: Ensures that lines that have already been completely invoiced are safely ignored and not inadvertently re-added to subsequent invoices. opw-6217684
This update resolves an issue where users without write access to invoice sequences would receive an error when generating global invoices in the Point of Sale (PoS) module. Previously, this prevented successful invoice creation. This change ensures invoices can be generated correctly regardless of user permissions, improving the reliability of the Mexican CFDI invoicing process.
Original PR description
When generating a global invoice, if the user has no write access to the sequence, an access error is triggered even though he can generate the invoice correctly. Steps to reproduce: ------------------- * Create some order in the PoS * Try to generate the global invoice with Marc Demo > Observation: You get an access error. * Create an invoice with CFDI to public checked * Add any product and validate the invoice * Try to generate the global invoice with Marc Demo > Observation: You get an access error. opw-6041291 Forward-Port-Of: odoo/enterprise#114478
This update ensures that shift workloads remain accurate after undoing the auto-plan feature. Previously, undoing the auto-plan would reset the allocated hours, leading to incorrect workload calculations. The fix maintains the original allocated hours while allowing the percentage to adjust based on the new slot context.
Original PR description
Steps to Reproduce --- 1. Open the Planning module 2. Create an open shift with allocated_hours 3. Click Auto Plan 4. Click Undo on the auto-plan notification Issue --- Undoing an auto-plan operation…
Steps to Reproduce --- 1. Open the Planning module 2. Create an open shift with allocated_hours 3. Click Auto Plan 4. Click Undo on the auto-plan notification Issue --- Undoing an auto-plan operation triggers recomputation of allocated_hours, causing the shift to lose its original workload value. Current Behaviour --- When resource_id is set to False during undo: - _compute_allocated_hours is triggered (depends on resource_id) - _compute_allocated_percentage is triggered (depends on allocated_hours) - Both fields are recalculated, potentially changing allocated_hours from its pre-assignment value Expected Behaviour --- Undoing auto-plan should preserve allocated_hours at its pre-assignment value while allowing allocated_percentage to adapt to the new context (open slot vs assigned resource). Fix --- Use protecting context manager in action_rollback_auto_plan_ids to prevent allocated_hours from being recomputed when resource_id is removed. This allows allocated_percentage to recalculate naturally based on slot duration while keeping allocated_hours stable. task - 4952149
This update resolves an issue where the URL used for OAuth authentication with the Romanian tax authority (ANAF) was inconsistent. Previously, the URL was dynamically generated based on the user's access method, leading to mismatches and authentication failures. This change ensures the correct, standard URL is used, enabling proper tax reporting functionality.
Original PR description
The `_compute_l10n_ro_edi_callback_url` method was using `request.httprequest.url_root` to build the OAuth callback URL. The URL is derived from the current HTTP request, meaning it reflects however the user accessed the session at that moment (e.g. internal IP, localhost, non-standard port). This produces a callback URL that does not match what was registered with ANAF, breaking the OAuth flow. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where moving Odoo databases via the command line would inadvertently deregister subscription codes. A new `--move` flag has been added to the `odoo db load` command, ensuring the database's original UUID is retained during a server-to-server move. This maintains the integrity of your Odoo subscriptions.
Original PR description
### What & why `odoo db load` always calls `restore_db(..., copy=True)`, which forces the generation of a new `dbuuid` via `ir.config_parameter.init(force=True)`. That is the right default when…
### What & why `odoo db load` always calls `restore_db(..., copy=True)`, which forces the generation of a new `dbuuid` via `ir.config_parameter.init(force=True)`. That is the right default when *duplicating* a database, but it breaks the intended behaviour when *moving* a database between servers: Enterprise subscription codes are registered against the database UUID, so regenerating it deregisters the moved database. The web database manager already lets the user choose between copying and moving (the `copy` flag of the `/web/database/restore` route), but the CLI exposed no equivalent and forced a copy unconditionally. The CLI is the better tool for server-to-server moves: it isn't subject to reverse-proxy upload/timeout limits and can run unattended or interactively. ### Steps to reproduce the current limitation 1. On server A: `odoo db dump mydb mydb.zip` (Enterprise DB registered to its UUID) 2. On server B: `odoo db load mydb mydb.zip` 3. `database.uuid` has changed → the subscription is deregistered ### Fix Add a `--move` flag to `odoo db load` that maps to `restore_db(copy=False)`, keeping the original UUID. The default remains `copy=True`, so existing behaviour is unchanged. ```sh odoo db load mydb mydb.zip # unchanged: restore as a copy (new UUID) odoo db load --move mydb mydb.zip # new: restore as a move (keep the UUID) ``` ### Backport request This would be greatly appreciated as a backport to 18.0, 17.0, and 16.0 as well. Those are precisely the versions that ship the `odoo db` CLI subcommand, so the fix is applicable to all of them — which is why the backport range is 16.0 → 19.0 and stops at 16.0. Forward-Port-Of: odoo/odoo#268501
This update fixes an issue where discounted vendor bills (UBL format) were incorrectly processed, leading to incorrect quantity and discount calculations. The change ensures that a 'LineExtensionAmount' of 0, representing a 100% discount, is correctly handled, improving the accuracy of imported invoice data.
Original PR description
When importing a Peppol/UBL vendor bill containing a line with a 100% discount, the line was created in Odoo with quantity=1 and discount of 100*original_qty, instead of the expected…
When importing a Peppol/UBL vendor bill containing a line with a 100% discount, the line was created in Odoo with quantity=1 and discount of 100*original_qty, instead of the expected quantity=qty_original and discount=100%. This happened because the line-level branching in `_import_ubl_invoice_line_add_price_unit_quantity_discount` relied on the truthiness of `line_extension_amount` to detect whether the `LineExtensionAmount` node was present in the XML. a line with a genuine `<cbc:LineExtensionAmount>0</...>` was indistinguishable from a line where the node was missing, and fell through to the fallback branch intended for incomplete XML. That fallback reconstructs the quantity from `<cbc:BaseQuantity>`, ignoring `<cbc:InvoicedQuantity>`, and then computes the discount percentage against the wrong denominator. a `LineExtensionAmount` of 0 is the only legal way to express a fully discounted line, so this case must be distinguished from the node being absent. the fix is simply checking if the line exist not if its True opw-6176349 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where purchase order confirmations would fail when a delivery type was configured to not use a warehouse. The fix ensures that the system correctly identifies the final destination location, even when a warehouse isn't associated with the delivery type, preventing a TypeError. This improves the reliability of purchase order processing.
Original PR description
Bug introduced in: https://github.com/odoo/odoo/commit/e2efdf75f67e631ed7622bb01c127120e639f6c5 Steps to reproduce: Clear the Warehouse field (set it to False) Create a purchase order Set "Deliver…
Bug introduced in: https://github.com/odoo/odoo/commit/e2efdf75f67e631ed7622bb01c127120e639f6c5
Steps to reproduce: Clear the Warehouse field (set it to False) Create a
purchase order Set "Deliver To" to the operation type with no warehouse
Add any product Confirm the PO → TypeError is raised
Steps to reproduce the bug:
- Have at least 2 warehouses
- Go to Inventory > Configuration > Operation Types > Receipts
- Clear the Warehouse field (set it to False)
- Create a purchase order:
- Set "Deliver To" to the operation type with no warehouse
- Add any product
- Try to confirm the PO
Problem:
A traceback is triggered:
``` return self.parent_path.startswith(other_location.parent_path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: startswith first arg must be str or a tuple of str, not bool
```
`_get_final_location_record` computes `wh_stock_loc` from
`picking_type_id.warehouse_id.lot_stock_id`. When `warehouse_id`
is False (a valid configuration, operation types can be detached from
any warehouse), `lot_stock_id` short-circuits to False
Solution:
guard the _child_of call with not wh_stock_loc. When the
picking type has no warehouse, wh_stock_loc is falsy and there is
nothing to compare against, so the method falls back to
default_location_dest_id (the only destination available).
opw-6253817This update fixes an error in the Colombian DIAN invoice processing that incorrectly flagged invoices due after 5 PM Bogota time. The change ensures the system uses local Bogota time for date calculations, resolving a validation issue and improving the accuracy of DIAN reporting. This prevents delays and errors when submitting invoices.
Original PR description
**Steps to reproduce:** * Install `l10n_co_edi` module with DEMO DIAN mode enabled. * Go to Accounting > Vendor > Bills and create a new bill. * Select any Colombian partner different from…
**Steps to reproduce:** * Install `l10n_co_edi` module with DEMO DIAN mode enabled. * Go to Accounting > Vendor > Bills and create a new bill. * Select any Colombian partner different from `Consumidor Final`. * Set the invoice date to 6 days in the past. * Select the DIAN Support Documents journal and a product with UNSPSC category. * Confirm the bill and click `Send Support Document to DIAN` after 5 PM Colombia time. **Observed behavior:** * An error is raised stating the issue date cannot be older than 6 days or more than 6 days in the future, even though the invoice date is within the allowed window in Colombia local time. **Cause:** * The date window validation in `_check_move_configuration` used `fields.Datetime.now()` which returns UTC time. Since Colombia is UTC-5, after 5 PM local time the UTC clock has already rolled over to the next calendar day, making a 6-day-old invoice appear 7 days old and failing the validation incorrectly. **Fix:** * Convert the current UTC datetime to the `America/Bogota` timezone and extract its local date before computing the allowed date window. * Compare directly against `move.invoice_date` (a `date` field) instead of using `fields.Datetime.to_datetime()`, keeping the comparison consistent as `date` vs `date`. opw-6011502