Monday, December 8, 2025
17 changes · 19.0
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 is integrated directly into the account module for seamless implementation.
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
Enhancements to existing features
This update enables administrators to modify the work entries associated with payslips that have been reversed or refunded. Previously, these entries were immutable. This change provides greater flexibility in managing payroll records and correcting errors related to refunded payments.
Original PR description
-Originally, work entries for validated payslips cannot be modified. -This task allows for the modification of the work entries for the reverted payslips. -State of work entries can be modified manually through list view + form view on gear icons Task-id: #5380821
Resolved issues and error corrections
This update resolves an issue where the Frontdesk kiosk URL didn't consistently display the correct company logo. The fix ensures the logo is always shown when switching companies, improving the user experience. It corrects a permission error preventing access to the company record.
Original PR description
When switching companies in a Frontdesk station and opening the kiosk URL, the company logo does not appear. **Steps to produce:** - Install the `frontdesk` module. - Ensure the database has at least…
When switching companies in a Frontdesk station and opening the kiosk URL, the company logo does not appear. **Steps to produce:** - Install the `frontdesk` module. - Ensure the database has at least two companies, each with a logo configured. - `Enable multi-company` access (user has access to all companies). - Open any Frontdesk station configuration and change the company to one different from the currently active company. - Copy the kiosk URL and open it in an incognito/private window. - The kiosk opens, but the company logo is missing. **Issue:** - Company logo not comes on frontdesk kiosk. **Root cause:** - When the kiosk URL is accessed, Odoo logs an `Access Denied by record rules`. - This happens because the selected company on the station is not included in the `Public User’s companies`. - As a result, the public user cannot read the company record, so the logo does not load. **Solution:** - Added an `onchange` on `company_id` to automatically include the selected company in the Public User’s `company_ids` if it is not already present. - This ensures the kiosk always has access to correct company record and logo. - Also added an XML-side fix to prevent an access error that occurs when a company is not activated and we attempt to select it in the company field. **Before:** <img width="500" height="500" alt="frontdesk_image_before" src="https://github.com/user-attachments/assets/b002ac6e-5271-4561-bf03-542a3feeefd1" /> **After:** <img width="500" height="500" alt="frondesk_image_after" src="https://github.com/user-attachments/assets/7b5bffe4-ccbf-48f5-ad9c-d5e6d2e7678e" /> **opw-5138980** Forward-Port-Of: odoo/enterprise#100300
This update ensures the E-Ledger report accurately reflects branch numbers by linking them to a new 'SUBENO' tag on partner records. This change aligns with a recent update to better define branch information within Odoo, improving the reliability of financial reporting. The update also ensures compatibility with related modules.
Original PR description
Currently, the BranchNumber field in the E-Ledger CSV is linked to res.company.company_id. However, a new res.partner.category 'SUBENO' was introduced to properly define branch numbers. So this change makes sure the branch number is captured from the tags on the branch's partner_id. l10n_tr_reports now also depends on l10n_tr_nilvera_einvoice because the SUBENO tag is created there. Task-id: 5022037
This update resolves an error that occurred when sending invoices through the Taiwan Electronic Invoicing module for ECpay. The issue stemmed from a system attempt to access a field that was previously removed, causing a crash. This fix ensures invoices can be successfully generated and sent.
Original PR description
This error occurs when the user try to send invoice. Steps to reproduce: - Install `l10n_tw_edi_ecpay` module > Switch to `Taiwan` company - SetUp `Taiwan Electronic Invoicing` in settings - Create a…
This error occurs when the user try to send invoice. Steps to reproduce: - Install `l10n_tw_edi_ecpay` module > Switch to `Taiwan` company - SetUp `Taiwan Electronic Invoicing` in settings - Create a New Customer with `Email` and `Tax ID` (eg: 12345678) - and no `phone` number. - Create New Invoice with created Customer > Confirm > Send > `Send to Ecpay` > Generate Traceback: `AttributeError: 'res.partner' object has no attribute 'mobile'` This issue occurs at [1] because when the `phone` field is not set, the system tries to fall back to the `mobile` field. However, the `mobile` field was removed from `res.partner` (see related reference), and it was reintroduced in the referenced [commit]. This commit cleans up the logic to avoid referencing a non-existent field. [1]: https://github.com/odoo/odoo/blob/f1deed16e2355a74fea522439826625535eb7052/addons/l10n_tw_edi_ecpay/models/account_move.py#L677-L678 reference- https://github.com/odoo/odoo/pull/189739 [commit]: https://github.com/odoo/odoo/pull/236938/commits/c7404dff58f232103af4271a445d3841a82be8a3 sentry-7086174794 Forward-Port-Of: odoo/odoo#238657
This update resolves an issue where users were incorrectly receiving access errors when working with Sales Orders and Projects across different companies. The fix ensures that users with access to multiple companies can correctly interact with linked records, improving usability in multi-company environments. This change enhances security by correctly validating access permissions.
Original PR description
**Steps to reproduce:** 1. Create a database in 19.0 version. 2. Create a second company (so there are two companies in total). 3. Install the Sales and Project applications. 4. In Company 1, create…
**Steps to reproduce:** 1. Create a database in 19.0 version. 2. Create a second company (so there are two companies in total). 3. Install the Sales and Project applications. 4. In Company 1, create a Sales Order. 5. In Company 2, create a Project that is restricted to Company 2 only (i.e., not shared across companies) and ensure it is billable. 6. Inside that project, create a Task and link it to the Sales Order from Company 1. Make sure both companies are selected in your company switcher. 7. Now, switch to only Company 1, and try to open the Sales Order that is linked to the task in Company 2. 8. At this point, an AccessError will be raised, even though the user has access rights in both companies. **Description of the issue:** The `AccessError` is being raised even though the user already has read access. This issue started after the following commit : (https://github.com/odoo/odoo/commit/aae732957c3c3b3590f5686cfccc0ab264d0b5c9) In that update, a new check was added requiring **read access** when performing operations on **many2many fields**. This behavior is correct and improves security. However, a problem occurs in **multi-company environments**. For example, if a user has access to two companies (Company A and Company B), and a **Sales Order** belongs to Company A while the linked **Project** belongs to Company B, then when the user opens or writes records with only one company selected, an `AccessError` is raised — even though the user has access to both companies. **Current behavior before PR:** When writing on a many2many field that links records across different companies, an `AccessError` is raised. This happens because the context does not include the `suggested_company`, so the system cannot detect that the user has access to both companies. In the [commit](https://github.com/odoo/upgrade/pull/7960/files#diff-df0a10c9996a33faffbfcd4f2126eb2143cc9ecaa7dc1c28dad7fe930b3c1388R475-R489) , the issue was avoided during tests by adding the `suggested_company` from the context to the allowed company list. But in the related Odoo commit: [6213c40](https://github.com/odoo/odoo/commit/6213c40932236101b529b82f0ea9fce1829c8c24#diff-706c5300f0b758ed43a362c85fa84a655c8bae12339bd882e98dc419623facc2R208) the context is always empty, meaning no company is added to the allowed list — leading to an unnecessary AccessError. **Desired behavior after PR is merged:** The `context` is now added before raising the AccessError. If the user has access to both companies (e.g., the one linked to the Sales Order and the one linked to the Project), the system correctly identifies this and does **not** raise an AccessError. If the user does **not** have access to the other company, the AccessError is still raised — ensuring that security remains intact. Desired behavior after PR is merged:c --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes an issue where old work entries persisted across different versions. Now, when a new version is created with a new schedule, outdated work entries are automatically removed, ensuring accurate reporting and data consistency. This improves the reliability of our scheduling and time tracking processes.
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 a bug preventing users from opening Sales Orders linked to projects in different companies. The fix removes a restrictive check, allowing users with appropriate access rights to view Sales Orders regardless of the linked project's company affiliation. This ensures consistent access for users across multiple companies.
Original PR description
**Steps to reproduce the issue** 1. Create a database in Odoo 19.0. 2. Create a second company (so now you have two companies). 3. Install the **sale_project** app. 4. In **Company 1**, create a…
**Steps to reproduce the issue** 1. Create a database in Odoo 19.0. 2. Create a second company (so now you have two companies). 3. Install the **sale_project** app. 4. In **Company 1**, create a Sales Order. 5. In **Company 2**, create a Project that belongs **only** to Company 2 and mark it as *billable*. 6. Inside this Project, create a Task and link it to the Sales Order from Company 1. Make sure both companies are selected in the company switcher. 7. Now, switch to **only Company 1**, then try to open that Sales Order. 8. You will get an **AccessError**, even though the user has access rights in both companies. **Second scenario** 1. Create another user (User 2) who has access **only** to Company 1. 2. Give User 2 manager access in both Sales and Project. 3. Log in as User 2 and try to open the Sales Order. 4. You will again get an **AccessError**. **What is the actual issue?** The AccessError happens in multi-company setups. Even if a user has read access to the Sales Order, The error still blocks them from opening it if: * The Sales Order belongs to Company A * The linked Project belongs to Company B * The user currently has only Company A selected or have Access to company A only. This is because of the `_compute_project_ids` https://github.com/odoo/odoo/blob/ac6960dc553088894e688bcc0f4a49245aa02d6c/addons/sale_project/models/sale_order.py#L127 This logic causes problems because: * It only uses this check when the user is *not* a project manager. * Even project managers can get AccessErrors if they don’t have the other company selected or not have access of other company. * This is wrong because a user who **has the right to access the Sales Order** should still be allowed to open it, even if they don’t have access to the project in the other company. **How the issue is fixed** I removed the condition: `if not is_project_manager` This allows the system to skip the problematic filtering behavior. A user who has access rights to the Sales Order can now open it normally even if the linked project belongs to another company. OPW: [5229806](https://www.odoo.com/odoo/project/70/tasks/5229806) UPG: [3485646](https://upgrade.odoo.com/odoo/upgrade.request/3485646) Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves a bug that prevented the generation of SAFT files when a journal entry lacked a partner but included a receivable account. The fix ensures that SAFT exports can now successfully process these entries, addressing a potential compliance issue for businesses using SAFT reporting.
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 fixes an issue where stock valuations were incorrect after splitting purchase order receipts into batches and validating the batch. The fix ensures the correct valuation is applied based on the ordered quantity, resolving a discrepancy in the calculated stock values.
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#238723
Forward-Port-Of: odoo/odoo#235601This update fixes layout issues within the calendar by allowing popovers to display naturally below or above events, regardless of event width. It also prevents popovers from sticking to screen edges, ensuring a cleaner and more consistent user experience. This improves the overall usability of the calendar feature.
Original PR description
This PR addresses two positioning issues: - **Calendar**: Removed forced horizontal positioning. Popovers can now display below/above events, fixing layout issues with wide events. - **Screen Edges**: Added a 20px buffer to the position calculation logic to prevent popovers from sticking to the edges of the screen/container. task-4453491
This update fixes an issue where subscription payments failed due to missing country information. The change ensures subscriptions, even for services, correctly require a country to be set, preventing payment failures and improving the reliability of recurring invoices. This resolves a technical glitch impacting subscription billing.
Original PR description
## Versions 19.0+ ## Issue A customer subscribing to a service can checkout without filling its data (incl. country). This leads to a failure of the next payment and a message in the chatter telling…
## Versions
19.0+
## Issue
A customer subscribing to a service can checkout without filling its data (incl. country). This leads to a failure of the next payment and a message in the chatter telling that "Automatic payment failed. No country specified on payment_token's partner".
## Steps to reproduce
*Ensure Sales app is installed*
- Create a customer account without filling personal data in;
- Navigate to the shop:
- Look for a subscription service (ending with "SUB") and add it to cart;
- Go to the cart and click the checkout button (automatically bypassing the addresses form);
- Pay with Demo.
- Logout and sign in as admin user:
- Go to Sales and open the latest SO (related to the test user):
- Duplicate the SO and activate debug mode;
- Open "Other Info" tab:
- Change the subscription starting date for any date in the past;
- Set the Payment Token selecting the available one; - Confirm the order.
- Navigate to Scheduled Actions:
- Look for "Sale Subscription: generate recurring invoices and payments" action and open it:
- Click "Run Manually".
- Come back to the duplicated subscription SO and look at the chatter's last message:
- OdooBot's message tells that "Automatic payment failed. No country specified on payment_token's partner".
## Cause
Task 4307281 introduced address info bypass to fasten checkout for services but subscriptions, even for services, require the country to be set for recurring payments as per https://github.com/odoo/enterprise/blob/f40e24e67a1664a13acdd01578d8269d084ee421/sale_subscription/models/sale_order.py#L1751-L1757
opw-5268156This update improves how Odoo handles Adyen payment rejections. Previously, a missing amount field in the rejection response would mask the actual reason for the decline. Now, the system correctly displays the refusal reason, ensuring accurate tracking and resolution of payment issues, particularly for offline payments.
Original PR description
When requesting a direct payment (for offline operation) and Adyen reject the it, we will get back a response that may not always have the amount information. This commit skip the amount and currency validation for refusal, so that the missing amount error message will not shadow the real refusal reason. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update adds a simple green dot to live chat channel categories in the discuss app, making it instantly clear if a live chat agent has joined a channel. This prevents agents from forgetting to join channels, improving efficiency and reducing errors. This fix addresses a UX issue introduced during the 19.0 release.
Original PR description
Before this commit, seeing whether a livechat channel was joined or not in discuss app sidebar required to mouse-hover the category and seeing whether the action join or leave was present. This is a…
Before this commit, seeing whether a livechat channel was joined or not in discuss app sidebar required to mouse-hover the category and seeing whether the action join or leave was present. This is a problem because using livechat as an agent requires frequent join and leave. The mouse-hover is too subtle to know for sure whether the channel is joined or not, which is crucial for agent to not mistakenly forgetting to join the channel at the start of their shift or leaving at the end of their shift. Also the mouse-hover technique on category shows the icon in muted state, and it's not easy to get at a quick glance since the icon are quite similar. The color is only shown on exact mouse-hover on the join/leave action. In previous versions, these category actions were always displayed on the sidebar, but have their visibility reduced in 19.0 to declutter the discuss app sidebar visually. However this introduced this UX regression. This commit fixes the issue by adding a small indicator on livechat categories that the user has joined as a tiny green dot. That way the discuss sidebar stays relatively simple visually but there's a quick and very easy indicator that the livechat channel has been joined. The agent can easily deduced the channel hasn't been joined by the non-presence of this indicator. Before: <img width="300" height="754" alt="Screenshot 2025-12-05 at 15 46 42" src="https://github.com/user-attachments/assets/f8940e69-779a-431d-ac2e-1b51fe36a2d5" /> After: <img width="308" height="735" alt="Screenshot 2025-12-05 at 15 31 57" src="https://github.com/user-attachments/assets/586be26e-3ab3-4d00-ba13-7255c1b74ec4" /> <img width="353" height="741" alt="Screenshot 2025-12-05 at 15 31 32" src="https://github.com/user-attachments/assets/43a91144-07f7-474a-84d1-b8f3718a1ace" />
This update enhances the reliability of Adyen payments by preventing errors caused by duplicate processing. When payment details are sent for validation, a webhook triggers a retry. Adding an idempotency key ensures the system recognizes and handles these retries correctly, avoiding transaction conflicts and rollbacks.
Original PR description
When submitting extra payment details (ex. for 3DS validation), a call to Adyen `/payment/details` will immediately trigger a webhook to `/payment/adyen/notification`.
If that webhook is processed before we have the change to process the `/payment/details` response ourself, we will crash with a `concurrent update` (for. ex. if the payment has been authorized both transactions will try to change the transaction state to `done`), so Odoo will rollback and retry posting to `/payment/details` endpoint, which now return the following response:
```
{
"status":422,
"errorCode":"704",
"message":"request already processed or in progress",
"errorType":"validation",
"pspReference":"{redacted}"
}
```
This commit add idempotency key when submitting the payment details to ensure we get back the same response in case the transaction is retried because of a concurrent update.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update addresses slow website loading times caused by excessive parsing of product variants for JSON-LD. We've added a parameter to limit the number of variants processed, improving page speed and overall user experience, particularly for businesses with large product catalogs.
Original PR description
After this [commit](https://github.com/odoo/odoo/pull/189289/commits/1d29eccb9b320fb8c41d9610368012edbedc8d3c), all the product_variants are being parsed to be on he markup json-ld schema. Some databases could have a lot of variants and product rules, and by consecuence slowness on the pages. To make a temporal fix to this behaviour, we decided to add a param to limit the quantity of products listed on this json. OPW-5349986 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes an issue where scanning a lot multiple times during barcode picking would incorrectly create a backorder. The fix ensures that quantity updates are applied correctly to the relevant lines, preventing this error and streamlining the picking process. This improves order fulfillment accuracy.
Original PR description
**Steps to reproduce:** - create a product tracked by lot - create a lot with a quantity of 2 - create a new sale order - add two sale order lines, both for a quantity of 1 of the product - confirm -…
**Steps to reproduce:** - create a product tracked by lot - create a lot with a quantity of 2 - create a new sale order - add two sale order lines, both for a quantity of 1 of the product - confirm - open the picking in barcode - scan the stock location - scan the lot - scan the lot another time - validate **Current behavior:** a backorder is created **Expected behavior:** No back order should be created **Cause of the issue:** After scanning the lot for the first time we have the following situation: two lines : - one with a quantity of 1, qty_done of 1 and reserved_uom_qty of 1 - one with a quantity of 1, qty_done of 0 and reserved_uom_qty of 1 both lined grouped in a parent line with quantity of 1 qty_done of 1 and reserved_uom_qty of 2 All of this is correct. when scanning the lot for the second time: _findLine iterates through the lines to select the right line to use. _findLine calls _lineIsNotComplete on the first line to check if it's complete (this first line is complete). https://github.com/odoo/enterprise/blob/58d55868750b827a9d5ebd8b4ab2cc23c4445eca/stock_barcode/static/src/models/barcode_model.js#L1684 But _lineIsNotComplete will actually do the check on the parent line (which is not complete), so the return value will be true. https://github.com/odoo/enterprise/blob/58d55868750b827a9d5ebd8b4ab2cc23c4445eca/stock_barcode/static/src/models/barcode_picking_model.js#L1338 As a consequence, the quantity will be added in the first line and we will have a qty_done of 2 in the first line and a qty_done of 0 in the second line. Which will lead to the creation of a back order opw Forward-Port-Of: odoo/enterprise#101321 Forward-Port-Of: odoo/enterprise#99774