Daily updates from Odoo
Thursday, July 2, 2026
192 changes
8 changes
Resolved issues and error corrections
This update makes work order durations reflect only the time that was actually spent on productive work, instead of counting downtime or blocked periods. It also prevents overlapping time entries from being counted twice, which improves the accuracy of costing and reporting.
Original PR description
[[FIX] mrp: calculate real duration excluding non-productive intervals](https://github.com/odoo/odoo/pull/248381/changes/fac6b2540a32a015f56085c2c27ba4281eb659cf) and deduplicating overlaps * Current…
[[FIX] mrp: calculate real duration excluding non-productive intervals](https://github.com/odoo/odoo/pull/248381/changes/fac6b2540a32a015f56085c2c27ba4281eb659cf) and deduplicating overlaps * Current Situation: Currently real duration is total duration of each time tracking which is not consistent with the time that use to calculate the cost for valuation , see https://github.com/odoo/odoo/pull/205154 .The real duration of a work order was incorrectly summing all time tracking entries regardless of their loss type, and using simple addition which double-counts overlapping intervals. * Solution: - Filter time entries to only 'productive' and 'performance' loss types, excluding 'availability' and 'quality' as they represent downtime/blocking time, not actual work duration. - Pool all productive and performance entries into a single Intervals call so that overlaps across both types are merged in one pass. Note: the enterprise17 implementation groups time entries by loss_type into separate buckets before calling Intervals, which means overlaps between 'productive' and 'performance' entries are not merged and get double-counted. Pooling both types together before the Intervals call avoids this. * This also fix: - Fix _set_duration to ensure newly created time entries start after the latest existing entry's end date. Without this, calling _set_duration twice in quick succession (e.g. in tests) produces two entries with overlapping timestamps, which Intervals correctly merges into one, causing the computed duration to be half the expected value. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270809 Forward-Port-Of: odoo/odoo#248381
When a new company is created, its employee documents folder will now be created in the company’s main Documents area instead of appearing in My Drive. This keeps employee folders organized in the expected company-level location and avoids clutter in personal storage.
Original PR description
Steps to reproduce =================== - Install documents_hr. - Log in with admin. - Create a new company `Test`. - Go to Document and choose the new company (top right). - Go to `My Drive`: a folder named `Employees - Test` has been created. This new folder should be created in the `Company` root instead of the `My Drive,` which will hold all the employee folders. Technical =========== When the main employee folder is created via `_generate_employee_documents_main_folders` `owner_id` falls back to the current user, which leads to computing the `user_folder_id` as `My drive,` and so that's why the newly created folder starts appearing there instead of the `Company` root. This PR addresses the issue and sets the `owner_id` to False, which leads to show the main employee folder in the company root. Task-6267352 Forward-Port-Of: odoo/enterprise#120677
This change prevents an error that could appear when managers create a time off request for multiple employees at once. It ensures the process still works even when no work time type has been configured, avoiding a blocked or broken user experience.
Original PR description
Currently, an error occurs when a user tries to create a group time off. **Steps to Reproduce:** - Install the `hr_presence` module without demo data. - Go to `Employees` > `Configuration` > `Working…
Currently, an error occurs when a user tries to create a group time off. **Steps to Reproduce:** - Install the `hr_presence` module without demo data. - Go to `Employees` > `Configuration` > `Working Times` > `Time Types` and delete all records. - Make sure there are at least `two employee` records. - Go to `Employees` and switch to the `list view`. - Select `both employees` > click `Presence Control` > click `Create a Time Off`. **Error1:** `TypeError: unsupported operand types in: hr.work.entry.type() | None` **Error2:** `AttributeError: 'NoneType' object has no attribute 'ids'` When a user creates a group time off record and the wizard is opened, it computes the valid work entry types. If no work entry type exists, accessing the `True` key (`requires_allocation`) from the empty dictionary returns None [1]. Later, when performing a union (|) between an empty work entry type recordset and None, it raises the first error [2]. Additionally, accessing ids on None raises the error [3]. This commit ensures that when no work entry type exists, accessing key(requires_allocation) from an empty dictionary returns an empty work entry type record instead of None. [1]- https://github.com/odoo/odoo/blob/374f48cfba75ff98f53d8c3fcc51847711bd406a/addons/hr_holidays/wizard/hr_leave_generate_multi_wizard.py#L144-L145 [2]- https://github.com/odoo/odoo/blob/374f48cfba75ff98f53d8c3fcc51847711bd406a/addons/hr_holidays/wizard/hr_leave_generate_multi_wizard.py#L146 [3]: https://github.com/odoo/odoo/blob/374f48cfba75ff98f53d8c3fcc51847711bd406a/addons/hr_holidays/wizard/hr_leave_generate_multi_wizard.py#L148 sentry-7552717400 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270302
This fix ensures that when a document is signed through eMSigner, the completed file stored in Odoo is the actual signed PDF returned by the service. Previously, some users could download the original unsigned document instead, which caused confusion and an incorrect final record of the signing process.
Original PR description
Version: - saas-19.3 Steps to reproduce: - Create a sign request using the eMSigner authentication method. - Complete the signing process. - Download the completed document. Issue: - Users received the original uploaded PDF instead of the signed PDF after completing the signing process through eMSigner. Cause: - After the BinaryValue migration, the completed document was initialized with the original document (document.raw) and only replaced with the eMSigner response for large compressed files. As a result, non-compressed responses stored the original document instead of the signed PDF returned by eMSigner. Fix: - Always use the signed document returned by eMSigner (decrypted_data) to create the completed document. Decode the base64 response and, for large files, decompress it before storing it as binary content. task-6329040 Forward-Port-Of: odoo/enterprise#121628
This change improves how overtime time is stored so very small time differences are not lost. It helps ensure overtime pay is calculated more accurately by keeping sub-second precision instead of rounding too early.
Original PR description
Overtime duration computed as fractional hours was rounded to 3 decimal places before being stored on the overtime line. Since 1 decimal hour = 3600 seconds, this gives only 3.6 seconds of precision and the rounding can go in the wrong direction due to floating-point representation. The fix consists in replacing the duration rounding to 4 decimals when building overtime work entries so stored durations keep sub-second precision needed for money computation. task-6212231 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270417 Forward-Port-Of: odoo/odoo#268889
This change prevents an error that could appear when users open the Stock report after removing Manufacturing. It restores the stock report setup during uninstall so the report continues to open normally even when MRP is no longer installed.
Original PR description
Currently an error occurs when user opens stock report after uninstalling mrp. Steps to replicate: - Install mrp. - Uninstall mrp and open `Stock > Reporting > Stock`. Error: ``` ValueError: Invalid…
Currently an error occurs when user opens stock report after uninstalling mrp.
Steps to replicate:
- Install mrp.
- Uninstall mrp and open `Stock > Reporting > Stock`.
Error:
```
ValueError: Invalid field product.product.is_kits in condition ('is_kits', '=', False)
```
Cause:
- The `mrp` module overrides the `stock.action_product_stock_view` window action domain with `is_kits` field referenced inside [1].
- When mrp is uninstalled, the `is_kits` field is removed from `product.product` but the overridden action domain remains stored in the database. Opening the action then tries to evaluate a domain referencing a non-existent field, resulting in this error.
Solution:
- Restore the original `stock.action_product_stock_view` domain during mrp uninstallation to remove the `is_kits` condition.
[1]: https://github.com/odoo/odoo/blob/c8390638cae4b4dafb805bc0d3a4149fb5194934/addons/mrp/views/product_views.xml#L164-L166
sentry-7332688253
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#269512This change prevents an access error that could block delivery validation when the delivery is linked to a sales order owned by another salesperson. It ensures the system can check the needed subscription information without exposing other sales data, so warehouse operations continue smoothly.
Original PR description
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by…
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by another salesperson. ## **Steps to reproduce:** - Install sale_subscription_stock. - Create a user with Sales: Own Documents Only and Inventory Administrator access rights. - Create a sale order as another user. - Validate the delivery with the restricted user. ## **Solution:** During _action_done(), [This line](https://github.com/odoo/enterprise/blob/19.0/sale_subscription_stock/models/stock_picking.py#L45) is checking subscription_state. Since the user does not have read access to the sale order, reading this field raises an access error and prevents the delivery from being validated. As the method only needs to read the subscription state, access the field with sudo() to avoid the unnecessary access error while preserving the existing business logic. Runbot Video : [Video](https://drive.google.com/file/d/1d7U2jTCxaaVk2YJcy3bi2SlYuT-yXMsu/view?usp=drive_link) OPW - 6295712 Forward-Port-Of: odoo/enterprise#122420
When a new file is uploaded in Documents, its available actions are now shown immediately. This fixes the previous behavior where users had to click away and reselect the file before the actions became visible.
Original PR description
Bug === When uploading a new file in documents, it's selected, but the actions are not visible (we need to unselect - select the record to see the actions). Task-5408471 Forward-Port-Of: odoo/enterprise#122396 Forward-Port-Of: odoo/enterprise#114770
16 changes
Enhancements to existing features
This change removes technical e-reporting fields from the standard invoice screen to make invoicing simpler and less cluttered for users. The relevant status, flow, and blocking error information is now available in the invoice chatter, with a direct link to the related flow, and address validation warnings are no longer shown for B2C invoices when they are not needed.
Original PR description
E-reporting technical fields were displayed directly on invoices, adding noise for regular invoicing users. Hide the e-reporting status columns and technical block from the standard invoice views. Log the relevant e-reporting flow, status and blocking errors in the invoice chatter instead, with a link to the related flow. Also avoid reporting address validation errors on B2C invoices, as they are not required for Flux 10 e-reporting. Task-6273226 Forward-Port-Of: odoo/odoo#271865
Resolved issues and error corrections
This fix prevents invoice notifications from crashing when they are sent in a different language than the one used while creating the invoice. It ensures Quick Edit invoice confirmations render properly for customers and users, avoiding failed notifications and interrupted workflows.
Original PR description
**Steps to Reproduce:** - Install the Accounting and Contacts modules. - Enable Quick Encoding for Customer Invoices and Vendor Bills in the company settings. - Create a new customer: Assign a…
**Steps to Reproduce:**
- Install the Accounting and Contacts modules.
- Enable Quick Encoding for Customer Invoices and Vendor Bills in the company
settings.
- Create a new customer: Assign a salesperson.
- Ensure:
- The salesperson is not a login user.
- The customer language, salesperson's language, and Login user's language
are different. Example:
- Customer language: English
- Salesperson language: French
- Login user language: French
- Create a customer invoice using the Upload Document functionality.
- Select the customer created above.
- Use Quick Edit mode and enter an amount and Click Confirm.
**Issue:**
- When the invoice notification is rendered in a language different from the one
used during the write operation, the notification rendering flow calls
_notify_by_email_prepare_rendering_context().
- During rendering, the code executes:
```
self.tax_totals.get('total_amount_currency', 0)
```
- Since tax_totals is protected, the ORM returns False instead of the expected
dictionary, leading to:
```
AttributeError: 'bool' object has no attribute 'get'
```
**Root Cause:**
- This issue occurs in Quick Edit mode because tax_totals is [not read-only](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/views/account_move_views.xml#L1359)
in Quick Edit mode and is included in [the values](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/web/static/src/model/relational_model/record.js#L708) sent by the web client during write().
- During create()/write(), _get_protected_vals() marks tax_totals as protected.
- Since tax_totals is a [@api.depends_context('lang')](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/models/account_move.py#L975) computed field, it
maintains a separate cache per language. [During write()](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/models/account_move.py#L3955), the [field becomes
protected](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/models/account_move.py#L3863) by [env.protecting()](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/odoo/orm/fields.py#L1738). While the protection is still active, the mail
notification flow renders the email using the recipient's language. If the
corresponding language-specific cache entry for tax_totals is not available,
the ORM cannot recompute the protected field and returns False instead
of the expected dictionary.
- The rendering code assumes tax_totals is always a dictionary and directly
calls .get(), leading to the crash.
**Solution:**
- Exclude tax_totals from _get_protected_vals().
- tax_totals is already handled explicitly after create()/write(), so protecting
it is unnecessary. This allows the field to be recomputed during notification
rendering when required.
**Result:**
- Invoice notifications render correctly in all languages.
- No RPC crash occurs when rendering notifications after Quick Edit.
**Runbot reproduction: [video](https://github.com/user-attachments/assets/5f045efb-37de-40aa-b135-1368b1601d61)**
**opw-6209647**
Forward-Port-Of: odoo/odoo#266335This fix avoids an error that could appear when a user removes the currency while registering a payment. It keeps the payment flow working smoothly in the Argentine withholding setup and prevents an unexpected interruption.
Original PR description
When the user removes the currency from the payment register, a traceback is raised. Steps to reproduce the error: - Install ``l10n_ar_withholding`` module - Switch to ``(AR) Exento`` company - Create a new invoice > Confirm > Pay > Unset the currency Traceback: ```py ValueError: Expected singleton: res.currency() ``` https://github.com/odoo/odoo/blob/d98afdc08b46bf458eaa287ea882cc7663286a59/addons/l10n_ar_withholding/wizards/account_payment_register.py#L27 This line causes a traceback with an empty currency when the user removes the currency from the payment register. sentry-7362499567 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272891 Forward-Port-Of: odoo/odoo#255825
Fixed an issue where new employee document folders were being created in a user's personal drive instead of the company’s main folder. This keeps employee folders organized in the correct company location and makes them easier to find and manage.
Original PR description
Steps to reproduce =================== - Install documents_hr. - Log in with admin. - Create a new company `Test`. - Go to Document and choose the new company (top right). - Go to `My Drive`: a folder named `Employees - Test` has been created. This new folder should be created in the `Company` root instead of the `My Drive,` which will hold all the employee folders. Technical =========== When the main employee folder is created via `_generate_employee_documents_main_folders` `owner_id` falls back to the current user, which leads to computing the `user_folder_id` as `My drive,` and so that's why the newly created folder starts appearing there instead of the `Company` root. This PR addresses the issue and sets the `owner_id` to False, which leads to show the main employee folder in the company root. Task-6267352 Forward-Port-Of: odoo/enterprise#120677
This change prevents an access error that could block delivery validation when a user can manage inventory but only sees their own sales documents. The system now checks the related subscription status in a safer way, so deliveries can be completed without exposing additional sales data or changing the existing business rules.
Original PR description
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by…
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by another salesperson. ## **Steps to reproduce:** - Install sale_subscription_stock. - Create a user with Sales: Own Documents Only and Inventory Administrator access rights. - Create a sale order as another user. - Validate the delivery with the restricted user. ## **Solution:** During _action_done(), [This line](https://github.com/odoo/enterprise/blob/19.0/sale_subscription_stock/models/stock_picking.py#L45) is checking subscription_state. Since the user does not have read access to the sale order, reading this field raises an access error and prevents the delivery from being validated. As the method only needs to read the subscription state, access the field with sudo() to avoid the unnecessary access error while preserving the existing business logic. Runbot Video : [Video](https://drive.google.com/file/d/1d7U2jTCxaaVk2YJcy3bi2SlYuT-yXMsu/view?usp=drive_link) OPW - 6295712 Forward-Port-Of: odoo/enterprise#122420
This change prevents an error that could appear when opening the Stock report after the Manufacturing app had been removed. It restores the report settings to a safe default during uninstall, so users can continue accessing stock reporting normally.
Original PR description
Currently an error occurs when user opens stock report after uninstalling mrp. Steps to replicate: - Install mrp. - Uninstall mrp and open `Stock > Reporting > Stock`. Error: ``` ValueError: Invalid…
Currently an error occurs when user opens stock report after uninstalling mrp.
Steps to replicate:
- Install mrp.
- Uninstall mrp and open `Stock > Reporting > Stock`.
Error:
```
ValueError: Invalid field product.product.is_kits in condition ('is_kits', '=', False)
```
Cause:
- The `mrp` module overrides the `stock.action_product_stock_view` window action domain with `is_kits` field referenced inside [1].
- When mrp is uninstalled, the `is_kits` field is removed from `product.product` but the overridden action domain remains stored in the database. Opening the action then tries to evaluate a domain referencing a non-existent field, resulting in this error.
Solution:
- Restore the original `stock.action_product_stock_view` domain during mrp uninstallation to remove the `is_kits` condition.
[1]: https://github.com/odoo/odoo/blob/c8390638cae4b4dafb805bc0d3a4149fb5194934/addons/mrp/views/product_views.xml#L164-L166
sentry-7332688253
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#269512This change corrects a rounding issue that could make overtime time entries overlap by a few seconds, especially around midnight. It now orders the entries more reliably and prevents one interval from starting before the previous one has finished, improving the accuracy of attendance and payroll data.
Original PR description
__Issue:__ `duration` is rounded to 3 decimals (~1.8s drift) while `time_stop` is exact, so the back-projected start could land before midnight on overnight overtime or middle of the day causing overlaps with the previous line Example: - time_start = 03/05 00:00:00 - time_stop = 03/05 07:07:14 actual duration 7h07m14s gets stored as `duration = 7.121` (= 7h07m15.6s) after `round(_, 3)`. Back-projection yields `datetime_start = 07:07:14 - 7.121h = 02/05 23:59:58`, overlapping by ~2s with the prior line ending at `02/05 23:59:59.999`. __Fix:__ Sort lines by `time_stop` within each date and clamp `datetime_start` to the previously emitted interval's stop when the two intervals genuinely intersect. opw-6170828 Forward-Port-Of: odoo/enterprise#121564 Forward-Port-Of: odoo/enterprise#116565
PDF generation for certain Guatemala vendor bills could fail with an error, preventing users from downloading the document. This update corrects the data setup and template reference so the PDF can be generated successfully again.
Original PR description
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Create a new vendor bill with: - Vendor: GT Company - GT Document Type: `FESP` - Add taxes `VAT Withholding…
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Create a new vendor bill with: - Vendor: GT Company - GT Document Type: `FESP` - Add taxes `VAT Withholding 12%` and `ISR Withholding 5%` in Invoice lines. - `Confirm` the bill and `Send to SAT`. - From the gear icon, click `Download` > `PDF`. **Error1:** `KeyError: 'gran_total'` **Error2:** `KeyError: 'retencion_grand_total'` **Root Cause:** In commit [1], the code at [2] missed calling `_l10n_gt_edi_add_base_values()` before `_l10n_gt_edi_add_withholding_values()`. However, `_l10n_gt_edi_add_withholding_values()` uses the `gran_total` value, which is initialized by `_l10n_gt_edi_add_base_values()`, resulting in a `KeyError`. Additionally, the report template at [3] references `retencion_grand_total` instead of the correct key `retencion_gran_total`, causing another `KeyError`. **Fix:** This commit prevents errors and ensures users can successfully download the PDF by applying a fix similar to [4], [1]: https://github.com/odoo/enterprise/commit/44afd19e4ed0827e343af0e584c81e579935c9e8 [2]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/models/account_move.py#L305-L328 [3]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/views/report_invoice.xml#L72 [4]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/models/account_move.py#L790-L800 opw-6323049 Forward-Port-Of: odoo/enterprise#122398 Forward-Port-Of: odoo/enterprise#122030
This change prevents the system from crashing when a session entry is missing an expected trust flag. It improves stability for affected devices and sessions by handling incomplete data safely instead of failing.
Original PR description
Some devices may not have a `trusted` key in their entry. This is the case for sessions created between these two commits: - https://github.com/odoo/odoo/commit/b6c2aafae2112ef98edca8a7f027716d9c15be11 - https://github.com/odoo/odoo/commit/61f22175ef3df37087887e7419dac54a620bbd55 Task-6348650 Forward-Port-Of: odoo/odoo#273062
This update prevents manually entered timesheet details from disappearing when users close the Timesheets systray after saving or resetting an entry. It helps ensure the description, project, and task they entered are kept and shown again later, reducing user frustration and rework.
Original PR description
## Issue When using the Timesheets systray, if we set a project after clicking the *Save* or *Reset* button, the project is not saved after closing the systray. ## Steps to reproduce 1. Install…
## Issue When using the Timesheets systray, if we set a project after clicking the *Save* or *Reset* button, the project is not saved after closing the systray. ## Steps to reproduce 1. Install *Timesheets* (`timesheet_grid`) 2. Open the Timesheets systray 3. Click *Reset* and set a description, a project and/or a task, then close the systray 4. Open the systray again 5. **The description/project/task set in step 3 do(es) not appear anymore.** ## Cause Commit https://github.com/odoo/enterprise/commit/b9b7f8a0acf7a1c545c6613cf8bbc29871632e26 introduced the `preventUnmountSave` attribute. The attribute is set to `true` after saving and discarding an entry. When the systray is unMounted, the manual values (e.g., description, project and task) are not saved if the attribute is set to `true`: https://github.com/odoo/enterprise/blob/7cd8dd008eb88d6c12f3e65fb8d311058290a301/timesheet_grid/static/src/components/timesheet_timer_inline_form/timesheet_timer_inline_form.js#L171-L174 ## Fix After discussing with the author of the previous commit, it appears this was done to prevent an issue with values stored in cache, but that issue does not seem to occur anymore, which leads to believe that the attribute is not required anymore. opw-6284016 Forward-Port-Of: odoo/enterprise#121605
This update prevents the editor menu from opening when an emoji shortcut is typed and converted into an emoji. It also makes emoji shortcuts work more reliably within a paragraph, so users can insert emojis without unexpected interruptions.
Original PR description
#### Description of the issue this PR addresses: - When an emoji shortcut ending with `/` (e.g. `:/` for 😕) is typed, the emoji plugin replaces the characters before the powerbox `on_input_handler`…
#### Description of the issue this PR addresses: - When an emoji shortcut ending with `/` (e.g. `:/` for 😕) is typed, the emoji plugin replaces the characters before the powerbox `on_input_handler` runs. Since `ev.data` still reflects the original typed `/`, the powerbox was incorrectly opening. - Emoji shortcuts works only when it is used at the end of a text node, because the matching logic checked the whole remaining substring from the current position. - Sometimes, pressing Backspace splits one text node into two, and then an emoji shortcut works at the end of the first text node even when the paragraph is visible as a single line. #### Desired behavior after PR is merged: - Check the DOM character at cursor position instead of `ev.data` to determine whether `/` is actually present before opening the powerbox. - Emoji shortcuts now works when used with a preceding space anywhere in the paragraph. Enterprise PR-https://github.com/odoo/enterprise/pull/118310 task-6243724 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266284
The attendance overtime calculation now includes all work periods that overlap the updated day, even when an attendance crosses midnight. This prevents overtime from being undercounted in cases where a later attendance was previously calculated without taking earlier overlapping hours into account.
Original PR description
Issue: ---------------------------------------- The overtime calculation ignores attendances overlapping midnight when creating an attendance on the day they overlap. Steps to reproduce:…
Issue:
----------------------------------------
The overtime calculation ignores attendances overlapping midnight when creating an attendance on the day they overlap.
Steps to reproduce:
----------------------------------------
- Have the standard 8 hours per day working schedule
- Use the default overtime ruleset:
- Quantity, per day, more than the contract
- Have no rule on weeks
- Create an attendance of 8+ hours overlapping midnight on a day:
- From 10pm to 10am (2h + 10h = 12h)
- Create another attendance on the day the first ended:
- From 2pm to 6pm (4h)
- The first attendance has 2h of overtime:
- 0h from the first worked day (from 10pm to midnight = 2 < 8)
- 2h on the next day (10h worked from midnight to 10am)
- The second attendance have 0h of overtime even though it should be 4h
- We only considered this attendance in the calculation, ignoring the 10h worked in the morning
Cause:
----------------------------------------
In `_update_overtime()` we create a domain to include all useful attendances in the calculation. As all rules are based on days, the domain will use the date of the attendance to get overlapping attendances. But the date of the attendance is the date of its `check_in` ([src](https://github.com/odoo/odoo/blob/4235b48c86077bd5bceb9e817cc45b2eec8697e8/addons/hr_attendance/models/hr_attendance.py#L91)). So when creating the second attendance, the domain only fetches attendance with their `date` on the same date as the `check_in` of the second one. This excludes the first one even though it overlaps on the same day.
Solution:
----------------------------------------
Don't use `date` but `check_in` and `check_out` in the domain to really get all attendances overlapping a day with an updated attendance.
As this domain was used on both `hr.attendance` and `hr.attendance.overtime.line`, we adapt it so it uses the correct fields (`time_start` and `time_stop`) from the overtime lines.
opw-6253777
Forward-Port-Of: odoo/odoo#272447This fix ensures the Italian withholding tax return is calculated independently from the regular tax return. As a result, the amount due on a withholding return no longer incorrectly includes balances from other tax returns, preventing wrong payment amounts.
Original PR description
Steps to reproduce: - setup an Italian company - make an invoice (for example in May) with a withholding tax and make a transaction to pay it - generate tax returns (opening date in June so that it generates from May) - validate regular tax return for May - validate withholding tax return for May -> The withholding tax return shows an amount to pay with a balance that is a combination of both the regular tax return and the withholding one, while it should be independent of the regular one. task-6116304 Forward-Port-Of: odoo/enterprise#121254 Forward-Port-Of: odoo/enterprise#119375
This fix adds descriptive alternative text to language flag images when the website language selector shows flags without text. It improves accessibility for screen readers and gives search engines the context they need to understand the language options.
Original PR description
Steps to reproduce: 1. Enable the language selector in the website header. 2. Enable the "Inline" and "Flag" options. 3. Inspect the flag images rendered in the inline variant. Issue: Flag images in the list items have an empty `alt=""` attribute in "Flag only" mode, where the flag is the sole visual indicator of the language, making the selector inaccessible to screen readers and providing no context for search crawlers. Expected behavior: Inline + Flag should have a descriptive ALT tag since there is no adjacent text or code to identify the language, the flag is not decorative. opw-6246464 Forward-Port-Of: odoo/odoo#273025 Forward-Port-Of: odoo/odoo#271362
This change prevents the accounting automation from marking work as complete when an unexpected error occurs. As a result, failed items are less likely to be skipped silently, improving the reliability of scheduled posting tasks.
Original PR description
The previous fix commits progress even when an unexpected exception escaped the loop iteration when _autopost_draft_entries. Now progress is only committed on success or when a UserError is explicitly handled. Reference: https://github.com/odoo/odoo/pull/271509 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273115
Public links for shared audio files will no longer try to play in the browser preview. This avoids Chrome-specific preview failures and keeps the sharing experience consistent by downloading the file instead of exposing it as streaming media.
Original PR description
**Steps to reproduce:** - Install Documents app - Upload a sound file (mp3 for example, but the behavior is the same for other formats) - Share the document and copy the link - Log out - Paste the…
**Steps to reproduce:**
- Install Documents app
- Upload a sound file (mp3 for example, but the
behavior is the same for other formats)
- Share the document and copy the link
- Log out
- Paste the link
- Click on preview button
- Media is working fine on Firefox
- Media won't read on Chrome
```
Loading media from '' violates the following Content Security Policy directive: "default-src 'none'".
Note that 'media-src' was not explicitly set, so 'default-src' is used as a fallback.
The action has been blocked.
```
**Issue:**
Since [1] default CSP Headers are too strict for Chrome default media rendering, which breaks the file preview (and force user download).
This only impacts Chrome as they seem to render generate `<video><source>` elements to render the file which triggers a secondary request and fails due to the CSP constraint.
**Fix:**
Could re-apply the header fix of 17.4 (see [2]), but it seems better to block the preview of audio files as well by default (to match how we manage videos).
(Note: we don't want to be used as a media streaming platform)
[1] (set csp to none by default) https://github.com/odoo/odoo/commit/64beb80205dffe4b432c8b5813a3271b073fa85e
[2] (similar issue which was not fixed in 18.0+) https://github.com/odoo/enterprise/commit/a7af78eeb2b9763045a5bda8714172f5e7402df8
[3] (mp4 preview removed) https://github.com/odoo/enterprise/commit/ea88cf7c6d5f077b60fb59347659507fded0e2fe
opw-6235043
Forward-Port-Of: odoo/enterprise#11964413 changes
Enhancements to existing features
The Expense dashboard now follows the same filtering rules as the list view for the 'To Submit', 'Waiting Approval', and 'Waiting Reimbursement' states. This makes dashboard totals more accurate, for example allowing managers to see the amounts for the employees they supervise.
Original PR description
For the expense dashboard with the states 'To Submit', 'Waiting Approval' and 'Waiting Reimbursement', make these states compliants with the current filters of the list view. It means, for example, that a manager can see the total amounts of the people he manages. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273302 Forward-Port-Of: odoo/odoo#270234
This change removes technical e-reporting fields from standard invoice screens so everyday users see a cleaner, less confusing form. The same information is still available in the invoice chatter, where related flow, status, and blocking errors are recorded with a direct link to the e-reporting process. It also avoids unnecessary address validation errors on B2C invoices when they are not needed for this reporting flow.
Original PR description
E-reporting technical fields were displayed directly on invoices, adding noise for regular invoicing users. Hide the e-reporting status columns and technical block from the standard invoice views. Log the relevant e-reporting flow, status and blocking errors in the invoice chatter instead, with a link to the related flow. Also avoid reporting address validation errors on B2C invoices, as they are not required for Flux 10 e-reporting. Task-6273226 Forward-Port-Of: odoo/odoo#271865
Resolved issues and error corrections
This fix ensures grouped customer payments are correctly marked back to “In Process” when a bank statement match is undone. It prevents inconsistent payment states that could otherwise cause problems when reconciling the same batch again.
Original PR description
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A *…
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A * Total; 10.00 - Confirm the invoice - From the invoice list, select both invoice - Create payment: * Journal: Bank * Group Payments: [checked] * Group Payments: [checked] * Amount: 40.00 - Create a third invoice for another customer: * Customer: Partner B * Total: 25.00 - Confirm the invoice - Register payment from the invoice - Create a fourth invoice for another customer: * Customer: Partner C * Total; 40.00 - Confirm the invoice - Register payment from the invoice - From the payment list, select all 3 payments and create batch payment - Validate the batch payment - From Accounting dashboard, open Bank journal - Create a new bank statement line of 105.00 - Match it with the batch payment At that point, the statement line is reconciled with the 4 invoices and the 3 payments are marked as paid. - Go to the fourth invoice - Reset it to draft - Change the price - Save When the amount of the invoice is changed, the statement line is unreconciled and all the payments should change state from "Paid" to "In Process". **Issue:** All the single payments have their state correctly changed to "In Process", except for the group payment for the 2 first invoices, which leads to undesired values when trying to reconcile the statement line with the batch payment again. **Cause:** When the statement is unreconciled, all the partial reconcile records are deleted and the state of the linked payments are updated to "In Process". The payments are retrieved by checking if there are linked to an account move present in the partial reconcile record and if the amount of the payment matches the amount of the partial reconcile record. In case of a group payment, there are 2 partial reconcile records for each invoice linked to the payment. Therefore, in that case, the amount doesn't match the amount of the payment because it matches the amount of one of the invoice. opw-6141089 Forward-Port-Of: odoo/enterprise#122195 Forward-Port-Of: odoo/enterprise#120210
This change prevents invoice notifications from crashing when they are sent in a different language than the one used during invoice entry. It ensures Quick Edit invoices can still be confirmed and emailed successfully, improving reliability for multilingual teams.
Original PR description
**Steps to Reproduce:** - Install the Accounting and Contacts modules. - Enable Quick Encoding for Customer Invoices and Vendor Bills in the company settings. - Create a new customer: Assign a…
**Steps to Reproduce:**
- Install the Accounting and Contacts modules.
- Enable Quick Encoding for Customer Invoices and Vendor Bills in the company
settings.
- Create a new customer: Assign a salesperson.
- Ensure:
- The salesperson is not a login user.
- The customer language, salesperson's language, and Login user's language
are different. Example:
- Customer language: English
- Salesperson language: French
- Login user language: French
- Create a customer invoice using the Upload Document functionality.
- Select the customer created above.
- Use Quick Edit mode and enter an amount and Click Confirm.
**Issue:**
- When the invoice notification is rendered in a language different from the one
used during the write operation, the notification rendering flow calls
_notify_by_email_prepare_rendering_context().
- During rendering, the code executes:
```
self.tax_totals.get('total_amount_currency', 0)
```
- Since tax_totals is protected, the ORM returns False instead of the expected
dictionary, leading to:
```
AttributeError: 'bool' object has no attribute 'get'
```
**Root Cause:**
- This issue occurs in Quick Edit mode because tax_totals is [not read-only](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/views/account_move_views.xml#L1359)
in Quick Edit mode and is included in [the values](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/web/static/src/model/relational_model/record.js#L708) sent by the web client during write().
- During create()/write(), _get_protected_vals() marks tax_totals as protected.
- Since tax_totals is a [@api.depends_context('lang')](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/models/account_move.py#L975) computed field, it
maintains a separate cache per language. [During write()](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/models/account_move.py#L3955), the [field becomes
protected](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/addons/account/models/account_move.py#L3863) by [env.protecting()](https://github.com/odoo/odoo/blob/1f7a62d38303a992f501b4ecdb1bee437f7279b8/odoo/orm/fields.py#L1738). While the protection is still active, the mail
notification flow renders the email using the recipient's language. If the
corresponding language-specific cache entry for tax_totals is not available,
the ORM cannot recompute the protected field and returns False instead
of the expected dictionary.
- The rendering code assumes tax_totals is always a dictionary and directly
calls .get(), leading to the crash.
**Solution:**
- Exclude tax_totals from _get_protected_vals().
- tax_totals is already handled explicitly after create()/write(), so protecting
it is unnecessary. This allows the field to be recomputed during notification
rendering when required.
**Result:**
- Invoice notifications render correctly in all languages.
- No RPC crash occurs when rendering notifications after Quick Edit.
**Runbot reproduction: [video](https://github.com/user-attachments/assets/5f045efb-37de-40aa-b135-1368b1601d61)**
**opw-6209647**
Forward-Port-Of: odoo/odoo#266335This update corrects how grouped customer payments are handled when a bank reconciliation is undone. It ensures those payments are moved back to "In Process" like other payments, so the statement can be matched again without errors or inconsistent payment states.
Original PR description
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A *…
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A * Total; 10.00 - Confirm the invoice - From the invoice list, select both invoice - Create payment: * Journal: Bank * Group Payments: [checked] * Amount: 40.00 - Create a third invoice for another customer: * Customer: Partner B * Total: 25.00 - Confirm the invoice - Register payment from the invoice - Create a fourth invoice for another customer: * Customer: Partner C * Total; 40.00 - Confirm the invoice - Register payment from the invoice - From the payment list, select all 3 payments and create batch payment - Validate the batch payment - From Accounting dashboard, open Bank journal - Create a new bank statement line of 105.00 - Match it with the batch payment At that point, the statement line is reconciled with the 4 invoices and the 3 payments are marked as paid. - Go to the fourth invoice - Reset it to draft - Change the price - Save When the amount of the invoice is changed, the statement line is unreconciled and all the payments should change state from "Paid" to "In Process". **Issue:** All the single payments have their state correctly changed to "In Process", except for the group payment for the 2 first invoices, which leads to undesired values when trying to reconcile the statement line with the batch payment again. **Cause:** When the statement is unreconciled, all the partial reconcile records are deleted and the state of the linked payments are updated to "In Process". The payments are retrieved by checking if there are linked to an account move present in the partial reconcile record and if the amount of the payment matches the amount of the partial reconcile record. In case of a group payment, there are 2 partial reconcile records for each invoice linked to the payment. Therefore, in that case, the amount doesn't match the amount of the payment because it matches the amount of one of the invoice. opw-6141089 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272954 Forward-Port-Of: odoo/odoo#269510
This fix prevents an error when downloading the PDF of certain Guatemalan vendor bills, specifically those marked as FESP. It also corrects a template reference so the invoice can be generated and downloaded successfully without interruption.
Original PR description
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Create a new vendor bill with: - Vendor: GT Company - GT Document Type: `FESP` - Add taxes `VAT Withholding…
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Create a new vendor bill with: - Vendor: GT Company - GT Document Type: `FESP` - Add taxes `VAT Withholding 12%` and `ISR Withholding 5%` in Invoice lines. - `Confirm` the bill and `Send to SAT`. - From the gear icon, click `Download` > `PDF`. **Error1:** `KeyError: 'gran_total'` **Error2:** `KeyError: 'retencion_grand_total'` **Root Cause:** In commit [1], the code at [2] missed calling `_l10n_gt_edi_add_base_values()` before `_l10n_gt_edi_add_withholding_values()`. However, `_l10n_gt_edi_add_withholding_values()` uses the `gran_total` value, which is initialized by `_l10n_gt_edi_add_base_values()`, resulting in a `KeyError`. Additionally, the report template at [3] references `retencion_grand_total` instead of the correct key `retencion_gran_total`, causing another `KeyError`. **Fix:** This commit prevents errors and ensures users can successfully download the PDF by applying a fix similar to [4], [1]: https://github.com/odoo/enterprise/commit/44afd19e4ed0827e343af0e584c81e579935c9e8 [2]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/models/account_move.py#L305-L328 [3]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/views/report_invoice.xml#L72 [4]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/models/account_move.py#L790-L800 opw-6323049 Forward-Port-Of: odoo/enterprise#122398 Forward-Port-Of: odoo/enterprise#122030
This update prevents an error that could occur when scrapping components from a subcontractor replenishment order. It also ensures forecast stock availability stays accurate in this subcontracting flow, avoiding interruptions for users working with purchase and inventory operations.
Original PR description
[FIX] stock,*: properly compute forecast availability after PO resupply scrap * : mrp_subcontracting_purchase # How to reproduce - Enable Subcontracting in the settings - Create Product A with : -…
[FIX] stock,*: properly compute forecast availability after PO resupply scrap * : mrp_subcontracting_purchase # How to reproduce - Enable Subcontracting in the settings - Create Product A with : - Quantity : > 0 - Routes : Buy & Resupply Subcontractor on Order - Create Product B - Create BOM for that Product with - BOM Type : Subcontracting - Subcontractors : any - Component : Product A - Create a PO for Product B - Confirm the PO Order - Use the Resupply smart button - Click on the gear icons > Scrap - Scrap Product A # The problem A traceback will appear. # Cause There are two main ways to get the picking type's code of a move. Either : - `product_code` which is a related field to `picking_id.picking_type_id.code` : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_move.py#L174 - `picking_type_id.code` where `picking_type_id` is a computed field : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_move.py#L283-L287 When we scrap the products, we call the `do_scrap()` function that creates a new scrap move : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_scrap.py#L158 When we do so, the create move's `picking_code` wil be the code of the picking type of the current picking (The subcontractor resupply) : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_scrap.py#L151 But `picking_type_id.code` will be different because there is a `default_picking_type_id` value set in the context by : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/purchase_stock/models/purchase_order.py#L223 In our case, theses values end up not being the same. Later, when we compute the forecast information of the move, we prefetch virtual available keys and put the moves in a dict based on those keys. The computation of the virtual available key is based on the `picking_code` of the move : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_move.py#L488-L490 https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_move.py#L496-L499 When later we try to fetch back the move, we compute the virtual available key based on `picking_type_id.code` : https://github.com/odoo/odoo/blob/0442c66d26b0c23313f17c566b16e34e7b22c2b6/addons/stock/models/stock_move.py#L529-L536 But since `picking_code` and `picking_type_id.code` are different, the output `key_virtual_available` is also different. Essentially, we add the move in the dict with key A and then try to fetch it back using key B, which gives us a KeyError. opw-6145887 Forward-Port-Of: odoo/odoo#272171 Forward-Port-Of: odoo/odoo#263799
This fix prevents a crash that could happen when a user removes the currency from the payment register in the Argentine withholding flow. It makes the payment screen handle an empty currency safely, so users can continue working without interruption.
Original PR description
When the user removes the currency from the payment register, a traceback is raised. Steps to reproduce the error: - Install ``l10n_ar_withholding`` module - Switch to ``(AR) Exento`` company - Create a new invoice > Confirm > Pay > Unset the currency Traceback: ```py ValueError: Expected singleton: res.currency() ``` https://github.com/odoo/odoo/blob/d98afdc08b46bf458eaa287ea882cc7663286a59/addons/l10n_ar_withholding/wizards/account_payment_register.py#L27 This line causes a traceback with an empty currency when the user removes the currency from the payment register. sentry-7362499567 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272891 Forward-Port-Of: odoo/odoo#255825
This change prevents an access error that could block delivery validation for users with limited Sales access when the related sales order belongs to another salesperson. The system now safely reads only the needed subscription status, so deliveries can be confirmed without exposing additional order details.
Original PR description
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by…
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by another salesperson. ## **Steps to reproduce:** - Install sale_subscription_stock. - Create a user with Sales: Own Documents Only and Inventory Administrator access rights. - Create a sale order as another user. - Validate the delivery with the restricted user. ## **Solution:** During _action_done(), [This line](https://github.com/odoo/enterprise/blob/19.0/sale_subscription_stock/models/stock_picking.py#L45) is checking subscription_state. Since the user does not have read access to the sale order, reading this field raises an access error and prevents the delivery from being validated. As the method only needs to read the subscription state, access the field with sudo() to avoid the unnecessary access error while preserving the existing business logic. Runbot Video : [Video](https://drive.google.com/file/d/1d7U2jTCxaaVk2YJcy3bi2SlYuT-yXMsu/view?usp=drive_link) OPW - 6295712 Forward-Port-Of: odoo/enterprise#122420
When a new company is created, its main employee folder will now be placed in the company root area instead of appearing in a personal drive. This keeps employee documents organized in the expected shared location and avoids confusion for administrators.
Original PR description
Steps to reproduce =================== - Install documents_hr. - Log in with admin. - Create a new company `Test`. - Go to Document and choose the new company (top right). - Go to `My Drive`: a folder named `Employees - Test` has been created. This new folder should be created in the `Company` root instead of the `My Drive,` which will hold all the employee folders. Technical =========== When the main employee folder is created via `_generate_employee_documents_main_folders` `owner_id` falls back to the current user, which leads to computing the `user_folder_id` as `My drive,` and so that's why the newly created folder starts appearing there instead of the `Company` root. This PR addresses the issue and sets the `owner_id` to False, which leads to show the main employee folder in the company root. Task-6267352 Forward-Port-Of: odoo/enterprise#120677
Uninstalling Manufacturing could leave behind a filter used by the Stock report, which caused an error when opening that report. This update restores the original behavior during removal, so users can access Stock reporting normally after removing MRP.
Original PR description
Currently an error occurs when user opens stock report after uninstalling mrp. Steps to replicate: - Install mrp. - Uninstall mrp and open `Stock > Reporting > Stock`. Error: ``` ValueError: Invalid…
Currently an error occurs when user opens stock report after uninstalling mrp.
Steps to replicate:
- Install mrp.
- Uninstall mrp and open `Stock > Reporting > Stock`.
Error:
```
ValueError: Invalid field product.product.is_kits in condition ('is_kits', '=', False)
```
Cause:
- The `mrp` module overrides the `stock.action_product_stock_view` window action domain with `is_kits` field referenced inside [1].
- When mrp is uninstalled, the `is_kits` field is removed from `product.product` but the overridden action domain remains stored in the database. Opening the action then tries to evaluate a domain referencing a non-existent field, resulting in this error.
Solution:
- Restore the original `stock.action_product_stock_view` domain during mrp uninstallation to remove the `is_kits` condition.
[1]: https://github.com/odoo/odoo/blob/c8390638cae4b4dafb805bc0d3a4149fb5194934/addons/mrp/views/product_views.xml#L164-L166
sentry-7332688253
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#269512This update prevents an error that could stop users from generating the GSTR-1 Excel file when data from multiple company branches is involved. It makes the export more reliable in common multi-company Indian localization setups, so users can complete report generation without interruption.
Original PR description
Steps to reproduce: - Install `l10n_in_reports` module(Indian Localisation) - Create a branch in `IN Company` > Select both - Create separate invoices for each company - Created the GSTR-1 report for…
Steps to reproduce:
- Install `l10n_in_reports` module(Indian Localisation)
- Create a branch in `IN Company` > Select both
- Create separate invoices for each company
- Created the GSTR-1 report for both company
- While generating Excel, select only main company
Traceback:
```py
File "/home/odoo/src/enterprise/19.0/l10n_in_reports/models/account_return.py", line 2537, in action_generate_gstr1_xlsx
gstr1_json = self._get_l10n_in_gstr1_json()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/19.0/l10n_in_reports/models/account_return.py", line 1071, in _get_l10n_in_gstr1_json
'b2cs': _get_b2cs_json(AccountMoveLine.search(self._get_section_domain('b2cs'))),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/19.0/l10n_in_reports/models/account_return.py", line 672, in _get_b2cs_json
for line, line_tax_details in tax_details.items():
^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'items'
```
Cause:
This issue occurs because, while generating the GSTR-1 Excel report for a particular month, [journal_items] contains account moves from both companies. This happens because the [domain] fetches records for both companies, resulting in move [lines] from both companies being included.
However, while generating the Excel report, only one company is selected. As a result, [tax_details_by_move] does not contain the move data for the branch company, which returns None, causing the error to be raised.
Solution:
Pass an empty `{}` for `tax_details` when only a single company is selected.
[journal_items]: https://github.com/odoo/enterprise/blob/3c3641d9f0753c1ca62285667c4a2786c15e2444/l10n_in_reports/models/account_return.py#L877
[domain]: https://github.com/odoo/enterprise/blob/770ffaac14bfcd2c54a7ce6aca27e0010e7884d4/l10n_in_reports/models/account_return.py#L1387-L1393
[lines]:
https://github.com/odoo/enterprise/blob/3c3641d9f0753c1ca62285667c4a2786c15e2444/l10n_in_reports/models/account_return.py#L1074
[tax_details_by_move]:
https://github.com/odoo/enterprise/blob/3c3641d9f0753c1ca62285667c4a2786c15e2444/l10n_in_reports/models/account_return.py#L880
opw-6242824
Forward-Port-Of: odoo/enterprise#118614When a restaurant order is split, the new order now keeps the original fiscal position and pricelist. This ensures the correct taxes and prices continue to apply after splitting, instead of falling back to default values.
Original PR description
When splitting an order, the new order was created without the original's fiscal position and pricelist, so its lines fell back to the default taxes Steps to reproduce: 1. Create a fiscal position with some tax mapping 2. Create a pricelist with some price rules 3. Add the fiscal position and pricelist to the delivery preset 4. Create a restaurant order as delivery 5. Split the order 6. Pay both of them 7. First order will have the default taxes and prices list instead of preset's ones Part of: https://github.com/odoo/odoo/pull/268862 -opw-6246434 Forward-Port-Of: odoo/odoo#273174 Forward-Port-Of: odoo/odoo#272837
17 changes
Enhancements to existing features
This change removes technical e-reporting details from the main invoice view to reduce clutter for regular users. The same information is still recorded in the invoice chatter, where users can follow the e-reporting flow, status, and any blocking issues through a link to the related record.
Original PR description
E-reporting technical fields were displayed directly on invoices, adding noise for regular invoicing users. Hide the e-reporting status columns and technical block from the standard invoice views. Log the relevant e-reporting flow, status and blocking errors in the invoice chatter instead, with a link to the related flow. Also avoid reporting address validation errors on B2C invoices, as they are not required for Flux 10 e-reporting. Task-6273226 Forward-Port-Of: odoo/odoo#271865
This update simplifies the website forum editor by removing unnecessary toolbar options and making the editing experience more consistent. It also fixes a crash in the table menu and prevents overlay styling issues, improving reliability for forum users and editors.
Original PR description
Description of the feature this PR addresses: - Remove unwanted toolbar features (heading, font_family, powerbuttons, undo/redo buttons) - Update toolbar styles in website_forum to keep them consistent - Fix table menu traceback by passing missing `localOverlayContainers` in `website_forum_wysiwyg` config task-6123698 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#263326
Resolved issues and error corrections
When a new company is created, its main employee folder will now be placed in the company’s root folder instead of appearing in an individual user’s My Drive. This keeps employee documents organized in the expected shared company location and avoids confusion for administrators.
Original PR description
Steps to reproduce =================== - Install documents_hr. - Log in with admin. - Create a new company `Test`. - Go to Document and choose the new company (top right). - Go to `My Drive`: a folder named `Employees - Test` has been created. This new folder should be created in the `Company` root instead of the `My Drive,` which will hold all the employee folders. Technical =========== When the main employee folder is created via `_generate_employee_documents_main_folders` `owner_id` falls back to the current user, which leads to computing the `user_folder_id` as `My drive,` and so that's why the newly created folder starts appearing there instead of the `Company` root. This PR addresses the issue and sets the `owner_id` to False, which leads to show the main employee folder in the company root. Task-6267352 Forward-Port-Of: odoo/enterprise#120677
This change prevents an error that could appear when opening the Stock report after the Manufacturing app had been removed. It restores the correct report behavior so users can keep accessing stock information normally after uninstalling the module.
Original PR description
Currently an error occurs when user opens stock report after uninstalling mrp. Steps to replicate: - Install mrp. - Uninstall mrp and open `Stock > Reporting > Stock`. Error: ``` ValueError: Invalid…
Currently an error occurs when user opens stock report after uninstalling mrp.
Steps to replicate:
- Install mrp.
- Uninstall mrp and open `Stock > Reporting > Stock`.
Error:
```
ValueError: Invalid field product.product.is_kits in condition ('is_kits', '=', False)
```
Cause:
- The `mrp` module overrides the `stock.action_product_stock_view` window action domain with `is_kits` field referenced inside [1].
- When mrp is uninstalled, the `is_kits` field is removed from `product.product` but the overridden action domain remains stored in the database. Opening the action then tries to evaluate a domain referencing a non-existent field, resulting in this error.
Solution:
- Restore the original `stock.action_product_stock_view` domain during mrp uninstallation to remove the `is_kits` condition.
[1]: https://github.com/odoo/odoo/blob/c8390638cae4b4dafb805bc0d3a4149fb5194934/addons/mrp/views/product_views.xml#L164-L166
sentry-7332688253
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#269512This change prevents an access error that could block delivery validation for users with limited Sales access when the related order was created by someone else. It keeps the same business rules while allowing the delivery to be completed normally.
Original PR description
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by…
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by another salesperson. ## **Steps to reproduce:** - Install sale_subscription_stock. - Create a user with Sales: Own Documents Only and Inventory Administrator access rights. - Create a sale order as another user. - Validate the delivery with the restricted user. ## **Solution:** During _action_done(), [This line](https://github.com/odoo/enterprise/blob/19.0/sale_subscription_stock/models/stock_picking.py#L45) is checking subscription_state. Since the user does not have read access to the sale order, reading this field raises an access error and prevents the delivery from being validated. As the method only needs to read the subscription state, access the field with sudo() to avoid the unnecessary access error while preserving the existing business logic. Runbot Video : [Video](https://drive.google.com/file/d/1d7U2jTCxaaVk2YJcy3bi2SlYuT-yXMsu/view?usp=drive_link) OPW - 6295712 Forward-Port-Of: odoo/enterprise#122420
Gift card redemptions now correctly account for taxes when the company uses tax-included pricing. This prevents customers from being undercharged or taxed twice, so the deducted gift card amount matches the intended value and the totals stay consistent.
Original PR description
We had a bug when redeeming a gift card when the default taxe of the company was tax_included. Steps to reproduce: ------------------- * Set default 15% tax to bo Tax Included * In PoS, sell a gift card * Use that gift card in a new order > Observation: Deducted amount is 43.48, that's 50 without taxes Why the fix: ------------ We now compute the gift card reward line from a tax-aware amount and choose the unit price based on whether the discount product’s tax is price-included, ensuring we deduct the full intended value while displaying the correct tax. This prevents under-deduction (untaxed base only) and avoids re-adding tax on top, keeping totals and tax lines consistent. opw-5441106 Forward-Port-Of: odoo/odoo#244735
This update fixes a problem in the Egyptian localization setup where token validation could fail during installation. It now correctly recognizes both the newly stored token and the previous hashed format, preventing setup errors and making the process more reliable.
Original PR description
In odoo/odoo#255121, the l10n_eg token flow was simplified to store the token automatically in the IoT config when running the installer, instead of showing a popup requiring the user to save the token manually. However, this broke the flow because previously, a *hash* of the token was being stored in the IoT config, but now the actual token is stored in the config (which allows it to be sent to the DB). The token validation logic was not updated accordingly, so it would try to use the token itself as a hash which would result in an `UnknownHashError`. To fix this, we first check if the provided token matches the stored token exactly. If it doesn't, we assume it is a hash and continue with the old flow as before. Logging statements are added in every failure case to ease debugging in the future. opw-6049363 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273033
The employee attendance balance now shows negative remaining extra hours when that is the real balance, instead of forcing the value to zero. This makes the summary consistent with the other overtime figures and avoids confusing time-off calculations.
Original PR description
## Issue In the attendance view of an employee, a recap of the current extra hours is displayed, showing four values: 1. Total Extra Hours Worked 2. Total Compensable Extra Hours 3. Time Off Taken…
## Issue
In the attendance view of an employee, a recap of the current extra hours is displayed, showing four values:
1. Total Extra Hours Worked
2. Total Compensable Extra Hours
3. Time Off Taken from Extra Hours
4. Remaining Extra Hours
Each of the above values can be negative but the last one, which can seem odd as it appears to be calculated from the other values.
<img width="299" height="168" alt="6293174-before" src="https://github.com/user-attachments/assets/4377e2fd-f5f2-41a4-a82b-6f2598378499" />
## Steps to reproduce
1. Install *HR Attendance Holidays* (`hr_holidays_attendance`)
2. In Settings, toggle *Absence Management* and *Display Extra Hours*
3. For an employee E:
- In the Payroll tab, set the Working Hours to the *Standard 40 hours/week* schedule
- In the Settings tab, set the Overtime Ruleset to the *Default Ruleset*, and toggle the *Give back as time off* action for the *Employee Schedule Rule* rule
4. Create an attendance for employee E:
- Any day where they are expected to work 8 hours
- From 10am to 5pm (6 hours with lunch)
5. In the Employees app, go to employee E and click the *Monthly Hours* smart button
6. __In the *Balance* recap above the list of attendances, the *Remaining Extra Hours* row shows 00:00, which seems wrong compared to the other fields above (*Total Extra Hours Worked* and *Total Compensable Extra Hours*) which appear negative.__
## Cause
The `unspent_overtime` (*Remaining Extra Hours* in the balance recap) is computed by adding positive values, making it strictly positive.
https://github.com/odoo/odoo/blob/30c9e8c5b1e34b94c8aab8681e2c051a3b70f013/addons/hr_holidays_attendance/models/hr_employee.py#L62-L65
This was added by https://github.com/odoo/odoo/commit/2144bcfba1ac53c82fc7f2870a72bb13abee97e4, with no justification on why this value needs to be positive.
## Impact on "Time Off taken from Extra Hours"
Before this change, after following the above steps, a value of `-2:00` would be displayed in the *Time Off Taken from Extra Hours* row. This is no longer the case after this fix, since the `'unspent_compensable_overtime'` (*Remaining Extra Hours*) value is used to compute that row:
https://github.com/odoo/odoo/blob/f7fb0a941d6bac39b7057db36f57be079559912c/addons/hr_holidays_attendance/static/src/views/extra_hours_list_view.js#L39-L42
Instead, a value of `00:00` is shown. Before, we were substracting 0 hour of `unspent_compensable_overtime` to the -2 hours of `compensable_overtime`, now we are subectracting -2 hours of `unspent_compensable_overtime` to the same -2 hours of `compensable_overtime`. This is a side effect that was ignored, as it seems to make at least as much sense as showing `-2:00`.
<img width="321" height="179" alt="6293174-after" src="https://github.com/user-attachments/assets/907d5fb8-0c36-4b2e-bca7-1cec41baf22b" />
opw-6293174
Forward-Port-Of: odoo/odoo#271272This fix ensures the product cost is calculated correctly when subcontracting and dropshipping are used together. When supplier bills are posted, the product value now reflects the full production cost instead of being undercounted, which keeps inventory valuation accurate.
Original PR description
*: mrp_subcontracting_{dropshipping, purchase} ### Steps to reproduce: - In the settings: Enable subcontracting, dropshipping - Create a storable dropshipped product FP with a set vendor for 5$ and…
*: mrp_subcontracting_{dropshipping, purchase}
### Steps to reproduce:
- In the settings: Enable subcontracting, dropshipping
- Create a storable dropshipped product FP with a set vendor for 5$ and subcontracting BOM: 1 X COMP. Value this product in avco perpetual
- Set the component to resupply subcontractor and standard price to 2$
- Create and confirm a sale order for 1 unit fo FP
- Validate the resupply to the subcontractor and then the dropship
> The FP standard price shoul dhave been updated to 5$ + 2$ = 7$
- Create and post a bill from the PO for 10$ rather than 5
#### > The FP standard price should have been updated to 11$ rather than 12$
Cause of the issue:
Posting the bill will call the `_set_value` method to re-evaluate the product in terms of the newly recorded `account.move`: https://github.com/odoo/odoo/blob/161715c850496d3683baa5d1600380470d0b5ff5/addons/stock_account/models/stock_move.py#L393-L395 Now, the issue is that due to our config, there are two relevant moves linked to the `order_line`: the final move of the subcontracted production (which `is_in`) and the dropship move going from the subcontractor to the customer. When it comes to the subcontracted move, it is appropriately valuated at 12$ by the `_get_value_from_account_move` because of this override which adds the components value via the extra cost since the move has a `production_id`:
https://github.com/odoo/odoo/blob/161715c850496d3683baa5d1600380470d0b5ff5/addons/mrp_subcontracting_purchase/models/stock_move.py#L14-L38 However, the dropship move will not add this extra cost (as no override sets it to have the same value as the subcontracted production it comes from) so that this move is valuated at 10$. This explains why the value of the avco product is then updated to 11$ since (12 + 10) /2 = 11
Note that the issue is not reproducible in the case of regular subcontracting since in that case the receipt from `subcontractor` to `stock` is not valuated.
opw-6318035
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#272813Overtime is now calculated correctly when an employee’s attendance spans midnight and another attendance is added on the following day. This ensures all overlapping work time is included, so overtime totals are accurate and employees are neither undercounted nor left with missing overtime.
Original PR description
Issue: ---------------------------------------- The overtime calculation ignores attendances overlapping midnight when creating an attendance on the day they overlap. Steps to reproduce:…
Issue:
----------------------------------------
The overtime calculation ignores attendances overlapping midnight when creating an attendance on the day they overlap.
Steps to reproduce:
----------------------------------------
- Have the standard 8 hours per day working schedule
- Use the default overtime ruleset:
- Quantity, per day, more than the contract
- Have no rule on weeks
- Create an attendance of 8+ hours overlapping midnight on a day:
- From 10pm to 10am (2h + 10h = 12h)
- Create another attendance on the day the first ended:
- From 2pm to 6pm (4h)
- The first attendance has 2h of overtime:
- 0h from the first worked day (from 10pm to midnight = 2 < 8)
- 2h on the next day (10h worked from midnight to 10am)
- The second attendance have 0h of overtime even though it should be 4h
- We only considered this attendance in the calculation, ignoring the 10h worked in the morning
Cause:
----------------------------------------
In `_update_overtime()` we create a domain to include all useful attendances in the calculation. As all rules are based on days, the domain will use the date of the attendance to get overlapping attendances. But the date of the attendance is the date of its `check_in` ([src](https://github.com/odoo/odoo/blob/4235b48c86077bd5bceb9e817cc45b2eec8697e8/addons/hr_attendance/models/hr_attendance.py#L91)). So when creating the second attendance, the domain only fetches attendance with their `date` on the same date as the `check_in` of the second one. This excludes the first one even though it overlaps on the same day.
Solution:
----------------------------------------
Don't use `date` but `check_in` and `check_out` in the domain to really get all attendances overlapping a day with an updated attendance.
As this domain was used on both `hr.attendance` and `hr.attendance.overtime.line`, we adapt it so it uses the correct fields (`time_start` and `time_stop`) from the overtime lines.
opw-6253777
Forward-Port-Of: odoo/odoo#272447This change prevents a crash in Manufacturing Planning when a negative forecast quantity is entered. If there is leftover negative quantity, it is now correctly applied to the first forecast period, keeping the plan consistent.
Original PR description
Steps to reproduce: - Fresh DB - Add a negative number to the forecast demand in the last period Cause: A variable was used without declaration Fix: According to odoo/enterprise#56128, it was intended that any remaining negative quantity to add should be added to the first forecast. Forward-Port-Of: odoo/enterprise#122261
This update adds meaningful alternative text to the website’s language selector flags when the flag is the only visible label. It improves accessibility for screen readers and gives search engines more context, while keeping the visual design unchanged.
Original PR description
Steps to reproduce: 1. Enable the language selector in the website header. 2. Enable the "Inline" and "Flag" options. 3. Inspect the flag images rendered in the inline variant. Issue: Flag images in the list items have an empty `alt=""` attribute in "Flag only" mode, where the flag is the sole visual indicator of the language, making the selector inaccessible to screen readers and providing no context for search crawlers. Expected behavior: Inline + Flag should have a descriptive ALT tag since there is no adjacent text or code to identify the language, the flag is not decorative. opw-6246464 Forward-Port-Of: odoo/odoo#273025 Forward-Port-Of: odoo/odoo#271362
This change fixes a problem that could cause the Spanish Verifactu module to fail during installation on databases that already contain accounting entries. It reduces the risk of timeouts or memory errors, making installation more reliable for existing customers.
Original PR description
### Description: When trying to install the module `l10n_es_edi_verifactu` on a database that already has moves, it is possible to encounter a timeout or a memory error. This is caused by the compute `l10n_es_edi_verifactu_state` and `l10n_es_edi_verifactu_clave_regimen`, both compute linked to the new model `l10n_es_edi_verifactu.document`. ### Reference: opw-6293590 Forward-Port-Of: odoo/odoo#271550
Audio files shared through Documents will no longer open in browser preview by default. This prevents preview failures in Chrome and avoids unexpected media streaming behavior when a shared link is opened.
Original PR description
**Steps to reproduce:** - Install Documents app - Upload a sound file (mp3 for example, but the behavior is the same for other formats) - Share the document and copy the link - Log out - Paste the…
**Steps to reproduce:**
- Install Documents app
- Upload a sound file (mp3 for example, but the
behavior is the same for other formats)
- Share the document and copy the link
- Log out
- Paste the link
- Click on preview button
- Media is working fine on Firefox
- Media won't read on Chrome
```
Loading media from '' violates the following Content Security Policy directive: "default-src 'none'".
Note that 'media-src' was not explicitly set, so 'default-src' is used as a fallback.
The action has been blocked.
```
**Issue:**
Since [1] default CSP Headers are too strict for Chrome default media rendering, which breaks the file preview (and force user download).
This only impacts Chrome as they seem to render generate `<video><source>` elements to render the file which triggers a secondary request and fails due to the CSP constraint.
**Fix:**
Could re-apply the header fix of 17.4 (see [2]), but it seems better to block the preview of audio files as well by default (to match how we manage videos).
(Note: we don't want to be used as a media streaming platform)
[1] (set csp to none by default) https://github.com/odoo/odoo/commit/64beb80205dffe4b432c8b5813a3271b073fa85e
[2] (similar issue which was not fixed in 18.0+) https://github.com/odoo/enterprise/commit/a7af78eeb2b9763045a5bda8714172f5e7402df8
[3] (mp4 preview removed) https://github.com/odoo/enterprise/commit/ea88cf7c6d5f077b60fb59347659507fded0e2fe
opw-6235043
Forward-Port-Of: odoo/enterprise#119644This change ensures the background process that posts draft accounting entries only records its progress when it actually succeeds, or when a known user-facing error is handled. This prevents the system from incorrectly marking work as completed after an unexpected failure, which helps keep accounting operations reliable.
Original PR description
The previous fix commits progress even when an unexpected exception escaped the loop iteration when _autopost_draft_entries. Now progress is only committed on success or when a UserError is explicitly handled. Reference: https://github.com/odoo/odoo/pull/271509 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273115
This fix closes a loophole in the Point of Sale so employees with minimal permissions can no longer create negative quantity lines by typing the minus key on a keyboard. It keeps the keyboard behavior aligned with the disabled on-screen button, ensuring access rules are applied consistently.
Original PR description
Currently minimal rights employee cannot select the "+/-" button to have a negative quantity line. However if they have a keyboard and press the "-" key they can modify the quantity to negative. Steps to reproduce: ------------------- * Modify the shop settings, give some employee minimal rights * Open shop and use the minimal employee as cashier * Add a product to the order * Press the "-" key on the keyboard > The line quantity becomes -1 Why the fix: ------------ The button on the product screen is disabled for the employee with minimal rights https://github.com/odoo/odoo/blob/4a2aa33ded628200935b22c501a5f94c21dffb1f/addons/point_of_sale/static/src/app/screens/product_screen/product_screen.js#L154 We extend that to the input key "-". opw-6248098 Forward-Port-Of: odoo/odoo#267748
This fixes an issue that could block POS managers from saving changes to a POS configuration when self-order images had been uploaded by someone else. With this update, managers without Settings or Admin access can edit the POS normally, avoiding an access error during routine configuration work.
Original PR description
When editing a POS config, `_ensure_public_attachments` wrote `public=True` on the self-ordering background/home images on every write. These images are Many2many attachments created with a `res_model` but no `res_id`, so the attachment access check denies write to any non-system user who is not their creator.
As a result, a POS manager without Settings/Admin rights could not edit a config whose images were uploaded by another user (e.g. an admin during setup), getting:
AccessError: Sorry, you are not allowed to access this document.
(Operation: write) - Records: ir.attachment(...), User: ...
Steps to reproduce:
1. Enable self-ordering on a POS and select a background image
2. Set self-ordering back to disabled
3. Log in as a POS admin without Admin/Settings rights
4. Try to edit the POS -> error
opw-6331261
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#2732992 changes
Resolved issues and error corrections
This update ensures that products whose barcode also matches a GS1 pattern are recognized correctly as product scans. It prevents the system from misreading repeated scans as a large quantity change, which avoids incorrect delivery lines and stock quantities.
Original PR description
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings…
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings enable "Default GS1 Nomenclature" - Create a storable product P with the barcode 3701762412212 - Create and confirm a delivery for 2 units of P and set the qty to 2 - Go to the barcode app and open your delivery - Scan 3701762412212 > The line of P is now selected with a quantity of 1/2 - Scan 3701762412212 #### > A new line is created for 1762411 units ### Cause of the issue: According to the GS1 nomenclature, the barcode 3701762412212 matches the scan of a quantity of "1762412" units of the lot name "2". As the scan of the of the product match a pattern for the GS1 nomenclature before matching a product, its barcode data is expected to be reset by these lines: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1320-L1324 In order to bypass the GS1 parser and to add 1 unit of the product. This is what happen on the first scan. However, performing the first scan also selects the associated line and, hence on the second scan the lines just above this check do set the product to match the product of the current line: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1294-L1320 In particular, we do not bypass the result provided by the GS1 parser and add `1762412` units of the product. opw-6175621 Forward-Port-Of: odoo/enterprise#122256 Forward-Port-Of: odoo/enterprise#120035
This fix ensures the SAF-T export uses the correct official grouping code when account numbers are sliced. It prevents the report from showing an incorrect code, helping maintain accurate statutory reporting.
Original PR description
Steps to reproduce: - change 1920 Banck account to 19204321 - go in general ledger and export to "SAF-T" Issue: The grouping code is 4321 Grouping code should match official grouping code. As a matter of fact the chart of account seems to match thos grouping account if we slice them correctly. opw-6285078 Forward-Port-Of: odoo/enterprise#121932
9 changes
Enhancements to existing features
This change removes technical e-reporting fields from standard invoice views, making invoices easier to read for regular users. The key e-reporting details and blocking issues are now shown in the chatter with a link to the related flow, and unnecessary address validation warnings are no longer shown on B2C invoices.
Original PR description
E-reporting technical fields were displayed directly on invoices, adding noise for regular invoicing users. Hide the e-reporting status columns and technical block from the standard invoice views. Log the relevant e-reporting flow, status and blocking errors in the invoice chatter instead, with a link to the related flow. Also avoid reporting address validation errors on B2C invoices, as they are not required for Flux 10 e-reporting. Task-6273226 Forward-Port-Of: odoo/odoo#271865
Backorder creation when validating very large receipts is now much faster and more reliable. The change reduces unnecessary processing and avoids database memory issues, helping large warehouse operations finish without timeouts.
Original PR description
## The Problem Validating receipts with a large number of operations by creating a backorder was timing out due to $O(N*M)$ filtering inside `_get_qty_received_without_self`, where N is the number of…
## The Problem Validating receipts with a large number of operations by creating a backorder was timing out due to $O(N*M)$ filtering inside `_get_qty_received_without_self`, where N is the number of moves in the picking, and M is the number of moves being processed for valuation. This happened while computing price units for moves one by one: each move filtered all picking moves to find the ones with the same `product_id`. Another issue was a PostgreSQL `"memory exhausted"` error caused by generating a large number of OR'ed conditions, equal to the number of processed moves. ## The Solution The massive filtering was fixed by filtering moves of the `purchase_line` instead of the `picking`, which is typically associated with only a few moves. This is still correct as the loop just after already ignores moves that don't have the same `purchase_line_id` of `self` anyways. The PostgreSQL error was fixed by grouping moves by `location_dest_id` and generating one condition per location using an `in` clause, which is typically much smaller than generating one condition per move. ## Benchmark Benchmark on a customer database, validating a receipt with 10k+ operations by creating a backorder: ```text Time: timeout -> 6 min ``` OPW-6272667 Forward-Port-Of: odoo/odoo#272603 Forward-Port-Of: odoo/odoo#269350
Resolved issues and error corrections
Restaurant PoS users can now merge or unmerge tables without running into permission errors. The update also hides the “Edit Plan” option for these users when they do not have the required access, preventing confusing failures during service.
Original PR description
This commit fixes access errors encountered by PoS users when merging or unmerging tables. The changes include: - Granting PoS users write access to restaurant tables required for the merge/unmerge flow. - Hiding the "Edit Plan" button for PoS users, as it requires write/create access to the floor plan. Task-6352316
WebP images are now checked against the same maximum size limit as other image formats when users upload them. This prevents very large images from being accepted and helps keep the system consistent and more reliable.
Original PR description
Since 17.0, `webp` images can be uploaded at any resolution, whereas every other format is refused above IMAGE_MAX_RESOLUTION (50 Mpx) when the attachment is created on the server. Root cause…
Since 17.0, `webp` images can be uploaded at any resolution, whereas every other format is refused above IMAGE_MAX_RESOLUTION (50 Mpx) when the attachment is created on the server. Root cause =========== `ImageProcess` grouped webp together with empty sources and SVG and set `self.image = False`, returning before the `verify_resolution` check. As a result the resolution limit enforced for `png/jpeg/...` was never applied to `webp`. Fix === Split `webp` out of the skip branch: it is still not processed as before, but its resolution is now read from the RIFF header with `get_webp_size()` and checked against `IMAGE_MAX_RESOLUTION`, so oversized webp images are refused on upload like any other format. Steps to reproduce =================== 1. Edit any page with the website editor 2. Upload a `webp` image larger than 50 Mpx (e.g. 8000x8000) => The image is accepted, while a `png/jpeg` of the same size is refused task-4134430 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273140 Forward-Port-Of: odoo/odoo#273010
This fix ensures the SAF-T export uses the correct official grouping codes for Norwegian accounts. It prevents certain account numbers from being sliced incorrectly, which could otherwise produce the wrong code in exported accounting reports.
Original PR description
Steps to reproduce: - change 1920 Banck account to 19204321 - go in general ledger and export to "SAF-T" Issue: The grouping code is 4321 Grouping code should match official grouping code. As a matter of fact the chart of account seems to match thos grouping account if we slice them correctly. opw-6285078 Forward-Port-Of: odoo/enterprise#121932
This change prevents a memory or timeout problem that could occur when installing the Spanish VeriFactu module on databases that already contain accounting entries. It makes the installation process more reliable and avoids failures during setup.
Original PR description
### Description: When trying to install the module `l10n_es_edi_verifactu` on a database that already has moves, it is possible to encounter a timeout or a memory error. This is caused by the compute `l10n_es_edi_verifactu_state` and `l10n_es_edi_verifactu_clave_regimen`, both compute linked to the new model `l10n_es_edi_verifactu.document`. ### Reference: opw-6293590 Forward-Port-Of: odoo/odoo#271550
This update fixes a problem where uploaded fonts with spaces in their filenames were not working correctly on websites. It also ensures font weight information is kept properly, so the right font style is displayed.
Original PR description
When uploading a font file "FontName 123 Light.otf" the baseFontName needs to be quoted in the font-face CSS to be valid. Single font files parsing for the shortestNamedFont now also correctly keeps…
When uploading a font file "FontName 123 Light.otf" the baseFontName needs to be quoted in the font-face CSS to be valid.
Single font files parsing for the shortestNamedFont now also correctly keeps the weight for the targetFonts.
Description of the issue/feature this PR addresses:
Uploaded fonts with spaces in the name are not working.
Current behavior before PR:
When uploading a font with a space in the filename like "FontName 123 Light.otf" the css declaration in the attachement is wrong and not working:
```css
@font-face {
font-family: FontName 123 Light;
font-style: normal;
font-weight: 400;
src: url("/web/content/1057/FontName 123 Light.otf");
}@font-face {
font-family: FontName 123 Light;
font-style: normal;
font-weight: 400;
src: url("/web/content/1057/FontName 123 Light.otf");
}
```
Desired behavior after PR is merged:
The font name is now correctly quoted and the font attributes are no longer overwritten for the shortestNameFont:
```css
@font-face {
font-family: "FontName 123 Light";
font-style: normal;
font-weight: 400;
src: url("/web/content/1057/FontName 123 Light.otf");
}@font-face {
font-family: "FontName 123 Light";
font-style: normal;
font-weight: 300;
src: url("/web/content/1057/FontName 123 Light.otf");
}
```
Info @wt-io-it
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#268842This update ensures that product barcodes are recognized correctly even when they also look like a GS1 barcode pattern. It prevents the system from mistaking a normal product scan for a quantity or lot scan, avoiding incorrect quantities being added to delivery lines.
Original PR description
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings…
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings enable "Default GS1 Nomenclature" - Create a storable product P with the barcode 3701762412212 - Create and confirm a delivery for 2 units of P and set the qty to 2 - Go to the barcode app and open your delivery - Scan 3701762412212 > The line of P is now selected with a quantity of 1/2 - Scan 3701762412212 #### > A new line is created for 1762411 units ### Cause of the issue: According to the GS1 nomenclature, the barcode 3701762412212 matches the scan of a quantity of "1762412" units of the lot name "2". As the scan of the of the product match a pattern for the GS1 nomenclature before matching a product, its barcode data is expected to be reset by these lines: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1320-L1324 In order to bypass the GS1 parser and to add 1 unit of the product. This is what happen on the first scan. However, performing the first scan also selects the associated line and, hence on the second scan the lines just above this check do set the product to match the product of the current line: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1294-L1320 In particular, we do not bypass the result provided by the GS1 parser and add `1762412` units of the product. opw-6175621 Forward-Port-Of: odoo/enterprise#122256 Forward-Port-Of: odoo/enterprise#120035
The payment flow now confirms that the self-order point of sale is actually set up as a kiosk before continuing. It also checks that an IoT payment method is configured, helping prevent payment errors and reducing failed transactions.
Original PR description
This commit makes the payment endpoint more robust by verifying the POS config is indeed a kiosk, and that it has an IoT payment method configured. Forward-Port-Of: odoo/enterprise#121894
2 changes
Resolved issues and error corrections
This fix ensures the SAF-T export uses the correct official grouping code when account numbers are sliced. It prevents wrong codes from appearing in the general ledger export, improving the accuracy of accounting reports.
Original PR description
Steps to reproduce: - change 1920 Banck account to 19204321 - go in general ledger and export to "SAF-T" Issue: The grouping code is 4321 Grouping code should match official grouping code. As a matter of fact the chart of account seems to match thos grouping account if we slice them correctly. opw-6285078 Forward-Port-Of: odoo/enterprise#121932
Bookings made through Reserve with Google will now create contacts using the customer’s first and last name from Google, instead of falling back to the email address. This improves the accuracy of contact records and makes appointment details display the customer’s real name in Odoo.
Original PR description
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to…
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to _mail_find_partner_from_emails. The new res.partner was therefore created with its name falling back to the email, see https://github.com/odoo/odoo/blob/aa7b5921191a0ff53ef1cc32af99fe458c45c0da/addons/mail/models/res_partner.py#L177 That name then flows into the calendar.event name, the attendee common_name and the contact details, all showing the email instead of the customer name. The module has read neither field since it was added in https://github.com/odoo/enterprise/commit/2e855b910173b56e8501d0ebe9ee6f83ac5845bc. Build the booker name from given_name and family_name and pass it with the email through formataddr in google_reserve_booking_create, so a newly created partner is named after the customer. A partner matched on an existing email keeps its current name. Steps to reproduce: 1. Enable Reserve with Google on an appointment type. 2. Book a slot from Google Maps with given name John and family name Doe. 3. Open the created booking and its contact in Odoo. => the contact name is the email instead of John Doe Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6232318) opw-6232318 Forward-Port-Of: odoo/enterprise#120604
19 changes
Enhancements to existing features
Peruvian electronic delivery slips now display a clearer title so they are easier to identify. They also include additional required transport information for both public and private shipments, helping ensure compliance with local delivery guide rules.
Original PR description
Peruvian transport guidelines specifies that the delivery guide should be explicitly and easily identifiable and should display mandatory transport information. This commit targets to achieve this: - Sent peruvian electronic delivery slips now explicit what they are on the doc title - added new mandatory transport data for public and private transports task-5866397
When a user manually sets allocated hours on a task, those values are now preserved even if the task dates change later. This prevents the system from overwriting user input and helps keep planning and time estimates consistent.
Original PR description
Before this commit, updating the planned start date or deadline recomputed the allocated hours automatically, even when the user had manually set a custom allocated hours value. In this commit ensures that once the allocated hours is manually updated by the user, the system marks the value as manually defined and prevents further automatic recomputation based on task scheduling changes.
The AI-related Discuss client action now uses a reactive signal for its action state instead of a plain property. This makes the interface update more reliably when the action changes, improving responsiveness and reducing the chance of stale behavior for users.
Original PR description
Pr community: https://github.com/odoo/odoo/pull/273286
A new “Daily Rates” smart button is added to rental pricelists, opening a calendar view of dated pricing rules. This makes it easier to review seasonal rates at a glance and create pricing periods by selecting dates directly on the calendar.
Original PR description
Seasonal rental prices are set through pricelist rules with validity dates. This commit adds a "Daily Rates" smart button on the pricelist that opens a month calendar of its dated rules, where selecting a period creates a single rule spanning it. task-4968689
The paid time off allocation process now automatically suggests postponed leave entries for employees who were absent during the relevant periods, reducing manual work during payroll runs. The interface also makes it easier to see which leaves are lost, postponed, or already allocated, improving clarity for payroll users.
Original PR description
Improve the paid time off allocation wizard by automatically suggesting postponed leaves for employees who were not working during the relevant periods and by enhancing the visibility of allocation information. - If an employee is absent in December, we prefill postpone N-1. - If an employee is absent the whole year, we prefill postpone N-2. - Improve the UI to better highlight lost leaves, postponed leaves, and already allocated leaves. - Remove the wizard form view, as the wizard is only used from the payrun flow and all form fields are hidden. Task: 6279404
Resolved issues and error corrections
When a sign template is duplicated, its roles are now copied too instead of being shared with the original template. This prevents changes made on one template from unexpectedly affecting another, keeping each document setup independent.
Original PR description
When duplicating a sign template, its sign items were copied but their `responsible_id` was kept as a reference to the same `sign.item.role` records. As a result, editing a role on one template (e.g. assigning a partner through `assign_to`) leaked to the other template sharing it. Copy the role when copying a sign item so each template owns its own roles. task-6288951 Forward-Port-Of: odoo/enterprise#121411 Forward-Port-Of: odoo/enterprise#119864
This update prevents an error that could occur when generating the GSTR-1 Excel report in a multi-company environment, especially when only one company is selected for export. It ensures the report completes successfully instead of failing during Excel generation, making tax reporting more reliable for users with branch companies.
Original PR description
Steps to reproduce: - Install `l10n_in_reports` module(Indian Localisation) - Create a branch in `IN Company` > Select both - Create separate invoices for each company - Created the GSTR-1 report for…
Steps to reproduce:
- Install `l10n_in_reports` module(Indian Localisation)
- Create a branch in `IN Company` > Select both
- Create separate invoices for each company
- Created the GSTR-1 report for both company
- While generating Excel, select only main company
Traceback:
```py
File "/home/odoo/src/enterprise/19.0/l10n_in_reports/models/account_return.py", line 2537, in action_generate_gstr1_xlsx
gstr1_json = self._get_l10n_in_gstr1_json()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/19.0/l10n_in_reports/models/account_return.py", line 1071, in _get_l10n_in_gstr1_json
'b2cs': _get_b2cs_json(AccountMoveLine.search(self._get_section_domain('b2cs'))),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/19.0/l10n_in_reports/models/account_return.py", line 672, in _get_b2cs_json
for line, line_tax_details in tax_details.items():
^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'items'
```
Cause:
This issue occurs because, while generating the GSTR-1 Excel report for a particular month, [journal_items] contains account moves from both companies. This happens because the [domain] fetches records for both companies, resulting in move [lines] from both companies being included.
However, while generating the Excel report, only one company is selected. As a result, [tax_details_by_move] does not contain the move data for the branch company, which returns None, causing the error to be raised.
Solution:
Pass an empty `{}` for `tax_details` when only a single company is selected.
[journal_items]: https://github.com/odoo/enterprise/blob/3c3641d9f0753c1ca62285667c4a2786c15e2444/l10n_in_reports/models/account_return.py#L877
[domain]: https://github.com/odoo/enterprise/blob/770ffaac14bfcd2c54a7ce6aca27e0010e7884d4/l10n_in_reports/models/account_return.py#L1387-L1393
[lines]:
https://github.com/odoo/enterprise/blob/3c3641d9f0753c1ca62285667c4a2786c15e2444/l10n_in_reports/models/account_return.py#L1074
[tax_details_by_move]:
https://github.com/odoo/enterprise/blob/3c3641d9f0753c1ca62285667c4a2786c15e2444/l10n_in_reports/models/account_return.py#L880
opw-6242824
Forward-Port-Of: odoo/enterprise#118614This update corrects how the current year’s earnings account is classified and simplifies a related balance sheet line in the Luxembourg reports. It helps ensure the financial statements show the result brought forward more accurately and with less complexity.
Original PR description
This commit addresses the account type for the current year earnings and simplifies the calculation for the "Result brought forward" line in the Luxembourg balance sheet reports.
Modifications:
* Changed the account type of account 142 ("Result for the financial year") from `equity_unaffected` to standard `equity`.
* Simplified the formula for the Balance Sheet line "Profit or loss brought forward" (codes `LU_BS_319` and `LU_BSABR_319`).
* The new formula simply targets the `14` accounts while explicitly excluding `142`.
Community PR: odoo/odoo#272362
Ticket [link](https://www.odoo.com/odoo/project.task/6059571)
opw-6059571
Forward-Port-Of: odoo/enterprise#122097
Forward-Port-Of: odoo/enterprise#121891This update fixes an error that could prevent PDF generation for certain Guatemala vendor bills, especially FESP documents with withholding taxes. Users can now download the bill PDF successfully after sending it to SAT, avoiding interruptions in the invoicing workflow.
Original PR description
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Create a new vendor bill with: - Vendor: GT Company - GT Document Type: `FESP` - Add taxes `VAT Withholding…
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Create a new vendor bill with: - Vendor: GT Company - GT Document Type: `FESP` - Add taxes `VAT Withholding 12%` and `ISR Withholding 5%` in Invoice lines. - `Confirm` the bill and `Send to SAT`. - From the gear icon, click `Download` > `PDF`. **Error1:** `KeyError: 'gran_total'` **Error2:** `KeyError: 'retencion_grand_total'` **Root Cause:** In commit [1], the code at [2] missed calling `_l10n_gt_edi_add_base_values()` before `_l10n_gt_edi_add_withholding_values()`. However, `_l10n_gt_edi_add_withholding_values()` uses the `gran_total` value, which is initialized by `_l10n_gt_edi_add_base_values()`, resulting in a `KeyError`. Additionally, the report template at [3] references `retencion_grand_total` instead of the correct key `retencion_gran_total`, causing another `KeyError`. **Fix:** This commit prevents errors and ensures users can successfully download the PDF by applying a fix similar to [4], [1]: https://github.com/odoo/enterprise/commit/44afd19e4ed0827e343af0e584c81e579935c9e8 [2]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/models/account_move.py#L305-L328 [3]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/views/report_invoice.xml#L72 [4]: https://github.com/odoo/enterprise/blob/9846b337cfe1876017c7c2ce3041569d7a2ac03f/l10n_gt_edi/models/account_move.py#L790-L800 opw-6323049 Forward-Port-Of: odoo/enterprise#122398 Forward-Port-Of: odoo/enterprise#122030
This update ensures invoices sent through the Guatemalan EDI service are encoded correctly, so names and product descriptions with accents or other special characters are preserved. It reduces failed submissions and prevents certified documents from coming back with missing or corrupted text.
Original PR description
**Steps to reproduce:** * Install the **l10n_gt_edi** module. * Configure a Guatemalan company with valid Infile credentials in the settings. * Create a product or customer with special characters…
**Steps to reproduce:**
* Install the **l10n_gt_edi** module.
* Configure a Guatemalan company with valid Infile credentials in the settings.
* Create a product or customer with special characters (e.g. `ñ`, `á`, `é`) in their name.
* Create a customer invoice containing this product/customer.
* Confirm the invoice to trigger the EDI send to the SAT (Infile).
**Observed behavior:**
* Infile intermittently rejects the invoice due to validation errors, or accepts it but the resulting certified XML has truncated or malformed text exactly where the special characters were located.
**Cause:**
* Odoo uses the `requests.post()` library to send the XML payload to Infile. By default, `requests` encodes string payloads using `latin-1` unless told otherwise.
* Because the request was missing the explicit `Content-Type: application/xml` header and the XML string was not explicitly encoded to `utf-8` before sending, Infile parsed the payload using an incorrect encoding. This caused it to drop or misinterpret special characters, leading to validation failures or corrupted XML content.
**Fix:**
* Explicitly include the `'Content-Type': 'application/xml'` header in the request to Infile.
* Explicitly encode the `xml_data` payload to `utf-8` (`xml_data.encode('utf-8')`) before passing it to `requests.post()` to guarantee the correct encoding is sent over the wire.
opw-6315654
Forward-Port-Of: odoo/enterprise#121729Selling combo products in the Kenyan Point of Sale will no longer be blocked by an eTIMS registration warning when only the items inside the combo are registered. The system now correctly ignores the combo wrapper item for eTIMS checks, so checkout can proceed normally and receipts are generated without errors.
Original PR description
Steps to reproduce ------------------ 1. Install l10n_ke_edi_oscu_pos. 2. Select the Kenyan company. 3. Enable eTIMS on the PoS. 4. Register the products inside a combo, but not the combo itself. 5.…
Steps to reproduce ------------------ 1. Install l10n_ke_edi_oscu_pos. 2. Select the Kenyan company. 3. Enable eTIMS on the PoS. 4. Register the products inside a combo, but not the combo itself. 5. Sell the combo in the PoS. Observation ----------- We see a warning that the combo must be registered to eTIMS, and the order can't be validated. What's happening ---------------- In the PoS a combo adds a 0 price parent line for the combo product, but the combo is not a real item to send to eTIMS, only the products inside it are, and (as per step 4) the combo is not registered. `checkEtimsFields` sees the combo as not registered, so it raises the warning in `showUnregisteredProductsWarning` and blocks the payment in `validateOrder`. Fix --- In the backend, we skip sending the parent combo line to eTIMS, and on the frontend, we make the combo parent line not need eTIMS registration, so the warning and the block don't apply to it. opw-6253306 Forward-Port-Of: odoo/enterprise#122179 Forward-Port-Of: odoo/enterprise#119362
This change makes the “Undo reconciliation” action bypass extra checks so the reconciliation line can be reset correctly. It helps users reverse a reconciliation without being blocked by validation steps that are not needed in this case.
Original PR description
When undoing the reconciliation from the "undo reconciliation" button. We want to bypass all the checks to be able to reset the line. no task id Forward-Port-Of: odoo/enterprise#122166 Forward-Port-Of: odoo/enterprise#121611
This fix ensures that documents signed through eMSigner are saved with the final signed PDF, instead of sometimes keeping the original uploaded file. It matters because users will now receive the correct completed document after signing, improving trust and avoiding rework.
Original PR description
Version: - saas-19.3 Steps to reproduce: - Create a sign request using the eMSigner authentication method. - Complete the signing process. - Download the completed document. Issue: - Users received the original uploaded PDF instead of the signed PDF after completing the signing process through eMSigner. Cause: - After the BinaryValue migration, the completed document was initialized with the original document (document.raw) and only replaced with the eMSigner response for large compressed files. As a result, non-compressed responses stored the original document instead of the signed PDF returned by eMSigner. Fix: - Always use the signed document returned by eMSigner (decrypted_data) to create the completed document. Decode the base64 response and, for large files, decompress it before storing it as binary content. task-6329040 Forward-Port-Of: odoo/enterprise#121628
When a new company is created, its main employee folder will now be placed in the Company root instead of being created inside a personal My Drive area. This makes the folder structure clearer and ensures employee folders are organized where users expect them.
Original PR description
Steps to reproduce =================== - Install documents_hr. - Log in with admin. - Create a new company `Test`. - Go to Document and choose the new company (top right). - Go to `My Drive`: a folder named `Employees - Test` has been created. This new folder should be created in the `Company` root instead of the `My Drive,` which will hold all the employee folders. Technical =========== When the main employee folder is created via `_generate_employee_documents_main_folders` `owner_id` falls back to the current user, which leads to computing the `user_folder_id` as `My drive,` and so that's why the newly created folder starts appearing there instead of the `Company` root. This PR addresses the issue and sets the `owner_id` to False, which leads to show the main employee folder in the company root. Task-6267352 Forward-Port-Of: odoo/enterprise#120677
This change prevents an access error that could block delivery validation for users with limited Sales access. It ensures the system can safely check the subscription status needed for the delivery process, without exposing unrelated sales documents.
Original PR description
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by…
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by another salesperson. ## **Steps to reproduce:** - Install sale_subscription_stock. - Create a user with Sales: Own Documents Only and Inventory Administrator access rights. - Create a sale order as another user. - Validate the delivery with the restricted user. ## **Solution:** During _action_done(), [This line](https://github.com/odoo/enterprise/blob/19.0/sale_subscription_stock/models/stock_picking.py#L45) is checking subscription_state. Since the user does not have read access to the sale order, reading this field raises an access error and prevents the delivery from being validated. As the method only needs to read the subscription state, access the field with sudo() to avoid the unnecessary access error while preserving the existing business logic. Runbot Video : [Video](https://drive.google.com/file/d/1d7U2jTCxaaVk2YJcy3bi2SlYuT-yXMsu/view?usp=drive_link) OPW - 6295712 Forward-Port-Of: odoo/enterprise#122420
This fix ensures planning hours are calculated correctly when a slot is moved in and out of an employee’s scheduled working time. It prevents incorrect break-time and allocated-hours values from appearing after repeated time changes, keeping planning reports and service scheduling accurate.
Original PR description
Issue: ---------------------------------------- When changing multiple times the hours of a slot to include out-of-schedule time. Steps to reproduce: ---------------------------------------- - Have…
Issue: ---------------------------------------- When changing multiple times the hours of a slot to include out-of-schedule time. Steps to reproduce: ---------------------------------------- - Have planning_field_service installed - Have an employee with a schedule from 7am to 3pm - In planning view, create a new slot for this employee from 7am to 3pm (8h) - Change the starting hour to 6am (8h + 1h of break time) - Change it back to 7am - The slot shows 7h07 of allocated hours and 53 minutes of break time Cause: ---------------------------------------- Since 8ca9faabfdf7d15883ba52da47bd8c562cf601de the compute of `allocated_percentage` is overriden in `planning_field_service`. The new compute uses `break_time` to recompute `allocated_percentage`. `break_time` is the not work time over the whole duration of the slot, including hours out of schedule. But the definition of `allocated_percentage` in `planning` is: the percentage of slot hours in schedule which are actually worked. So when changing the start to 6am `allocated_percentage` is still supposed ot be 100% because the employee is working 100% of the hours he is supposed to work considering its schedule. With the actual code `allocated_percentage` is actually computed as 8/9 = 0.88888... because it will take into account the hours out of schedule. As `allocated_percentage` is not recomputed if `allocated_hours` or `break_time` aren't modified by the user. It is then used [here](https://github.com/odoo/enterprise/blob/ae5008bdaf1b87269083f82280c7df44390129ff/planning/models/planning_slot.py#L2865-L2867) to compute the allocated_hours and the number of hours in schedule is divided base onthe percentage. Solution: ---------------------------------------- We only consider the hours in schedule to recompute `allocated_percentage`. `allocated_percentage` was used in `_onchange_break_time()` to get the previous ratio and calculate the allocated hours from which we deduct the break time. We cannot do this now so we also need to compute the working hours. ----------------------------------------- # [FIX] planning_field_service: handle input of negative break_time Issue: ---------------------------------------- When inputting negative break_time for a slot, it's possible to get a traceback. Steps to reproduce: ---------------------------------------- - Have planning_field_service installed - Have an employee with a schedule from 7am to 3pm - In planning view, create a new slot for this employee from 7am to 3pm (8h) - Input 9h of break time - Input -1h of break time - Traceback Cause: ---------------------------------------- When `slot.allocated_hours` is 0 and we input a negative value in `break_time`, the code in `_onchange_break_time()` will give `allocated_hours` the positive value of `break_time` making them opposite. Then in [`_compute_allocated_percentage()`](https://github.com/odoo/enterprise/blob/188dcc5078be7c7fee1a52f86505144d3b6309cf/planning_field_service/models/planning_slot.py#L98) we divide by their sum, which equals 0. Solution: ---------------------------------------- We compute the divider part and check if it's zero in `_compute_allocated_percentage()`. Also add a `max()` in `_onchange_break_time()` to convert the negative break time in allocated hours and resets `break_time` to zero. This ensures the same behavior as inputting negative values in `allocated_hours`. opw-6273559 Forward-Port-Of: odoo/enterprise#122279 Forward-Port-Of: odoo/enterprise#121168
The Planning / Timesheets Analysis report now correctly includes work slots scheduled on calendars that use duration-based attendances. This fixes missing entries in reporting so businesses get a complete view of planned time and timesheet analysis.
Original PR description
Issue: ---------------------------------------- The Planning / Timesheets Analysis report doesn't include most of the planning slots if they have a calendar based on duration. Steps to reproduce:…
Issue: ---------------------------------------- The Planning / Timesheets Analysis report doesn't include most of the planning slots if they have a calendar based on duration. Steps to reproduce: ---------------------------------------- - Have a 1 day planning slot (8h-17h) for an employee with a calendar based on duration. - Planning > Reporting > Planning / Timesheets Analysis - The slot is not included in the report Cause: ---------------------------------------- The update of how calendars work in saas-19.2 included the `duration_based` option but the query was not adapted. It still checks if the slot start time is lower than the calendar end time on that day: ```sql F.start_datetime < (d.date::date + (A.hour_to || ' hour')::interval) AND F.end_datetime > (d.date::date + (A.hour_from || ' hour')::interval) ``` But for duration-based calendars `hour_from` and `hour_to` are stored as `0.0`. So `F.start_datetime < (d.date::date + (A.hour_to || ' hour')::interval)` evaluates to False. Solution: ---------------------------------------- If the calendar has `duration_based` to True we only check the date. opw-6217643 Forward-Port-Of: odoo/enterprise#122173 Forward-Port-Of: odoo/enterprise#118133
This change prevents an error when a user opens a shift that has overlapping conflicts they are not allowed to see. For users without Planning Administrator rights, conflict details are no longer computed, which avoids the access issue and keeps shift viewing smooth.
Original PR description
Steps to reproduce: - Create a shift assigned to resources A and B - Create another overlapping shift assigned only to resource B - Login as resource A with internal user access only - Open the first shift Issue: An access error is raised when opening the shift. Cause: The conflict computation fetches overlapping shifts using SQL, which can return shifts that are not accessible to the current user. Solution: Return empty conflict values for users without Planning Administrator access, as conflict warnings are only available to planning managers. task-6313628 Forward-Port-Of: odoo/enterprise#122252 Forward-Port-Of: odoo/enterprise#121465
When users work across multiple companies, the Helpdesk ticket quick-create form will now only show customers from the appropriate company. This prevents selecting the wrong customer and helps teams create tickets more accurately.
Original PR description
Steps to reproduce: - Create two companies (Company A and Company B) - Create one partner in each company - Enable both companies for the user - Open Helpdesk and go to the tickets Kanban view for a Company A team. - In the quick create form, the customer dropdown shows customers from Company B Issue: - Customers from other companies are visible in the customer field, Cause: - The partner_id field in the quick create view had no domain, so it displayed partners from all allowed companies. Solution: - Added a domain on partner_id in the ticket quick create form view. task-4971466 Forward-Port-Of: odoo/enterprise#122358 Forward-Port-Of: odoo/enterprise#121944
8 changes
New functionality added to Odoo
This update establishes the initial payroll framework for Oman, including a local working schedule, demo company and employee data, and a first version of the salary structure. It helps businesses test and prepare payroll processes that match local working patterns and compensation rules.
Enhancements to existing features
Odoo can now use the Central Bank of Azerbaijan as a source for daily currency rates. This helps companies with multi-currency accounting and taxable transactions convert amounts into Azerbaijani manat (AZN) using the official rate for the transaction day.
Original PR description
This commit adds the Central Bank of Azerbaijan (CBA) as a supported service provider for automatic currency rate updates. Purpose: To ensure multi-currency accounting entries and taxable transactions are accurately translated into the national currency (AZN) using the official exchange rate defined by the CBA for the transaction day. Functionality: -Enables fetching official daily exchange rates directly from CBA via XML. -Automatically handles rates defined for different nominal quantities (e.g., rates quoted per 100 units instead of 1 unit). Related Community PR: https://github.com/odoo/odoo/pull/262471 Related Upgrade PR: https://github.com/odoo/upgrade/pull/10107 task-6112867
Resolved issues and error corrections
The planning preview now displays shifts exactly as they were created, instead of splitting them into smaller parts based on working schedules. It also avoids timezone-related visual offsets, so users see the correct shift times in the preview.
Original PR description
Steps to reproduce: ------------------------- 1. Install Planning. 2. Create a full day shift (8h) for an employee with a fully fixed schedule. 3. Publish the shift. 4. Go to Actions > Preview and…
Steps to reproduce: ------------------------- 1. Install Planning. 2. Create a full day shift (8h) for an employee with a fully fixed schedule. 3. Publish the shift. 4. Go to Actions > Preview and observe the shift. Current behavior and issue: ------------------------------------ **Shift Splitting:** The system fetches [attendance_intervals](https://github.com/odoo/enterprise/blob/6318e5cc392324ed43f3d34cf3f1282f055a5b3e/planning/controllers/main.py#L122) based on the employee's working schedule and cuts the shift into multiple segments (e.g., splitting a full-day shift to exclude lunch time). **Incorrect Start/End Time:** The preview displays shift starting times based on the working schedule rather than the specific times defined during shift creation. **Timezone Discrepancy:** When a normal shift (e.g., 11 AM to 12 PM) is created, it is stored in UTC based on the current user's timezone. However, the preview calculation attempts to convert this value to the [employee's timezone](https://github.com/odoo/enterprise/blob/2a97fd904d618b123500920c082e8e5537d27e56/planning/controllers/main.py#L58), leading to a visual offset if the user and employee are in different regions. Expected behavior: ------------------------ 1. Full-day shifts should be displayed as a single continuous block and should not be cut based on work intervals/attendance. 2. The previewed shift time should exactly match the created shift time. opw-5913944 **Before fix:** <img width="1372" height="738" alt="image" src="https://github.com/user-attachments/assets/7dbbf161-85c3-440d-bd4f-9d481656e016" /> **After fix:** <img width="1458" height="875" alt="image" src="https://github.com/user-attachments/assets/6e058468-aebc-438a-a7c3-3fb9b5c2eda8" />
This fix ensures that when capacity management is turned off, multiple bookings for the same time slot are all assigned to the first matching resource as expected. It restores the previous scheduling behavior so customers can book simultaneous appointments without bookings being spread across different resources.
Original PR description
Steps to reproduce: 1. Install Appointments, create an Appointment Type scheduled based on Resources and add 3 resources. 2. Uncheck "Manage Capacities" on the Appointment configuration. 3. Set 3…
Steps to reproduce: 1. Install Appointments, create an Appointment Type scheduled based on Resources and add 3 resources. 2. Uncheck "Manage Capacities" on the Appointment configuration. 3. Set 3 simultaneous appointments per resource. 4. Click on Share and open the given link in a new tab. 5. Attempt to book 3 appointments for the same slot in the portal. Issue: - If you click the Appointments smart button in the Appointment form, you will find each booking assgined to one of the resources Expected: - All 3 bookings should be assigned to the first resource Why this happens: - A recent performance optimization (9a48e80a3382bb4895013ae6b9b28e2827ac90aa) introduced batch resource checking via `_slot_available_resources`. - Inside its filter logic, the block evaluating unshareable resources was compressed into `not (self.manage_capacity and resource.shareable)`. - When `manage_capacity` is False, the resulting evaluation of that block of code marks the resource as unavailable, so the next resource was picked for the following appointment. - Before the optimization, the equivalent block explicitly returned True if `manage_capacity` was disabled opw-6344712
Payslips for Mexican employees now count only the days that fall within the selected payslip period. This prevents off-cycle payslips from showing too many worked days when the pay schedule is bi-weekly but the period is shorter.
Original PR description
## Issue With a Mexican company, creating a payslip for a duration of one week for an employee with a bi-weekly `schedule_pay`, the payslip will account for 15 days. ## Steps to reproduce 1. Install…
## Issue
With a Mexican company, creating a payslip for a duration of one week for an employee with a bi-weekly `schedule_pay`, the payslip will account for 15 days.
## Steps to reproduce
1. Install *"Mexico - Payroll"* (`l10n_mx_hr_payroll`)
2. Using a Mexican company, create a new Employee E:
- Set a contract (e.g., January 1st to Indefinite)
- Wage: $1,500.00 / Bi-weekly
3. In Payroll > Payslips > Payslips, create a new Off-Cycle
- Employee E
- Period: Any month, from the 8th to the 15th of the month
4. **In the _Worked Days_ tab, 15 days are counted, even though that's more than the period covers.**
## Cause
In the `_get_worked_day_lines` method, the amount of days is taken from `_get_schedule_days` [[1](https://github.com/odoo/enterprise/blob/7092dd2cc3578c3f22d1fbc82d958d57e2f93553/l10n_mx_hr_payroll/models/hr_payslip.py#L121)], which uses the `l10n_mx_schedule_table` [[2](https://github.com/odoo/enterprise/blob/7092dd2cc3578c3f22d1fbc82d958d57e2f93553/l10n_mx_hr_payroll/models/hr_payslip.py#L98-L102)] and returns `15` days for a bi-weekly schedule [[3](https://github.com/odoo/enterprise/blob/7092dd2cc3578c3f22d1fbc82d958d57e2f93553/l10n_mx_hr_payroll/data/hr_rule_parameters_data.xml#L850-L858)]. This does not take into account the period (`date_from`/`date_to`) of the payslip.
For the cases where the period is shorter than the default period (which usually either goes from the 1st to the 15th of the month, or the 16th to the end of the month), we should only consider the days within that period.
\[1]: https://github.com/odoo/enterprise/blob/7092dd2cc3578c3f22d1fbc82d958d57e2f93553/l10n_mx_hr_payroll/models/hr_payslip.py#L121
[2]: https://github.com/odoo/enterprise/blob/7092dd2cc3578c3f22d1fbc82d958d57e2f93553/l10n_mx_hr_payroll/models/hr_payslip.py#L98-L102
[3]: https://github.com/odoo/enterprise/blob/7092dd2cc3578c3f22d1fbc82d958d57e2f93553/l10n_mx_hr_payroll/data/hr_rule_parameters_data.xml#L850-L858
opw-6192639When users export an audit report to PDF, images inserted with the /file command will now appear correctly instead of being left out. This makes the exported document match what users see in the report and improves the readability of shared PDFs.
Original PR description
Currently, when a user uses the `/file` command to insert an image into an audit report and exports the report to PDF, the image is omitted from the generated PDF. To improve the support of those blocks, we will pre-process the document and replace the embedded files that correspond to images with standard image elements before PDF generation. This will ensure that images are correctly rendered and displayed within the document's text flow in the exported PDF. Task [link](https://www.odoo.com/odoo/project.task/5115280) task-5115280
When processing a package during barcode operations, the system now correctly recognizes it as the destination package instead of wrongly blocking it for containing other products. This prevents unnecessary errors during warehouse picking and lets operators complete transfers smoothly.
Original PR description
### Steps to reproduce: - In the settings Enable: Multi-steps Routes, Packages - Put your warehouse in delivery in 2-steps - On the Pick operation type in the barcode tab disable: "Allow extra…
### Steps to reproduce: - In the settings Enable: Multi-steps Routes, Packages - Put your warehouse in delivery in 2-steps - On the Pick operation type in the barcode tab disable: "Allow extra products" - Create two storable products P1 and P2 - On P2 > On hand > Update Quantity > New - Create a new line in WH/Output with a package POOK for 1 unit - Create a new internal transfer for 1 unit of P1 using the pick operation type so that the picking goes WH/Stock -> WH/Output - Set the quantity of the move to 1 unit and go to the barcode app - Open the Pick > Scan WH-STOCK > Scan P1 > Scan POOK #### > An error is raised: This package contains extra products and extra products are not allowed on this operation. #### Expected behavior: The package should be set as result package. ### Cause of the issue: In the `_processPackage`, a check that is done to ensure that the package scan will not add extraproduct to the picking if this operation is not allowed: https://github.com/odoo/enterprise/blob/5e4c8ecb0c644e21755570ed59cd8f6e9f618c8a/stock_barcode/static/src/models/barcode_picking_model.js#L2024-L2035 Unfortunately, this check is done just before a possible usage of the package as package dest. And, in that case, since we do not try to add any product to the picking the check is irrelevant anyway. opw-6303969
This fix ensures that product barcodes are recognized properly even when they could also be interpreted as a GS1 barcode format. As a result, scanning the same product multiple times will update the delivery quantity correctly instead of creating an incorrect extra line with a huge quantity.
Original PR description
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings…
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings enable "Default GS1 Nomenclature" - Create a storable product P with the barcode 3701762412212 - Create and confirm a delivery for 2 units of P and set the qty to 2 - Go to the barcode app and open your delivery - Scan 3701762412212 > The line of P is now selected with a quantity of 1/2 - Scan 3701762412212 #### > A new line is created for 1762411 units ### Cause of the issue: According to the GS1 nomenclature, the barcode 3701762412212 matches the scan of a quantity of "1762412" units of the lot name "2". As the scan of the of the product match a pattern for the GS1 nomenclature before matching a product, its barcode data is expected to be reset by these lines: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1320-L1324 In order to bypass the GS1 parser and to add 1 unit of the product. This is what happen on the first scan. However, performing the first scan also selects the associated line and, hence on the second scan the lines just above this check do set the product to match the product of the current line: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1294-L1320 In particular, we do not bypass the result provided by the GS1 parser and add `1762412` units of the product. opw-6175621 Forward-Port-Of: odoo/enterprise#122256 Forward-Port-Of: odoo/enterprise#120035
3 changes
Resolved issues and error corrections
This change fixes how Italian declaration-of-intent amounts are calculated when a DoI tax is used together with another tax on the same invoice line. As a result, invoices now correctly reduce the plafond, preventing incorrect available allowance balances.
Original PR description
- Create a declaration of intent in the customer's contact - Issue an invoice that includes both the 0% E (DoI tax) and any other tax - You will see how the plafond is not updated and the amount of this invoice is not deducted from it The method _compute_l10n_it_edi_doi_amount specifically exclude from the doi amount lines with the doi tax and another tax. However it should be possible to use both on a single line. We can use the amount subtotal because the doi is always 0%. opw-6253475 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267669
This update prevents the Spanish Verifactu e-invoicing module from running out of memory or timing out during installation on databases that already contain accounting entries. It makes the setup process more reliable and reduces the risk of failed installations for existing customers.
Original PR description
### Description: When trying to install the module `l10n_es_edi_verifactu` on a database that already has moves, it is possible to encounter a timeout or a memory error. This is caused by the compute `l10n_es_edi_verifactu_state` and `l10n_es_edi_verifactu_clave_regimen`, both compute linked to the new model `l10n_es_edi_verifactu.document`. ### Reference: opw-6293590 Forward-Port-Of: odoo/odoo#271550
This fix prevents incorrect slicing of account numbers when generating the SAF-T export. As a result, the grouping code now matches the official format, ensuring the exported accounting data is accurate.
Original PR description
Steps to reproduce: - change 1920 Banck account to 19204321 - go in general ledger and export to "SAF-T" Issue: The grouping code is 4321 Grouping code should match official grouping code. As a matter of fact the chart of account seems to match thos grouping account if we slice them correctly. opw-6285078 Forward-Port-Of: odoo/enterprise#121932
3 changes
Resolved issues and error corrections
Checks printed in the Philippines format will now always show the cents portion rounded to two digits. This prevents incorrect amounts from appearing on printed checks when the payment currency supports more than two decimal places.
Original PR description
Current behavior: --- When paying with checks, if the currency has more than 2 decimals, the decimal amount is printed with more than 2 decimals. Steps to reproduce: --- 1. Switch to PH company 2. Set setting Check Layout as "Print Check - PH" 3. In the PHP currency, change rounding factor to 0.0001 4. In Decimal accuracy > product price, set 4 digits 5. Create a new Vendor Payment, payment method Check, amount 100.1268 PHP 6. Results: One Hundred and 1268/100, should be 13/100 Expected behavior: --- The xx/100 part of amount in words text in the check should always be rounded to 2 decimals. opw-6302337
When a customer returns an item through Point of Sale, the refund is now valued using the original sale cost instead of the product’s later cost. This keeps inventory valuation and return cost accounting accurate when product costs change over time.
Original PR description
#### Description of the issue/feature this PR addresses: POS refunds are valued at the current product cost instead of the original sale cost. With FIFO/AVCO + perpetual valuation, when the cost drifts between sale and refund, the inventory valuation and return COGS are wrong. The same return from the backend is valued correctly. #### Current behavior before PR: The POS refund move never sets origin_returned_move_id, so stock valuation can't reuse the original sale cost and falls back to the current cost. #### Desired behavior after PR is merged: The POS refund move is linked to the original sale move via origin_returned_move_id, so it is valued at the original sale cost, like a backend return. opw-6216531 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix prevents packages from showing incorrect negative quantities when an inventory adjustment is reverted. It restores the package contents to the expected state so stock information remains accurate and easier to trust.
Original PR description
Currently when the user reverts an inventory adjustment move line with a package the package contains extra line showing negative quantity of the product. ## Steps to produce: - Install Inventory…
Currently when the user reverts an inventory adjustment move line with a package the package contains extra line showing negative quantity of the product.
## Steps to produce:
- Install Inventory without demo data
- Settings Enable 'Packages'
- Create a product:
- Cheese burger
- On hand > Create a new quant
- Package: 'Burgerbox' and 'On Hand Quantity`: 1 and save
- Set the On Hand quantity to zero and save
- History > Revert the Inventory adjustment line from WH/stock to Inventory adjustment by selecting it and reverting via actions.
- Products > Packages > BurgerBox
## Observed Behaviour:
After reverting an inventory adjustment that set the product's physical quantity to 0, the package contains two lines for the same product with quantities 1 and -1.
This is inconsistent because a package should not contain a product with a negative quantity.
The package should be restored to its original state and contain only the expected positive quantity.
## Root cause:
When the user reverts the move line, `action_revert_inventory` is called. This method creates the revert move and then marks that move as done at [1].
Marking the move as done subsequently marks all related move lines as done at [2]. During this process, the system first unreserves the quantity from the virtual location / inventory adjustment and then removes the quantity from that location (resulting in a -1 quantity move line at that location). This is performed through `_synchronize_quant`, which is responsible for synchronizing the physical inventory with the move line at [3].
The `_synchronize_quant` method uses the move line's `package_id` when updating the corresponding quant at [4]. As a result, `_update_available_quantity` creates a new quant with the following values at [5]:
```
{
'product_id': 1,
'location_id': 14,
'lot_id': stock.lot(),
'package_id': 1,
'owner_id': res.partner(),
'in_date': datetime.datetime(2026, 6, 22, 12, 42, 11),
'quantity': -1.0,
}
```
This creates a quant with a negative quantity that is linked to the package because `package_id` is set on the newly created quant. Consequently, the move line with the negative quantity becomes associated with the package.
[1]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move_line.py#L1016-L1035
[2]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move.py#L1956 [3]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move_line.py#L662-L666
[4]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move_line.py#L678-L687
[5]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_quant.py#L1130-L1143
## Solution:
Remove the source `package_id` when creating revert moves for inventory adjustment locations.
When an inventory adjustment sets a product's quantity to 0, the adjustment is completed without a destination package, meaning the product is effectively removed from the package. Therefore, the corresponding revert move should not retain the package as its source. Keeping the package as the source is inconsistent because package information should not exist on a virtual inventory adjustment location, and the original inventory adjustment removes the product from the package (there is no destination package).
By removing the source `package_id` from the revert move, the system avoids creating negative quants associated with the package during quant synchronization. This also ensures that, after the inventory adjustment is reverted, the quantities of products inside the package are restored correctly and match their state prior to the adjustment.
opw-6285739