Wednesday, March 11, 2026
16 changes · saas-18.4
Resolved issues and error corrections
This fix ensures sales orders show the correct unpaid balance when a down payment invoice is cancelled through a credit note. It prevents negative unpaid amounts, helping staff settle point-of-sale linked sales orders with accurate balances.
Original PR description
When having a down payment that is reversed by a credit note, the amount unpaid is wrongly computed. This is because we take the sum of invoice lines price total, regardless they come from invoice or credit note. Therefore we end up with negative value. Steps: - Have a SO for 500 - Make a downpayment for 300, confirm - Make a credit note for the downpayment invoice, confirm -> SO's amount unpaid is -100, it should be 500. If you now settle the SO, the amount unpaid will be -300 instead of 0. opw-5175562 Forward-Port-Of: odoo/odoo#252559 Forward-Port-Of: odoo/odoo#233248
This fixes a timing issue where edits made while a save was still finishing could be incorrectly treated as already saved. Users editing HTML content, such as mass mailings, will now keep the correct unsaved-changes indicator and avoid accidentally leaving newer edits unsaved.
Original PR description
Prior to this commit, it was possible to: - make change A inside a html_field - save/commitChanges - make change B inside the html_field, before the end of the save/commitChanges - the field ends up incorrectly marked as "not dirty" (user can't use the FormStatusIndicator) even though change B was not committed yet. Solution: Give an id to the dirtiness, and associate that id with an extracted value from the editor. When the record update is done, mark the field as not dirty ONLY IF the current dirty id is the same as the id previously associated with the extracted value, else the field stays dirty. task-5976348 Forward-Port-Of: odoo/odoo#252655
Point of Sale now correctly handles barcodes assigned to product packaging, even when the product itself has no barcode. This prevents an error during checkout and lets cashiers scan packaged variants reliably.
Original PR description
Step to reproduce - Create a product - Add two attributes: 1. One with Instantly creation mode 2. One with Never creation mode - Define packaging from the Sales tab - Add a barcode on the variant packaging ex: 111356,11357 - Scan the packaging barcode in POS Observation: - we get a traceback `TypeError: Cannot read properties of undefined (reading 'product_template_attribute_value_ids')` Cause: - when we do not have barcode on product, when opening `openConfigurator` - (as we have few varianst) product get undefined. https://github.com/odoo/odoo/blob/f229f23d7bf3d837ff5577c36145bf2ba410ea22/addons/point_of_sale/static/src/app/services/pos_store.js#L738 - Hence the traceback Fix: - For the case, when packaging has barcode but not the product, we search for product in that case too. opw-5886570 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#248838
This fix prevents non-date values that contain slashes or similar characters from being mistaken for a date format during file imports. Users should see fewer import errors and more reliable automatic detection of actual date columns.
Original PR description
## Description of the issue/feature this PR addresses: If you try to import an excel sheet for example with these column on sale order, but the issue is at every model: (this is an example)…
## Description of the issue/feature this PR addresses: If you try to import an excel sheet for example with these column on sale order, but the issue is at every model: (this is an example)  First column: Client ref Second column: committment date Third column: Customer ## Current behavior before PR: When you upload the file to import, the extract_header_types calls _try_match_date_time that try to guess the date column. The first column makes the _try_match_date_time to guess that the format is %Y.%m.%d format . This is an error because that column does not contain a date . The reason is that check_patterns when convert the pattern to reg ex using `def to_re(pattern):` on base_import/base_import.py, does not escape the "." so it works as "every char" wildcard character on regex . ## Desired behavior after PR is merged: No error should appear and the correct date format from the right date column should be guessed --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#252488 Forward-Port-Of: odoo/odoo#196477
This fixes an error that could stop PDF quotes from being generated when using Quote Builder with newer PDF software dependencies. Customers and sales teams can continue producing quote PDFs without interruptions after the dependency update.
Original PR description
Issue: --- Due to this issue, generating PDF Quote using Quote Builder leads to traceback. Steps to reproduce: --- 1- Using a python 3.13 env, install requirements.txt. (You could instead uninstall…
Issue: --- Due to this issue, generating PDF Quote using Quote Builder leads to traceback. Steps to reproduce: --- 1- Using a python 3.13 env, install requirements.txt. (You could instead uninstall pypdf2 and install pypdf==5.4.0) 2- Enable Quote Builder. 3- Create a SO and in quite builder tab, select a document. 4- Print -> PDF Quote. This will lead to traceback. Cause: --- There is a requirement change on https://github.com/odoo/odoo/pull/233600, as pypdf2 will not be supported in future. Instead we use pypdf==5.4.0. In pypdf 5.4.0 it is required to have `Fields` present in `Acro Form` (introduced in [1] v3.13.0): https://github.com/py-pdf/pypdf/blame/f20954f2241640feb484800e191373f8fbdfa44b/pypdf/_writer.py#L1060-L1061 FIX: --- We could add an empty `fields` dictionary when it's not present. The entry should be `/Fields`: https://github.com/py-pdf/pypdf/blob/f20954f2241640feb484800e191373f8fbdfa44b/pypdf/constants.py#L362-L370 Note: --- In this fix, we replace `is_upper_version_pypdf2` with specific version comparison. To be precise `getNumPages` is depreciated in version 1.28.0 [2]. References: --- [1]- https://github.com/py-pdf/pypdf/commit/dcf997a028e993b215457c5629cb4e78186e11c0 [2]- https://github.com/py-pdf/pypdf/blob/3ab1581a51f446f86dd445662005f8747941c2b6/pypdf/_writer.py#L507-L514 opw-5784464 Forward-Port-Of: odoo/odoo#250329
This fixes how prepaid and payable amounts are reported for Malaysian credit notes, debit notes, refund notes, and related self-billed documents. The change helps ensure exported e-invoices match MyInvois requirements and reduces the risk of rejected submissions.
Original PR description
Currently, the `prepaid_amount` in the UBL export is calculated as `amount_total - amount_residual` for all document types. However, for credit notes, debit notes, and refund notes (both standard and self-billed, corresponding to document type codes 02, 03, 04, 12, 13, and 14), this amount should be 0 to comply with Malaysian e-Invoicing (MyInvois) API requirements. This commit introduces the following fixes: - Sets the `prepaid_amount` to 0 for document types '02', '03', '04', '12', '13', and '14'. - Update the `payable_amount` to the full `invoice.amount_total`. Task-5971843 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#252382 Forward-Port-Of: odoo/odoo#251915
Vendor bills imported from electronic invoice formats now automatically follow the supplier’s previous grouping preference. If the last posted bill from the same vendor was grouped, the new bill is grouped by tax too, reducing manual cleanup and keeping accounting entries consistent.
Original PR description
[FIX] account_edi_ubl_cii: automate bill line grouping
This commit automates vendor bill line grouping during import based on the vendor's most recent posted bill.
- Logic: Added `_has_lines_grouped()` to `account.move` to detect if lines follow the grouping pattern.
- Heuristic: During UBL/CII import, the system now checks the last posted bill from the same vendor; if it was grouped, the new bill is automatically grouped by tax.
task-5979667
Forward-Port-Of: odoo/odoo#251948
Forward-Port-Of: odoo/odoo#251419Odoo no longer adds Danish customer reference values to a Peppol field that requires extra identification details. This prevents Danish invoices from being rejected during Peppol submission when a customer reference is set.
Original PR description
Currently, if a Danish partner has a reference set, Odoo adds it under PartyIdentification. This violates Peppol `DK-R-013`, which mandates using schemeID when PartyIdentification is used. Adding the Danish schemeID would also trigger another error, `PEPPOL-COMMON-R042`, as the organization number (CVR) must be included in the `_text`. Including schemeID seem therefore unnecessary since it will appear in CompanyID. Steps to reproduce: - Create a Danish company and enable Peppol - Create a Danish customer with a reference - Create an invoice and submit to Peppol, `DK-R-013` error occurs opw-5921602 Forward-Port-Of: odoo/odoo#251737
This fixes Indian HR time off calculations when sandwich leave overlaps a full-day public holiday. Leave duration now uses the company's timezone for public holiday dates, preventing undercounted absences such as showing 1 day instead of 3.
Original PR description
Steps to Reproduce: 1. Install the `l10n_in_hr_holidays` module. 2. Enable the "sandwich leave" option for the time off type. 3. Create public holidays that last the entire day, for example from 00:00 to 23:59. 4. Create a leave around the public holiday 5. Duration should be 3 days instead of 1 Cause: When creating a dictionary for company-specific public holidays, the dates from and to are not converted to the company's timezone when calculating the days between public holidays. Fix: To resolve this, the first step is to localize the `date_from` and `date_to` to the company's timezone before counting the days between the public holidays. Task-6012992 Forward-Port-Of: odoo/odoo#252466
Point of Sale invoice creation now uses only bank accounts that are allowed for outgoing payments. This prevents invoice failures and avoids relying on unsupported or untrusted bank accounts, especially when processing refunds.
Original PR description
Before this commit: --- - Invoice generation could fail when the selected partner or company bank did not allow outgoing payments. - The first available bank account was used without checking whether it was valid for out payments. After this commit: --- - Select only bank accounts that allow outgoing payments. - Prioritize customer banks for refunds, then payment journal banks, and finally company banks as fallback. - Prevent errors caused by untrusted or unsupported bank accounts. task-5954530 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#251526 Forward-Port-Of: odoo/odoo#250062
Fixed a website editor issue that could cause crashes in some browsers after saving repeated changes to a product page. The editor now cleans up old page-editing connections when it reloads, so users can continue editing reliably.
Original PR description
Steps to reproduce: =================== 1. In Website > Shop, open any product. 2. Click "Edit" on the product. 3. Make a change (for example, toggle "Zoom on click") 2 times. -> In the second time a…
Steps to reproduce:
===================
1. In Website > Shop, open any product.
2. Click "Edit" on the product.
3. Make a change (for example, toggle "Zoom on click") 2 times.
-> In the second time a traceback will appear `(Safari, Epiphany)`.
Cause:
======
The website builder uses two contexts:
- The **iframe** runs services (e.g. websiteEditService)
- The **parent window** runs editor plugins (e.g. EditInteractionPlugin)
They communicate via custom events on window.parent.document. The service (in the iframe) registers a listener for
"edit_interaction_plugin_loaded" on the parent document, and responds with a "transfer_website_edit_service" event carrying its service object.
When the iframe reloads after a save, the old listener was never removed from window.parent.document. The new iframe added a second listener. This meant two listeners existed on the parent document:
1. Old listener → responds with OLD websiteEditService (stale)
2. New listener → responds with NEW websiteEditService (correct)
Both fire when the plugin dispatches "edit_interaction_plugin_loaded". But the plugin only accepts the first response ({ once: true }), and since listeners fire in registration order, it always received the OLD stale service.
With the stale service:
- installPatches() early-returned (patches.length > 0 from session 1)
- destroy() called uninstallPatches() on the old service, removing stopInteractionByName from the old prototype
- stopInteraction() then tried to call the now-deleted method → crash: TypeError: publicInteractions.stopInteractionByName is not a function
Solution:
=========
Extract the anonymous event handlers into named functions and register a "beforeunload" listener on the iframe's window that removes them from window.parent.document. This ensures that when the iframe reloads, the old listeners are cleaned up before the new iframe registers its own, so the plugin always receives the current service.
opw-5864798
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prIncoming emails with certain malformed attachment types are now handled safely instead of failing during processing. This helps ensure emails sent to aliases, including those used for vendor bill creation, continue to be processed and attachments are preserved.
Original PR description
When parsing incoming emails, mail.thread normalizes some malformed MIME types before calling part.get_content(). However, attachments using Content-Type `bin/plain` are not normalized. As a result,…
When parsing incoming emails, mail.thread normalizes some malformed MIME types before calling part.get_content(). However, attachments using Content-Type `bin/plain` are not normalized.
As a result, Python's email content manager raises KeyError('bin/plain') during parsing, which aborts the whole message processing. This prevents the incoming email from being processed, including vendor bill creation from email aliases.
Steps to reproduce:
- build an email with an attachment using Content-Type `bin/plain`
- parse it through `mail.thread.message_parse`
Before this commit, parsing crashes with KeyError('bin/plain').
This commit treats `bin/plain` like the other unsupported attachment MIME types already handled in stable, by falling back to `application/octet-stream`, allowing the message to be parsed and the attachment to be preserved.
opw-5439156
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#251440This update fixes an issue where attendance schedules weren't correctly displayed when employees had multiple working schedules with overlapping contract dates. Now, the system accurately shows the correct schedule for each period, ensuring accurate tracking of employee availability. This improves reporting and scheduling accuracy.
Original PR description
Description of the issue/feature this PR addresses: Based on this feedback : [https://www.odoo.com/odoo/project.task/5436300 ](https://www.odoo.com/odoo/project.task/5436300%C2%A0) When I got two…
Description of the issue/feature this PR addresses: Based on this feedback : [https://www.odoo.com/odoo/project.task/5436300 ](https://www.odoo.com/odoo/project.task/5436300%C2%A0) When I got two versions with different working schedules, normally, in Attendance, the gant view should show the unavaibilities by putting in gray days you're not working. As the feedback shows:- . If you have two different working schedules on two different versions and two different occupations period (contract dates), it's working fine. . If the two versions have the same occupation period (contract date), it's only considering the latest working schedule. . If both versions are under the same contract, then it only shows the working schedule on the latest version. This is not what we expect Instead, it should show the correct working schedule for each period Current behavior before PR: Desired behavior after PR is merged: . Modify _get_calendar_periods() method to return the correct working schedule for each period . Fix version_date to use the specified date instead of the creation date. . Add the corresponding tests task-5473047 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update corrects a technical issue preventing electronic invoices in the RIMPE Emprendedor regime from being properly processed. The change ensures the correct string value is used for the invoice structure, resolving a validation error that was causing invoice processing failures. This ensures compliance with Ecuadorian tax regulations.
Original PR description
Corrected the hardcoded string for the RIMPE Emprendedor regime to match the SRI structure According to SRI technical specifications, the <contribuyenteRimpe> tag only accepts two specific values:…
Corrected the hardcoded string for the RIMPE Emprendedor regime to match the SRI structure According to SRI technical specifications, the <contribuyenteRimpe> tag only accepts two specific values: CONTRIBUYENTE RÉGIMEN RIMPE (Fixed value) CONTRIBUYENTE NEGOCIO POPULAR - RÉGIMEN RIMPE Steps to reproduce: Install l10n_ec_edi module Go to Settings > Invoicing > Ecuadorian Localization In Electronic Invoicing > Regime, select rimpe_emprendedor In Electronic Invoicing > Regime, configure a SRI Connection Post an customer invoice **Validation error occurring during the electronic signing process (using .p12 certificates):** `35 - Se encontró el siguiente error en la estructura del comprobante: cvc-pattern-valid: Value 'CONTRIBUYENTE EMPRENDEDOR - RÉGIMEN RIMPE' is not facet-valid with respect to pattern 'CONTRIBUYENTE RÉGIMEN RIMPE|CONTRIBUYENTE NEGOCIO POPULAR - RÉGIMEN RIMPE' for type 'contribuyenteRimpe'.. - ARCHIVO NO CUMPLE ESTRUCTURA XML - ERROR ` Forward-Port-Of: odoo/enterprise#109147
This update fixes an issue where currency exchange difference values were missing from DATEV exports. The fix correctly uses the line balance instead of the currency amount, ensuring accurate reporting of exchange rates for DE company transactions. This improves the reliability of financial data sent to DATEV.
Original PR description
**Steps to reproduce: 1. Create DE company (EUR currency) 2. Add USD -> EUR exchange rates for XX/01/26 and XX/15/26 (XX is target month) 3. Install l10n_de_reports 4. Make sure bank journal has…
**Steps to reproduce: 1. Create DE company (EUR currency) 2. Add USD -> EUR exchange rates for XX/01/26 and XX/15/26 (XX is target month) 3. Install l10n_de_reports 4. Make sure bank journal has 'outstanding receipts' set for incoming manual payment [Accounting -> Config -> Journals -> Bank] 5. Create USD invoice for XX/02/26 and confirm it 6. Register a Payment for XX/16/26 and confirm it (you should see the exchange difference entry matched alongside the payment) 7. Go to [Accounting -> Reporting -> General Ledger] and export DATEV data **Description of issue: The currency exchange rate difference entries in the exported file are shown as 0 **Expected behavior: The actual currency exchange difference values should be displayed **Why this happens? The DATEV export currently sets the amount based on 'amount_currency'. For currency exchange difference entries, this value is 0.0 in the General Ledger, resulting in 0 values in the export. **The fix: Updated the logic to use the line balance when the entry is identified as a currency exchange difference. opw-5358954 Forward-Port-Of: odoo/enterprise#109655 Forward-Port-Of: odoo/enterprise#107268
This update fixes a previous issue where certain salary deductions (specifically 'ATTACH_SALARY') weren't correctly reflected in employee net pay calculations for the Kenyan payroll module. The changes add four new rules to the deduction line, adjusting their sequence and sign to accurately account for these attachments, ensuring accurate net pay reporting.
Original PR description
**Behavior before this commit** Some salary rules (e.g. `ATTACH_SALARY`) were ignored in the NET calculation. **Behavior after this commit** - Four rules are now added to the "Total deductions" line: their sequence and category has been changed. - The sign of these lines has also been switched: an attachment of salary of a positive amount should be added to the amount of total deductions, which is then deducted from the net.  opw-5894647 Forward-Port-Of: odoo/enterprise#107033