Wednesday, August 26, 2026
13 changes · 18.0
Resolved issues and error corrections
Vendor bill XML imports now handle cases where the supplier country is not included in the file. When that information is missing, Odoo uses the country already set on the supplier record, avoiding unnecessary upload failures for accounting users.
Original PR description
Steps to reproduce: - Install accounting and create BE company - Create BIS3 xml where there's no country for AccountingSupplierParty - From BE company, upload the xml vendor bill Current behavior: Error when trying to upload xml Expected behavior: No error Cause of issue: Currently there's no check to see if a country exists in the BIS3 xml. This PR adds a check and adds a fallback to get the country attached to the partner record if there's none present in the xml opw-6498830
Changing a project's visibility no longer fails when the project folder contains shortcuts to other documents. This ensures project access updates are applied as expected while still preventing direct access changes on shortcut-only selections.
Original PR description
Changing a project's visibility fails when its documents folder contains a shortcut. The visibility change is never applied and the following error is raised: "You can not update the access of a…
Changing a project's visibility fails when its documents folder contains a shortcut. The visibility change is never applied and the following error is raised: "You can not update the access of a shortcut, update its target instead." ### Reproduction steps - Create a project and add a document to its folder. - Create another document outside the project's folder. - Create a shortcut to that document in the project's folder. - Change the project's visibility. ### Cause Changing a project's visibility updates the access rights of its folder and documents together. The shortcut access check is meant to reject operations performed only on shortcuts. However, reading `shortcut_document_id` on a recordset returns the shortcut targets found across that recordset. Therefore, the presence of a single shortcut makes the check reject the whole operation. This prevents regular documents and the project folder from having their access updated. ### Fix Only reject access updates when all records involved are shortcuts. This preserves the protection against changing shortcut access directly while allowing project access updates to include shortcuts alongside regular documents and folders. opw-6472637
This fixes an Outlook calendar sync issue where editing one moved occurrence could cause the whole recurring series to be deleted and recreated. The change keeps attendee and occurrence-specific updates limited to the intended event, preventing incorrect changes from spreading across the series.
Original PR description
The stored rrule of a recurrence embeds a DTSTART line based on the recurrence dtstart (the smallest start among its events). When the first occurrence is moved in Outlook, the Odoo dtstart no longer…
The stored rrule of a recurrence embeds a DTSTART line based on the recurrence dtstart (the smallest start among its events). When the first occurrence is moved in Outlook, the Odoo dtstart no longer matches that DTSTART, but the stored rrule is not recomputed at that point (it only depends on the pattern fields). On a later sync touching the seriesMaster (e.g. after adding an attendee to the moved occurrence), the recurrence values are written again and the rrule is reserialized with a DTSTART based on the moved occurrence. _write_from_microsoft() took this new rrule string as a pattern change and reapplied the recurrence: all occurrences were deleted and recreated as copies of the moved one, spreading its specific data (e.g. the newly added attendee) to the whole series. Ignore the DTSTART line when comparing the rrule before and after the write: a DTSTART-only difference does not reflect any pattern change in Outlook. An actual pattern change (FREQ, UNTIL, INTERVAL, ...) still reapplies the recurrence as before. Steps to reproduce: 1. In Outlook, create a recurring event 2. In Odoo, run the calendar sync 3. In Outlook, move the first occurrence of the recurrence (shift its start and stop time by 30 minutes) 4. In Odoo, run the sync 5. In Outlook, add an attendee to that same first occurrence 6. In Odoo, run the sync All the occurrences are deleted and recreated as copies of the first one, and the attendee ends up on every occurrence instead of one. opw-5129848 Forward-Port-Of: odoo/odoo#269549
The website shop now rejects combo products when required choices are missing, even if someone bypasses the disabled button in the browser. This prevents customers from placing and paying for orders with incomplete product configurations.
Original PR description
Steps to reproduce: =================== 1. Publish a combo product whose choices each offer more than one item, so the combo configurator is shown. 2. On the shop, open the product and click "Add to…
Steps to reproduce: =================== 1. Publish a combo product whose choices each offer more than one item, so the combo configurator is shown. 2. On the shop, open the product and click "Add to Cart". 3. Select an item for one combo choice only. The dialog's "Add to cart" button stays disabled. 4. Remove the `disabled` attribute from that button with the browser developer tools and click it. => The combo is added to the cart with one of its choices unanswered, and the order can be paid in that state. Root cause: =========== The incomplete selection is only prevented on the client side, by disabling the button until every choice has been answered. Server side, `/website_sale/combo_configurator/update_cart` only rejects a completely empty selection, never that the selected items cover every choice. Fix: ==== Reject the request unless the selected combo items cover exactly the combo choices of the product. Comparing the set of choices rather than counting the items also rejects a selection answering the same choice twice while leaving another one unanswered. opw-6478837 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update prevents users from creating a fiscal year that fully contains an existing fiscal year. It helps keep accounting periods accurate and avoids reporting or closing issues caused by overlapping fiscal year dates.
Original PR description
Before this commit: - The current constraint for overlap check allows if we define a new, larger fiscal year that completely swallows an existing smaller one (e.g., creating Aug 2025 - Nov 2026 when Sept 2025 - Oct 2026 already exists). After this commit: - The constrain domain was changed to consider the above missed case. no task Forward-Port-Of: odoo/enterprise#128942
Databases created with a selected country can now install Point of Sale demo data successfully. The accounting setup now completes earlier so required bank journals are available before later apps load their sample data.
Original PR description
Fixes #266631 ## Problem When creating a database with a country selected (e.g. India or any country with a localization module), installing point_of_sale with demo data enabled raises a UserError…
Fixes #266631
## Problem
When creating a database with a country selected (e.g. India or any
country with a localization module), installing point_of_sale with demo
data enabled raises a UserError about a missing bank journal, causing
the entire demo data installation to fail with this warning:
Module point_of_sale demo data failed to install, installed without demo data
The issue does NOT occur when no country is selected during database
creation, because Odoo falls back to generic_coa which sets up all
journals before POS demo data loads.
## Root Cause
Module loading follows this sequence:
data -> demo -> state='installed' -> commit
When a localization module (e.g. l10n_in) reaches the installed state,
IrModule.write detects the missing chart template and stores try_loading
on registry._auto_install_template. However this deferred loading only
executes in _register_hook, which runs after ALL modules finish loading.
When point_of_sale loads after l10n_in but before _register_hook fires,
its demo data calls load_onboarding_furniture_scenario() which calls
_create_journal_and_payment_methods(). At this point the bank journal
has not been created yet, causing the crash.
Debug proof:
With India selected:
Chart Template: False
Journals: Cash Furn. Shop (cash), Point of Sale (general)
Bank journal found: False <- causes UserError
With no country selected:
Chart Template: generic_coa
Journals: Bank (bank), Cash (cash), Customer Invoices (sale)...
Bank journal found: True <- works fine
## Fix
Add a cr.precommit call in IrModule.write to execute
_auto_install_template. This ensures the chart template and its journals
get loaded at the end of the localization module's loading cycle,
making the bank journal available for subsequent modules like
point_of_sale during their loading phase.
The _register_hook fallback is kept as a safety measure and now acts
as a no-op if precommit already handled the installation.
## Steps to Reproduce
1. Create a new database from /web/database/manager
2. Enable Load Demo Data
3. Select any country (e.g. India)
4. Login and install point_of_sale
5. Observe: Module point_of_sale demo data failed to install
## Current behavior before PR
point_of_sale demo data fails to install when any country/localization
is selected at database creation.
## Desired behavior after PR is merged
point_of_sale demo data installs successfully regardless of which
country or localization is selected at database creation.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prPoint of Sale now checks whether combo items are still available before completing an order. If an item was removed in another session, staff see a clear, user-friendly message instead of a confusing technical error.
Original PR description
**Steps to reproduce:** - Open a PoS with a combo already in, like the sushi combo - In a duplicate tab, go in the combo settings - Delete an option from a combo, like the maki menu - Go back to the POS tab, order the combo with the deleted combo item - Pay for the order, an error appears **Why the fix:** Once the order goes to the backend, it realizes that the combo item is not available anymore, so it throws an error. The problem is that this error is a bit verbose and not very user friendly. We now check that the combo items are still available for the current combo before creating the order. If we can't find the product in the combo's available products, we throw a user error explaining the situation. opw-5952766
Costs linked to projects are now matched to the correct sales order even when projects share the same analytic account or a bill line uses multiple analytic accounts. This prevents valid reinvoiceable costs from being missed, helping ensure customers are billed correctly.
Original PR description
### Before this fix --- The `_get_so_mapping_from_project()` method returns a mapping where the key is the move line ID and the value is a `sale.order` record (or `None`). Because of the issues…
### Before this fix
---
The `_get_so_mapping_from_project()` method returns a mapping where the key is
the move line ID and the value is a `sale.order` record (or `None`).
Because of the issues described below, a valid `sale.order` could be available
for reinvoicing, but the corresponding move line might still not be mapped to
that sale order. As a result, the move line is not added to the reinvoiceable
sale order.
However, the implementation has two issues:
#### 1. Projects are overwritten when they share the same analytic account
`project_per_accounts` is built as a dictionary mapping an analytic account ID
to a single project. If multiple projects reference the same analytic account,
each new assignment replaces the previous one. As a result, only the last
project associated with a given analytic account is retained.
**Example:**
* Analytic Account **AA1** is linked to **Project A** and **Project B**.
* The dictionary becomes `{AA1: Project B}`.
* **Project A** is lost, even though it also references **AA1**.
**Steps to reproduce:**
1. Create an analytic account **AA1**.
2. Create **Project A** and **Project B**, both linked to **AA1**.
3. Create **Sale Order SO1** linked only to **Project A**.
4. Create a vendor bill (or expense) that generates an AML using **AA1** for a
product configured with **Reinvoice Costs = At Sales Price**.
5. Validate the document.
**Expected behavior:**
The product should be added to **SO1** for reinvoicing.
**Actual behavior:**
The move line is not mapped to **SO1**, so no sale order line is created.
#### 2. Previously found projects are overwritten during iteration
The `project` variable is reassigned on every iteration of the loop. After the
loop completes, it only contains the project (or lack of one) corresponding to
the last processed analytic account. This can cause valid projects found earlier
in the loop to be discarded.
**Example:**
* Move line has analytic accounts **AA1** and **AA2**.
* **AA1** maps to **Project A**.
* **AA2** has no linked project.
* After the loop, `project` is `None`, even though **Project A** was found.
**Steps to reproduce:**
1. Create analytic accounts **AA1** and **AA2**.
2. Create **Project A** linked to **AA1** only.
3. Create **Sale Order SO1** linked to **Project A**.
4. Create a vendor bill (or expense) whose AML is distributed between **AA1**
and **AA2**, where **AA2** is processed after **AA1**.
5. Validate the document.
**Expected behavior:**
The move line should still be mapped to **SO1** because **AA1** references
**Project A**.
**Actual behavior:**
The last processed analytic account (**AA2**) overwrites the previously found
project, causing the move line not to be linked to **SO1**.
### After this fix
---
* `project_per_accounts` stores **all** projects associated with each analytic
account instead of keeping only the last one.
* The project lookup preserves all valid project candidates instead of
overwriting previously found results during iteration.
* As a result, the method can resolve the related `sale.order` in more cases,
improving the overall accuracy of the mapping.
> **Note:** This change prevents valid project associations from being lost
> when multiple projects share an analytic account or when multiple analytic
> accounts are processed for the same move line.
**OPW:** 6294615Payments in currencies with whole-number rounding, such as HUF, now correctly record small exchange rate gains or losses. This prevents valid exchange differences from being misclassified as suspense amounts or left open on receivables, improving accounting accuracy.
Original PR description
Steps to Reproduce: - Set company currency to EUR (or USD). - Configure a bank journal in HUF (or any 0-decimal currency) with Gain/Loss accounts set and Sales journal as well. - Set two HUF exchange…
Steps to Reproduce: - Set company currency to EUR (or USD). - Configure a bank journal in HUF (or any 0-decimal currency) with Gain/Loss accounts set and Sales journal as well. - Set two HUF exchange rates: 1 EUR = 270.6 (invoice date) and 1 EUR = 272.9 (payment date) - giving a ~0.35 difference. - Create and post a customer invoice for 11,480 HUF on the first date. - Register a bank payment for 11,480 HUF on the second date. - Reconcile the payment against the invoice and validate. Issue: No Exchange Gain/Loss line is created for the ~0.35 difference. Instead it's posted to the Suspense account, or left as an open balance on Receivable, even though a real exchange difference exists. Differences of 0.50 or more are handled correctly, confirming the failure is tied to a fixed 0.50 threshold. Root Cause: `_lines_get_account_balance_exchange_diff` correctly computes `exchange_diff_balance` in company currency and correctly checks it for zero using `company_currency_id.is_zero()`. Immediately after, `_lines_get_exchange_diff_values` performs a second zero-check on the same value, but against `line.currency_id` (the transaction currency, e.g. HUF) instead of company_currency_id. Since HUF's rounding=1.0 gives an `is_zero()` threshold of 0.5 (half the rounding unit), any real company-currency difference below 0.50 passes the first (correct) check but is wrongly discarded by the second (wrong-currency) check. Solution: Corrected the second zero-check to use self.company_currency_id instead of line.currency_id, matching the value's actual currency. Result: Exchange differences now post correctly to Gain/Loss regardless of the transaction currency's rounding precision. opw - 6421574
Fixed an issue that could prevent HR users from marking several appraisals as done at once. Completion notifications are now sent separately for each appraisal, so the batch action finishes reliably and keeps employees informed.
Original PR description
Steps to reproduce: - select multiple appraisals and try to mark as done from list view. Issue: - The completion notification uses an appraisal variable assigned by a previous loop, raising an UnboundLocalError. Furthermore, message_notify() requires a singleton. Fix: - notify and post the completion message for each appraisal explicitly. task-6479018 Forward-Port-Of: odoo/enterprise#128207
This change rolls back a recent GIF resizing update because it caused slowdowns and memory errors when pages displayed several GIF images. It helps restore more reliable loading of views that include animated images, such as Kanban pages.
Original PR description
Revert commit d9fae40571c4f10c17fe00efc087cb25b30b85ab as it's slow on odoo.com and the call to `frame.copy()` is raising a MemoryError when loading a KanbanView with multiple gifs. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes inconsistent timezone setup in HR Attendance overtime tests by matching each test employee's work calendar to their own timezone. It helps prevent false test failures and keeps attendance absence checks reliable across locations such as Tokyo and Honolulu.
Original PR description
The overtime tests created employees in Tokyo and Honolulu while leaving them on the company calendar configured in another timezone. This made attendance day computation depend on inconsistent employee and calendar timezones, causing the Tokyo absence detection test to fail after technical attendances started being created at the employee's local midnight. This commit assigns each employee a resource calendar using the same timezone as the employee so the test setup reflects a consistent working schedule. This commit backports test adjustments from https://github.com/odoo/odoo/pull/189839 to make sure the test passes. [error-242469 ](https://runbot.odoo.com/odoo/error/242469) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Changing the unit of measure on manufacturing component lines no longer overwrites an existing lot expiration date. This prevents accidental changes to expiry information during production operations, helping maintain accurate traceability and compliance data.
Original PR description
Version: -------- - 18.0+ Steps to reproduce: ------------------- - Install `mrp_product_expiry` - Enable **Lots & Serial Numbers** , **Expiration Dates** and **Units of Measure**. - Create a…
Version: -------- - 18.0+ Steps to reproduce: ------------------- - Install `mrp_product_expiry` - Enable **Lots & Serial Numbers** , **Expiration Dates** and **Units of Measure**. - Create a lot-tracked product and enable **Expiration Date** - Update the product's on-hand quantity and assign an expiration date to the lot - Create and confirm a Manufacturing Order using this product as a component - Open the detailed operations of the component move - Change the move line UoM Issue: ------ Changing the move line UoM recomputes the expiration date, replacing the existing value. Cause: ------ The expiration date is computed by an onchange that depends on `product_uom_id`. https://github.com/odoo/odoo/blob/0bb7f7f73ca919b10ad986f3357b4c3d53e511b9/addons/product_expiry/models/stock_move_line.py#L44-L52 `picking_type_use_create_lots` is a related field to `picking_type_id.use_create_lots` and `use_create_lots` is default value as `True` https://github.com/odoo/odoo/blob/ab031c4f552a3ec1ba5d367938fe7551428da48e/addons/stock/models/stock_picking.py#L51-L52 The `mrp_operation` picking type is configured with `use_create_lots = True` so that users can create new lots/serial numbers during production. As a result, `picking_type_use_create_lots` evaluates to `True` for manufacturing move lines, causing the onchange to recompute the expiration date. The product UoM does not affect expiration date computation, making this dependency unnecessary. Fix: ---- Remove `product_uom_id` from the onchange dependencies. This prevents changing the UoM from recomputing the expiration date while preserving the existing expiration date assigned to the lot. Alternative Fix: ----------------- * We can add the same logic used in the compute method to the `onchange` so that, when a lot is selected, the expiration date is taken from the lot if an expiration date is already defined on it. https://github.com/odoo/odoo/blob/5d5f5381c27f67a8655a1c18bf1802c877d4cae2/addons/product_expiry/models/stock_move_line.py#L34-L35 * We can also add`product_uom` to the compute dependencies Note: ------ This issue is not reproducible from saas-18.4 it resolve in this [commit](https://github.com/odoo/odoo/commit/fa764f16ab39ddff1deb49745dc53ee43a95f3b8#diff-66c730afeacd06cdad658f5414a5c7aa68917be400829b07adc636f35113f04c) --- opw-6409214 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr