Tuesday, June 17, 2025
26 changes · 18.0
New functionality added to Odoo
Adds business planning documents covering platform features, pricing, onboarding, support, and go-to-market strategy for a proposed multi-tenant e-commerce offering. This helps align product, sales, and implementation teams before development begins.
Original PR description
This commit includes documentation outlining: - Core platform features. - 'Sweetener' features to attract small businesses. - Pricing and packaging models. - A high-level technical implementation approach, favoring Odoo. - User onboarding and support strategies. - Marketing and sales strategies. These documents provide a strategic foundation for the platform's development. 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
Enhancements to existing features
The Indian financial reports Balance Sheet now opens with the horizontal split option turned off by default. This makes the default report view simpler and avoids users needing to manually untick the option when they prefer the standard layout.
Original PR description
before this PR: split horizontally is ticked by default on Balance Sheet. after this PR: split horizontally is unticked by default. Task Id: 4836667
Resolved issues and error corrections
This fixes cases where Odoo could send duplicate or inconsistently formatted Date headers in web responses, which created unnecessary warnings in server logs. It also standardizes date-related headers for generated editor images, helping caching behave more predictably without changing user-facing features.
Original PR description
Forward-port of https://github.com/odoo/odoo/pull/206505
Miscellaneous changes
The tax breakdown is required by Argentinian law to be displayed in the bottom left corner of the invoice report. This was added in [^1] and works well for the HTML view but min-width related classes don't work well with pdf rendering, so the table stretched across the entire width of the pdf. The fix is to follow the rest of the file and use a fixed col width on the table for the pdf view. task-4779975 [^1]: https://github.com/odoo/odoo/pull/201257 Forward-Port-Of: odoo/odoo#214463
Original PR description
The tax breakdown is required by Argentinian law to be displayed in the bottom left corner of the invoice report. This was added in [^1] and works well for the HTML view but min-width related classes don't work well with pdf rendering, so the table stretched across the entire width of the pdf. The fix is to follow the rest of the file and use a fixed col width on the table for the pdf view. task-4779975 [^1]: https://github.com/odoo/odoo/pull/201257 Forward-Port-Of: odoo/odoo#214463
This fix makes the Accounting area check that a menu item exists before including it in results. It prevents unnecessary errors when a menu is unavailable, helping users continue working without interruption.
Original PR description
Check that the menu actually exists before adding it to the results. Also don't raise error if not found. 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 makes an automated test for image transformation more stable, reducing random failures in Odoo's validation process. It helps developers get more reliable test results without changing how users interact with the HTML editor.
Original PR description
Purpose of this PR: - The image transformation test was failing non-deterministically on runbot due to bare `expect(...).toHaveCount` calls. This commit replaces them with the `expectElementCount` utility. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes downloads for files whose extensions include an underscore, such as Parasolid .x_t files. Odoo will now preserve the original filename instead of adding an extra .txt extension, reducing confusion for users sharing or retrieving documents.
Original PR description
Step to reproduce; - install documents - upload a parasolid file, it has extension `x_t` - download it Observation: if a file is uploaded with file named as `file.x_t`, it will be downloaded as `file.x_t.txt` Issue: currently, the `get_extension` method only allow alphanumeric values for extension, which do not consider extension having '_' https://github.com/odoo/odoo/blob/15fd3f62769b137cb9a0625f47b333424b851a27/odoo/tools/mimetypes.py#L212-L218 when such file is downloaded, `_get_stream_from` appends extra extension to the filename, depending upon its mimetype. https://github.com/odoo/odoo/blob/15fd3f62769b137cb9a0625f47b333424b851a27/odoo/addons/base/models/ir_binary.py#L148-L150 Fix: instead of `isalnum()`, use a regex that allows alphanumeric and underscore in extension. opw-4801263 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Returned products that were not part of the original sale are now placed after existing sales order lines instead of appearing in the middle of the order. This keeps sales orders easier to read and avoids confusion when reviewing returns involving replacement or different products.
Original PR description
Issue ----- When returning different products than the ones sold on the SO, the returned products have their sequence set to 10 so they all appear between the first and second sold products. Steps to reproduce ----- - Install both Sale & Stock apps - Create & confirm a sale for 2 different products - Confirm the delivery - Create & validate a return for a third product - Open the SO -> The returned product sol is second in sequence Cause ----- The return SOL are created with no specified sequence value, so they all have the default (10). See [review](https://github.com/odoo/odoo/pull/209091#pullrequestreview-2828126823) for details. ----- Ticket: opw-4564504
The slide sharing dialog now explains that email shares may be sent later because messages are queued and processed in batches. This avoids confusing users into thinking the share failed and helps prevent duplicate email sends.
Original PR description
This PR updates the share dialog message shown when a slide is shared via email. Since emails are queued and sent later in batches, the previous message could be misleading and prompt users to send multiple emails unnecessarily. Task-4797324
Changing a sales quotation template from one with a recurring plan to one without now correctly clears the recurring plan field. This prevents outdated subscription plan information from remaining on sale orders and helps users avoid incorrect subscription setup.
Original PR description
**Issue:** - In sale order, first select the quotation template with a recurring plan, then, change the quotation template to without a recurring plan. After changing the quotation template, the…
**Issue:** - In sale order, first select the quotation template with a recurring plan, then, change the quotation template to without a recurring plan. After changing the quotation template, the 'Recurring Plan' (`plan_id`) field still shows the value from the previously selected template. This happens because the `plan_id` is not reset when the new template has no recurring plan. - In version 17, this case was handled in the else part and set [default value](https://github.com/odoo/enterprise/blob/17.0/sale_subscription/models/sale_order.py#L490) (company_id.subscription_default_plan_id), but in version 18.0, the field was [removed](https://github.com/odoo/enterprise/pull/55355/files). **Steps to reproduce:** - Install the Sales and Subscriptions modules. - Create two quotation templates — one with a recurring plan and one without. - Create a Sale Order and first select the quotation template 'with a recurring plan'. - Then, change the quotation template to 'without a recurring plan'. **Solution:** - Reset `plan_id` to `None` before computing the new value to ensure accurate computation. If the selected quotation template has a recurring plan, it will be assigned; otherwise, the plan_id field will remain empty. **Runbot v18.0 (without fix)**   OPW: [4845478](https://www.odoo.com/odoo/70/tasks/4845478)
Hong Kong payroll tax report exports no longer fail when a married employee has no spouse name recorded. This allows businesses to generate required IRD reports from confirmed payslips without needing unnecessary placeholder spouse details.
Original PR description
Steps: - Create an employee with marital status is married - Keep the spouse name empty - Try to export ird reports with a confirmed payslip Current behavior: - Error raised Expected behavior: - Should be able to export the report even spouse name is empty
This fix prevents users from clearing or editing currency settings in Studio when doing so would cause an error. It keeps monetary fields stable while users customize list views, reducing failed saves and support issues.
Original PR description
Currently an error occurs when the user tries to remove the currency on any monetary field through web studio.
Steps to replicate:
- Open any list view with web_studio.
- Drag and drop a monetary field and remove the currency field and save.
Error:
`TypeError: Argument must be bytes or unicode, got 'NoneType'`
This error occurs because the `attrs` dictionary contains `{'name': None}`, and `etree.Element()` doesn't accept attributes with None values, causing it to raise a `TypeError`.
This commit fixes the issue by making the field required so that user cant remove the value from currency field and hence preventing error at line [1].
[1]-https://github.com/odoo/enterprise/blob/a41cca06bc1e25614390f9207c937566557350a0/web_studio/controllers/main.py#L928
sentry-4244801243Importing bank statement lines from CSV now preserves an included statement reference instead of always creating a new bank statement. This prevents duplicate statements and keeps imported reconciliation data tied to the correct existing statement.
Original PR description
…id during import In the override of execute_import of account_bank_statement_import_csv.py a new account.bank.statement was always created even if the import contained statement_id. Steps to reproduce: - Export an account.bank.statement.line in bank rec with the statement_id included. - Import it back. The statement_id of the imported lines is a new one. opw-4753864
When calculating line discounts, extra decimal places are being used when computing the total in intermediate steps. This discrepancy is interpreted as a small discount, that shouldn't be there. We should instead use the current currency's precision. Example: ``` qty: 1.65 unit_price: 29.9 total: 1.65 * 29.9 = 49.335, rounded to 49.34 discount = 0.005 * 100 / 49.335 = 0.010 ``` Steps: - Create an invoice with a product - Set quantity to 1.65, price to 29.9 - Confirm & get the invo
Original PR description
When calculating line discounts, extra decimal places are being used when computing the total in intermediate steps. This discrepancy is interpreted as a small discount, that shouldn't be there. We should instead use the current currency's precision. Example: ``` qty: 1.65 unit_price: 29.9 total: 1.65 * 29.9 = 49.335, rounded to 49.34 discount = 0.005 * 100 / 49.335 = 0.010 ``` Steps: - Create an invoice with a product - Set quantity to 1.65, price to 29.9 - Confirm & get the invoice PDF - Upload the PDF in accounting app - Check the "discount" value Slight improvement to odoo/odoo#206107 opw-4776391 Forward-Port-Of: odoo/odoo#211032
<b>Steps to Reproduce:</b> 1. Navigate to Sales → Products → Products. 2. Click on Print Labels. 3. Select label format 2×7. 4. Add an image to the "Extra Content" field (e.g., by typing `/image`). <b>Issue:</b> - When printing labels, the image added via `extra_html` is not fully displayed. It gets cut off due to the fixed height and overflow settings on the `.o_label_extra_data` container. <b>Solution:</b> - Added responsive styling to o_label_extra_data for img so they resize pr
Original PR description
<b>Steps to Reproduce:</b>
1. Navigate to Sales → Products → Products.
2. Click on Print Labels.
3. Select label format 2×7.
4. Add an image to the "Extra Content" field (e.g., by typing `/image`).
<b>Issue:</b>
- When printing labels, the image added via `extra_html` is not fully displayed. It gets cut off due to the fixed height and overflow settings on the
`.o_label_extra_data` container.
<b>Solution:</b>
- Added responsive styling to o_label_extra_data for img so they resize properly and stay within bounds:
```css
.img {
max-height: 2.5em;
max-width: 100%;
}
```
ensures image appear without being cropped.
<b>opw-4741550</b>
Before FIX:

After FIX:

Forward-Port-Of: odoo/odoo#212903Write some bytes in a `field.Binary(attachment=False)` field. The ORM doesn't encode the bytes in b64, and the value is stored as a binary blob in postgres. Attempt to download the content via /web/content (actually any route that uses `http.Stream` is affected). It sometimes download something, sometimes fail with an "Incorrect padding" error. The `http.Stream` class wrongly assumes that reading a binary/image field is always going to return the value base64-encoded, thus it always attemp
Original PR description
Write some bytes in a `field.Binary(attachment=False)` field. The ORM doesn't encode the bytes in b64, and the value is stored as a binary blob in postgres. Attempt to download the content via…
Write some bytes in a `field.Binary(attachment=False)` field. The ORM doesn't encode the bytes in b64, and the value is stored as a binary blob in postgres. Attempt to download the content via /web/content (actually any route that uses `http.Stream` is affected). It sometimes download something, sometimes fail with an "Incorrect padding" error. The `http.Stream` class wrongly assumes that reading a binary/image field is always going to return the value base64-encoded, thus it always attemps to decode it. The `b64decode` function silently discard non-b64 characters and only complain if the final thing lacks the b64 `=` padding (to make the length a multiple of 4). So when it downloaded something, it downloaded crap. Makes the code actually raise an error should the binary field not contains b64 data. Fixing the problem by using the data as-is (with no b64 decoding) is not desirable. We use `Binary(attachment=False)` when we need to store sensitive documents, often cryptographic keys, and exporting them is often not desirable. 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#214340 Forward-Port-Of: odoo/odoo#213997
Backport of e21ff0ed57574694e75ef2b4f4e2e41f8bb0412a Manager of an employee could only approve a Time Off request Steps to reproduce: ------------------- * Revoke Marc Demo's Time Off Access Rights in Settings * Assign Marc Demo as manager to an employee * Create a New Time Off request for that employee * Log in as Marc Demo * Head to Time Off > Management > Time Off > Observation: The request can only be approved. Time Off Access Rights' tooltip specifiy that `A user without an
Original PR description
Backport of e21ff0ed57574694e75ef2b4f4e2e41f8bb0412a Manager of an employee could only approve a Time Off request Steps to reproduce: ------------------- * Revoke Marc Demo's Time Off Access Rights in Settings * Assign Marc Demo as manager to an employee * Create a New Time Off request for that employee * Log in as Marc Demo * Head to Time Off > Management > Time Off > Observation: The request can only be approved. Time Off Access Rights' tooltip specifiy that `A user without any rights on Time Off will be able to see the application, create his own holidays and manage the requests of the users he's manager of.` opw-4725537 Forward-Port-Of: odoo/odoo#213292
- The "Clear" button is only accessible by "group_stock_manager" but without a group attached, "stock_user" can still see it and operate it, resulting in an unnecessary permission error, confusing the user. Current behavior before PR:  
Original PR description
- The "Clear" button is only accessible by "group_stock_manager" but without a group attached, "stock_user" can still see it and operate it, resulting in an unnecessary permission error, confusing the user. Current behavior before PR:   --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#213508
The "Alert Date Reached" activity was not correctly assigning the activity to the "Default User" specified in the `mail.activity.type` settings. This did not align with user expectations that the activity type's default user should be primarily considered. To reproduce the issue: 1. Configure a "Default User" (e.g., User A) for the Alert Date Reached activity type. 2. Create a product tracked by lots. Ensure its "Responsible User" (on the product's Inventory tab) is either not set or is a d
Original PR description
The "Alert Date Reached" activity was not correctly assigning the activity to the "Default User" specified in the `mail.activity.type` settings. This did not align with user expectations that the…
The "Alert Date Reached" activity was not correctly assigning the activity to the "Default User" specified in the `mail.activity.type` settings. This did not align with user expectations that the activity type's default user should be primarily considered. To reproduce the issue: 1. Configure a "Default User" (e.g., User A) for the Alert Date Reached activity type. 2. Create a product tracked by lots. Ensure its "Responsible User" (on the product's Inventory tab) is either not set or is a different user (e.g., User B). 3. Receive the product with a lot number and set its alert date to be in the past. 4. Trigger the scheduler for checking lot expirations (via Operations > Run Scheduler). 5. The generated "Alert Date Reached" activity would be assigned to User B (if set) or the superuser, incorrectly ignoring User A. This commit rectifies this behavior by modifying the user assignment logic for these lot expiry alerts. The new priority for determining the assignee is: 1. The "Default User" configured on the "Alert Date Reached" activity type. 2. If no default user is set on the activity type, then the "Responsible User" defined on the related product. 3. If neither is set, the activity is assigned to SUPERUSER. [opw-4640027](https://www.odoo.com/odoo/project.task/4640027) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#212154
### Steps to reproduce: - Install PoS mexican localization - Navigate to PoS and create an order with a discount line - Go to back end and try to refund this order - Notice an error pops-up ### Cause: This is happening because when refunding an order we are checking if every line has positive price but since discount lines will have negative value it trigger the validation error. https://github.com/odoo/enterprise/blob/78bcd2e0b9296ad124ea1c3157a884fa6e62999a/l10n_mx_edi_pos/model
Original PR description
### Steps to reproduce: - Install PoS mexican localization - Navigate to PoS and create an order with a discount line - Go to back end and try to refund this order - Notice an error pops-up ### Cause: This is happening because when refunding an order we are checking if every line has positive price but since discount lines will have negative value it trigger the validation error. https://github.com/odoo/enterprise/blob/78bcd2e0b9296ad124ea1c3157a884fa6e62999a/l10n_mx_edi_pos/models/pos_order.py#L286 ### Fix: We check if the order lines are positive but after filtering the discount lines out opw-4528737 Forward-Port-Of: odoo/enterprise#84331
**Version:** 16.0 **Steps to reproduce:** - Install industry_fsm_sale - Create two tasks without linking them to a Sale Order - Go to list view and select those tasks - Click "Create Invoice" **Issue:** When the user selects tasks from the list view that are not linked to any Sale Order and tries to create an invoice, a traceback occurs. **Cause:** At least one linked Sale Order record is required when generating an invoice. If the selected tasks are not associated w
Original PR description
**Version:**
16.0
**Steps to reproduce:**
- Install industry_fsm_sale
- Create two tasks without linking them to a Sale Order
- Go to list view and select those tasks
- Click "Create Invoice"
**Issue:**
When the user selects tasks from the list view that are not linked to any Sale Order and tries to create an invoice, a traceback occurs.
**Cause:**
At least one linked Sale Order record is required when generating an invoice. If the selected tasks are not associated with any Sale Order, the process fails.
**Fix:**
This commit raise a red toast notification if none of the selected tasks are linked to a Sale Order. This helps the user understand the issue and prevent traceback..
task-4594178`
Forward-Port-Of: odoo/enterprise#87606
Forward-Port-Of: odoo/enterprise#83661Steps to reproduce: 1. Install the german localization 2. Create company in DE 3. Create a partner that has country = PL 4. Create a customer invoice for the PL partner 5. Open: Accounting > Reporting > EC Sales List 6. Hit the wheel and create the CSV export. 7. Open the file Issue: see that the amount is a float Ticket [link](https://www.odoo.com/odoo/project/967/tasks/4575788) opw-4575788 Forward-Port-Of: odoo/enterprise#87421 Forward-Port-Of: odoo/enterprise#83822
Original PR description
Steps to reproduce: 1. Install the german localization 2. Create company in DE 3. Create a partner that has country = PL 4. Create a customer invoice for the PL partner 5. Open: Accounting > Reporting > EC Sales List 6. Hit the wheel and create the CSV export. 7. Open the file Issue: see that the amount is a float Ticket [link](https://www.odoo.com/odoo/project/967/tasks/4575788) opw-4575788 Forward-Port-Of: odoo/enterprise#87421 Forward-Port-Of: odoo/enterprise#83822
opw-4772870 opw-4664501 Forward-Port-Of: odoo/enterprise#86891
Original PR description
opw-4772870 opw-4664501 Forward-Port-Of: odoo/enterprise#86891
When generating the accounting entry from the Corporate Tax Report, the system first tries to find a miscellaneous journal with the short code `MISC`. If this specific journal does not exist, the logic attempts to fall back and find any other journal of type 'Miscellaneous' (`type = 'general'`). However, this fallback search fails with an error due to an incorrect search domain syntax. Steps to reproduce: 1. Go to Accounting > Configuration > Journals. 2. Ensure no journal exists with th
Original PR description
When generating the accounting entry from the Corporate Tax Report, the system first tries to find a miscellaneous journal with the short code `MISC`. If this specific journal does not exist, the logic attempts to fall back and find any other journal of type 'Miscellaneous' (`type = 'general'`). However, this fallback search fails with an error due to an incorrect search domain syntax. Steps to reproduce: 1. Go to Accounting > Configuration > Journals. 2. Ensure no journal exists with the short code MISC. 3. Ensure at least one other journal of type "Miscellaneous" exists (for example, with short code GEN or MSC). 4. Go to Accounting > Reporting > Corporate Tax Report. 5. Try to generate the accounting entry. opw-4836686 Forward-Port-Of: odoo/enterprise#87300
Currently, a raceback occurs when the user changes or adds the expression label of the column in the "Generic Tax report". **To reproduce this issue:** 1) Install "account_reports" 2) Open "Generic Tax report" from "Accounting Reports" 3) In columns change the "Expression Label" and save the record 4) Open the "Tax Report" in "Reporting" 5) A traceback occurs **Error:** ``` UnboundLocalError: local variable 'col_value' referenced before assignment ``` **Cause:** The "co
Original PR description
Currently, a raceback occurs when the user changes or adds the expression label of the column in the "Generic Tax report". **To reproduce this issue:** 1) Install "account_reports" 2) Open "Generic Tax report" from "Accounting Reports" 3) In columns change the "Expression Label" and save the record 4) Open the "Tax Report" in "Reporting" 5) A traceback occurs **Error:** ``` UnboundLocalError: local variable 'col_value' referenced before assignment ``` **Cause:** The "col_value" is assigned based on the "expr_label" if it doesn't match the if conditions it leads to a traceback. https://github.com/odoo/enterprise/blob/d154cbf1bd5b4cc104ff0e2443047aff0c05330f/account_reports/models/account_generic_tax_report.py#L921-L932 **Solution:** This commit will resolve this issue by assigning a fallback value of an empty string to col_value. opw-4841789 Forward-Port-Of: odoo/enterprise#87277
Currently, an error is produced when the payslip start date is not set, but the end date is provided. **Steps to reproduce:** - Install `hr_payroll` module(with demo). - Create new **Payslip** for employee **Anita Oliver**. - Clear both the start and end dates under the "Period" section. - Set only the end date. **Error:** `TypeError: '<' not supported between instances of 'bool' and 'datetime.date'` **Cause:** The `_compute_warning_message` method performs a comparison between `s
Original PR description
Currently, an error is produced when the payslip start date is not set, but the end date is provided. **Steps to reproduce:** - Install `hr_payroll` module(with demo). - Create new **Payslip** for…
Currently, an error is produced when the payslip start date is not set, but the end date is provided. **Steps to reproduce:** - Install `hr_payroll` module(with demo). - Create new **Payslip** for employee **Anita Oliver**. - Clear both the start and end dates under the "Period" section. - Set only the end date. **Error:** `TypeError: '<' not supported between instances of 'bool' and 'datetime.date'` **Cause:** The `_compute_warning_message` method performs a comparison between `slip.date_from` and `contract_id.date_start` without verifying if `date_from` is set. When `date_from` is `False`, the comparison `False < datetime.date(...)` - [1], raises a `TypeError`. [1] - https://github.com/odoo/enterprise/blob/a65314702b99df97c778d4f12f943191a19dafd1/hr_payroll/models/hr_payslip.py#L1029-L1031 This commit adds checks to ensure that start and end date is defined before performing date comparisons in warning message computation, preventing the error. Sentry - 6618275041 Forward-Port-Of: odoo/enterprise#86091