Monday, December 8, 2025
14 changes · saas-18.4
New functionality added to Odoo
This update adds support for the ICE (Identifiant Commun de l'Entreprise), a mandatory identification number for Moroccan businesses, to invoices. It ensures that invoices issued to Moroccan companies include this number, complying with local regulations. This change directly impacts invoicing processes for Moroccan clients.
Original PR description
Backport ICE number from 18.0 to 16.0: f9d00e684b3fa395a33ae4b5b795d9fc6e4fcf0e Reason: The ICE (Identifiant Commun de l'Entreprise) is an identification number assigned to businesses and legal entities for various administrative and legal purposes in Morocco. If the partner has one, it must be indicated on the invoice. The ICE number is supposed to be put on all the invoices made to Moroccan companies, whatever the country of the company issuing those invoices. We hence add that directly into the account module. task-4879950 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#238687 Forward-Port-Of: odoo/odoo#237068
Resolved issues and error corrections
This fix resolves an issue where stock valuations were incorrect after splitting a purchase order receipt into a batch. The problem stemmed from how the system calculated values during batch validation, leading to inaccurate stock valuation amounts. This update ensures correct stock valuation calculations when using batch billing with split receipts.
Original PR description
…n batch billed on ordered qty **Problem:** When the picking of a purchase order (of a product billed on ordered quantity) is split into different moves and put in a batch, at batch validation, svls…
…n batch billed on ordered qty
**Problem:**
When the picking of a purchase order (of a product billed on ordered quantity) is split into different
moves and put in a batch, at batch validation, svls are created with the wrong values.
**Steps to reproduce:**
- enable "Batch, Wave & Cluster Transfers" settings
- create a storable product with a standard price of 1
- set the category as avco
- in the Purchase tab select the control policy as
"on ordered quantities"
- create and confirm a purchase order for 50 of this product
- on the Receipt, change the quantity to 20 and split the
picking
- go back the the PO and create and confirm a bill for
the full amount
- click on the receipt smart button
- select the two pickings and then the 'Action' button
- select add to batch
- check 'new batch transfer' and confirm
- open the batch and validate it
- open stock valuation
**Current behavior:**
the newly created svls have total values of
50 and 50.10
**Expected behavior:**
it should be 20 and 30
**Cause of the issue:**
When the batch is validated, _action_done is called
on the two stock moves.
https://github.com/odoo/odoo/blob/dc57ea4d306f8745d37f2c5d2c3d3fa4bcaf7253/addons/stock/models/stock_picking.py#L1258
In the stock_account override:
- first the super method is called
As a consequence the state of the two moves becomes 'done'
and the qty_received of the linked purchase order line becomes 50.
- then product_price_update_before_done is called before creating
the svls.
Inside product_price_update_before_done we call _get_price_unit.
In the purchase_stock override of _get_price_unit :
- because the super method of action_done was already called,
qty_received of the purchase order line is 50, so _get_qty_received_without_self
will return 30.
https://github.com/odoo/odoo/blob/dc57ea4d306f8745d37f2c5d2c3d3fa4bcaf7253/addons/purchase_stock/models/stock_move.py#L50
So received_qty is 30 and later remaining_qty will be 20
https://github.com/odoo/odoo/blob/dc57ea4d306f8745d37f2c5d2c3d3fa4bcaf7253/addons/purchase_stock/models/stock_move.py#L86
- but because no svl was created yet receipt_value will stay 0 and later
remaining_value will be 50
https://github.com/odoo/odoo/blob/dc57ea4d306f8745d37f2c5d2c3d3fa4bcaf7253/addons/purchase_stock/models/stock_move.py#L55-L63
Therefore price_unit will be 2.5 (50/20) instead of 1
**fix**
We do not take into account the move(s) of the
same batch in the remaining value (because svls are not created yet)
so we should not take them into account in the remaining quantity.
opw-5179581
Forward-Port-Of: odoo/odoo#238222
Forward-Port-Of: odoo/odoo#235601This update fixes a potential error in the Razorpay payment integration. If the Razorpay secret key is missing, the system would previously fail. The change now gracefully handles this situation by logging a warning and preventing signature calculations, ensuring smooth transaction processing.
Original PR description
An error is expected to occur at line [1] if the secret is missing when a transaction is processed through Razorpay and the page is redirected. **Error:** `AttributeError:'bool' object has no attribute 'encode'` **Solution:** * Added a check to log a warning and return None to abort signature calculation if the secret is missing similar to [2]. [1]: https://github.com/odoo/odoo/blob/bb37b3e320395c6e96b6a0c0c96367bd87d1c702/addons/payment_razorpay/models/payment_provider.py#L232 [2]: https://github.com/odoo/odoo/blob/bb37b3e320395c6e96b6a0c0c96367bd87d1c702/addons/payment_razorpay/models/payment_provider.py#L236-L238 **Sentry-6767571136**
This update fixes a bug where old work entries persisted across different versions of our scheduling system. The change ensures that outdated work entries are automatically removed when a new version with a different schedule is created, maintaining data accuracy and preventing confusion.
Original PR description
Problem ---------- When we create a new version with a new working schedule, it will generate correct work entries (because no one was generated for this version before) But it will not remove the previous one for the other previous versions. Solution ---------- Nullify work entries if outside the valid period of the version if they were already created before. task-5065139
This update resolves an issue preventing users from adding products from the parent company to quotation templates within the multi-company setup. Previously, this was allowed in standard sales orders, but not quotation templates. This change aligns the quotation template functionality with the existing sales order flow, improving usability and flexibility for our business users.
Original PR description
### Issue In this issue, having multi-company setup, we cannot make a quotation template with a product from the parent company. While this is allowed in sale order. #### To reproduce: 1- Create a product and in the product form, set the the company field to the parent company. 2- Create a quotation template and set the company field to the child branch. 3- In the quotation template, add a line and use the created product from the parent company. 4- Saving the form will raise an error. Talked with PO about the issue and he agreed that the quotation template should allow product from the parent company. This is already the flow in the quotation itself. opw-5177590 Forward-Port-Of: odoo/odoo#237732
This update resolves an issue where the SAFT export process would fail when a journal entry lacked a partner but included a receivable account. The fix ensures the system can now correctly generate SAFT files in these scenarios, preventing export errors and improving compliance. This impacts companies using the SAFT reporting feature.
Original PR description
If we try to export a SAF-T file when a line doesn't have any partner but having a receivable account, then a traceback is displayed.
(Backport of #98240)
How to reproduce?
1. Use a company with a localization using SAF-T (e.g. l10n_dk)
2. Create and post a journal entry with no partner, and with a line having a receivable account.
3. Go on the general ledger, and export in the SAF-T format
opw-5260937
Forward-Port-Of: odoo/enterprise#100960
Forward-Port-Of: odoo/enterprise#100296This update resolves an issue where marking multiple manufacturing orders as done resulted in an error. The fix ensures accurate precision rounding when handling multiple units of measure within the manufacturing process, preventing data inconsistencies.
Original PR description
Currently, an error occurs when user marks multiple Manufacturing Orders as Done. **Steps to Reproduce…
Currently, an error occurs when user marks multiple Manufacturing Orders as Done.
**Steps to Reproduce ([Video](https://drive.google.com/file/d/1XfkMB001rMiyulRGrP4dlJFDYByo_5Bv/view?usp=drive_link)):**
- Install the `mrp` module.
- Go to `Settings` and enable `Units of Measure & Packagings`.
- Go to `Products and `create two products` with different `units of measure`.
- Go to `Manufacturing Orders`, create a manufacturing order by `adding one of the products`, and then `create work order` in the Work Orders section and `confirm` it.
- Create another `manufacturing order` with the `same quantity` for the second product and add a `Work Order` for it as well and `confirm` it.
- Go to the `list view`, select `both orders`, and click `Mark as Done` from the `Actions` menu.
**Error:**
```
ValueError: ValueError('Expected singleton: uom.uom(4, 6)') while evaluating
"if records:\n res = records.filtered(lambda mo: mo.state in {'confirmed', 'to_close', 'progress'}).button_mark_done()\n if res is not True:\n action = res"
ValueError: Expected singleton: uom.uom(4, 6)
```
After [this commit], which improves the performance of button_finish, when a user marks multiple orders as done with the same quantity but different uom , it creates all_vals_dict based on the vals[1] data as the key and the work order as the value[2]. Then it stores two or more work orders with different UoMs under the same vals key. When attempting to write multiple work orders[3], the precision rounding is calculated, which raises the error[4] due to multiple UoMs.
The commit ensures that when writing records, precision_rounding is calculated separately for each Work Order's UoM.
[this commit]: https://github.com/odoo/odoo/pull/223715/commits/b857d192085a38b612335223d04f8bdff91b898c
[1]- https://github.com/odoo/odoo/blob/186a9eb4a6c55c9c4c2178d4b2492a9a23a267fe/addons/mrp/models/mrp_workorder.py#L698-L703
[2]- https://github.com/odoo/odoo/blob/186a9eb4a6c55c9c4c2178d4b2492a9a23a267fe/addons/mrp/models/mrp_workorder.py#L706
[3]- https://github.com/odoo/odoo/blob/186a9eb4a6c55c9c4c2178d4b2492a9a23a267fe/addons/mrp/models/mrp_workorder.py#L708
[4]- https://github.com/odoo/odoo/blob/186a9eb4a6c55c9c4c2178d4b2492a9a23a267fe/addons/mrp/models/mrp_workorder.py#L477
sentry-7050854871
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#238086This update ensures POS orders are processed immediately after online payments, regardless of whether the user views a confirmation page. Previously, delays caused confusion for customers and cashiers. Now, transactions are processed directly after payment confirmation, maintaining accurate order status.
Original PR description
..., pos_online_payment_self_order Task: [#5217268](https://www.odoo.com/odoo/project/1737/tasks/5217268) --- Previously, when an online payment was made, the user was supposed to be redirected to a…
..., pos_online_payment_self_order Task: [#5217268](https://www.odoo.com/odoo/project/1737/tasks/5217268) --- Previously, when an online payment was made, the user was supposed to be redirected to a payment confirmation page, which triggered the payment transaction post-processing. However, in some cases, the user never reaches this page. For example: the user sees that the payment succeeded in their banking app and closes the tab before being redirected to the confirmation page. To still process the orders, a cron runs every 10 minutes to post-process transactions that were not processed yet. However, for POS self-orders this is not ideal: we need the order to be processed as soon as possible since we are in direct contact with the user. A situation where the customer insists their payment went through but the cashier sees no updated order creates unnecessary confusion. --- To fix this, we now trigger the cron directly after receiving the callback from the payment provider. This ensures that the transaction (and therefore the order) is always post-processed immediately and kept up-to-date, even if the user never reaches the confirmation page. Forward-Port-Of: odoo/odoo#235254
This update ensures that orders are automatically sent to the kitchen (PDIS) after a self-order payment is confirmed, regardless of whether the user sees a confirmation page. Previously, reliance on the confirmation page was unreliable, leading to potential delays and confusion. This change improves the overall POS experience by guaranteeing timely order processing.
Original PR description
pos_online_payment* = pos_online_payment_self_order_preparation_display Task: [#5217268](https://www.odoo.com/odoo/project/1737/tasks/5217268) --- Previously, when an online payment was made, the…
pos_online_payment* = pos_online_payment_self_order_preparation_display Task: [#5217268](https://www.odoo.com/odoo/project/1737/tasks/5217268) --- Previously, when an online payment was made, the user was supposed to be redirected to a payment confirmation page which, once the transaction succeeded, sent the related order to the kitchen (PDIS). However, in some cases, the user never reaches this page. For example, the user may see the payment succeed in their banking app and close the tab before the redirection happens. For POS self-orders, we must send the order to the kitchen as soon as the payment is confirmed to avoid confusion between the customer, the cashier, and the kitchen staff. Relying solely on the confirmation page was therefore unreliable. --- To fix this, we now leverage the cron that post-processes payment transactions: we gather all transactions made in self-order or kiosk mode that are not yet post-processed, and send their corresponding orders to the kitchen. This ensures that orders reach the PDIS even when the user never lands on the confirmation page. Forward-Port-Of: odoo/enterprise#99249
A recent update to Odoo's security features caused a problem where users couldn't successfully revoke trusted devices through the portal. This fix corrects two typos in the system's dynamic content, ensuring that users can now properly remove previously trusted devices from their accounts. This resolves a potential security concern.
Original PR description
After public widgets have been rewritten as Interactions [1], there were 2 typos in `dynamicContent` that led to the wrong behavior. Because of that, we couldn't revoke a trusted device, or all of them. Steps to see the issue, - Turn the 2FA on - Add a trusted device, for example, by checking `Don't ask again on this device` when prompted to enter the authentication code while logging in. - Go to /my/security - Try to revoke a trusted device, either just by clicking on the trash icon button, or the 'Revoke all' button. => Nothing happens. [1]: https://github.com/odoo/odoo/commit/22e777c046521f3f89b62caa5876680beb7f5aba Forward-Port-Of: odoo/odoo#238830
This update fixes an issue where the keyboard would unexpectedly appear on mobile date fields, causing a frustrating user experience. The change prevents the keyboard from opening and hides the cursor, resulting in a smoother and more intuitive date selection on smaller screens.
Original PR description
Before this commit:
- The cursor was shown inside the date/datetime input field on mobile,
which triggered the keyboard unnecessarily and degraded the user
experience.
Steps to reproduce:
1. Add a form snippet.
2. Add a Date/Datetime field.
3. Click on the Date field.
- The virtual keyboard appears and the datepicker popover may be
clipped or partially hidden.
After this commit:
- The virtual keyboard is now prevented from opening on date/datetime
inputs, and the text cursor within these fields is also hidden.
task-[4745714](https://www.odoo.com/odoo/project/974/tasks/4745714)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#238771
Forward-Port-Of: odoo/odoo#212053This update resolves an issue where the automatic link between purchase orders and repair orders breaks when a purchase order is confirmed. The fix ensures the smart link remains active, streamlining the process of managing stock and related orders. This improves efficiency and accuracy in order fulfillment.
Original PR description
The link between purchase order and a repair order break at when the PO is confirmed. ### Steps to reproduce: * Install the Repair and Purchase modules * Activate multi-steps routes * Unarchive the…
The link between purchase order and a repair order break at when the PO is confirmed. ### Steps to reproduce: * Install the Repair and Purchase modules * Activate multi-steps routes * Unarchive the MTO route * Create a product with the MTO route enabled * Create a Repair * On the Repair Order, in part add: - type : ADD - product : mto product * Save the RO * Go to Purchase Order * Confirm the PO -> Issue Smart link between PO and RO broken. ### Observation: The smart link is defined on: RO -> PO: https://github.com/odoo/odoo/blob/a2be8182010613c6f92f59e686a2fbf066cc6b68/addons/purchase_repair/models/repair_order.py#L15-L17 PO -> RO: https://github.com/odoo/odoo/blob/a2be8182010613c6f92f59e686a2fbf066cc6b68/addons/purchase_repair/models/purchase_order.py#L15-L17 When we confirm the PO, from the picking information it will create new moves: https://github.com/odoo/odoo/blob/2c87f3b2b397f268f0e50cb73cd81de992ddd42e/addons/purchase_stock/models/purchase_order.py#L293-L298 To create those stock moves, we go into_create_stock_moves where, for each POL, we will generate their values and erase the smart link: https://github.com/odoo/odoo/blob/a2be8182010613c6f92f59e686a2fbf066cc6b68/addons/purchase_stock/models/purchase_order_line.py#L362-L365 ### Origin: In this commit https://github.com/odoo/odoo/commit/9d98c43581e2579f43b35541b43264866dede5a5: "`created_purchase_line_id` is cleared after confirming the RFQ. This allows to merge more in `_merge_moves`." This breaks the link between PO <-> RO to maybe merge the move in the future. This issue is not present in 19.0 since it was solve in this commit : https://github.com/odoo/odoo/commit/2713876dbc70d3984e584a9037a2206dcda4e84a ### About the fix: The root cause of this issue remains ambiguous despite the analysis. Therefore, in the interest of stability and caution, we opted to implement the fix in a safer location. opw-5121816 Forward-Port-Of: odoo/odoo#232999
This update fixes an issue where holiday pay recovery was incorrectly applied to older employees when contract start and end dates were changed. The fix ensures that holiday pay recovery is applied appropriately based on the employee's start date, aligning with standard payroll practices. This improves the accuracy of payroll calculations.
Original PR description
Purpose ======= Normally contracts start and end dates should be configured without being closed and reopened at each version date. But, if it is the case, holiday pay recovery could be applied on older employees because it is considered the employee just joined the company, and there is an amount to recover.
This update resolves an issue where user notifications within the messaging menu were failing to function correctly. The fix ensures that notifications triggered by duplicate record searches properly open the correct chat window, improving the user experience for data management tasks. This was caused by a mismatch in how message threads were created and assigned.
Original PR description
**Steps to reproduce:** - Install `Data Cleaning` app - Activate notification in Odoo in the admin user profile - Create a few duplicate contacts - Go the the "Data Merge: Find Duplicate Records"…
**Steps to reproduce:**
- Install `Data Cleaning` app
- Activate notification in Odoo in the admin user profile
- Create a few duplicate contacts
- Go the the "Data Merge: Find Duplicate Records" scheduled action
- Run the action manually
- You should see new notifications telling you that they found potential duplicates
- In the top right MessaginMenu click on the notification, it opens a chatter
- Try to send a message in the chat window
- Traceback : `AttributeError: 'data_merge.model' object has no attribute '_get_thread_with_access'`
**Issue:**
The model doesn't inherit `mail.thread` so it uses `self.env['mail.thread']` directly to send notification:
```
self.env['mail.thread'].sudo().message_notify(
...
model=self._name,
notify_author=True,
partner_ids=partner_ids,
res_id=self.id,
)
```
But when sending the information with the `model` and `res_id` parameters the newly created `Store` uses `self.add("mail.thread", {"id": data.id, "model": data._name, **values})` and the message is assigned to a non-existing thread in the frontend.
**Fix:**
Explicitly check if the message is a `user_notification` and redirect the user to the discuss inbox if it's the case by reapplyng part of https://github.com/odoo/odoo/commit/b3be992c57dc5e412a127d05fc50b059814523aa
opw-5101510
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#238563
Forward-Port-Of: odoo/odoo#234737