Tuesday, November 18, 2025
24 changes · 18.0
New functionality added to Odoo
This update adds a new Spanish tax rule to distinguish income and withholdings related to temporary incapacity from regular payroll amounts. It helps businesses generate AEAT Form 190 more accurately and reduces the risk of reporting errors in annual tax filings.
Original PR description
### Description of the feature this PR addresses: **Specific tax on withholdings for incapacity to work created to correctly reflect the amounts derived in Form 190 of the AEAT.** A new tax called…
### Description of the feature this PR addresses: **Specific tax on withholdings for incapacity to work created to correctly reflect the amounts derived in Form 190 of the AEAT.** A new tax called "**100% WHI monies**" has been created with the aim of correctly reflecting the income derived from incapacity for work in the AEAT's Model 190. ### Current behavior before PR: Currently, Odoo does not allow automatic differentiation between monetary payments derived from work incapacity and those not derived from it. This creates a problem when generating Model 190, as the Spanish Tax Agency (AEAT) requires both types of payments to be reported separately (according to the codes and subcodes established in the model). **In practice, this separation is necessary because:** - Income derived from incapacity for work (e.g., sick leave) is considered employment income with differentiated tax treatment. - Withholdings made on these amounts must be declared in specific sections of Form 190. - If they are not separated correctly, the totals on the form may be incorrect or incomplete, affecting the accuracy of the tax information submitted. ### Desired behavior after PR is merged: A new tax has been added to represent “100% Withholding income tax (workers)”, allowing Odoo to: - Correctly identify and calculate the related amounts. - Report them separately in the AEAT Model 190. - A new tax group has also been created to distinguish these withholdings from regular ones. ### Benefits: - It allows you to correctly generate Form 190, separating income derived from and not derived from work disability. - It facilitates the accounting and tax traceability of this type of income. - It ensures consistency with the information structure required by the Spanish Tax Agency (AEAT), avoiding errors in the annual filing. - It improves the flexibility of the Odoo tax system, adapting it to actual tax needs. ### Technical summary: - A **new specific tax** has been created for withholdings associated with incapacity for work benefits. - This tax **allows the amounts corresponding to these benefits to be identified, accounted for, and reported independently.** - In addition, a **new tax group "Whitholdings IRPF Workers" has been added that groups these withholdings together**, allowing them to be clearly distinguished from other withholdings on earned income. The related issue: https://github.com/OCA/l10n-spain/issues/4416 ### Follow-up suggestion: adjust Odoo’s base tax “15% WHI monies” **Proposal:** Change the base tax “15% WHI monies” to 100% and move it to the new “Whitholdings IRPF Workers” tax group. **Why:** The current 15% rate is not aligned with how AEAT Model 190 requires amounts to be computed: the base should reflect 100% of the earnings derived from temporary incapacity, with the withholding rate applied on top of that base. Keeping 15% leads to misclassification and wrong totals in the "_percepciones_" and "_retenciones_" sections. These are variable withholdings, not fixed taxes — each worker’s rate can change monthly depending on their income and number of days worked. Therefore, having a fixed 15% rate is conceptually incorrect and causes misclassified amounts and inaccurate totals, forcing users to adjust values manually after payroll. Ideally, this tax should not have any fixed percentage defined. Since Odoo currently requires a rate, setting the base to 100% is a pragmatic workaround that ensures more accurate and flexible withholding calculations. **Outcome:** - Correct calculation and reporting of **_percepciones derivadas de incapacidad laboral_**. - Clean separation from other withholdings via the new tax group. - Consistency between accounting, payroll, and the 190 export. Would you accept this change? @moduon @rafaelbn @EmilioPascual @chklop @jco-odoo MT-11667 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update adds support for carrying key website checkout details into Taiwan electronic invoices for Ecpay. It helps ensure the invoice is created with the right customer and order information after an online purchase.
Original PR description
This module adds extra functions on the website sale for l10n_tw_edi_ecpay, passing values from e-commerce to invoice for creating Taiwan E-invoice task-5122489 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change adds a new EC Sales List report for Finland, along with its export file. It helps businesses prepare and submit the required cross-border sales information in a format suited to Finnish reporting needs.
Original PR description
The aim of this commit is adding the Finnish EC Sales List report. task-5126664
Enhancements to existing features
This change updates the Accounting area together with related project documentation and language files. It appears to improve the module setup and user-facing content so the product is easier to maintain and use in different languages.
Original PR description
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
Resolved issues and error corrections
This change corrects how leave days are calculated for accrual-based allocations when the start date is updated. As a result, employees now receive the full number of accrued days expected from their plan instead of an undercount.
Original PR description
Version: * 17.0 Steps to Reproduce: 1. Create an accrual plan with: * Accrued gain time: At the start of the accrual period * Carry-over time: Other * Carry-over date: 1 January * Add a milestone where the employee accrues 2 days monthly, with a milestone reached = 0 days. 2. Create a new allocation: * Set allocation Type to accrual allocation * Select the accrual plan created above * Set date_from to the 1st of the previous month Issue: * The expected accrued days are 4, but the system only calculates 2. Fix: * When changing the `date_from` value, set `already_accrued` to False. * This ensures `_process_accrual_plans` runs `_add_days_to_allocation` properly and recalculates the correct accrued days. After: * Accrued days now calculate correctly based on the accrual plan. task-5236714 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#235229
The mail plugin can now identify the Odoo version it is connecting to. This lets the add-in show a clear message when it is used with an unsupported Odoo version, reducing confusion for users.
Original PR description
Purpose ======= The new addin has been refactored and doesn't work with older Odoo version, and so we add an endpoint to be able to show a message if we don't support that Odoo version. Task-4727609
The Point of Sale sales report now includes a clearer breakdown of payments by payment method. This makes it easier for businesses to review how customers paid and compare payment types in the report.
Original PR description
In this commit: ----------- - Enhances the PoS sales report by adding detailed breakdowns of payments grouped by payment method. task-5184319
Odoo Point of Sale and Self-Ordering now support Chrome’s Local Network Access feature, which allows the browser to reach local devices over HTTP without triggering mixed-content errors. In practice, this makes it easier to connect to Epson printers and the black box, removing the need for certificates in these setups.
Original PR description
*: pos_self_order, pos_epson_printer Feature: https://chromestatus.com/feature/5152728072060928 Since Chrome 142, a new feature called “Local Network Access” has been added, allowing local IPs to be contacted via HTTP without mixed content errors. This means that certificates are no longer required to contact Epson printers or the black box.
This update adds support for triangular taxes in the Finnish tax report so they can be used in the EC Sales List report. It also changes the company registry label from "Company ID" to "Business ID" for Finnish partners and companies, making the wording clearer and more locally appropriate.
Original PR description
The aim of this commit is adding the triangular taxes into the tax report to use it in EC Sales List report. task-5126664 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Users can now export records even when the list view is grouped by a property field. This fixes a crash that occurred during export and makes the export action work reliably in these grouped views.
Original PR description
Step to reproduce
- open a task
- add a property field , say test
- add values for this field in few records
- go to list view and group by test
- select a record from result and export it (from Action btn)
Observation:
- traceback
```
File "/home/odoo/17.0/addons/web/controllers/export.py", line 486, in base
groupby_type = [Model._fields[x.split(':')[0]].type for x in groupby]
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
KeyError: 'task_properties.b60ee9baefee14a8'
```
Cause:
- The issue is caused by splitting, which didn't considered property field
- it tried to look for `task_properties.b60ee9baefee14a8` in _fields which causes KeyError
FIx:
- split the field name properly to bring out actual field name while considering granularity as well as the property fields
opw-5159155
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#235209This pull request fixes several issues that could cause inconsistent behavior or failed operations in everyday Odoo use, including calendar reminders, CRM lead conversion, accounting searches, and external browser requests during testing. It also improves configuration handling and translations, helping make the system more reliable and easier to maintain.
Original PR description
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
The employee org chart button now opens the Hierarchy view on mobile devices instead of defaulting to the Kanban view. This makes the org chart accessible and easier to use on smaller screens.
Original PR description
Steps to Reproduce: - Open an employee record. - Set managers for the employee. - Open the employee’s form view on mobile. - Click org chart stat button. Before: - On mobile, the org chart button opened the Kanban view by default. After: - On mobile, the org chart button now opens the Hierarchy view by default. task-5245129 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#235228
The activity list now keeps pagination usable even when some activities are filtered out by access rules. This prevents users from getting stuck on a page that appears complete while additional accessible activities still exist on later pages.
Original PR description
**Steps to reproduce:** - Create some activities which should not be accessible to a specific user (according to the `_search` filtering of `mail.activity`) - Go to Activity Menu > View all…
**Steps to reproduce:** - Create some activities which should not be accessible to a specific user (according to the `_search` filtering of `mail.activity`) - Go to Activity Menu > View all activities as the given user - Ensure that the limit (default: 80) is lower than the total number of activities which should be returned and that the new activities are in the returned elements - On `web_search_read` some records are removed by the `_search` override - The pagination navigation buttons are disabled as the returned number of records is lower than the limit - This means that some activities are not accessible to the user (everything above the given limit) **Issue:** The issue comes from the `_search` override which checks the records available to the user. As it's done after fetching with the limit, the resulting number of records can be lower than expected and this breaks the `_format_web_search_read_results` which considers that we have all the possible records and doesn't try to fetch the total count of records. **Fix:** The main issue can't be directly fixed without modifying the way the access are checked in the `_search` override. This could be mitigated by changing the search limit, making the search as superuser, or adding specific filtering but each has its own limitations. Adding `force_search_count` should allow the user to navigate between pages anyway and see all the available activities. But the number displayed in the pagination will often be incorrect for the current and total count. (e.g. we can have 75 records but 1-80/150 is displayed out of 140 actually readable records) opw-5046389 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix ensures replenishment filters show the right records when users search for items with a to-order value of zero. It removes a mismatch that could incorrectly include products that actually need to be ordered, making inventory filtering more reliable.
Original PR description
**Issue** In replenishment, filtering with `to_order = 0` does not correctly exclude records where `to_order != 0`. **Steps to reproduce** 1. Go to Inventory > Operations > Procurement >…
**Issue** In replenishment, filtering with `to_order = 0` does not correctly exclude records where `to_order != 0`. **Steps to reproduce** 1. Go to Inventory > Operations > Procurement > Replenishment 2. Create a replenishment with a forecast quantity smaller than the min and max quantity (without editing the To Order) 3. Apply a custom filter `to_order = 0` → Records with non-zero `to_order` are incorrectly included **Cause** `qty_to_order` was split into `qty_to_order_computed` and `qty_to_order_manual` in [this commit](https://github.com/odoo/odoo/commit/156bed3f430d706e13822bbd95d91c8dfd3ea42d#diff-0eb18a8d7773b5f99b402392188594178c3ba2004e4bcab26dbc84b1c8d7256a). In the [`_search_qty_to_order` method](https://github.com/odoo/odoo/blob/322c6d0468bf79e9d29e1375c49aa13d4a7b7a67/addons/stock/models/stock_orderpoint.py#L338), all records with `qty_to_order_manual = 0` are included. Since `qty_to_order_manual` defaults to 0 when untouched by the user, this causes incorrect results. Additionally, [`to_order`](https://github.com/odoo/odoo/blob/322c6d0468bf79e9d29e1375c49aa13d4a7b7a67/addons/stock/models/stock_orderpoint.py#L323) displays `qty_to_order_computed` if `qty_to_order_manual = 0`, creating inconsistency. **Solution** Fix the inconsistency by ignoring `qty_to_order_manual` when searching for zero `to_order` values. opw-5150643
This fix ensures users see the full list of unbalanced accounting entries when a balance check fails. It improves the error message so teams can identify and correct all affected records more quickly.
Original PR description
The commit 3467b5971423f70581c6be2caf7f8a8d86ee70f1 intended to improve the error message in `_check_balanced()` by tailoring it based on the number of affected entries. However, in the case of multiple affected entries, the error was raised after the first iteration, preventing the full list of unbalanced entries from being collected and displayed to the user. no-task --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When a cashier tries to request an invoice and the order does not meet the required conditions, the system will now display the error instead of hiding it. This helps users understand why the action failed and correct the order information before trying again.
Original PR description
Initially, all errors emerging from the `action_pos_order_invoice` call were ignored through a `silentCall`.…
Initially, all errors emerging from the `action_pos_order_invoice` call were ignored through a `silentCall`.
https://github.com/odoo/odoo/blob/eac2a1132fd7a9a6ba51b87195c5f0b5a706b191/addons/point_of_sale/static/src/app/models/data_service.js#L638-L645
This prevents the user from being shown an error when they attempt to perform a forbidden action. An example of an error silenced by this issue is shown in https://github.com/odoo/enterprise/pull/98802, which was also the initial reason for this fix.
Replacing the `silentCall` by a `call` allows us to work with the RPCErrors raised from the `action_pos_order_invoice` call and show the users why their operations might be invalid. Other errors are only displayed as a warning, just like they would have been using a `silentCall`.
Steps to reproduce an error which required this fix:
- Install the POS app and the "_Mexican localization for the Point of Sale_" module (`l10n_mx_edi_pos`)
- Set the company to a Mexican one (e.g. _ESCUELA KEMPER URGATE_)
- Open the POS app
- **Sell a product**
- Open a register
- Select a product and click "Add"
- Click "Payment"
- Set the Customer to a new customer with only a name
- Click "Cash" to set the Remaining to 0
- Click "Validate"
- **Request an invoice**
- Once the payment is done, get to the Orders tab (in the POS)
- Set filter to "Paid"
- Select the transaction at the top of the list
- Click "Invoice"
- Set "Invoice to public" to "Yes"
- Click "Ok"
- An error should be displayed, because the selected customer does not have a country or zip code set. This error is prevented by the `silentCall` mentionned above.
opw-5171035This update ensures Flutterwave payment references are always unique by adding a timestamp to each one. It prevents payment requests from reusing the same identifier, which helps avoid provider-side errors when tests or database resets create repeated reference sequences.
Original PR description
The `/payments` endpoint of the Flutterwave v3.0.0 API expects unique `tx_ref` parameters (matching Odoo's payment transaction `reference` field) to be passed. This is guaranteed by a UNIQUE() SQL constraint in Odoo, but testing sometimes involves dropping the database, leading to transaction references being repeated at the provider level for a given merchant account. This commit singularizes all transaction references by suffixing them with the current timestamp, ensuring that the `tx_ref` API parameter remains unique across transaction reference sequences. Forward-Port-Of: odoo/odoo#235799
The Belgian Partner VAT Listing now correctly leaves out exempt transactions, instead of showing some 0% taxes when a partner’s total base exceeds the reporting threshold. This makes the report align with the tax rules for exempt operations and reduces the risk of misleading VAT declarations.
Original PR description
Currently, the behavior is wrong and 0% taxes appear in the report (if the cumulative base for a partner is > 250) A distinction needs to be done here. The operations are taxable (even at a zero rate) or exempt. We shall rely on the Tax Category Code (E = Exempt) When a tax belongs to E, it cannot appear in the Partner VAT Listing. It is exempt from taxation. It does not open the right to deduction of vat on purchases. task-5269970
This fix restores the correct sizing for calendar views when they are added to My Dashboard. As a result, the calendar is visible and usable again instead of appearing collapsed or blank.
Original PR description
Problem: When a calendar view is added to the My Dashboard menu, it is rendered with style height: 100%. This results in a height of 0px, making the calendar unviewable. Purpose: Reintroduce code that sizes the calendar renderer based on page size. Steps to Reproduce on Runbot: 1. Navigate to any Calendar view, then select Actions>Dashboard>Add 2. Refresh the page, then navigate to Dashboards>My Dashboard opw-5227497
This update fixes several layout issues in the Documents app on mobile devices. It removes unnecessary spacing, makes folders and documents use the available screen width more effectively, and restores scrolling so users can view all recent documents.
Original PR description
This commit fix several issue in kanban mobile view: - When a folder has folders AND documents, there is a huge gap between the two because of the kanban ghost records. - In the 'Recent' folder, folders and documents doesn't take all width. - In the 'Recent' folder, we can't scroll to see all the documents. Task-4963198
Reprinting a previously sold receipt in the Italian point of sale now prints the selected order instead of always printing the most recent one. This fixes a frustrating issue for staff and ensures customers receive the correct ticket when past orders need to be reissued.
Original PR description
before this commit, when trying to reprint a past order it would not work. Instead it would print the last order no matter what order is selected. Steps to reproduce: 1. setup an DB with an italian…
before this commit, when trying to reprint a past order it would not work. Instead it would print the last order no matter what order is selected. Steps to reproduce: 1. setup an DB with an italian POS 2. make 2 sales with a different product (easier tracking) 3. open the "orders" view 4. try to reprint the ticket of the firt order result: the receipt of the second order is printed the reason for this is that we were using the printer's built in command "printDuplicateReceipt" which is inteded for printing the very last receipt. With this commit, we changed the behavior and invoke another printer command. That command is meant to reprint any receipt, based on the provided reference. After this commit, trying to print any past receipt will print that exact receipt. IMPORTANT NOTE: In theory, the printer command can reprint any number of receipts. We decide that we will only use it to reprint the one receipt selected by the user. This moves the complexity of parsing date strings and ranges to the command component and therefore will keep the rest of the code cleaner. opw-5008702 opw-4882480
This fix restores drop-off point selection for Sendcloud delivery methods that use locker-based last-mile options. Customers will now see the map to choose a drop-off location when the delivery service supports lockers or a locker/service point combination, preventing these shipping methods from being incorrectly hidden.
Original PR description
Steps to reproduce ----- - Create a Sendcloud delivery method - Select a delivery service with "Locker or service point" as "Last mile" (eg "bpost @ bpack") > "Use Sendcloud locations" is set to…
Steps to reproduce ----- - Create a Sendcloud delivery method - Select a delivery service with "Locker or service point" as "Last mile" (eg "bpost @ bpack") > "Use Sendcloud locations" is set to false Cause ----- There is a problem with the values retrieved from the Sendcloud API call, more specifically the `available_functionalities` > `last_mile` value. The Sendcloud API (of both previous and current beta version) specifies the possible values to only be the following - `home_delivery` - `mailbox` - `pobox` - `service_point` - null https://api.sendcloud.dev/docs/sendcloud-public-api/shipping-options/operations/create-a-shipping-option https://api.sendcloud.dev/docs/sendcloud-public-api/branches/v2/shipping-products/operations/list-shipping-products However, it seems like they have added some new undocumented values `locker` and `locker_or_service_point`. To detect whether to use drop-off locations, we do https://github.com/odoo/enterprise/blob/5b64c63301bc814c7c9d99146af6a86d37563762/website_delivery_sendcloud/models/delivery_sendcloud.py#L51-L53 Where we compare the retrieved value with the string 'Service point' https://github.com/odoo/enterprise/blob/5b64c63301bc814c7c9d99146af6a86d37563762/website_delivery_sendcloud/models/delivery_sendcloud.py#L13 In our "Locker or service point" case, this does not work because the `in` operator makes a case sensitive comparison. Solution ----- Functionally, both lockers and service points work the same. The user should be prompted a map on which they choose where the delivery should be dropped off. So we can add `Locker` and `Locker or service point` as accepted values and enable the use of sendcloud locations for both. ----- Ticket: opw-5217796
This change prevents automatic quality checks from being created for component lines during manufacturing. It ensures quality controls are only triggered where they are intended, avoiding unnecessary checks on consumed materials and reducing confusion for users.
Original PR description
### State of the art: Control point for the manufacturing operation type are not expected to create QC when they refer to components. ### Steps to reproduce: - Create a BOM for a final product FP: -…
### State of the art:
Control point for the manufacturing operation type are not expected to create QC when they refer to components.
### Steps to reproduce:
- Create a BOM for a final product FP:
- 1 X COMP (consumable)
- Create a Quality Control Point:
- Control: Quanity
- Operations: Manufacturing
- Product: COMP
- Create and confirm an MO for 1 unit of FP
#### > A QC is created for the component
### Cause of the issue:
Quantity quality checks related to MOs are expected to be created by `_create_quality_checks_for_mo`, which ensures that only moves referring to the production are considered:
https://github.com/odoo/enterprise/blob/931779b845291e1dc7efdea91d91bdfa5ab703d6/quality_mrp/models/stock_move.py#L23-L29
However, each time a `stock.move.line` is created, it triggers the related "quantity" control points if it is not filtered out of the applicable lines:
https://github.com/odoo/enterprise/blob/931779b845291e1dc7efdea91d91bdfa5ab703d6/quality_control/models/stock_move_line.py#L28-L35
The issue is that move lines related to `move_raw_ids` are always considered applicable:
https://github.com/odoo/enterprise/blob/931779b845291e1dc7efdea91d91bdfa5ab703d6/quality_mrp/models/stock_move_line.py#L31-L34
and that the `_create_check` triggers "quantity" control points that directly refer to the `product_id` of the move line:
https://github.com/odoo/enterprise/blob/931779b845291e1dc7efdea91d91bdfa5ab703d6/quality_control/models/stock_move_line.py#L79-L88
Note, however, that `_create_check` ignores control points of move lines related to a raw move if they do not refer to any product_ids, due to `_get_quality_points_all_products` (which is only called to find control points without a set `product_ids`):
https://github.com/odoo/enterprise/blob/931779b845291e1dc7efdea91d91bdfa5ab703d6/quality_mrp/models/stock_move_line.py#L20-L24
This explains why the test `test_04_quality_check_on_quantity` did not trigger the creation of quality checks for components.
### opw-5137594This update prevents an error that could happen if a user adds a product from the sales catalog and immediately removes it. The sales order now handles this case safely, so the product price is still shown correctly and the order stays usable.
Original PR description
Currently, an error occurs when the user immediately removes a catalog product after adding it. Steps to Reproduce ([Video](https://drive.google.com/file/d/12hOavt1zCa6hbG0EWHsIDGxfgVkxJmLW/view)): -…
Currently, an error occurs when the user immediately removes a catalog product after adding it. Steps to Reproduce ([Video](https://drive.google.com/file/d/12hOavt1zCa6hbG0EWHsIDGxfgVkxJmLW/view)): - Install the `sale_management` module. - Go to `Sales Orders` and create a new `sale order`. - In the order line, click on the `Catalog` button. - `Add` a product and then immediately `remove` it. `ValueError: Expected singleton: sale.order.line()` After [this commit], when the user clicks the Remove button immediately after clicking the Add button (within 500 ms). In this case, the system proceeds with the last request due to the useDebounced delay [1], which removes the product. However, since there is no order line yet for that product [2] and the quantity is 0, the order line [3] is not created. When it attempts to retrieve the discounted price, it raises the error [4]. This commit ensures that if no order line exists, the product's price is returned according to the sale order's pricelist. [this commit]: https://github.com/odoo/odoo/pull/233098/commits/697c559791fdf00b5602b9459bbdf21f392757d8 [1]- https://github.com/odoo/odoo/blob/ec212f38e50520edf612522717952855c8c09a80/addons/product/static/src/product_catalog/kanban_record.js#L17-L19 [2]- https://github.com/odoo/odoo/blob/ec212f38e50520edf612522717952855c8c09a80/addons/sale/models/sale_order.py#L2202 [3]- https://github.com/odoo/odoo/blob/ec212f38e50520edf612522717952855c8c09a80/addons/sale/models/sale_order.py#L2218-L2219 [4]- https://github.com/odoo/odoo/blob/ec212f38e50520edf612522717952855c8c09a80/addons/sale/models/sale_order_line.py#L1602-L1603 sentry-7019831319 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr