Friday, August 21, 2026
16 changes · saas-18.4
Resolved issues and error corrections
Odoo now hides deprecated Peppol EAS identifier codes from partner and Peppol registration selection lists. This helps users avoid registering invalid electronic invoicing identifiers and reduces failed or non-compliant Peppol setup.
Original PR description
Peppol EAS codes 0037, 0213, 9955, and 0193 are deprecated or removed from the Peppol specification but are still present in the selection field on stable branches, allowing users to register invalid identifiers. See: [eas codes](https://docs.peppol.eu/edelivery/codelists/v9.7/Peppol%20Code%20Lists%20-%20Participant%20identifier%20schemes%20v9.7.html) Before: - deprecated EAS codes were listed alongside valid ones in the partner's available Peppol EAS options, allowing users to select an outdated identifier for new or duplicated partners, or during Peppol registration. After: - Excluded deprecated EAS codes from the available Peppol EAS selection list on partners, preventing users from selecting them for new or duplicated partners, or during Peppol registration. Removed Deprecated codes in Master: odoo/odoo#271288 Task [link](https://www.odoo.com/odoo/project.task/6299691) task-6299691 Forward-Port-Of: odoo/odoo#283249 Forward-Port-Of: odoo/odoo#271435
German DIN 5008 invoice PDFs sent by post now place the recipient address correctly in the required address window. This prevents Pingen validation failures, so affected snailmail letters can be sent successfully without changing the normal report layout.
Original PR description
**Steps to reproduce:** - Install l10n_din5008 and accountant. - Enable Snailmail from Accounting → Settings. - Create a German customer (Fiscal Country: Germany). - Create and post a customer…
**Steps to reproduce:** - Install l10n_din5008 and accountant. - Enable Snailmail from Accounting → Settings. - Create a German customer (Fiscal Country: Germany). - Create and post a customer invoice using the DIN5008 report layout. - Select Send by Post. - Enable Developer Mode and navigate to `Settings → Technical → Email → Snailmail Letters`. - Open the generated letter and send it. **Current behavior:** The letter fails to be sent to Pingen with the following error: An error occurred when sending the document by post. Error: ` The attachment of the letter could not be sent. Please check its content and contact the support if the problem persists.` **Cause:** For Snailmail documents, Pingen validates that the recipient address is located within the DIN5008 address window. The current l10n_din5008 report renders additional document information instead of the address in the address area, preventing the compliance validation to fail. **Fix:** When rendering the report for Snailmail, ensure that only the recipient address is displayed in the DIN5008 address window while suppressing the additional information that would otherwise occupy this area. This preserves the standard DIN5008 layout for regular reports while generating a Snailmail-compliant PDF that passes Pingen’s validation. **Reference:** [Pignen Recipient Address Validation Rule](https://help.pingen.com/en/fix-and-enhance-letters/issue-with-recipient-address#040201) Ticket [link](https://www.odoo.com/odoo/project.task/6387869) opw-6387869 Forward-Port-Of: odoo/odoo#280320
This fixes an issue where cost adjustment accounting entries for certain multi-company stock operations could be posted under the wrong company. The change helps keep inventory valuation and expense revaluation records aligned with the company that owns the stock movement.
Original PR description
When the FIFO vacuum creates the "Expenses Revaluation" journal entry for an anglo-saxon delivery whose cost is adjusted by a later receipt, the JE was built using `env.company` instead of the…
When the FIFO vacuum creates the "Expenses Revaluation" journal entry for an anglo-saxon delivery whose cost is adjusted by a later receipt, the JE was built using `env.company` instead of the company of the vacuumed SVL. Steps to reproduce: - Enable multi-company and activate anglo-saxon accounting on two companies A and B. - In company B, on the product category: set FIFO costing + Automated valuation, and set the stock input / stock output / stock valuation accounts and the stock journal. The Stock Output account must have "Allow Reconciliation" enabled. - In company B, on the product: set an Expense Account and set the Cost (e.g. 10.0) this is the price the delivery will be valued at while the stock is negative. The product must have no quantity on hand in company B. - While working in company B, sell and deliver 1 unit of that product: the delivery is valued at 10.0 and creates a negative valuation layer. - Still in company B, create and post the customer invoice of that sale, so the Stock Output line of the delivery entry gets reconciled with the Stock Output line of the anglo-saxon COGS entry of the invoice. - Switch the active company to A, and from there create a purchase order of that product for company B at a different price (e.g. 15.0), then validate the linked receipt into company B's warehouse. - The vacuum compensates the negative layer, but the resulting "Expenses Revaluation of ..." journal entry is posted in company A instead of company B. This fix forces the company context to `vacuum_svl.company_id` when fetching the product accounts and preparing the move lines so the JE is always created in the company of the SVL being vacuumed. opw-6066970 opw-6419188 Forward-Port-Of: odoo/odoo#283057 Forward-Port-Of: odoo/odoo#259133
Odoo now shows the specific error details returned by Serbia's eFaktura service when an invoice submission fails. This helps users understand why an invoice was rejected instead of seeing only a generic connection or HTTP error.
Original PR description
**Steps to reproduce:** - Install the Serbian EDI module `l10n_rs_edi`. - Configure eFaktura credentials on the company. - Create and confirm a Serbian customer invoice. - Send the invoice to…
**Steps to reproduce:**
- Install the Serbian EDI module `l10n_rs_edi`.
- Configure eFaktura credentials on the company.
- Create and confirm a Serbian customer invoice.
- Send the invoice to eFaktura.
**Observed Behavior:**
When the eFaktura API returns an HTTP error, Odoo only displays the generic exception generated by `requests`, for example an HTTP 400/500 error.
The actual error information returned by eFaktura in the response body is not shown to the user, making it difficult to understand why the invoice was rejected.
**Cause:**
`_l10n_rs_edi_send` catches `HTTPError`, `Timeout`, and `ConnectionError`, but the error message is built only from the Python exception.
For HTTP errors, the eFaktura API may return a response containing more precise information such as:
```json
{
ErrorCode: ...,
Message: ...
}
```
This response was not being used when displaying the error in Odoo.
**Fix:**
When an HTTP response is available and contains an eFaktura error payload, use the returned `ErrorCode` and `Message` as the error displayed on the invoice. Fallback to the existing connection/HTTP exception message when no usable API response is available.
opw - 6453653
Forward-Port-Of: odoo/odoo#281490This fix ensures invoice tax totals are calculated correctly when one tax increases the base amount used by another tax on the same line. It helps prevent inaccurate tax details and totals from appearing in accounting records and invoice calculations.
Original PR description
**Steps to reproduce:** - Create a tax that affects the base of the subsequent ones - Create an invoice with this tax and another one on the same line **Issue:** In "_aggregate_base_line_tax_details", the tax amount from the first tax should be included in the following values of the second tax: - raw_total_excluded - raw_total_excluded_currency - target_total_excluded - target_total_excluded_currency - total_excluded - total_excluded_currency But it is not. opw-6235909 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283219 Forward-Port-Of: odoo/odoo#279335
Imported UBL invoices with document-level discounts or extra charges now assign percentage tax amounts to the right tax subtotal. This prevents incorrect tax adjustments and helps keep invoice tax totals accurate.
Original PR description
When importing UBL invoices that contain document-level allowances or charges with percentage taxes, the tax values were not linked to their corresponding `TaxSubtotal` group (`related_taxes_values`). As a result, the tax correction step (`_import_ubl_invoice_fix_taxes_amounts`) was unaware of document-level taxes, which caused wrong tax corrections. opw-6388544 Forward-Port-Of: odoo/odoo#279350
Fixes an issue where partially received subcontracted products could cause related regular products to be left out of the receipt and fully pushed to a backorder. This keeps receipt validation and backorder quantities accurate when subcontracted and standard products are received together.
Original PR description
### Steps to reproduce: - Create a subcontracted product P1 - Create a storable product P2 - Buy 5 units of both products from your subcontractor - On the receipt set both moves quantity to 2 Units -…
### Steps to reproduce: - Create a subcontracted product P1 - Create a storable product P2 - Buy 5 units of both products from your subcontractor - On the receipt set both moves quantity to 2 Units - Validate the receipt and create a backorder #### > Only the subcontracted move has been kept on the receipt and a backorder was created for 3 units of P1 and 5 of P2. ### Cause of the issue: Setting the quantity of the subcontracted move will automatically record the quantities on the subcontracted MO: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/stock_move.py#L83 https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/stock_move.py#L123 https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/mrp_production.py#L91 However, the `_update_finished_move` method adds and update the related subcontracted move lines marking them as *picked* to adapt the related reservation: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/mrp_production.py#L118-L164 This is problematic since picking a move line will also pick the move: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/stock/models/stock_move.py#L261-L267 And only picked moves are considered to be processed at picking validation. ### Note: The exact same issue had already been fixed in 17.0: db8b33ebb9fe23507bcba30b12741e4d688ae549 However, the fix had an issue concerning the barcode behavior as it removed the picked computation for subcontracted moves which made hybrid pickings such as the above one (with one subcontracted and one non-subcontracted move) impossible to process in the barcode app. As such, the fix and test where reverted in cf2d18c92bee55ef79db1a338e9baf12f258ee5b The present commit provides an alternative fix of the original issue keeping subcontracted moves unpicked by quantity changes without affecting the picked computation of subcontracted moves (e.g. adding a picked move line on a subcontracted move will still pick that move). Enterprise: https://github.com/odoo/enterprise/pull/123884 opw-6330584 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275304
Setting a contact on a delivery transfer no longer replaces a custom destination location from the operation type with the generic Customers location. This prevents accidental routing changes for businesses that use specific customer stock locations.
Original PR description
### Steps to reproduce: - In the settings: Enable Storage Locations - Create a customer location "Customer stock" with "Customers" as its parent location - Create a delivery operation type "Deliver…
### Steps to reproduce: - In the settings: Enable Storage Locations - Create a customer location "Customer stock" with "Customers" as its parent location - Create a delivery operation type "Deliver Super Customer" and set its default destination location to "Customer stock" - Go to Inventory > Overview > Deliver Super Customer > New - Set a contact on the transfer #### > The destination location switches from "Customer stock" to "Customers" ### Cause of the issue: The `location_dest_id` of `stock.picking` depends on its `partner_id`. So that changing the partner recomputes the locations of the transfer. However, as soon as the destination of the operation type has a `customer` usage, the `property_stock_customer` of the contact replaces it unconditionally: https://github.com/odoo/odoo/blob/04f3a7bca99d0144a4ea871be9625db368b196ca/addons/stock/models/stock_picking.py#L949-L963 However, the `property_stock_customer` falls back to an `ir.default` pointing at the default `Customers` location when nothing is set on the contact: https://github.com/odoo/odoo/blob/1c40fab04b71def8f3645c4c4bb0c1441057f307/addons/stock/data/stock_data.xml#L71-L72vs The override comes from 8a0775aa1dd9, which replaced an `elif` fallback on the contact by an "unconditional" substitution as this fallback had become unreachable once `default_location_src_id` and `default_location_dest_id` were made required: https://github.com/odoo/odoo/blob/04f3a7bca99d0144a4ea871be9625db368b196ca/addons/stock/models/stock_picking.py#L34-L41 opw-6421090 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280016
Odoo now matches formatted sender addresses more precisely, so messages sent from templates use the intended company or contact even when multiple records share the same email address. This prevents invoices and chatter messages from showing the wrong sender, reducing confusion for recipients and users.
Original PR description
### Issue: When multiple partners share the same email address, `_mail_find_partner_from_emails` may resolve to the wrong partner when the input is a formatted email like "`Name <email>`" This…
### Issue:
When multiple partners share the same email address, `_mail_find_partner_from_emails` may resolve to the wrong partner when the input is a formatted email like "`Name <email>`"
This affects use cases like email templates using `{{object.company_id.email_formatted}}` as sender, where the wrong company partner could be selected
### Cause:
The lookup in `done_partners` only matched on `email_normalized`, which cannot distinguish partners sharing the same email but with different names
The `email_formatted` field carries both name and email, allowing an exact match when the input is a formatted email
### Steps to reproduce:
- Install `account`
- Create an Email Template (Applies to: account.move, From: {{object.company_id.email_formatted}})
- Create a second company B with the same email as the default (e.g. info@yourcompany.com)
- In Settings (logged in as company B), set a Fiscal Position (e.g. US Taxable)
- Create an Invoice on company B
- In the chatter, click Send message, click the expand arrows button, use the three dots menu to select the template
- Send and check the Sender in the chatter
Before the fix, the sender resolves to the default company even though the invoice belongs to company B
opw-6260992
Forward-Port-Of: odoo/odoo#282966
Forward-Port-Of: odoo/odoo#269509Chilean supplier e-invoices that include foreign currency details but omit an optional foreign-currency total can now be imported successfully. The import process falls back to the standard total when the optional amount is absent, preventing failed mail-based invoice processing.
Original PR description
When importing an incoming DTE through the fetchmail server, the total amount is read from the MntTotOtrMnda as soon as a Moneda node is present in the document. Steps to reproduce: - Set up a CL company with a DTE mail server - Fetch a DTE that includes the line-level Moneda node but does not include the header OtraMoneda block, so no MntTotOtrMnda - Run the fetchmail cron and check the logs Issue: The DTE fails to import Analysis: Occurs since https://github.com/odoo-dev/enterprise/commit/5805a92f91411846fdffa245cb047397cfc9b1f3 Moneda is defined at line level while MntTotOtrMnda in the optional header block Encabezado/OtraMoneda. Instead of assuming MntTotOtrMnda is always present whenever the document carries a foreign currency, fall back to the base-currency total MntTotal when it is missing. opw-6432612 Forward-Port-Of: odoo/enterprise#126869
This fixes a rounding mismatch in Peruvian electronic invoices that could cause tax authority validation errors, especially on down payment invoices. The taxable amount now aligns with the invoice line amount, helping businesses successfully submit compliant documents.
Original PR description
**Steps to reproduce:** - Install Accounting, Sales and l10n_pe_edi - Switch to a Peruvian company (e.g. PE Company) - Create a SO: * Customer: [a Peruvian customer] * Order Lines: | Product |…
**Steps to reproduce:**
- Install Accounting, Sales and l10n_pe_edi
- Switch to a Peruvian company (e.g. PE Company)
- Create a SO:
* Customer: [a Peruvian customer]
* Order Lines:
| Product | Quantity | Unit Price | Taxes |
| ------- | -------- | ---------- | ------- |
| any | 3.00 | 123.50 | VAT 18% |
| any | 2.00 | 27.544216 | 0% Ina |
| any | 1.00 | 43.490867 | 0% Exo |
- Confirm the SO
- Create a 40% down payment
- Confirm the down payment
- Process it to sent it to Peru UBL 2.1
**Issue:**
The following error message is returned by the OSE:
`3272|La base imponible a nivel de línea difiere de lainformación consignada en el comprobante - Detalle: xxx.xxx.xxx ticket : 20260000000000221633458 error: Error en la Linea Nro. :1. : 3272 (nodo: "cac:TaxSubtotal/cbc:TaxableAmount" valor: "148.20")`
**Cause:**
In the XML, one line has 148.19 for "cbc:LineExtensionAmount", but 148.20 for "cac:TaxSubtotal/cbc:TaxableAmount".
The issue is coming from the fact that "base_amount_currency" is used instead of "total_excluded_currency" for the computation of "cac:TaxSubtotal/cbc:TaxableAmount".
**Issue 2:**
When a tax is impacting the base amount of a following tax, its tax amount is not taken into account in "total_excluded_currency".
opw-6235909
Forward-Port-Of: odoo/enterprise#128379
Forward-Port-Of: odoo/enterprise#122310German SEPA Credit Transfer files now exclude company LEI information when using older XML formats that do not allow it. This keeps exported payment files compliant with bank requirements and helps prevent payment batch rejections.
Original PR description
### Issue before this commit: When generating a SEPA Credit Transfer batch using the German XML format (pain.001.001.03), the <LEI> tag is erroneously included in the exported file if an LEI is…
### Issue before this commit: When generating a SEPA Credit Transfer batch using the German XML format (pain.001.001.03), the <LEI> tag is erroneously included in the exported file if an LEI is configured on the company. This invalidates the XML, causing banks to reject the file. ### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Go to Settins > Vendor Payments > SEPA Credit Transfer / ISO20022 and set Name Identification as 529900T8BM49AURSDO55 and Issuer as LEIMAN 3. Go to companies and set 529900T8BM49AURSDO55 as LEI in the DE company 4. Go to Accounting dashboard and click the 3 dots of the bank group, go to Configuration and set the Account Number and be sure in the Outgoing Payments tab XML Format is German 5. Create a new German company from Contacts with: 1. Country as Germany 2. VAT 3. Account Number in the Bank Accounts by adding one line: 1. example Account Number: DE65100500007201811026 2. example Bank: BNP Paribas 3. activate the Send Money button 7. Then go to Vendor > Payments and create a new one with Payment Method as SEPA Credit Transfer for the German company created 8. Go back and select the new payment from the list and click create batch and print it 9. In the XML of pain.001.001.03.(DE) file, the LEI tag should not be included. ### Cause of the issue: The XML generation logic does not filter out the <LEI> element for older schema versions like pain.001.001.03, which do not support this tag. ### Reason to introduce the fix: To ensure strict schema compliance and prevent bank rejections. The <LEI> element is now properly omitted from pain.001.001.03 files and restricted only to newer formats (e.g., pain.001.001.09) where it is valid. opw-6428150 Forward-Port-Of: odoo/enterprise#127758
When Colombian vendor bill XML files are uploaded, Odoo now recognizes withholding taxes such as ReteRenta, ReteIVA, and ReteICA. This helps invoices reflect the correct tax amounts automatically, reducing manual corrections and accounting errors.
Original PR description
Currently, Odoo doesn't detect Withholdings taxes for Colombia while uploading vendor bill XML, causing ReteRenta, ReteIVA, ReteICA withholdings to not being added in invoice lines, for versions under 19.2 Fix: Backport commit https://github.com/odoo/enterprise/commit/edc67858350d1b8408019e51751240026d931dab Versions: 18.0 -> 19.1 Task-id: [6417175](https://www.odoo.com/odoo/project/49/tasks/6417175) Forward-Port-Of: odoo/enterprise#126186
Pending operation-level quality checks are no longer removed when users partially receive products in the Barcode app and return to the transfer. This helps ensure required receipt quality controls remain visible and can still be completed before the transfer is finalized.
Original PR description
Steps to reproduce --- 1. Create a quality control point on the Receipts operation type with Control per set to Operation. 2. Confirm a receipt of 2 units of the product: one pending operation…
Steps to reproduce --- 1. Create a quality control point on the Receipts operation type with Control per set to Operation. 2. Confirm a receipt of 2 units of the product: one pending operation quality check is created. 3. In the Barcode app, receive 1 unit and go back to the transfer with the back button. 4. The pending operation quality check is gone. Issue --- Going back from the Barcode app calls `post_barcode_process`, which on a partial reception splits the picked move into a done move and a remaining move, then merges the transient duplicate back with `_merge_moves`. https://github.com/odoo/enterprise/blob/b89614661682ecbd131d940539aac8afdd9d7289/stock_barcode/models/stock_move.py#L57-L60 `_merge_moves` cancels that transient duplicate through `_action_cancel` before unlinking it. https://github.com/odoo/odoo/blob/8f3100ca597559945cc42d9ef9517edbb40a900b/addons/stock/models/stock_move.py#L1400-L1401 The `quality_control` override of `_action_cancel`, picks the pending checks to drop from `is_product_canceled`, a `defaultdict(lambda: True)` keyed by `(picking, product_id)`. An operation check has no `product_id`, so its key is never computed by the loop and reads back the `True` default, so it is deleted even though the transfer still has a live move. Since an operation check covers the whole transfer, it must be dropped only when every move of its picking is cancelled. https://github.com/odoo/enterprise/blob/b89614661682ecbd131d940539aac8afdd9d7289/quality_control/models/stock_move.py#L68-L76 opw-6439179 Forward-Port-Of: odoo/enterprise#127427
This fixes a problem where Android users could not download files, such as images opened from Discuss, because the app was given an unsupported download link type. Downloads are now passed to the mobile app in a way Android accepts, restoring the expected download behavior.
Original PR description
Steps to reproduce: - send an image in a Discuss channel - click the image to open the file viewer - click the download button => Android shows "The Odoo Mobile Apps only supports file downloads…
Steps to reproduce: - send an image in a Discuss channel - click the image to open the file viewer - click the download button => Android shows "The Odoo Mobile Apps only supports file downloads using the HTTP protocol." downloadFile()'s GET-by-URL case fetches the URL via XHR, then saves the Blob response by clicking a hidden <a download> anchor on a blob: URL. Android's DownloadManager only accepts http(s) URLs, so it rejects that blob: URL instead of downloading anything. Patch downloadFile._download to hand the URL directly to a new mobile.methods.saveFile bridge method when available, the same way download._download already delegates to mobile.methods.downloadFile. Blob/string content downloads aren't handled here — the only such call site (spreadsheet JSON export) is debug-mode only, so this is left as a console.warn for now. Related to odoo/odoo@e83fd8c08c879f5e262d39f24edcb3f81238ea82 Code made by Claude Changes supervised by HUVW Forward-Port-Of: odoo/enterprise#128409 Forward-Port-Of: odoo/enterprise#127693
This fix ensures Brazilian point-of-sale tax adjustment entries use the correct sales tax when similar sales and purchase taxes exist. It prevents accounting entries from becoming unbalanced, improving reliability for Brazilian fiscal reporting in POS transactions.
Original PR description
The chart template gives the same Avatax code and price_include_override to the sale and the purchase tax, and creates both in the same transaction. Without an explicit type_tax_use the lookup used to return either of them at random, and picking the purchase one left the entry unbalanced. The purchase taxes got their Avatax code in 18.4+. https://github.com/odoo/enterprise/pull/101072 runbot-945969