Daily updates from Odoo
Monday, June 8, 2026
17 changes · saas-18.3
New functionality added to Odoo
This update adds support for the Hacienda Foral de Navarra tax agency within Odoo's SII invoicing system. It addresses a specific requirement for explicit XML namespace declarations, ensuring correct invoice submission to the Navarra SII system. This expands Odoo's compliance with Spanish tax regulations.
Original PR description
The Hacienda Foral de Navarra uses the same SII XML format as AEAT but sends invoices to a different endpoint. Additionally, Navarra requires explicit XML namespace declarations in the SOAP envelope header, which the standard zeep serializer does not include by default. This adds the Navarra tax agency as a new option in the company SII configuration, defines its production and test endpoints, and injects the required namespaces in the request header when the Navarra agency is selected. task-5946583 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#263048
Resolved issues and error corrections
This update fixes a calculation error in online orders using UrbanPiper, ensuring that the displayed price (including tax) accurately reflects the total cost. Previously, the system incorrectly calculated the price excluding tax. This change ensures accurate pricing and a better customer experience for online transactions.
Original PR description
Steps to reproduce: --- - Configure Point of Sale with UrbanPiper credentials. - Sync a product priced at 100 with a 5% GST (tax type = Tax Included). - Place a test order. Issue: --- - Wrong calculation in order line: - unit_price: 95.24 - Tax Excl. price: 90.70 - Tax Incl. price: 95.24 - Expected: - unit_price: 100 - Tax Excl. price: 95.24 - Tax Incl. price: 100 Cause: --- - While computing the unit_price with Tax Included, the tax amount was not added back. Fix: --- - Ensure unit_price includes the tax amount when tax type is Tax Included. task-5031196 Forward-Port-Of: odoo/enterprise#119314 Forward-Port-Of: odoo/enterprise#92854
This update resolves an issue that prevented Odoo from correctly duplicating databases used for testing the German POS certification module (l10n_de_pos_cert). Specifically, the system was removing key identifiers during duplication, leading to errors. This change ensures proper functionality during database duplication, improving testing and development processes.
Original PR description
In this commit: -------------------- - On a duplicate database `client_id` and `tss_id` are removed so it works as test in neutralized dbs without throwing errors. task- 5457231 Forward-Port-Of: odoo/enterprise#104119
This update resolves an issue that prevented users from successfully attaching PDF invoices when using the Nilvera e-invoicing client. The fix ensures that the system correctly handles binary PDF data, addressing a compatibility problem with Python 3.14's stricter base64 validation rules. This ensures invoices with attachments are processed correctly.
Original PR description
This commit resolves an error encountered when running on Python 3.14, which enforces stricter base64 validation. When adding a PDF to the invoice, the PDF is fetched using the Nilvera client. This client performs an HTTP request and returns a raw binary response, not a base64 representation. However, the Attachment interface handles raw binary data via the 'raw' field, whereas the 'datas' field strictly expects base64-encoded values. runbot-938173 Forward-Port-Of: odoo/odoo#266718
This update resolves a technical issue where the ‘Configuration’ menu item within the Contracts module was being incorrectly positioned due to a low sequence number. This caused conflicts with other modules and disrupted the standard Odoo menu structure. The change ensures the Contracts menu remains in its intended last position, maintaining a consistent and predictable user experience.
Original PR description
## Description of the issue/feature this PR addresses The “Configuration” menu item defined by the *Contracts* module uses a very low sequence value, causing menu ordering conflicts when other…
## Description of the issue/feature this PR addresses The “Configuration” menu item defined by the *Contracts* module uses a very low sequence value, causing menu ordering conflicts when other modules (e.g. [OCA](https://github.com/OCA/partner-contact/pull/2202/files)) add menu items in the same section. This affects not only external modules but also internal ones that add menu items under *Contacts*. ## Current behavior before PR When other modules add new menu items to *Contacts*, the *Configuration* menu moves out of its intended last position, breaking Odoo’s default menu hierarchy. <img width="467" height="148" alt="Behavior before PR:" src="https://github.com/user-attachments/assets/4cb6e3bb-00c0-4636-87de-c51b572dc42c" /> ## Desired behavior after PR is merged The sequence of the *Configuration* menu item is adjusted so that it always remains last, aligning with Odoo’s default menu hierarchy and avoiding friction between modules. <img width="467" height="148" alt="Behavior after PR is merged" src="https://github.com/user-attachments/assets/314c2556-5f2b-403d-af8d-ab550bff41a9" /> --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#234909
This update fixes an issue where invoices from certain Peppol suppliers (using a specific XML format) weren't being correctly imported. The fix ensures the system correctly identifies the supplier's VAT information, automatically creating the invoice and linking the bank account, resolving a previous import failure.
Original PR description
Some Peppol emitters carry the supplier VAT in cac:PartyIdentification/cbc:ID instead of the BIS3-standard cac:PartyTaxScheme/cbc:CompanyID. The import then extracted no VAT, the partner auto-creation not available (needs name+vat) and invoice.partner_id stayed empty. As a side effect, when the XML also carried a PayeeFinancialAccount, the bank account creation crashed with a NOT NULL violation on partner_id. Fall back on cac:PartyIdentification/cbc:ID when cbc:CompanyID is empty, so the partner is found (or auto-created) and the bank account is properly linked. Steps to reproduce: - Create a XML with the supplier VAT only in cac:PartyIdentification/cbc:ID and a cac:PayeeFinancialAccount/cbc:ID. - Upload on a purchase journal: import fails, the bill stays empty with an error in chatter. - With the fix: partner auto-created, bill filled, bank linked. opw-6148974 Forward-Port-Of: odoo/odoo#268011 Forward-Port-Of: odoo/odoo#261933
This update corrects an issue where the balance sheet report was generating incorrect data due to missing or incorrect values in specific XML fields. The changes ensure these fields (2955 and 2956) are always set to zero, aligning with Luxembourg's eCDF reporting requirements. This prevents report rejections and ensures 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 corrects a technical issue where archived delivery carriers were being unintentionally included in the carrier selection process. Previously, the system would pass information about inactive carriers, leading to incorrect choices in the delivery wizard. This change ensures only active carriers are considered, improving data accuracy and usability.
Original PR description
Issue: property_delivery_carrier_id on res.partner can hold an archived delivery.carrier record. Meaning that we pass an archived record to the context and that we can select the archievd delivery.carrier in the choose.delivery.carrier wizard. Solution: Only pass active records through the context. opw-6125792 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#264324 Forward-Port-Of: odoo/odoo#263819
This update fixes a bug where credit limit warnings were incorrectly triggered by bank payments. Now, the system accurately considers outstanding bank payments when calculating a customer's outstanding balance, ensuring warnings only appear when limits are genuinely exceeded. This improves the accuracy of credit risk management.
Original PR description
Before this fix: The credit limit warning calculation only considered credit notes but ignored outstanding bank payments when computing the partner's effective outstanding balance. For example, if a…
Before this fix: The credit limit warning calculation only considered credit notes but ignored outstanding bank payments when computing the partner's effective outstanding balance. For example, if a customer had a credit limit of 1,000 and an invoice of 2,000 was created, then a bank payment of 1,500 was received, the warning would still incorrectly appear showing the customer exceeded their limit (2,000 > 1,000), even though the actual outstanding amount was only 500. After this fix: The credit limit warning now properly includes outstanding bank payments in the calculation. Two cases are handled: - Bank payments received but not yet matched to any invoice, these are identified by their open suspense account entry and deducted from the partner's outstanding exposure. - Bank payments already matched to the invoice, the reconciled amount is read from the invoice's receivable line and deducted accordingly. So with this fix, after a 1,500 bank payment, the system correctly recognises the outstanding amount as 500 and does not show a warning since it is within the 1,000 credit limit. task-5427613
This update fixes an issue where DATEV exports incorrectly populated fields for customers outside the European Union. Now, the correct country code (`Land`) is automatically filled for non-EU customers, ensuring accurate reporting and compliance with DATEV's data format requirements. This ensures data consistency and avoids errors in financial reports.
Original PR description
### Issue: In DATEV customer and supplier exports, partners outside the European Union still had the `EU-Land` and `EU-UStID` fields filled However, these fields must only be used for EU countries…
### Issue: In DATEV customer and supplier exports, partners outside the European Union still had the `EU-Land` and `EU-UStID` fields filled However, these fields must only be used for EU countries For non-EU countries, the `Land` field should be filled instead, and is required whenever the country is not Germany https://developer.datev.de/en/file-format/details/datev-format/format-description/debitorskreditors ### Cause: `_l10n_de_datev_get_partner_list` did not distinguish between EU and non-EU countries As a result, any partner with a VAT number could populate `EU-Land` and `EU-UStID`, even if the country was outside the EU Greece also requires a special case: its VAT prefix is `EL` so the `EU-Land` too, while the country code used in `Land` must remain `GR` ### Steps to reproduce: - Install `l10n_de_reports` and switch to the DE company - Create a customer in Switzerland with a valid VAT number - Create and confirm an invoice for that customer - Go to Accounting → Audit Reports → General Ledger - Select the full year - From the gear menu, export DATEV DATA (zip) - Open the `EXTF_customer_accounts` file ### Before the fix: `EU-Land` and `EU-UStID` are filled for the Swiss customer, while `Land` is empty ### After the fix: `EU-Land` and `EU-UStID` are empty for non-EU countries such as Switzerland, while `Land` is correctly filled `Land` is filled using the following priority: 1. Partner country_code 2. Country extracted from the VAT number 3. Empty opw-5902565 Forward-Port-Of: odoo/enterprise#113835
This update significantly speeds up the process of checking if a field can be deleted within website forms. Previously, this check took several minutes, causing delays. Now, it completes in just milliseconds by focusing only on the HTML fields that actually need to be validated, dramatically improving user experience.
Original PR description
Summary ======= `_check_if_used_in_website_form`, the ondelete hook on `ir.model.fields` that guards against deleting a field referenced by a website form, performs poorly on realistic databases. It…
Summary
=======
`_check_if_used_in_website_form`, the ondelete hook on
`ir.model.fields` that guards against deleting a field referenced by
a website form, performs poorly on realistic databases. It can take
multiple minutes to validate a single field deletion, blocking user
actions such as removing a Studio field.
This commit restricts the scan to columns that can actually contain
website form markup, bringing the hook from multi-minute to
sub-second without any loss of coverage.
The Problem
===========
Deleting any `ir.model.fields` record triggers this validation hook,
which must ensure the field is not referenced inside any website
form. The implementation iterates every stored HTML column returned
by `website._get_html_fields()` and runs one case-insensitive
`ILIKE '%data-model_name="<model>"%'` search per column against
`<model>.<html_field>`, then parses each match with `lxml` and
validates it with XPath.
Two root issues cause the multi-minute cost:
- **Unbounded scan surface**: all stored HTML columns are scanned
(~95 on realistic databases), even though the vast majority of them
declare `sanitize=True` and `sanitize_form=True` (the defaults).
When both flags are True, `<form>` tags are stripped on write and
the column can never physically contain website form markup.
- **Per-column `ILIKE` cost**: `ILIKE` on large TEXT/JSONB columns
performs a sequential scan. A single large HTML column is enough
to make the hook run for several minutes on its own.
Improvements
============
- Scan only columns that can actually contain forms:
- `ir.ui.view.arch_db` , primary target; all website forms are
stored there.
- HTML fields whose sanitization either is disabled
(`sanitize=False`, e.g. `blog.post.content`,
`website.custom_code_head`) or explicitly allows forms
(`sanitize_form=False`, e.g.
`product.template.website_description`, `hr.job.description`,
`event.event.description`). Any other HTML field strips `<form>`
on write and will never contain a form.
- Batch searches: group the deleted fields by model once and emit a
single `OR`-domain search per candidate column, instead of one
search per (field, column) pair.
- Parse each returned record with `lxml` and validate with XPath
directly. The `ILIKE` domain already filters out non-matching rows
DB-side.
Benchmarks
==========
Profiled on a database containing ~95 stored HTML columns and ~5.2k
views. The hook was invoked read-only via
`field._check_if_used_in_website_form()` on a custom field.
| Metric | Before | After |
| :----------------------------- | ---------: | ---------: |
| Hook wall time | ~444 s | ~173 ms |
| HTML columns scanned | 95 | 5 |
| SQL queries issued | 96 | 6 |
Key results:
- Hook wall time reduced from multi-minute to sub-second
(~2,570× faster on the profiled database).
- Scan surface reduced from ~95 columns to a handful (1 +
the form-capable HTML fields installed on the database, typically
under 10).
opw-6086536
Forward-Port-Of: odoo/odoo#259846This update resolves an issue where the barcode inventory count feature would fail when using archived units of measure. The fix ensures that archived UOMs are correctly included in the inventory count cache, allowing accurate counts to be performed. This prevents errors during physical inventory adjustments.
Original PR description
### Steps to reproduce: - In the settings enable: "Units of Measure & Packagings", "Storage Locations" - Create a product in units and register 1 unit in stock - Inventory > Operations > Adjustments…
### Steps to reproduce: - In the settings enable: "Units of Measure & Packagings", "Storage Locations" - Create a product in units and register 1 unit in stock - Inventory > Operations > Adjustments > Physical Inventory - Select your line and request a count > Set Current Value - Inventory > Configurations > units of measures > UOM categories - Select unit and archive it - Go to the barcode app > Click Count inventory ### > Owl error: Uncaught promise ### Cause of the issue: Since the uom used on the quant is archived, it is not found by the search used to fill the barcodeCache: https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/static/src/components/main.js#L209-L213 https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/models/stock_quant.py#L104-L106 https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/static/src/components/main.js#L229 https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/static/src/models/barcode_model.js#L37-L39 However, if the uom is not present in the barcode cache the `BarcodeQautnModel` will fail to createLinesState whihc raises a missing error: https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/static/src/models/barcode_quant_model.js#L712 https://github.com/odoo/enterprise/blob/26546bcd3beebc7f65ce08385441b6284b46598e/stock_barcode/static/src/lazy_barcode_cache.js#L107-L110 opw-6250090 Forward-Port-Of: odoo/enterprise#118877 Forward-Port-Of: odoo/enterprise#118813
This update prevents the checkout page from repeatedly reloading when discounts are applied to products with different tax configurations. The change ensures discount lines are correctly grouped, resolving a synchronization issue between the backend and frontend, and improving the user's checkout experience.
Original PR description
**Step to reproduce :** 1. Create a deliverable product with a sales tax. 2. Create another product with a different sales tax. 3. Publish both products on the eCommerce website. 4. Create a discount…
**Step to reproduce :**
1. Create a deliverable product with a sales tax.
2. Create another product with a different sales tax.
3. Publish both products on the eCommerce website.
4. Create a discount program.
5. Add both products to the shopping cart.
6. Apply the discount code.
7. Proceed to checkout.
**Issue :**
Applying a discount on multiple products with different taxes causes an infinite reload cycle during checkout.
**Reason :**
The reload is supposed to sync the discount lines in the back-end with the discount lines displayed during checkout. If the number of lines don't match, a reload is triggered.
https://github.com/odoo/odoo/blob/18.0/addons/website_sale_loyalty/static/src/js/checkout.js#L22-L24
After the fix introduced in:
https://github.com/odoo/odoo/pull/248215
However, when a discount is applied to products with different taxes, the corresponding reward lines are still categorized as `discounted_lines` instead of `groupable_lines`. As a result, they continue to be processed individually rather than being grouped by reward.
This leads to a mismatch between the backend, which generates one discount line per tax combination, and the frontend, which expects a single discount entry per reward. Consequently, the checkout page continuously reloads while attempting to synchronize both states.
**Solution:**
When a discount applies to products with different tax configurations, the corresponding reward lines should be included in `groupable_lines` rather than `discounted_lines`. This ensures that discount lines are grouped by
`reward_id` consistently on both the frontend and backend, preventing the checkout reload loop.
opw-6210411
Forward-Port-Of: odoo/odoo#265740This update addresses a slow file preview issue when handling large files. Previously, users experienced a blank screen while a large file downloaded and rendered, leading to a frustrating wait. Now, a loading indicator provides feedback to the user while the preview is being prepared, improving the overall experience.
Original PR description
When previewing a big file, the download might take long and the rendering might take even more time. The UI is blocked until the iframe is ready, but there is no feedback for the user. This commit adds some loading feedback until the iframe is rendered. Steps to reproduce: - Go to a Knowledge article - Upload a file with `/file` - Add a huge JSON file (~30MB) - Save - Click on the file icon => The preview opened but took ages to be displayed without giving any feedback to the user task-6014223 Forward-Port-Of: odoo/odoo#264136
This update fixes an issue where certain configuration settings, specifically a 'bin_path' option, weren't being saved to the system's configuration files when using the '--save' command. This change ensures that any custom settings defined in a configuration file are consistently preserved across saves, maintaining the desired system setup. This improves the reliability of the system's configuration.
Original PR description
Have a configuration file with a "bin_path" entry. Use that config file and --save it. The "bin_path" entry is removed from the new config file, it should had been persisted. The problem is common to all "undocumented options", options that did not exist in `config.py` before ConfigCleaner(7) and that were not created upon --save. We can argue about creating or not those options upon --save with the default config, but what's sure is that when the option be set in the config file, then it must be persisted across saves. Task-6106771 Reference-to: 80007415d621 ([REF] core: ConfigCleaner(7) remove deprecated options) 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 Forward-Port-Of: odoo/odoo#258377
This update resolves an issue where moving Odoo databases via the command line would inadvertently deregister subscription codes. The new `--move` flag ensures the database's original UUID is retained during a move, maintaining the user's subscription. This improves the reliability and usability of server-to-server database transfers.
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 resolves an issue where the commission report displayed empty groups when linked to inactive commission plans. By excluding these plans from the report, the report now accurately shows populated groups, providing a cleaner and more reliable view of commission achievements. This ensures accurate reporting for sales teams.
Original PR description
Steps to reproduce: 1. create a commission plan 2. invoice an SO with the linked salesperson to the plan to progress towards the target 3. Archive the commission plan 4. Go to Sales > Commissions > Commissions 5. Remove all filters The `sale.commission.report` includes empty groups for `sale.commission.achievement.report` that are linked to inactive commission plans By excluding said plans from the initial join, the report would display populated groups only without the clutter. opw-6177132 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#117615