Wednesday, March 4, 2026
17 changes · saas-18.4
Resolved issues and error corrections
Down payment invoice lines now receive an appropriate 0% tax when tax is required on every invoice line, including sales orders and Point of Sale flows. This helps keep invoices compliant in cases involving fixed-price taxes or configurations that mandate tax details on all lines.
Original PR description
In certain conditions all lines in invoice require a tax. When making a down payment from an order containing products using fixed price tax, the corresponding invoice line was created without tax.…
In certain conditions all lines in invoice require a tax. When making a down payment from an order containing products using fixed price tax, the corresponding invoice line was created without tax. The issue appear both when making the down payment from the sale order and from the PoS. Steps to reproduce: ------------------- * Create a fixed price tax of 10€ * Create a product with this tax * Create a sale order with this product and make a downpayment of 10% > Observation: The down payment line has no tax set. * Open PoS and make a down payment of 10% for the same order * Pay and invoice the order > Observation: The down payment line has no tax set. Why the fix: ------------ If the tax is required on every invoice line we manually add a 0% tax to the down payment line to ensure that the invoice is compliant. At the moment we only add the tax when peppol is activated on the current company. But the `_require_tax_ids_on_invoice_lines` method can be overriden by other modules if downpayment lines also require tax. opw-5853070 Forward-Port-Of: odoo/odoo#251650 Forward-Port-Of: odoo/odoo#247748
Point of Sale now shows a clear popup when invoice creation fails for a completed order, such as when a company has an untrusted bank account. This helps cashiers understand why an invoice cannot be generated instead of seeing no feedback.
Original PR description
Steps to reproduce: - Add untrusted bank account to the database's selected company's contact - Finalize an order in point of sale through register - While in register, go to orders and click on the invoice button for the finalized order Current behavior: - There is no indication of why you can't generate an invoice Expected behavior: - There should be a popup to the user identifying the error (e.g. untrusted bank account) This addresses a side effect of: https://github.com/odoo/odoo/pull/248108 opw-5946239 Forward-Port-Of: odoo/odoo#251197 Forward-Port-Of: odoo/odoo#249558
Self-service point-of-sale orders now use the same validation checks as regular POS orders. This helps prevent invalid order data from being accepted, improving reliability for online payments, restaurant orders, and self-ordering flows.
Original PR description
*: pos_online_payment_self_order, pos_restaurant, pos_self_order This commit improves the data validation of pos self order by using the same validation as the one used for regular pos order. Forward-Port-Of: odoo/odoo#251379 Forward-Port-Of: odoo/odoo#250415
Fixed an accounting issue where taxes marked as applying to all fiscal positions could be skipped when a customer’s fiscal position was automatically selected. This ensures sales and invoices calculate expected taxes more reliably for affected customers.
Original PR description
### Issue: No tax will be applied if in taxes, fiscal position is set to all. #### Steps to reproduce: 1- Create a tax, and in the tax form, leave `Fiscal Position` field blank, which in this case…
### Issue: No tax will be applied if in taxes, fiscal position is set to all. #### Steps to reproduce: 1- Create a tax, and in the tax form, leave `Fiscal Position` field blank, which in this case `all` will be shown in placeholder. 2- Set Domestic FP to be applied automatically, and set the country to `US`. 3- Create a Partner with `US` country_id. 4- Create a product, and apply the created tax to sale taxes. 5- Create a SO with created partner and the created product. 6- As you see, the tax is not applied to the line, while if you check SO's fiscal position, it is set to Domestic. Expected: As tax's fp is set to all, we expect this tax being applied with Domestic fp. ### Cause: In this line, if no `tax_ids` is set, it means fp has not tax_ids: https://github.com/odoo/odoo/blob/0c3ae7f78d313885984c99a4e57485d9660dd974/addons/account/models/partner.py#L154-L158 However, this might also mean the tax has no fp because `fp.tax_ids` is a Many2Many relation. In the forms, `tax.fiscal_position_ids` being empty is shown as `all` in the placeholder, which means when no tax applied to fp, we expect all taxes to be mapped. ### Fix: This can be fixed by making sure the fp.tax_ids is not empty because there is no `tax.fiscal_position_ids` set. ### Remark: In this fix we rename `TestInvoiceTaxes._create_invoice` to `_create_invoice_taxes_per_line` to avoid override of `AccountTestInvoicingCommon._create_invoice`. This is already done on saas-19.1+. opw-5463245 Forward-Port-Of: odoo/odoo#244155
Fixes an issue where users configuring related fields could see fields from the wrong model when two linked fields shared the same name. This helps Studio users select the correct relationship path and avoids confusion or incorrect setup during customization.
Original PR description
You cannot create a related field with a related field chain that has two or more fields with the same name in a row. When you click the relation icon for a field the wrong model will be displayed if…
You cannot create a related field with a related field chain that has two or more fields with the same name in a row. When you click the relation icon for a field the wrong model will be displayed if the related model you are trying to show has a many2one with the same name as the field that was selected. Steps to reproduce 1. Create two many2one fields with studio that have the same name, one of the fields must link to the model the other field is on. i.e. `model_a.x_studio_test(relation=model_b), model_b.x_studio_test(relation=other_model)`. 2. Create a related field on model_a and click the related icon for the test field. 3. The popover will now be displaying the fields for other_model instead of model_b. Cause: This behavior was introduced by adding support for properties in this [pr](https://github.com/odoo/odoo/pull/189841). Solution: Check if `fieldDef` is a property or not in order to decide what to pass to `loadPath`. opw-ticket 5459944 Forward-Port-Of: odoo/odoo#249185
This fix keeps table editing controls from spilling into nearby table areas when only part of a table is visible. It also ensures the table menus appear correctly when users hover over lists inside table cells, making editing tables more reliable in the HTML editor and Studio.
Original PR description
**Current behavior before PR:** - Table menu handlers could overflow into adjacent table areas when the targeted part of the table was only partially visible within the container. - When a table cell contained a list, hovering over the list element did not display the table UI menus, even though the mouse was inside the cell. **Desired behavior after PR is merged:** - Use a local overlay for the table menu to prevent overflow into adjacent cells. - Table UI menus are now correctly displayed when hovering over list elements inside a table cell. task-5353518 Forward-Port-Of: odoo/odoo#249957 Forward-Port-Of: odoo/odoo#240342
Fixes an issue where changing the bill of materials on a draft manufacturing order could repeatedly add duplicate work steps when the quantity was edited. This keeps manufacturing orders cleaner and helps avoid confusion or extra manual cleanup for production teams.
Original PR description
Steps to reproduce: 1. Create a product and two BoMs: BoM A (with operations) and BoM B (empty). 2. Create a Manufacturing Order (MO) for the product selecting BoM A. 3. Switch BoM A to BoM B, then…
Steps to reproduce:
1. Create a product and two BoMs: BoM A (with operations) and BoM B (empty).
2. Create a Manufacturing Order (MO) for the product selecting BoM A.
3. Switch BoM A to BoM B, then switch back to BoM A.
4. Modify the production quantity field. -> New operation lines are appended every time the quantity is changed.
The issue occurred because _compute_workorder_ids used 'wo.ids' to filter existing workorders. In the "Draft" state (UI/onchange), records exist as "virtual records" (NewIds). For these records, .ids returns an empty list [], which evaluates to False in Python.
Consequently, the existing virtual workorders were filtered out of the dictionary used to map operations to existing lines. The logic assumed the lines didn't exist and used Command.create() instead of Command.update(), causing duplication. Similar issues existed where 'NewIds' were ignored during BoM swaps, leaving "phantom" records in the cache.
Solution:
Removing the '.ids' check and using '.mapped('id')' ensures the computation remains "virtual-aware" and stable across sequential onchanges.
TECHNICAL JUSTIFICATION:
In Odoo 18.0, the ORM explicitly supports using Command.update and Command.delete with virtual records (NewIds) without an origin. This is handled by the 'write_new' method in relational fields:
- Virtual browse wraps IDs in NewId: https://github.com/odoo/odoo/blob/f688c6b66310438fa3e36a207770a63d0d8fffa5/odoo/fields.py#L4826-L4855
opw-5489862
Forward-Port-Of: odoo/odoo#246995Odoo now handles a wider range of errors from the EU VIES VAT validation service. This prevents invoice OCR and partner creation workflows from failing with an error screen when VIES returns malformed responses or is temporarily unreliable.
Original PR description
Catch all `zeep` exceptions instead of only `zeep.Fault`. On 14th of February 2026, the VIES service wasn't working properly, they were returning invalid XML in their response. This caused the `check_vies` call to raise a `zeep.XMLSyntaxError` which wasn't caught, causing a traceback every time VIES was used to validate a VAT number. opw-5938723 (OCR couldn't be refreshed on an invoice because it tried to create a partner from its VAT number and it couldn't be checked with VIES). Forward-Port-Of: odoo/odoo#250123 Forward-Port-Of: odoo/odoo#249853
The analytic distribution filters now correctly distinguish between records where a distribution is present and records where it is missing. This helps accounting and purchasing users get accurate search results when reviewing journal entries, invoice lines, and purchase orders.
Original PR description
**Problem:** When filtering by "Analytic Distribution" in views, using "is set" or "is not set" filters (or searching for False) returns incorrect results. When the filter is 'set' it returns all…
**Problem:** When filtering by "Analytic Distribution" in views, using "is set" or "is not set" filters (or searching for False) returns incorrect results. When the filter is 'set' it returns all records (even the ones without an analytic distribution) and when the filter is 'not set' it returns no records (even the ones without an analytic distribution). **Steps to reproduce:** 1) Go to Accounting > Journal Entries. 2) Apply a filter for Invoice lines > Distribution Analytic Account. 3) Select "is set" or "is not set". 4) Check records. Issue is also reproduceable on Purchase Orders. **Cause:** The `_search_analytic_distribution` method did not correctly handle the case when the value is [False], so it results in an invalid Query. **Solution:** - We need to handle the case when we have False in the value on it's own. opw-5478688 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#251096 Forward-Port-Of: odoo/odoo#247777
This fixes an issue in Recruitment where candidates did not receive an email after their application was refused, even when the user selected the option to send one. Refusal communication now reaches the candidate as expected, helping recruiters keep applicants informed.
Original PR description
__ ## Short functional explanation of the error When a candidate is refused, an email isn't sent to their email address. ## Reproduction Steps 1. Open Mailhog in a separate tab. 2. Go to the Recruitment app and select any job position. 3. Click on new to create a new application. Enter an applicant name and an applicant email. 4. Check Mailhog: a job application has been sent to the applicant. 5. Go back on the Recruitment app and click on Refuse. In the wizard, make sure you toggle Send Email and click on Refuse. ### Expected behavior In Mailhog, a refusal mail has been sent to the applicant. ### Unexpected behavior Nothing is sent. ## Origin of the issue When refusing a candidate, we create a notification in the chatter but we don't call the code to send an email. __ opw-5980079
Employees with flexible work schedules now show as available throughout the week in Gantt views, except during public holidays or approved leave. This prevents Planning, Time Off, Project, and Attendance views from incorrectly blocking days based on assumed work patterns.
Original PR description
### Issue: When an employee has a flexible calendar, its gantt view in planning and other modules, like project or time off, shows incorrect grayed-out days. In general, employees with a flexible…
### Issue:
When an employee has a flexible calendar, its gantt view in planning and other modules, like project or time off, shows incorrect grayed-out days. In general, employees with a flexible calendar should not have any grayed out days other than public holidays.
### Steps to reproduce:
- Create a new work schedule:
- Flexible Hours
- 24 hours per week
- 8 average hours per day
- Create an employee with this work schedule
- Open Planning app
- Only the three first days of the week are not grayed out
### Cause:
With 24 hours per week, the worked time can be done in three days. Odoo considers that the first three days of the given time frame are worked, but the others aren't. This result is returned by `_work_intervals_batch()`. In `_unavailable_intervals_batch()` we then build the unavailabilities by taking the inverse of the work intervals. The only exception was for fully flexible resources (i.e. without a calendar).
### Solution:
The case we need to consider is for flexible resources: they are available anytime, all week long except on public holidays and leaves.
To do this we fix the method `_unavailable_intervals_batch()` which is then called by each module. If the resource is flexible, then we only return the interval of the public holidays overlapping with the time frame.
Works in `appointment`, `hr_holiday_gantt`and `project_enterprise`.
In `planning`, we need to skip the case where nothing is returned in `leaves_mapping` otherwise it will consider the `company_leaves` during weeks with no public holiday or leaves.
In `hr_attendances_gantt`, `_unavailable_intervals_batch()` is not called. So we change the way the unavailabilities were computed to call `_unavailable_intervals_batch()` instead.
opw-4879481
Forward-Port-Of: odoo/odoo#251580
Forward-Port-Of: odoo/odoo#245741This fixes an issue where Studio's XML editor could show translations from the default language of the first website in the database. Website-specific translations are now only applied when editing website content, helping prevent confusing or incorrect translated text in non-website views.
Original PR description
Problem: When opening the Studio XML editor when Website is installed, the translation terms corresponding to the Default Language of the first website in the database are used. This behavior should only be applied to the HTML/CSS Editor in Website. Purpose: Modify Website's override of get_related_views to only return translated views when called with a specific website in context. This is done here by adding a context flag, as to not interfere with customizations made in stable versions. This will be changed for master. Steps to Reproduce in Runbot: 1. Activate a non-English (US) language. 2. Add this language to the Website with the lowest ID in the database, then set it to the Default Language of the Website. 3. Enter Studio and navigate to a view that has translation terms in its view (ex. Invoice PDF Report), then open the XML editor. opw-5136124 Forward-Port-Of: odoo/odoo#249938 Forward-Port-Of: odoo/odoo#237000
Users can now reply to task messages that come from another company, as long as they have access to that company. This removes an error that blocked collaboration in multi-company setups and makes notifications usable across permitted company contexts.
Original PR description
Before these changes, messages from other companies were received, but when trying to reply to them, an error occurred that prevented the response. Steps to reproduce the issue in runbot: 1. In one tab, log in as admin, and in another incognito tab, open demo. 2. Make sure demo has Handle Notifications in Odoo enabled. 3. Set admin in one company and demo in another company. 4. Assign a task to demo. 5. Click on the notification to open the chatter and try to reply. An error is thrown With these changes, the response can be logged when the user has access to the company from which the task was assigned. cc @Tecnativa TT61176 ping @pedrobaeza --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#251327 Forward-Port-Of: odoo/odoo#250677
This fix prevents access errors when users send follow-up reports by post without permission to modify company settings. It ensures the required layout update happens with the appropriate elevated access, so postal follow-ups can be sent reliably.
Original PR description
Issue: Before this commit, when sending a follow up report by post, an access error is thrown if the user doesn't have enough access to modify the res.company model Fix: modifying the external_report_layout_id as sudo opw-5482855 Forward-Port-Of: odoo/odoo#248677
This update fixes an issue where employees with flexible calendars were incorrectly displaying unavailable days in planning and related modules. The change ensures that only public holidays and leaves are reflected as unavailable, providing a more accurate representation of employee availability. This improves the usability of the planning app for flexible workers.
Original PR description
### Issue: When an employee has a flexible calendar, its gantt view in planning and other modules, like project or time off, shows incorrect grayed-out days. In general, employees with a flexible…
### Issue:
When an employee has a flexible calendar, its gantt view in planning and other modules, like project or time off, shows incorrect grayed-out days. In general, employees with a flexible calendar should not have any grayed out days other than public holidays.
### Steps to reproduce:
- Create a new work schedule:
- Flexible Hours
- 24 hours per week
- 8 average hours per day
- Create an employee with this work schedule
- Open Planning app
- Only the three first days of the week are not grayed out
### Cause:
With 24 hours per week, the worked time can be done in three days. Odoo considers that the first three days of the given time frame are worked, but the others aren't. This result is returned by `_work_intervals_batch()`. In `_unavailable_intervals_batch()` we then build the unavailabilities by taking the inverse of the work intervals. The only exception was for fully flexible resources (i.e. without a calendar).
### Solution:
The case we need to consider is for flexible resources: they are available anytime, all week long except on public holidays and leaves.
To do this we fix the method `_unavailable_intervals_batch()` which is then called by each module. If the resource is flexible, then we only return the interval of the public holidays overlapping with the time frame.
Works in `appointment`, `hr_holiday_gantt`and `project_enterprise`.
In `planning`, we need to skip the case where nothing is returned in `leaves_mapping` otherwise it will consider the `company_leaves` during weeks with no public holiday or leaves.
In `hr_attendances_gantt`, `_unavailable_intervals_batch()` is not called. So we change the way the unavailabilities were computed to call `_unavailable_intervals_batch()` instead.
Forward-Port-Of: odoo/enterprise#109281
Forward-Port-Of: odoo/enterprise#105521This update resolves an issue where foreign vendor VAT invoices were not correctly identifying the country of origin for JPK reports. The team has implemented a fix to ensure the country code is accurately included in vendor bills, aligning with Polish tax regulations and improving reporting accuracy. This change was prompted by previous work to address invoice-going-out country codes.
Original PR description
PR #81359 fixed the country code for foreign VAT companies by adding the country code to the start. However, this was only fixed for invoices going out, not vendor bills coming in. [opw-5917264](https://www.odoo.com/odoo/project.task/5917264) Forward-Port-Of: odoo/enterprise#109080
This update corrects inaccuracies in the XML files used for processing Swedish payments (SEPA). Specifically, it ensures the correct BIC number is used, removes a misleading placeholder value, and allows users to select the appropriate payment version even without using the SEPA payment method. This improves the accuracy and reliability of Swedish payment processing.
Original PR description
We currently have customizations for the iso20022 xml file for payments in Sweden. But those customizations aren't correct. This commit fix multiples issues: 1) In DbtrAgt, we sometimes have bankgiro information. But this node should always contain the BIC number for Swedish payments. 2) The _get_cleaned_bic_code method was replacing the real bic code with a fake value like 'SE:Bankgiro', but this seems to be wrong. None of the SE banks ask for this BIC, so we remove it. 3) The sepa_pain_version field is supposed to tell Odoo which pain version to use. But the problem is this field is computed, and only editable once the user set the SEPA payment method, but for iso_se, we want to let the user choose as well, even if he didn't add SEPA as payment method. This commit change the invisible on the field, so it can be edited as soon as iso_se is in the journal payment methods. task-5427570 Forward-Port-Of: odoo/enterprise#105536