Tuesday, March 24, 2026
15 changes · saas-18.4
Resolved issues and error corrections
Odoo now avoids formatting certain email headers in a way that some strict email providers reject. This reduces failed outgoing emails, especially messages with long or encoded subject lines sent through providers like Yahoo.
Original PR description
…r rejections Yahoo and other strict mail servers reject emails with folded Subject headers containing RFC 2047 encoded-words when the folding occurs at inappropriate positions, resulting in "554…
…r rejections Yahoo and other strict mail servers reject emails with folded Subject headers containing RFC 2047 encoded-words when the folding occurs at inappropriate positions, resulting in "554 Invalid Subject header" errors. The root cause is in Python's stdlib (bpo-144156). In an ideal world we would be fixing the issue there, but experience tells us that they are very slow to fix bugs / merge PRs in the email module, and even when they do they usually don't backport the fixes in the python versions we use. This commit extends the existing IdentificationFieldsNoFoldPolicy to also prevent Subject header folding, keeping long subjects on a single line (up to 998 characters per RFC 5322 "MUST" requirement, from the 98 "SHOULD" limit). Since at it, include the other "user defined" smtp headers: to, from, ... The solution follows the same pattern already established for identification headers (Message-ID, In-Reply-To, References) where Odoo prevents folding to avoid MTAs rewriting these critical headers and breaking email threading. closes odoo/odoo#250388 See-also: #243119 Backport: #247057 Forward-Port-Of: odoo/odoo#254670
Sales dashboards now keep the original Point of Sale order status instead of changing it to a regular sales order status. This prevents fulfilled POS orders from being counted incorrectly in sales dashboard views, improving reporting accuracy.
Original PR description
Step to reproduce: - install spreadsheet_dashboard_sale and pos_sale - create a order in pos , invoice it too - open sale dashboard Observation: - the order fulfilled in pos, does not reflect in…
Step to reproduce: - install spreadsheet_dashboard_sale and pos_sale - create a order in pos , invoice it too - open sale dashboard Observation: - the order fulfilled in pos, does not reflect in dashboard Cause: - sale has 4 status i.e ["draft", "sent", "sale", "cancel"] - when pos_sale is installed, new status oders are added i.e ['paid', 'invoiced', 'done'] - sale dashboard pivot relies on sale defined status only, which so not consider orders that have status in ['paid', 'invoiced', 'done'] Fix: - fix the domain of pivots such that, it will now accept other orders too **Before:** <img width="1058" height="277" alt="image" src="https://github.com/user-attachments/assets/e58c88fa-5ad3-4194-9f9c-ddf41f2f73de" /> <img width="1116" height="190" alt="image" src="https://github.com/user-attachments/assets/259e0347-5d5b-4d5c-9aeb-74102aa4becd" /> <br/> **After** <br/> <img width="1137" height="232" alt="image" src="https://github.com/user-attachments/assets/406b71a5-1dd8-4164-9d4e-4f0bca34c9e8" /> <img width="1125" height="235" alt="image" src="https://github.com/user-attachments/assets/fded3203-7d72-45ea-b5aa-142ebcd52136" /> opw-5487654 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#248142
POS invoices no longer fail when cash rounding is configured only for cash payments but the customer pays with a non-cash method. This prevents unexpected validation errors and helps staff complete card or other non-cash sales smoothly.
Original PR description
## Issue before this commit: Creating an invoice from a POS order with **Cash Rounding enabled only for cash payment methods** raised an unexpected validation error: > *"The operation cannot be…
## Issue before this commit: Creating an invoice from a POS order with **Cash Rounding enabled only for cash payment methods** raised an unexpected validation error: > *"The operation cannot be completed: Missing required account on accountable line."* This happened when the order was paid using a **non-cash payment method**, but rounding logic was still applied. ## Steps to Reproduce: 1. Install the `point_of_sale` module. 2. Go to POS Configuration → Settings: * Enable **Cash Rounding** * Set a **Rounding Method** * Enable **Only on cash methods** 3. Create a product: * Sale Price: 260 * Tax: 6% 4. Open a POS session. 5. Add the product to an order. 6. Apply a discount (e.g., 1.123). 7. Pay using a **non-cash payment method** (journal not marked as cash). 8. Enable **Invoice** and validate the order *(or create the invoice later from the Orders menu)* ## Cause of the Issue: While `_prepare_invoice_vals` correctly avoids setting `invoice_cash_rounding_id` for non-cash payments, `_create_invoice` still executes rounding logic whenever cash rounding is enabled on the POS configuration. This leads to a mismatch where: * No rounding configuration is set on the invoice * Rounding logic still attempts to create/update rounding lines * Required accounts (profit/loss) cannot be determined * A validation error is raised due to missing account on the generated line ## With This Commit: The rounding logic in `_create_invoice` is now guarded by checking the presence of `invoice_cash_rounding_id`. This ensures rounding is only applied when properly configured and avoids unexpected validation errors for non-cash payment invoices. Steps To Reporduce: [Video Link](https://drive.google.com/file/d/10ticlUW5i5pbu_oDDPqR-jg0hVcNWf3Z/view?usp=sharing) opw-6005320 opw-5951991 opw-6036870 Forward-Port-Of: odoo/odoo#254844
This fix prevents Point of Sale orders from counting an online down payment twice when settling a sales order with automatic invoicing enabled. It also corrects the remaining unpaid amount calculation, helping staff charge customers the right balance and avoid invoice/payment discrepancies.
Original PR description
Case 1: --- **Steps to produce:** - Install `pos_sale` module. - Enable `Automatic Invoice` in settings - Create a new SO with product price 1000. - In `Other Info`, set `Online Payment` to 30%. -…
Case 1: --- **Steps to produce:** - Install `pos_sale` module. - Enable `Automatic Invoice` in settings - Create a new SO with product price 1000. - In `Other Info`, set `Online Payment` to 30%. - Preview > make payment > down payment of 300 is created in SO. - In POS, open Furniture Shop register > Actions > Quotation/Order > select the SO > settle order. **Issue:** - The down payment line is added twice in the POS order. **Root cause:** - At [1], `sale_order.amount_paid` = 300, so `addDownPaymentProductOrderlineToOrder` adds the line in order. - At [2], the down payment line from the SO is added again. - Here, when `Automatic invoice` is on and we make the online payment then `amount_paid` is updated and the downpayment invoice is also created. - So, we have also downpayment line in sale order also. **Solution:** - Ensure that if a downpayment line has already been added to the POS order, the first downpayment line matching `amount_paid` is skipped. [1]: https://github.com/odoo/odoo/blob/54a62bdbe927108a7f85374db26787f8ba45f6ac/addons/pos_sale/static/src/overrides/models/pos_store.js#L88-L93 [2]: https://github.com/odoo/odoo/blob/54a62bdbe927108a7f85374db26787f8ba45f6ac/addons/pos_sale/static/src/overrides/models/pos_store.js#L109-L111 Before: <img width="484" height="279" alt="image" src="https://github.com/user-attachments/assets/c803c9bd-0751-4a90-81f4-8fb3da3b393e" /> After: <img width="490" height="235" alt="image" src="https://github.com/user-attachments/assets/2ec4ac43-1db3-4c2e-bfcf-8c52a4830dac" /> Case 2: --- **Steps to produce:** - Install `pos_sale` module. - Enable `Automatic Invoice` in settings - Create a new SO with product price 1000. - In `Other Info`, set `Online Payment` to 30%. - Preview > make payment. **Issue:** -The computed value of amount_unpaid is 400, whereas it should be 700. **Root cause:** - When Automatic Invoice is enabled and an online payment is made, the invoice is automatically created and amount_paid is also updated. - At [3], the logic subtracts both the total invoice amount and amount_paid from the actual total, which results in an incorrect calculation. **Solution:** - When an online payment is made, a transaction is created and linked to an invoice. - While computing the total invoice amount, if the transaction’s invoice ID is encountered again, it should be skipped to avoid double-counting. [3]: https://github.com/odoo/odoo/blob/75f6be6744006ed1a3c0857881822723f90f5d4a/addons/pos_sale/models/sale_order.py#L46-L51 opw-5415404 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#255247 Forward-Port-Of: odoo/odoo#242026
Products tagged as excluded from the Pick Up in Store delivery method will no longer show that pickup option on the product page. This prevents customers from seeing an unavailable delivery choice and keeps the product page consistent with checkout behavior.
Original PR description
Currently, when a product has a tag that is configured as an Excluded Tag on the Pick Up in Store delivery method, the method is still shown on the product page. Steps to produce: --- - Install…
Currently, when a product has a tag that is configured as an Excluded Tag on the Pick Up in Store delivery method, the method is still shown on the product page.
Steps to produce:
---
- Install `website_sale` module.
- Enable `Click and Collect` in settings.
- Go to `website > ecommerce > products > product tags.`
- Create a new tag and add a product in product template.
- Go to` website > configuration > ecommerce > delivery method.`
- Open` pick up in store`:
- In the `Stores` tab, set your company warehouse.
- In the `Availability` tab, add the created tag to Excluded Tags.
- Publish the delivery method.
- Open the tagged product on the website.
Issue:
---
- The Pick Up in Store option is still displayed on the product page, even though the product has a tag listed in the carrier’s Excluded Tags.
Root cause:
---
- Here at [1], the method `_get_additional_combination_info ()` does not check whether the product has tags that are excluded by the delivery method.
- However, at [2], during checkout, the exclusion works correctly because `_match_excluded_tags` in `delivery.carrier` filters the carrier based on excluded tags.
Solution:
---
- Hide the Pick Up in Store option when the product has tags excluded
for that delivery method. This keeps the behavior consistent across
the website, avoids showing unavailable delivery options, does not
impact other flows and aligns with the existing behavior during
checkout.
[1]https://github.com/odoo/odoo/blob/1c483c3a8d7d079bd34a378f9f8716551e4bab93/addons/website_sale_collect/models/product_template.py#L17-L21
[2]https://github.com/odoo/odoo/blob/1c483c3a8d7d079bd34a378f9f8716551e4bab93/addons/delivery/models/delivery_carrier.py#L192-L194
opw-5921268
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#255241
Forward-Port-Of: odoo/odoo#250837Invoices for customers in Åland Island can now be sent through Peppol correctly, with generated documents appearing in the invoice chatter as expected. Companies based in Åland Island can also activate Peppol without being treated as Finnish VAT registrations.
Original PR description
Before this commit, invoice to a partner in Åland Island can't be sent via Peppol. XML and PDF are generated, linked to the account.move, but are not sent and don't appear in the chatter. Steps to reproduce: - Create a partner in Åland Island - Create an invoice - Send to Peppol Current behavior: - Invoice is not sent, appear in the attachment, but doesn't appear in the chatter. Expected behavior: - invoice is sent and attachments are in the chatter This also allow activating Peppol for companies in Åland Island. Ticket [link](https://www.odoo.com/odoo/project.task/5949439) opw-5949439 Forward-Port-Of: odoo/odoo#251943
This fix stops cancellations from being sent to TicketBAI when the related invoice is protected by a secure hash and cannot be cancelled in Odoo. It prevents situations where TicketBAI shows an invoice as cancelled while Odoo cannot update it, reducing the risk of blocked records and inconsistent compliance data.
Original PR description
Before this commit, if the user configured the sales journal to be locked by a hash, then a cancellation in ticketbai would 1/ send the cancel request to ticketBAI. This would be processed…
Before this commit, if the user configured the sales journal to be locked by a hash, then a cancellation in ticketbai would 1/ send the cancel request to ticketBAI. This would be processed successfully 2/ try to reset the invoice to draft inside of Odoo, then cancel it. This would fail with an error since account moves protected by a hash cannot be reset to draft. The result is a blocked database where the invoice cannot be altered in Odoo while its status doesn't match the status in ticketBAI. In this commit, we propose to check for the secure hash before sending the invoice over to ticketBAI. The invoice is not altered yet at that stage to account for potential ticketBAI errors in the normal flow. While this option is not great from a usability perspective (preventing secure hashes with ticketBAI is probably best), we believe the current solution offers the best compromise in the context of a bugfix. The issue does not seem to be reproducible outside of production as the core of the problem is a mismatch in state between ticketBAIand Odoo. opw-5912848 Forward-Port-Of: odoo/odoo#250886
Invoices containing negative lines with fixed recycling fees now generate valid Peppol XML. This prevents invoice sending or validation failures when credit-like lines include Belgian recupel-style fees and VAT.
Original PR description
**PROBLEM** If you set a recupel tax (fixed tax affecting base) and use it on a negative line, the generate xml will not pass validation. **STEP TO REPRODUCE** 1. Setup Peppol. 2. Create a recupel tax (fixed tax of 1€, affecting the base). 3. Create an invoice with a negative line, with a VAT and the recupel tax. 4. Send the invoice using peppol, and validate the xml. 5. Notice the xml doesn't pass validation. **CAUSES** 1. The negative fixed tax should be an allowance, but is marked as a charge in the xml. 2. Only fixed taxes that are charges influences the line_extension_amount, but it should also be the case with negative fixed taxes. 3. Negative fixed taxes should have a ChargeAllowanceReasonCode that is in the AllowanceReasonCode list. opw-5955289 Forward-Port-Of: odoo/odoo#255259 Forward-Port-Of: odoo/odoo#252716
This fix ensures the website/page editor interface is restored even when a reloadable operation fails. It prevents users from getting stuck with a blocked screen after an error, improving reliability during editing workflows.
Original PR description
Since commit [1], the UI is blocked during a reloadable operation, but an early exit on error prevented unblock() from being called. This commit fixes it by wrapping it in a try/finally to ensure the UI is always unblocked. [1]: https://github.com/odoo/odoo/commit/453b7eb8e038ee8e8a54de16fc1a45fb2fab573a
This fix ensures manually adjusted component quantities on manufacturing orders are preserved when producing items. It prevents incorrect resets, missing warnings, and false lot/serial number errors, helping production teams complete manufacturing orders reliably.
Original PR description
# Product Configuration *Manufactured Product* - Storable - Tracked by Quantity - Manufacture Route - Has a BOM with atleast 1 component *Component Product* - Storable - Tracked By Lot # How to…
# Product Configuration
*Manufactured Product*
- Storable
- Tracked by Quantity
- Manufacture Route
- Has a BOM with atleast 1 component
*Component Product*
- Storable
- Tracked By Lot
# How to reproduce
- Ensure there is available stock for the component product in a lot
- Create a MO for the Manufatured Product
- Confirm the MO
- Click "Details" on the component product
- Remove the reserved quant and add a new one
- Increase the quantity of this new quant to more than "To Consume"
- Save
- Observe that "Consumed" = The quantity you just set on the quant
- Click on "Produce All"
# The issue
- The Consumed quantity is reset to the "To Consume" quantity.
- Furthermore, a warning popup should be displayed when clicking on "Produce All" but there is none.
- Finally, depending on the version you may get this error message : "You need to supply Lot/Serial Number for products and 'consume' them: - Component Product" even though a lot is already assigned
# Why
All these issues stem from the fact that move_raw_ids.picked from mrp.production is set to False instead of True.
This issue was introduced by this commit (https://github.com/odoo/odoo/commit/ef592464983d66ac76bc71a9886462f1f47dc28d) that changed the way the picked value is set.
In write(self, vals) de stock_move, we have :
```py
if self.env.context.get('force_manual_consumption') and 'quantity' in vals:
moves_to_update = self.filtered(lambda move: move.product_uom_qty != vals['quantity'])
if moves_to_update:
moves_to_update.write({'manual_consumption': True, 'picked': True})
```
Followed a bit later by :
```py
res = super().write(vals)
```
This usually works fine except when vals contains edition commands for move_line_ids. Then, the first write will correclty set picked to True, but then picked will be reevaluted after the second write with :
```py
@api.depends('move_line_ids.picked', 'state')
def _compute_picked(self):
for move in self:
if move.state == 'done' or any(ml.picked for ml in move.move_line_ids):
move.picked = True
else:
move.picked = False
```
If all the resulting move_line_ids from the commands edition have picked set to False, then move.picked will also be set to False.
opw-5937171
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#253607This update resolves two issues preventing new employee creation in the Belgian payroll module. The first prevented saving with a start date, and the second caused errors when adding wages. The fix ensures proper record creation and avoids duplicate activity triggers, improving employee onboarding.
Original PR description
First bug: Steps: - Switch to belgian company - Create new employee - Set contract start date - Click save manually -> boom Cause: in _trigger_l10n_be_next_activities, we create a new mail activity for the created employee which is already created in the default create function leading to duplicate follower records. Fix: in the super.create, pass the context variable mail_create_nosubscribe=True to disable adding the current user as a follower again to the same record Second bug: Steps: - Switch to belgian company - Create new employee - Set contract date - Add a wage then click anywhere -> boom Cause: _trigger_l10n_be_next_activities is called before the record is saved, hence trying to link to a null object Fix: check if the record is created before working on the activities
This update resolves an issue where the XML generated for Swiss payments (iso20022_ch) was using an outdated payment schema. The fix ensures the XML adheres to current banking standards, specifically the pain.001.001.09 format required by Swiss financial institutions. This improves payment processing accuracy and compliance.
Original PR description
**PROBLEM** According to documentation (https://www.six-group.com/dam/download/banking-services/standardization/sps/ig-credit-transfer-sps-2025-en.pdf) PstlAdr must be structured. This isn't the case when generating a xml for the payment method iso20022_ch. **STEP TO REPRODUCE** 1. install l10n_ch and account_iso20022. 2. Create a swiss contact with a full address. And activate payment on the bank account of this contact. 3. Select the Company CH, and set a bank account in the bank journal configuration. 4. Create a vendor payment to the swiss contact. 5. Create a batch payment with it, and validate to get the xml. 6. Open the xml, and notice the PstlAdr isn't structured. Ticket [link](https://www.odoo.com/odoo/project.task/5880247) opw-5880247 Forward-Port-Of: odoo/enterprise#111158 Forward-Port-Of: odoo/enterprise#107025
This update resolves a problem where invoices with discounts and decimal values (over 2 decimals) were failing to send to ARCA. The fix uses a simplified unit price to calculate discounts, ensuring accurate decimal calculations for EDI invoice generation. This prevents errors and ensures proper invoice transmission.
Original PR description
After changes made in Odoo of how the decimal precision works some of the code we use to prepare the data to create EDI invoices now fails. We already adapt the code to fix the data depending of the expected webserive format but we miss a case related to when invovice has discounts. The problem is that any invoice with lines that has more than 2 decimals and also have a discount will fail when trying send it to ARCA because the computed amount has differences in the decimals. Now we use the truncated unit price to compute the discount instead of the full amount with decimal of the `line.price_unit` value. Forward-Port-Of: odoo/enterprise#110706
This update fixes an issue in our tax reporting module where calculations for previous tax periods were inaccurate, particularly with trimester-based tax periods. The fix ensures correct period boundaries are used, preventing incorrect report values and improving the reliability of tax reporting data.
Original PR description
To reproduce the issue: - Setup tax periodicity to "trimester" - Create a report evaluating something with previous_tax_period date_scope (real cases tend to do that for carryover ; see monthly…
To reproduce the issue: - Setup tax periodicity to "trimester" - Create a report evaluating something with previous_tax_period date_scope (real cases tend to do that for carryover ; see monthly Italian tax report for an example) - Create the appropriate data so that in the current trimester, the report line evaluates to 42, and to 1 in the previous trimester - Open the report for the second month of the trimester => The line has value 42, while it should have 1. This happens because the date bounds for previous_tax_period were computed too naively, considering the date_from was always the first day of the tax period. The first day of the second month of the trimester, it's not the case, and we return the period boundaries of the day before that day. That day is the last day of the first month of the trimester, but belongs to the same trimester, so it's the same tax period. Therefore, we display the value of the current tax period, which is wrong. Forward-Port-Of: odoo/enterprise#111483 Forward-Port-Of: odoo/enterprise#110504
This update ensures that all attendees of an appointment – including internal users and organizers – receive booking notifications, regardless of whether the booking syncs with Google or Outlook. Previously, notifications were limited, but this change ensures consistent communication for all involved parties.
Original PR description
In [1] we prevented cancelation emails from being sent when the booking was synced via google or outlook calendar. However this means even followers who would not be notified by the mail provider (not assisting to the meeting) would not be notified. As well as the organizer who is doing to booking/cancelling from the perspective of the mail provider, as the meeting is created from their account. Instead we should keep sending the "appointment booked" template in all cases as it is only followed by internal users to whom it is always relevant. As for cancelation templates, it should stil be sent to internal users. Partners of the meeting however need not be notified and may be unsubscribed if syncing is enabled, as cancellation typically only happens once. task-5152917 [1]: https://github.com/odoo/enterprise/pull/60913 Forward-Port-Of: odoo/enterprise#111174 Forward-Port-Of: odoo/enterprise#96638