Monday, August 24, 2026
41 changes · 19.0
Enhancements to existing features
Website product pages now include the product internal reference as the SKU in structured data when it is available. This helps search engines and other services better identify products, improving product information consistency outside Odoo.
Original PR description
Include default_code as the Schema.org sku property in the product structured data when it is set. @Tecnativa TT64220 **Description of the issue/feature this PR addresses:** Product structured data does not expose the product internal reference as a SKU. **Current behavior before PR:** The sku property is absent even when default_code is set. **Desired behavior after PR is merged:** The product structured data includes default_code as the Schema.org sku property when available. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Stock quantity updates for multiple products now avoid repeating the same warehouse lookup for each item. This reduces unnecessary database work during batch operations, helping inventory updates run more efficiently without changing user workflows.
Original PR description
When `_inverse_qty_available` processes multiple products, it performs the same warehouse search for every eligible product, resulting in redundant queries during batch operations. Look up the warehouse lazily once and reuse it for all products in the recordset. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283564
Resolved issues and error corrections
Bulk emails to multiple applicants now create a missing contact only for the intended applicant. This prevents other applicants in the same email batch from being incorrectly linked to that contact or having their email details overwritten.
Original PR description
**Problem:** When sending an Email to multiple Applicants when one Applicant does not have a `partner_id` set, all Applicants set to receive the email will copy the `email_from` of the Applicant…
**Problem:** When sending an Email to multiple Applicants when one Applicant does not have a `partner_id` set, all Applicants set to receive the email will copy the `email_from` of the Applicant without a `partner_id`. **Cause:** When sending an Email to an Applicant record that does not have a `partner_id` set on it, a new Contact is created to be set to the Applicant. When this Contact is created, its `applicant_ids` value defaults to the Applicants in the context. This causes all Applicants in the current context (i.e. the recipients of the Email) to be set on the Contact, also causing that Contact to be set as the `partner_id` of all the Applicants, rather than just the one missing a `partner_id`. This then causes the `email_from` of the Contact to be set on all the Applicants. https://github.com/odoo/odoo/blob/ccd167e23ea80545e4f09e2302c1b2489e8c42d8/addons/hr_recruitment/wizard/applicant_send_mail.py#L40-L42 https://github.com/odoo/odoo/blob/ccd167e23ea80545e4f09e2302c1b2489e8c42d8/odoo/orm/models.py#L1292-L1293 **Purpose:** Modify the `create` call used to create the new Contact to define `applicant_ids` as only the Applicant that the Contact is being created for. **Steps to Reproduce in Runbot:** 1. Delete the Contact corresponding to the `partner_id` of any given Applicant. 2. Select multiple Applicants, including the one whose `partner_id` was deleted, then send an email to them using the Actions menu. opw-6383263
Code cleanup and technical improvements
This update removes redundant internal code from the GCC invoicing module because the standard system behavior already covers the needed processing. It keeps maintenance simpler without changing how users create or manage invoices.
Original PR description
Remove create() and _compute_narration() method overrides from l10n_gcc_invoice as they only existed to call _load_narration_translation(), which has already been disabled. The parent class implementations handle all required functionality. Keeps the codebase clean by removing unnecessary method overrides. Forward-Port-Of: odoo/odoo#281565 Forward-Port-Of: odoo/odoo#281395
Documentation and clarification updates
This update records an Individual Contributor License Agreement signature from trungminhdo4-glitch. It helps ensure future contributions from this person are legally covered for inclusion in Odoo.
Original PR description
This pull request submits my Odoo Individual Contributor License Agreement signature. Forward-Port-Of: odoo/odoo#282045
Miscellaneous changes
Stock transfers recorded with zero demand are now included when calculating past forecasted inventory. This prevents historical forecasts from incorrectly showing negative quantities after unplanned physical transfers.
Original PR description
**Problem:** When creating a transfer that moves out a product with zero demand quantity, it will change the forecasted quantity of that product in the past. **Cause:** The query filtered out the stock move with zero demand quantity, which preventing the system from accounting for unplanned physical transfers when retroactively calculating past inventory balances **Steps to reproduce the issue:** 1. Create a stock picking with 0 demand quantity that moves a product from an internal location to a virtual location or production location. 2. The forecasted quantity of the product becomes negative in the past. **Fix:** Add another check in the query to include stock moves with zero demand quantity. **Notes:** Since the forecast report is made from a SQL view, this will require a -u to update the report. opw-6462883 Forward-Port-Of: odoo/odoo#283577
The Point of Sale variant selection popup now shows the truly free stock quantity, excluding items already reserved by confirmed sales orders. This avoids misleading cashiers into thinking stock is available when it has already been committed elsewhere.
Original PR description
## Steps to reproduce: - Create another warehouse - Create a product with a variant, like Color, values black and white - Track the product, add a qty on hand of 50 on the black product - Go to the sales app, make a quotation of 50 for the black product - Confirm the quotation - Go to the PoS, click on the product, check the available qty in the popup - It is still 50, even though the forecasted is correct at 0 ## Why the fix: Having the actual free qty was added in this commit 682bc82 to be able to check the qty that was really free instead of the available qty. This means that we subtract the reserved_qty from the qty_available to get the free_qty. The variant popup was forgotten in this commit, so it was still displaying the qty_available. This is why there was a difference in the qty if we press the product normally or if we long press it, because the variant popup was forgotten in said commit. opw-6382845 Forward-Port-Of: odoo/odoo#280330
This fix ensures delivery charge lines keep the correct unit of measure when they are created. It prevents Odoo from recalculating related sales amounts incorrectly, helping avoid wrong delivery pricing or order totals in specific sales setups.
Original PR description
In this PR, https://github.com/odoo/odoo/pull/186250, the `product_uom` field was renamed to `product_uom_id`. However, in the `delivery` module, `product_uom_id` is dropped from the values when the…
In this PR, https://github.com/odoo/odoo/pull/186250, the `product_uom` field was renamed to `product_uom_id`. However, in the `delivery` module, `product_uom_id` is dropped from the values when the delivery line is created. This causes `product_uom_id` to be recomputed. This commit reintroduces `product_uom_id` in the values to prevent the field from being recomputed. **Description of the issue/feature this PR addresses:** For a strange reason, when a module inherits from `sale.order.line` and adds some computed fields with `precompute=True`. `price_unit`, `price_subtotal`, and `price_total` are computed incorrectly. I have attached a module to demonstrate the issue. https://github.com/user-attachments/assets/ebdd8695-c9d8-477b-b5cf-ba6d8d41e84a Without this change, the test fails, and Odoo incorrectly recomputes the fields, as shown in the video. <img width="1232" height="515" alt="image" src="https://github.com/user-attachments/assets/27370f1f-e7b7-4102-a606-0181b9d1a97a" /> When the ORM computes fields marked as `precompute=True`, in this function `_add_precomputed_values` https://github.com/odoo/odoo/blob/0d44f26d9b0fb1c1a5db463cf1f8dd0d3c72ba26/odoo/orm/models.py#L4836, `price_unit` is 0, but the records get `price_unit` from the product. Therefore, when [_compute_amount](https://github.com/odoo/odoo/blob/0d44f26d9b0fb1c1a5db463cf1f8dd0d3c72ba26/addons/sale/models/sale_order_line.py#L855) is called, the values are computed with an incorrect `price_unit`. <img width="1087" height="940" alt="image" src="https://github.com/user-attachments/assets/92feadf0-7f93-4acc-8f1a-931db0655fcc" /> **Steps to reproduce the issue:** - Install the attached module. [sale_precompute.zip](https://github.com/user-attachments/files/31265993/sale_precompute.zip) - Configure a delivery carrier as free for orders over 1, and set the fixed price to 5, for example. - Create a sales order and add a product with a value greater than 1. - Add the shipping method. The price should be 0. In the sales order line, `price_unit` is 0, but `price_subtotal` and `price_total` are equal to 5 (the product's sale price). For more context, this module is a simple example extracted from the OCA `product_secondary_unit` module, which adds a mixin with these fields: https://github.com/OCA/product-attribute/blob/18.0/product_secondary_unit/models/product_secondary_unit_mixin.py. In the `sale_order_secondary_unit` module, `sale.order.line` inherits from this mixin. You can see the error in this PR: https://github.com/OCA/sale-workflow/pull/4535. https://github.com/OCA/sale-workflow/actions/runs/32259842816/job/96090194021?pr=4535#step:8:509 I understand that this requires a deeper investigation into precompute to solve the underlying issue, but I propose setting `product_uom_id` in the `_prepare_delivery_line_vals` method as a temporary solution while the final solution is being investigated. I understand that this field should not have been removed from `_prepare_delivery_line_vals`; the referenced PR only renamed the field and did not intend to remove the value from this method. @Tecnativa @pedrobaeza @kcv-odoo @Feyensv coudl you please review this? --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an issue where certain employee searches could fail or return incorrect results for users without access to private employee data. It helps keep HR search behavior consistent while preserving existing access restrictions.
Original PR description
The hack to search fields as a user that has no access to private employee data and searching on the `current_version_id` instead of the provided field since we force to wrap searchable fields domains in a Query in odoo/odoo#280373. The hack did not support usage of the 'any!' operator on `current_version_id` leading to a query like: "hr_employee.id in (select id from hr_version ...)". task-6468820 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Vendor bills created from employee expenses in Mexico now correctly display their CFDI XML attachment when one exists. This helps users access required tax documents directly from the bill instead of having attachments hidden in the system.
Original PR description
**Current behavior:** Currently, account moves created from expenses (type receipt) don't include the XML when it is a CFDI. Causing users cannot see their attachment even though it is created on DB. https://docs.google.com/videos/d/1eFSAA-wvUzPDwIJDeiS2dkne94lGM7QBxRfjN3HxaLw/play **Versions:** 19+ **Fix:** Implementing a new helper to identify those moves that can actually hold a CFDI document (for now, all `is_invoice()` documents + vendor bill receipt, `in_receipt`), so now, we include 'in_receipts' in _compute_l10n_mx_edi_cfdi_state_and_attachment, _compute_l10n_mx_edi_document_ids, _compute_l10n_mx_edi_update_sat_needed and l10n_mx_edi_cfdi_try_sat. As these documents might need to fetch SAT services as well. Task-id: [6397080](https://www.odoo.com/odoo/project/49/tasks/6397080)
The French VAT report submission now treats an express mention containing only spaces as empty. This prevents invalid tax return files being sent to ASPOne and reduces filing errors caused by incomplete required information.
Original PR description
While sending the tax return to ASPOne, before adding the BC zone we are checking that BA zone won't be empty as if BC is completed there must be the BA zone in the xml file. The problem is that when we have only whitespaces, the condition will be respected but later on due to cleanup_xml_node(), the BA zone will not be rendered in the xml but BC will and it leads to an error This commit checks that express_mention_reason fields is not empty or not only whitespaces task-6476440
This update fixes an issue in ISO 20022 payment processing caused by a removed legacy function. It ensures payment communication references are cleaned using the supported method in Odoo 19, helping avoid errors when preparing bank payment files.
Original PR description
Commit 964c451bb86a210922bdf87cc793b82cd48a5298 was forward-ported without removing a call to the `_sepa_sanitize_communication`, which was deprecated and got removed in Odoo 19. This commit replaces that call with the proper function call. opw-6494497 opw-6498770 opw-6498768
The HTML editor now places the drag-and-drop move handle on the correct side when working in right-to-left languages. This improves editing usability for users creating Arabic, Hebrew, or other RTL content by making block movement controls appear where expected.
Original PR description
Problem: In MoveNodePlugin, `setMovableElement` sets the position of the drag-and-drop handler without considering `this.config.direction === "rtl"`. The handler is placed on the left side regardless of text direction. Solution: - In RTL mode, calculate the handle position from the right edge of the element so it is placed on the right side with the same distance as in LTR. - Update hover hooks, editable bounds, and dropzone rectangles for RTL mode. Steps to reproduce: 1. Open the editor in RTL mode. 2. Hover over a movable block element (e.g. `<p>`). => The move handle appears on the left side of the element instead of the right. task-6442717 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283662 Forward-Port-Of: odoo/odoo#281249
This update removes an obsolete setting from a Philippines localization screen that could cause validation issues in newer Odoo versions. The screen keeps the same behavior, but the underlying view definition is now cleaner and compatible with current standards.
Original PR description
The `modifiers` attribute was used in older Odoo versions to define field properties (invisible, readonly, required, etc.) Since the field already declares these same properties directly…
The `modifiers` attribute was used in older Odoo versions to define field properties (invisible, readonly, required, etc.) Since the field already declares these same properties directly [state](https://github.com/odoo/odoo/blob/14.0/addons/account/models/account_move.py#L150-L155) , [amount_tax_signed](https://github.com/odoo/odoo/blob/14.0/addons/account/models/account_move.py#L229)
(e.g. `invisible=...`, `readonly=...`), the `modifiers` attribute is redundant and serves no purpose.
This attribute was never added manually by us — it was auto-generated by Odoo Studio when the default view was created. Studio's default views inject `modifiers` alongside the direct attributes. [Here](https://github.com/odoo/odoo/pull/104741/changes/975e875046691c898e8c1acb87d3626cd299e5aa#diff-dfebe5a93e1b8880e88268b024be4c6f106d144b20298d7bb6c4ae09a18bafd0L67-L145)
Also the `modifiers` attribute was fully simplified [removed](https://github.com/odoo/odoo/pull/104741/changes/975e875046691c898e8c1acb87d3626cd299e5aa#diff-849f1ed2a35a8b0b9cdd67f8e34de5d2ea7bf928103a83828587ba7ec14a62e4L52) starting from version 17.0, where views rely exclusively on direct attribute expressions (`invisible`, `readonly`, `required`) instead of the `modifiers` JSON encoding [main Patch](https://github.com/odoo/odoo/pull/104741) Keeping it around in the arch is therefore dead code with no effect.
However it needs to give the error on 17.0+ like this
```
ERROR LOG:
<string>:1:0:ERROR:RELAXNGV:RELAXNG_ERR_NOELEM: Expecting an element data, got nothing
<string>:1:0:ERROR:RELAXNGV:RELAXNG_ERR_INVALIDATTR: Invalid attribute modifiers for element field
<string>:1:0:ERROR:RELAXNGV:RELAXNG_ERR_EXTRACONTENT: Element tree has extra content: field
```
As the modifer has been remove from the field [common.rng](https://github.com/odoo/odoo/pull/104741/changes/975e875046691c898e8c1acb87d3626cd299e5aa#diff-849f1ed2a35a8b0b9cdd67f8e34de5d2ea7bf928103a83828587ba7ec14a62e4L52) RelaxNG schema but modifiers set on fields here root tag is **form**, and the modifiers sit on fields inside a nested list. And Form views aren't RNG-validated from 17.0 till now —
[@validate('calendar', 'graph', 'pivot', 'search', 'list', 'activity')](https://github.com/odoo/odoo/blob/f0e58b9324af18d0cf0264aec2886d098e997f03/odoo/tools/view_validation.py#L314) has no form, and there's no [form_view.rng](https://github.com/odoo/odoo/tree/19.0/odoo/addons/base/rng).
Current senario
<img width="998" height="415" alt="image" src="https://github.com/user-attachments/assets/1a678c8f-8401-4e12-826f-9e98f6f2fe20" />
After removing the modifer: it show the same view because of field property
<img width="998" height="415" alt="image" src="https://github.com/user-attachments/assets/1a678c8f-8401-4e12-826f-9e98f6f2fe20" />
After removing the modifer still it shows the **modifiers="{'readonly':true, 'required':true}"** because the modifer is stay in the 14.0 but the 17.0 onwards it was not please see the scrrenshot its field preprty always.
<img width="1003" height="462" alt="image" src="https://github.com/user-attachments/assets/5e833924-b17c-417f-9e63-5a01c185f588" />
This Fix removes the unused `modifiers` attribute from the view arch, keeping only the direct attribute already present, with no functional change to the view's behavior.
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
Forward-Port-Of: odoo/odoo#282623
Forward-Port-Of: odoo/odoo#279976This fixes an issue where companies that cannot receive Peppol invoices through Documents, such as French companies using electronic invoicing, could lose their required incoming invoice journal setting. Incoming Peppol documents will now continue to be handled as vendor bills when Documents reception is not allowed, preventing missing settings and misplaced invoices.
Original PR description
Peppol documents can be received in a journal or in the Documents app (peppol_reception_mode). Some companies cannot use Documents: _peppol_allows_document_reception() returns False and the journal…
Peppol documents can be received in a journal or in the Documents app (peppol_reception_mode). Some companies cannot use Documents: _peppol_allows_document_reception() returns False and the journal stays required. This is the case of French companies (via l10n_fr_pdp). The onchange of the settings and the import did not check this method. So on a French company with the mode set to 'documents': - the Settings cleared the journal on each opening, while it was still required - the incoming documents were saved in Documents instead of vendor bills Steps to reproduce: - Create a Belgian company, with a purchase journal, and register it on Peppol as receiver - Set the reception mode to "Receive in Documents" - Change the fiscal position to France, and install l10n_fr_pdp, the Peppol part is replaced by "French Electronic Invoicing", so the radio button is not visible anymore, but the company still has peppol_reception_mode == 'documents'. - Open the Settings again: the field "Incoming Invoices Journal" is empty. opw-6429691 Forward-Port-Of: odoo/enterprise#126462
Odoo now correctly reads Colombian vendor bill XML files that contain withholding taxes. This ensures ReteRenta, ReteIVA, and ReteICA amounts are added to invoice lines, reducing manual corrections and improving tax accuracy.
Original PR description
Currently, Odoo doesn't detect Withholdings taxes for Colombia while uploading vendor bill XML, causing ReteRenta, ReteIVA, ReteICA withholdings to not being added in invoice lines, for versions under 19.2 Fix: Backport commit https://github.com/odoo/enterprise/commit/edc67858350d1b8408019e51751240026d931dab Versions: 18.0 -> 19.1 Task-id: [6417175](https://www.odoo.com/odoo/project/49/tasks/6417175) Forward-Port-Of: odoo/enterprise#128158 Forward-Port-Of: odoo/enterprise#126186
This fixes an issue where some incoming Chilean electronic invoices could fail to import when they included foreign currency details on lines but did not include a foreign-currency total in the header. The import now falls back to the standard total, helping automated mail-based invoice processing continue reliably.
Original PR description
When importing an incoming DTE through the fetchmail server, the total amount is read from the MntTotOtrMnda as soon as a Moneda node is present in the document. Steps to reproduce: - Set up a CL company with a DTE mail server - Fetch a DTE that includes the line-level Moneda node but does not include the header OtraMoneda block, so no MntTotOtrMnda - Run the fetchmail cron and check the logs Issue: The DTE fails to import Analysis: Occurs since https://github.com/odoo-dev/enterprise/commit/5805a92f91411846fdffa245cb047397cfc9b1f3 Moneda is defined at line level while MntTotOtrMnda in the optional header block Encabezado/OtraMoneda. Instead of assuming MntTotOtrMnda is always present whenever the document carries a foreign currency, fall back to the base-currency total MntTotal when it is missing. opw-6432612 Forward-Port-Of: odoo/enterprise#128631 Forward-Port-Of: odoo/enterprise#126869
Sales users without accounting permissions can now view invoices created from sales orders that use cash rounding. This prevents an unnecessary access error while keeping invoice access aligned with the user's existing permissions.
Original PR description
**Behavior:** When a sales user without accounting access rights tries to view an invoice created from a sale order where a cash rounding is applied, an AccessError is raised. This occurs because…
**Behavior:** When a sales user without accounting access rights tries to view an invoice created from a sale order where a cash rounding is applied, an AccessError is raised. This occurs because loading the invoice view triggers `_compute_tax_totals()`, which then passes the invoice's `invoice_cash_rounding_id` to `_get_tax_totals_summary()`. Which then ends up failing when trying to access fields on the `cash_rounding` record due to missing accounting rights, even though the user is allowed to view the parent invoice. This is fixed by ensuring reading fields on `cash_rounding` during tax total computation bypasses the access check using `sudo()`, as the user already has legitimate access to the invoice itself. **Steps to reproduce:** - As an admin, enable cash rounding then create one. - Create an invoice and set the Cash Rounding Method - In debug mode, go to 'Set Default Values' in the debug dropdown and set Cash Rounding Method = your rounding for all users - Go to users, and ensures that Demo has no accounting rights but has sales user rights - As Demo, create a sale order, confirm it, then create the related invoice. - When trying to acces said invoice, you should get an Access Error opw-6379781
When tasks are duplicated, created from templates, or generated as recurring tasks, their sub-task dependency chains are now preserved correctly. This prevents copied project work from having tasks linked in the wrong order, reducing manual cleanup and scheduling confusion.
Original PR description
**Problem:** Duplicating a task, creating a task from a task template, or generating the next occurrence of a recurring task scrambles the dependencies between its sub-tasks: each copied sub-task…
**Problem:** Duplicating a task, creating a task from a task template, or generating the next occurrence of a recurring task scrambles the dependencies between its sub-tasks: each copied sub-task carries the dependencies of a different sub-task instead of its own. **Steps to reproduce:** 1. Enable Task Dependencies on a project. 2. Create a task with three sub-tasks and chain them: the second depends on the first, the third depends on the second. 3. Duplicate the task, or use "Create from template" if the task is a template. 4. Open the sub-tasks of the new task and look at their dependencies. **Current behavior:** The dependencies of the copied sub-tasks are shifted: the chain runs in the reverse order of the original one. **Expected behavior:** Each copied sub-task depends on the copy of the sub-task its original depended on, so the new task reproduces the original chain. **Cause of the issue:** `_create_task_mapping` builds the original to copy mapping by pairing `original_task.child_ids` with `copied_task.child_ids` positionally, on the assumption stated in its docstring that both recordsets share the same index order. They do not. `project.task._order` ends with `id desc`, so `child_ids` is read newest-first, while the copies are created by iterating the original `child_ids` in that same order. The copies' ids therefore ascend along the original list, and reading them back through `child_ids` returns them in the exact reverse order. `zip` then pairs each original with the copy of the sub-task at the mirrored position, and `_resolve_copied_dependencies` writes every `depend_on_ids` and `dependent_ids` onto the wrong copy. This affects every caller of that method: `copy`, the task template action, and the creation of the next occurrences of a recurring task. **Fix:** Sorting the copied children by id restores the correspondence because id order is the order in which the copies were created from the original list, an invariant that holds whatever `_order` does, whereas the previous code silently depended on `_order` producing the same sequence on both sides. `test_duplicate_project_with_subtask_dependencies` and `test_recurrence_copy_task_dependency` were reading the copies by `child_ids` index too, which the mirrored mapping happened to satisfy, so they passed on a wrong result; they now index them in creation order as well. opw-6386578
This fixes a notification issue where mentions could be sent to an archived user account linked to the same contact, causing the intended person to miss the message. The system now selects an active user for each recipient, making inbox notifications more reliable.
Original PR description
Before this commit, mentioning a partner that has an archived user sent the inbox notification to that archived user, so the mentioned person never saw the mention. This happens because the query picking the user of a recipient joins res_users without filtering on active, and keeps one row per partner with DISTINCT ON and no ORDER BY, so which row survives is arbitrary. One solution could have been to keep every active user of the partner, which is what we want as each of them has its own notification type, but a notification is stored per partner, so the type of a single user applies to all of them. Picking one user is a current limitation. This commit fixes the issue by taking the first active user of each partner in a lateral join, ordered as mail.followers._get_recipient_data already does: internal users first, then the lowest id. Forward-Port-Of: odoo/odoo#283914 Forward-Port-Of: odoo/odoo#283806
The Colombian DIAN workflow now handles missing or malformed document attachments when preparing commercial event history. This prevents users from hitting a crash when acknowledging receipt of vendor bills and keeps the process moving even if a prior DIAN response was not stored as a valid ZIP file.
Original PR description
When building the commercial event history for DIAN documents, the system crashes if an intermediate document's attachment is missing or is not a valid ZIP file. Steps to reproduce: - Create a vendor bill and send it to DIAN to generate a commercial event document. - Manually alter or corrupt the attachment of the first response document (e.g., save plain XML instead of a ZIP). - Click "Acusar Recibo" (Acknowledge Reception) on the bill. Issue: The system crashes when attempting to unzip a malformed, plaintext, or missing attachment while iterating through past documents to build the event history. Analysis: The system aggregates the XML of previous events to maintain the history trail. Doing so, the system assumes that all past attachments are ZIP archives. However, interacting with the DIAN API can occasionally result in plaintext XML, that raises `zipfile.BadZipFile` when unzipping. opw-5467690
Partial barcode receipts no longer incorrectly remove pending operation-level quality checks when users return to the transfer. This helps ensure required receipt quality controls remain visible and enforceable until the full transfer is properly processed or cancelled.
Original PR description
Steps to reproduce --- 1. Create a quality control point on the Receipts operation type with Control per set to Operation. 2. Confirm a receipt of 2 units of the product: one pending operation…
Steps to reproduce --- 1. Create a quality control point on the Receipts operation type with Control per set to Operation. 2. Confirm a receipt of 2 units of the product: one pending operation quality check is created. 3. In the Barcode app, receive 1 unit and go back to the transfer with the back button. 4. The pending operation quality check is gone. Issue --- Going back from the Barcode app calls `post_barcode_process`, which on a partial reception splits the picked move into a done move and a remaining move, then merges the transient duplicate back with `_merge_moves`. https://github.com/odoo/enterprise/blob/b89614661682ecbd131d940539aac8afdd9d7289/stock_barcode/models/stock_move.py#L57-L60 `_merge_moves` cancels that transient duplicate through `_action_cancel` before unlinking it. https://github.com/odoo/odoo/blob/8f3100ca597559945cc42d9ef9517edbb40a900b/addons/stock/models/stock_move.py#L1400-L1401 The `quality_control` override of `_action_cancel`, picks the pending checks to drop from `is_product_canceled`, a `defaultdict(lambda: True)` keyed by `(picking, product_id)`. An operation check has no `product_id`, so its key is never computed by the loop and reads back the `True` default, so it is deleted even though the transfer still has a live move. Since an operation check covers the whole transfer, it must be dropped only when every move of its picking is cancelled. https://github.com/odoo/enterprise/blob/b89614661682ecbd131d940539aac8afdd9d7289/quality_control/models/stock_move.py#L68-L76 opw-6439179 Forward-Port-Of: odoo/enterprise#128654 Forward-Port-Of: odoo/enterprise#127427
The link tracking page no longer shows SEO optimization, page properties, or link tracker menu options that are not useful for website visitors. This keeps website editing menus cleaner and avoids business users spending time on settings that do not apply to tracking pages.
Original PR description
Since [this commit][1] you're able to optimize the link tracker page using "optimize seo." This makes no sense as it contains no useful content for visitors to the website. Access to the action is now disabled when the current page is the link tracking page. The page properties and link tracker menu items have also been removed for similar reasons. [1]: https://github.com/odoo/odoo/commit/ac55f2bb113ecf7c774fe6e96d28e716184a97d1 Task-6288891 Forward-Port-Of: odoo/odoo#283710 Forward-Port-Of: odoo/odoo#278132
This fix allows users who are assigned as editors on a shared document folder to update access settings as expected. It removes an incorrect restriction that prevented legitimate editor members from adjusting internal user access, helping teams manage folder permissions more reliably.
Original PR description
1. Create a non-company root folder 2. Edit rights as follows: * add Marc Demo as editor member * access for internal users and link to None 3. As Marc Demo, try updating Internal users access to "editor" ⮕ You can't. Task-6410610
This fix ensures that when users translate text from a record opened in a related-record dialog, Odoo first saves the edits made in that dialog. As a result, the translation window shows the current text instead of outdated or missing content, while preserving existing behavior in editable lists.
Original PR description
Clicking the translate button saves the form's root record before opening the translation dialog, since https://github.com/odoo/odoo/commit/9da52919a03dbcee5209430918195158c0652099. A record opened…
Clicking the translate button saves the form's root record before opening the translation dialog, since https://github.com/odoo/odoo/commit/9da52919a03dbcee5209430918195158c0652099. A record opened in an x2many form dialog keeps its changes for itself until the dialog is saved, see https://github.com/odoo/odoo/blob/242f6d3cf7288853f163ac6986a3b7aa4279efaf/addons/web/static/src/model/relational_model/static_list.js#L193. Its pending changes are not part of the root record changes, so saving the root sends nothing to the server, and the translation dialog then shows the stored terms instead of the current content, or no terms at all when the stored value is empty. The fix changes openTranslationDialog in translation_button.js, the place that decides which record to save. When the record keeps its changes for itself (record._noUpdateParent), the record is saved directly, like the button did before the commit above. The root record is still saved in the other cases, so the editable list case that commit fixed keeps working. Steps to reproduce: 1. Activate a second language in Settings > Translations > Languages 2. Open the Surveys app, open a survey and click a question in the Questions tab 3. In the Description tab, change the description 4. Click the EN button on the description field => the translation dialog shows the terms of the previous description, not the current one Ticket [link](https://www.odoo.com/odoo/project.task/6237291) opw-6237291 Forward-Port-Of: odoo/odoo#269507
This fixes an issue where pressing Shift+Enter in Safari created a full paragraph break instead of a simple line break in the HTML editor. Users editing Knowledge articles on Mac Safari can now format text as intended without unwanted spacing or splits.
Original PR description
**Steps to reproduce:** - Use a Mac with Safari - Install Knowledge app - Go to any article - Press Shift+Enter to try to enter a soft line break - Hard split is done instead **Issue:** Shift+Enter causes a `insertParagraph` event instead of `insertLineBreak` in Safari, which triggers the `SplitPlugin` instead of the `LineBreakPlugin`. **Fix:** Check if the browser is Safari and call `insertLineBreak` from the `SplitPlugin` (when needed) by listening to the "keydown" events. (note: I was not able to find any other key combination to properly trigger the `insertLineBreak` event in Safari) opw-6413507 Forward-Port-Of: odoo/odoo#281458
Odoo now correctly handles Peppol invoices where the same company is both sender and receiver. These messages are no longer mistaken for duplicates, so the matching vendor bill can still be created.
Original PR description
Edge case: self-addressed messages (sender == receiver). i.e. a company genuinely invoicing itself. The outgoing invoice already carries the message UUID, so the duplicate check would wrongly discard the incoming document. Exclude those messages from the check so the vendor bill can still be created. task-no --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283663 Forward-Port-Of: odoo/odoo#283574
This fixes several mislabeled entries in the Mexican chart of accounts so their names match the official SAT catalogue. The correction helps electronic accounting exports show the proper descriptions, reducing confusion and compliance review issues without changing accounting balances or calculations.
Original PR description
Seven entries of the Mexican chart of accounts template carry a name belonging to a **different** group, copied from a neighbouring entry. Each record's XML ID still states the intended name, which…
Seven entries of the Mexican chart of accounts template carry a name belonging
to a **different** group, copied from a neighbouring entry. Each record's XML ID
still states the intended name, which is what this restores.
| Code | Field | Before | After |
|---|---|---|---|
| `6` | `name@es` | Gastos generales | Gastos |
| `252.07` | `name@es` | `account_subgroup_hipotecas_por_pagar_a_largo_plazo_nacional` | Hipotecas por pagar a largo plazo nacional |
| `602` | `name`, `name@es` | Cost of sales / Costo de venta | Selling expenses / Gastos de venta |
| `613` | `name@es` | Amortización contable | Depreciación contable |
| `614` | `name` | Accounting depreciation | Accounting amortisation |
| `701.06` | `name`, `name@es` | Interest on foreign bank charges / Intereses a cargo bancario extranjero | Interest payable by national natural persons / Intereses a cargo de personas físicas nacional |
| `702` | `name@es` | Utilidad cambiaria | Productos financieros |
### Why it is not cosmetic
The electronic accounting Chart of Accounts XML takes the `Desc` attribute of
every `<Ctas>` element from the *account group name* — `cfdicoa.xml`
(`t-att-Desc="account.get('name')"`), fed by `trial_balance.py`
`_l10n_mx_get_coa_values()`. Any `es_*` database therefore declares:
```xml
<catalogocuentas:Ctas CodAgrup="702" NumCta="702" Desc="Utilidad cambiaria" Nivel="1" Natur="A"/>
```
whereas the SAT catalogue (Anexo 24) publishes `702` as *Productos financieros*,
with `702.01 Utilidad cambiaria` … `702.10 Otros productos financieros` beneath
it. `CodAgrup` comes from `code_prefix_start` and stays correct, so the file
still validates against the XSD, but the declared description does not match the
official nomenclature. Trial Balance and Pólizas are unaffected — neither
exports group names.
### Evidence
- `252.07` contains its own XML ID as the Spanish name.
- `602` duplicates `501.01`, yet its children are `Sueldos y Salarios`,
`Compensaciones`, `Tiempos extras`.
- `613` and `614` are swapped in one language each: `613`'s children are
depreciations, `614`'s are amortisations.
- `701.06` duplicates `701.05` in both languages; the correct name is symmetric
to `701.07` and to `702.06`.
- `6` is the only single-digit root group whose Spanish name does not match its
XML ID (`account_group_gastos`).
### Notes
Introduced in d782b8b92557; correct in 15.0, where the names lived in
`account.account.tag.csv`. Still present in 18.0, 19.0 and master, hence
targeting 17.0. Template data only — existing databases are unaffected until the
chart is (re)installed, and renaming a group moves no balance.
Forward-Port-Of: odoo/odoo#277426Website editors can now click and edit previously locked sections within mega menu templates, such as footer areas and logo containers. This makes menu customization smoother and reduces the need for technical workarounds.
Original PR description
### Issue: Some elements in mega menu templates are not editable inline in the website builder. ### Steps to reproduce: - Go to Website > Site > Menu Editor and add a mega menu item. - Edit the mega menu and set its template (e.g. 'Thumbnails' or 'Logos'). - Try to inline edit certain sections (e.g. footer or logos container). ### Reason: `BuilderContentEditablePlugin` does not apply `contenteditable="true"` to these elements because they do not match any of the selectors defined in `content_editable_selectors`. ### Fix: Add missing element classes to `content_editable_selectors` so that these elements become editable inline. task-[6116253](https://www.odoo.com/odoo/project/974/tasks/6116253) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#263021
Sales users limited to their own documents can now cancel orders that include loyalty programs without hitting an access error. The fix ensures temporary loyalty point records are cleaned up correctly during cancellation, reducing workflow interruptions for sales teams.
Original PR description
Steps to produce: --- - Install `sale_management` and `sale_loyalty` module without demo. - From sales > products > discounts & loyalty, create new loyalty card program and save. - Now create new…
Steps to produce: --- - Install `sale_management` and `sale_loyalty` module without demo. - From sales > products > discounts & loyalty, create new loyalty card program and save. - Now create new product of 100$. - Create a user which have sales rights as `user: own documents only`. - With that user, create new sale order with product and confirm. - Try to cancel the order. Issue: --- - It shows the access error: ```py You are not allowed to delete 'Sale Order Coupon Points - Keeps track of how a sale order impacts a coupon' (sale.order.coupon.points) records. This operation is allowed for the following groups: - Sales/Administrator Contact your administrator to request access if necessary. ``` Root cause: --- - Users with the `Sales: Own Documents Only` access right only have read permissions ([1]). When they cancel a Sales Order, the `_action_cancel` method attempts to clean up the temporary pending points allocated to the order by calling `self.coupon_point_ids.unlink()`. Because this call is executed without elevated privileges, the system blocks the deletion and raises an Access Error Solution: --- - Added `.sudo()` to the `unlink()` call for `coupon_point_ids` in the `_action_cancel` method. This ensures the pending point records are cleaned up with the necessary elevated privileges. [1]https://github.com/odoo/odoo/blob/23af2b443735c6d3a2f64e44f9ea5da45638b052/addons/sale_loyalty/security/ir.model.access.csv#L16 opw-6453016 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283535 Forward-Port-Of: odoo/odoo#281477
This fix prevents invoice recalculations from creating incorrect inventory valuation differences when average-cost products are affected by landed costs. Businesses get more reliable cost of goods sold and stock variation figures after resetting and confirming invoices.
Original PR description
**Issue** Recalculating an invoice after applying a landed cost could lead to a wrong stock variation. **Steps to reproduce** - Create 2 products: - Product A: valuated using AVCO tracked by quantity…
**Issue** Recalculating an invoice after applying a landed cost could lead to a wrong stock variation. **Steps to reproduce** - Create 2 products: - Product A: valuated using AVCO tracked by quantity - Product B: service with landed cost enabled - Create and confirm a PO for 10 units @ 500 of product A and validate the receipt - Create and confirm a SO for 3 units of the product A and validate the delivery - Create and validate the invoice - Create a Bill for the PO and add 1 unit @ 100 of product B, using the expense account - Create the landed cost and confirm it and the Bill - Reset the invoice to draft and confirm it again -> In inventory valuation, Stock Variation is 30 instead of 0 **Cause** Each time an invoice is validated, it recompute the cogs values: https://github.com/odoo/odoo/blob/791e5423a73acbef69a5ffe26b3f6036269395f2/addons/stock_account/models/account_move.py#L29-L37 https://github.com/odoo/odoo/blob/791e5423a73acbef69a5ffe26b3f6036269395f2/addons/stock_account/models/account_move.py#L122 which needs the cogs unit price: https://github.com/odoo/odoo/blob/791e5423a73acbef69a5ffe26b3f6036269395f2/addons/stock_account/models/account_move_line.py#L68 https://github.com/odoo/odoo/blob/791e5423a73acbef69a5ffe26b3f6036269395f2/addons/stock_account/models/stock_move.py#L275-L280 This returns the standard price (and not the move value) since the product is average-costed but not lot-valuated. The `move.value` originating from the SO is 500*3 = 1500, since it has been computed before adding the landed cost and stay constant afterwards. However, the `move.value` originating from the PO becomes 5000 + 100 = 5100. Indeed, when confirming the landed cost, it recomputes the value of the move: https://github.com/odoo/odoo/blob/791e5423a73acbef69a5ffe26b3f6036269395f2/addons/stock_landed_costs/models/stock_landed_cost.py#L152 https://github.com/odoo/odoo/blob/791e5423a73acbef69a5ffe26b3f6036269395f2/addons/stock_account/models/stock_move.py#L323 https://github.com/odoo/odoo/blob/791e5423a73acbef69a5ffe26b3f6036269395f2/addons/stock_account/models/stock_move.py#L441 https://github.com/odoo/odoo/blob/791e5423a73acbef69a5ffe26b3f6036269395f2/addons/stock_landed_costs/models/stock_move.py#L24 Which updates the standard price to 510: https://github.com/odoo/odoo/blob/791e5423a73acbef69a5ffe26b3f6036269395f2/addons/stock_account/models/stock_move.py#L356-L359 So there is a discrepancy between the `stock.value` (1500) and the cogs values (510*3=1530), which explains why the Stock variation is 30. opw-6416072
This fix restores the official SAT names for seven Mexican chart of accounts groups that had incorrect labels copied from neighboring entries. It improves the accuracy of electronic Chart of Accounts XML reports so their descriptions match the official Mexican tax authority catalogue, while Trial Balance and Policies reports remain unaffected.
Original PR description
Seven entries of the Mexican chart of accounts template carry a name belonging to a **different** group, copied from a neighbouring entry. Each record's XML ID still states the intended name, which…
Seven entries of the Mexican chart of accounts template carry a name belonging
to a **different** group, copied from a neighbouring entry. Each record's XML ID
still states the intended name, which is what this restores.
| Code | Field | Before | After |
|---|---|---|---|
| `6` | `name@es` | Gastos generales | Gastos |
| `252.07` | `name@es` | `account_subgroup_hipotecas_por_pagar_a_largo_plazo_nacional` | Hipotecas por pagar a largo plazo nacional |
| `602` | `name`, `name@es` | Cost of sales / Costo de venta | Selling expenses / Gastos de venta |
| `613` | `name@es` | Amortización contable | Depreciación contable |
| `614` | `name` | Accounting depreciation | Accounting amortisation |
| `701.06` | `name`, `name@es` | Interest on foreign bank charges / Intereses a cargo bancario extranjero | Interest payable by national natural persons / Intereses a cargo de personas físicas nacional |
| `702` | `name@es` | Utilidad cambiaria | Productos financieros |
### Why it is not cosmetic
The electronic accounting Chart of Accounts XML takes the `Desc` attribute of
every `<Ctas>` element from the *account group name* — `cfdicoa.xml`
(`t-att-Desc="account.get('name')"`), fed by `trial_balance.py`
`_l10n_mx_get_coa_values()`. Any `es_*` database therefore declares:
```xml
<catalogocuentas:Ctas CodAgrup="702" NumCta="702" Desc="Utilidad cambiaria" Nivel="1" Natur="A"/>
```
whereas the SAT catalogue (Anexo 24) publishes `702` as *Productos financieros*,
with `702.01 Utilidad cambiaria` … `702.10 Otros productos financieros` beneath
it. `CodAgrup` comes from `code_prefix_start` and stays correct, so the file
still validates against the XSD, but the declared description does not match the
official nomenclature. Trial Balance and Pólizas are unaffected — neither
exports group names.
### Evidence
- `252.07` contains its own XML ID as the Spanish name.
- `602` duplicates `501.01`, yet its children are `Sueldos y Salarios`,
`Compensaciones`, `Tiempos extras`.
- `613` and `614` are swapped in one language each: `613`'s children are
depreciations, `614`'s are amortisations.
- `701.06` duplicates `701.05` in both languages; the correct name is symmetric
to `701.07` and to `702.06`.
- `6` is the only single-digit root group whose Spanish name does not match its
XML ID (`account_group_gastos`).
### Notes
Introduced in d782b8b92557; correct in 15.0, where the names lived in
`account.account.tag.csv`. Still present in 18.0, 19.0 and master, hence
targeting 17.0. Template data only — existing databases are unaffected until the
chart is (re)installed, and renaming a group moves no balance.Updating a contact linked to more than one WhatsApp signature request no longer causes an error. The system now handles email and WhatsApp signature notifications separately, making contact updates more reliable.
Original PR description
Steps to reproduce: ---------------------------------------- 1. Install `whatsapp_sign` and Contact modules 2. Go to Sign > templates 3. Make two sign requests for the same partner 4. Go to partner…
Steps to reproduce:
----------------------------------------
1. Install `whatsapp_sign` and Contact modules
2. Go to Sign > templates
3. Make two sign requests for the same partner
4. Go to partner record and try to change the email (remove or add a character)
Observation:
----------------------------------------
Traceback occurs:
```
File '/home/odoo/odoo/enterprise/whatsapp_sign/models/sign_request_item.py', line 101, in _send_signature_access_message
is_whatsapp = self.sign_request_id.send_channel == 'whatsapp'
File '/home/odoo/odoo/community/odoo/orm/fields.py', line 1657, in __get__
record.ensure_one()
File '/home/odoo/odoo/community/odoo/orm/models.py', line 5942, in ensure_one
raise ValueError('Expected singleton: %s' % self)
ValueError: Expected singleton: sign.request(3, 4)
```
Issue:
----------------------------------------
In `_send_signature_access_message()` which accessed `self.sign_request_id.send_channel` directly on the full multi-record recordset. When `res_partner.write()` detects an email change, it searches for all sent sign request items of that partner and calls `send_signature_accesses()` on the combined recordset. Accessing `sign_request_id` on this multi-record set resolved to multiple sign requests, and the subsequent field access triggered `ensure_one()`.
Solution:
----------------------------------------
* Refactored `_send_signature_access_message()` to iterate over each item individually, checking `send_channel` per item's own `sign_request_id`. Items are partitioned into `email_items` and `whatsapp_items` batches. Email items are delegated to `super()` and WhatsApp items are processed individually.
* Refactored to cleaner and more readable code and correctly handles mixed-channel recordsets where items may belong to different sign requests with different send channels.
opw-6387586This fixes a problem where Android users could not download files from the Odoo mobile app, such as images opened from Discuss. Downloads are now sent through the mobile app's supported download path, preventing the error message and allowing users to save files normally.
Original PR description
Steps to reproduce: - send an image in a Discuss channel - click the image to open the file viewer - click the download button => Android shows "The Odoo Mobile Apps only supports file downloads…
Steps to reproduce: - send an image in a Discuss channel - click the image to open the file viewer - click the download button => Android shows "The Odoo Mobile Apps only supports file downloads using the HTTP protocol." downloadFile()'s GET-by-URL case fetches the URL via XHR, then saves the Blob response by clicking a hidden <a download> anchor on a blob: URL. Android's DownloadManager only accepts http(s) URLs, so it rejects that blob: URL instead of downloading anything. Patch downloadFile._download to hand the URL directly to a new mobile.methods.saveFile bridge method when available, the same way download._download already delegates to mobile.methods.downloadFile. Blob/string content downloads aren't handled here — the only such call site (spreadsheet JSON export) is debug-mode only, so this is left as a console.warn for now. Related to odoo/odoo@e83fd8c08c879f5e262d39f24edcb3f81238ea82 Code made by Claude Changes supervised by HUVW Forward-Port-Of: odoo/enterprise#128471 Forward-Port-Of: odoo/enterprise#127693
The LinkedIn integration now handles cases where LinkedIn returns no account statistics. This prevents refreshes from failing and helps users keep social account data updates running smoothly.
Original PR description
Bug === When the LinkedIn API returns no statistics for the account, the refresh crashes. Task-6425391 Forward-Port-Of: odoo/enterprise#126326
This fix restores delegation support in Studio approval workflows, helping teams keep approval processes moving when responsibilities are assigned to someone else. It reduces the risk of blocked business operations caused by approvals not reaching the delegated person.
Original PR description
opw-6321766 Forward-Port-Of: odoo/enterprise#122441
The AI Livechat snippet in the website editor now includes its missing preview image. This helps users recognize and select the snippet more easily when building website pages.
Original PR description
Steps to reproduce: - Install Website on an Enterprise database. - Open the website editor. - Open the snippets dialog. - See the AI Livechat snippet install preview. => The preview image is missing. Before this commit, the AI Livechat install preview referenced a missing preview image. After this commit, the preview image is available and the preview is rendered correctly. The file name does not follow the usual snippet preview image naming convention because this is a stable fix. The XML keeps its existing path so current users get the fixed preview without a view update. task-6303725
Users can now open web links placed inside spreadsheet cell comments with a regular click, as expected. This removes a frustrating interaction issue and makes shared references in comments easier to access.
Original PR description
Current behavior before PR: - Clicking a link in a cell comment did not work. A left click was blocked, while Ctrl+click (or Cmd+click) opened the link in a new tab. - This was caused by `t-on-click.prevent` on the comment thread and popover. It was originally added because the scroller service used the URL hash to scroll to anchors, which was removed in https://github.com/odoo/odoo/commit/711e9c9f24818714129f55283e2df64503d93605 Desired behavior after PR is merged: - `t-on-click.prevent` is removed and links in cell comments can be opened normally with both left click and Ctrl+click (Cmd+click on macOS). Task: [6448651](https://www.odoo.com/odoo/project/2328/tasks/6448651) Forward-Port-Of: odoo/enterprise#128448 Forward-Port-Of: odoo/enterprise#127473
This fix lets users enter and compare budget amounts on the Moroccan profit and loss report, even though it uses multiple columns. Budget figures now stay visible and are compared against the correct balance total, improving reporting accuracy for Moroccan accounting users.
Original PR description
Before this commit, it was impossible to use budget on the Moroccan P&L, for the following reasons: - The feature was designed for one-column reports. MA's P&L uses 3, one of which is the total of…
Before this commit, it was impossible to use budget on the Moroccan P&L, for the following reasons:
- The feature was designed for one-column reports. MA's P&L uses 3, one of which is the total of the two others.
=> We remove that requirement, and make sure to always select the 'balance' column as the reference for the budget comparison.
- When trying to input a budget amount in the report, the amount disappeared entirely.
=> This was because the total column of report was not using 'balance' as its expression label. We fix that by rewriting the expression labels of that report.
The fact we hardcode the use of 'balance' is arguable. It is however not possible here to rely on some custom handler to change a specific option key that would be used to generate the budget comparison data, since some of those data need to be generated in the get_options, before _custom_options_initializer even gets called. This is the simplest approach, and this case is rare enough for us to deem it acceptable.
opw-6385229
Forward-Port-Of: odoo/enterprise#128816
Forward-Port-Of: odoo/enterprise#128266The repository now records that GitHub user kshitij-nariya has signed the Odoo Individual Contributor License Agreement. This clears a legal contribution requirement so their future submissions can be accepted and merged.
Original PR description
Description of the issue/feature this PR addresses: Signed the Odoo Individual Contributor License Agreement to contribute to the Odoo repository. Current behaviour before PR: The CLA signature is missing for GitHub user `kshitij-nariya`, which will prevent future contributions from being accepted and merged. Desired behaviour after PR is merged: The CLA signature for `kshitij-nariya` is recorded in the repository, allowing future pull requests and contributions to be successfully merged. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282808
Manually merged Weblate translations to fix a merge conflict.
Original PR description
Manually merged Weblate translations to fix a merge conflict.