Tuesday, July 14, 2026
187 changes
5 changes
Resolved issues and error corrections
This update corrects a bug where reverting an inventory adjustment with a package resulted in negative quantities appearing within the package. The fix ensures that quantities are accurately restored to their original state after a revert, preventing inconsistencies in inventory tracking. This improves data reliability and avoids potential errors in stock management.
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
Forward-Port-Of: odoo/odoo#274663
Forward-Port-Of: odoo/odoo#271440This update resolves an issue where Odoo was incorrectly sending duplicate capture requests to Stripe for EFTPOS payments in Australia. By adjusting how the system handles these payments, the fix ensures that orders are completed successfully and avoids errors related to duplicate capture attempts, improving the reliability of POS transactions.
Original PR description
In Australia, Terminal payments using `payment_method_options.card_present.capture_method=manual_preferred` are not always captured later. When a payment is processed on the `eftpos_au` network, Stripe authorizes and captures it in a single step. However, the POS Stripe flow only skipped the extra capture based on the card brand instead of the processed network. As a result, payments such as `brand = visa` and `card_present.network = eftpos_au` were treated as capturable, and Odoo sent a second capture request. Stripe then rejected it with `payment_intent_unexpected_state` because the PaymentIntent had already been captured, leaving the POS order unfinished. This patch skips the extra capture call when the payment was processed on `card_present.network = eftpos_au`. opw-6228977 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271609 Forward-Port-Of: odoo/odoo#270293
This update fixes an issue where cash rounding records were incorrectly shared across all Indian companies. Previously, new companies would inherit records from the last created company, leading to errors. The change ensures each new Indian company has its own unique cash rounding record, resolving this conflict and improving data accuracy.
Original PR description
### Issue: When creating a new Indian company, the `Half Up` cash rounding is reassigned to the new company instead of being duplicated Previous Indian companies lose access to it, causing errors…
### Issue: When creating a new Indian company, the `Half Up` cash rounding is reassigned to the new company instead of being duplicated Previous Indian companies lose access to it, causing errors when opening invoices that reference the cash rounding if the user doesn't have access to that company ### Cause: `cash_rounding_in_half_up` was defined as a `data` record with a fixed XML ID (`l10n_in.cash_rounding_in_half_up`) `_get_in_account_cash_rounding` referenced that XML ID directly and set `company_id` to the current company on each chart of accounts installation This reassigned the single shared record to the new company instead of creating a new one Moving the definition to the `@template` decorator without a module-prefixed XML ID lets the chart of accounts system create one record per company, as intended ### Steps to reproduce: - Install `l10n_in` and switch to `IN Company` - Check the Cash Rounding records grouped by company - Create a new Indian company - Enable both `IN Company` and the new company - Check the Cash Rounding records grouped by company again Before the fix, only the last created Indian company has the Cash Rounding record opw-6318857 Forward-Port-Of: odoo/odoo#272866
This update ensures that loyalty rewards are only applied when a customer's order contains the specific products defined in the reward rule. Previously, a rule with no product restrictions would incorrectly grant rewards even with other products in the order. This fix aligns the POS frontend with the backend's behavior, improving the accuracy and reliability of the loyalty program.
Original PR description
Steps to reproduce: - Create a promotion program (e.g. "10% discount on your order", reward_point_mode "per order") and restrict its rule to a specific product A; leave the minimum quantity at 0 -…
Steps to reproduce: - Create a promotion program (e.g. "10% discount on your order", reward_point_mode "per order") and restrict its rule to a specific product A; leave the minimum quantity at 0 - Open a PoS session and add any other product B to the order Issue: The discount was applied even though the order contained none of the rule's valid products. Cause: In `pointsForPrograms`, a rule was only gated on its quantity and amount thresholds (`totalProductQty < rule.minimum_qty`), never on the actual presence of a valid product in the order. Program templates (promotion, promo_code, next_order_coupons) create rules with minimum_qty = 0, so a product-restricted rule passed with zero matching items and, in "order" point mode, granted its points unconditionally. The same hole existed in `_canGenerateRewards` for scanned coupon programs, where rules act as conditions. The backend does not have this issue: `_program_check_compute_points` in sale_loyalty skips any rule whose valid products are not present in the order. Fix: Mirror the backend behavior in the PoS frontend: skip a product-restricted rule in `pointsForPrograms` when no (non-reward) order line matches its valid products, and make `_canGenerateRewards` return false in the same situation. Gift card and eWallet flows are unaffected since their "money"/"unit" point modes already gave 0 points when the trigger product was absent. opw-6357241 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275073
The barcode scanner check-in process in kiosk mode was previously inaccurate, with location data off by several kilometers. This update now uses the browser's geolocation to provide more precise location data, resolving this issue and improving the accuracy of check-in times.
Original PR description
**Issue** Check-in and check-out performed in kiosk mode via the barcode scanner were less accurate than those made via the manual selection. The reported inacurracy between the actual and real locations was several kilometers. **Cause** `attendance_barcode_scanned` was called without a location coming from the browser's geolocation API. In that case, the location was determined by the geoip database https://github.com/odoo/odoo/blob/51f59a293de1e86f66f30257f8fc0c419463d18c/addons/hr_attendance/controllers/main.py#L69-L70 which is generally not as accurate as the location provided by the browser. opw-5889102 Forward-Port-Of: odoo/odoo#273044 Forward-Port-Of: odoo/odoo#251478
5 changes
Enhancements to existing features
This update enhances the testing framework for Odoo's mass mailing functionality. Specifically, it incorporates simulated user actions like email opens and replies to more accurately verify the scheduling and execution of marketing campaigns. This improves the reliability of marketing automation processes.
Original PR description
Improve (mass_)mailing asserts and tools, notably to use their usage in marketing automation where simulating user actions (open emails, reply, ...) is necessary to check marketing activities scheduling and execution. Task-4224152: [marketing_automation] Performance / Scalability Forward-Port-Of: odoo/odoo#275964
1 change
Resolved issues and error corrections
This update resolves an issue where web assets weren't correctly loaded within iframes, particularly in scenarios like displaying emails. The change ensures assets are properly added to secondary documents, improving functionality in complex use cases.
Original PR description
Commit [1] introduces the concept of "global" cache for optimization. However when loading a bundle inside a secondary document such as an iframe, containing source files that are already loaded in…
1 change
Resolved issues and error corrections
This update corrects a bug in how overtime is calculated for employees with flexible work schedules. Specifically, it resolves a discrepancy in the week's starting day, leading to incorrect overtime calculations when tolerance time is adjusted. The fix ensures accurate overtime reporting for employees with varied working hours.
Resolved issues and error corrections
This update resolves an issue where batch payment sequences were incorrectly created when a new company was initially set up. The change ensures sequences are properly associated with the correct company during creation, preventing errors in payment processing. This improves the reliability of our payment system.
Original PR description
Previously, batch payment sequence will be created by simply select to create new company due to having lambda in default. Hence, the created sequence does not have a correct company_id set as company hasn't yet created. Switch to creating sequence in ``create`` function to avoid this issue. Also use ``range_year`` for payment prefix because it was set to use date range. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273852 Forward-Port-Of: odoo/odoo#268689
This update resolves an issue where reverting an inventory adjustment with a package resulted in a negative quantity being displayed within the package. The fix ensures that quantities are accurately restored to their original state after a reversion, preventing inconsistencies in package inventory tracking. This improves data accuracy and reliability for stock management.
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
Forward-Port-Of: odoo/odoo#274663
Forward-Port-Of: odoo/odoo#271440This update resolves an issue where Odoo was incorrectly sending duplicate capture requests to Stripe for EFTPOS payments in Australia. This resulted in payment failures and incomplete orders. The fix ensures that Stripe only captures payments on the EFTPOS network, streamlining the payment process and improving reliability.
Original PR description
In Australia, Terminal payments using `payment_method_options.card_present.capture_method=manual_preferred` are not always captured later. When a payment is processed on the `eftpos_au` network, Stripe authorizes and captures it in a single step. However, the POS Stripe flow only skipped the extra capture based on the card brand instead of the processed network. As a result, payments such as `brand = visa` and `card_present.network = eftpos_au` were treated as capturable, and Odoo sent a second capture request. Stripe then rejected it with `payment_intent_unexpected_state` because the PaymentIntent had already been captured, leaving the POS order unfinished. This patch skips the extra capture call when the payment was processed on `card_present.network = eftpos_au`. opw-6228977 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271609 Forward-Port-Of: odoo/odoo#270293
This update resolves a bug where duplicate stock availability messages were appearing on product pages when using mega menus. The fix ensures that stock messages are correctly cleared and updated, providing a consistent and accurate display of product availability to customers. This improves the user experience and prevents confusion.
Original PR description
Steps to reproduce: - Add an `s_add_to_cart` snippet inside a mega menu - Open a product detail page for a storable product - Change the product variant several times - Stock availability messages…
Steps to reproduce:
- Add an `s_add_to_cart` snippet inside a mega menu
- Open a product detail page for a storable product
- Change the product variant several times
- Stock availability messages keep appending under `availability_messages` instead of replacing the previous one
`_onChangeCombinationStock` removed existing messages with `document.querySelector('.oe_website_sale').querySelectorAll(...)`, but appended the new message with
`this.el.querySelector('div.availability_messages').append(...)`.
`document.querySelector('.oe_website_sale')` only returns the first `.oe_website_sale` element in the document. When a mega menu contains an `s_add_to_cart` snippet, that element appears before the product page container, so the removal step runs on the wrong subtree and never clears the messages on the product page.
Fix by scoping the removal to `this.el`, the current `WebsiteSale` interaction root, so both removal and insertion target the same product page container.
Forward-Port-Of: odoo/odoo#276007
Forward-Port-Of: odoo/odoo#274928Commit [1] introduces the concept of "global" cache for optimization. However when loading a bundle inside a secondary document such as an iframe, containing source files that are already loaded in the main document, those source files are not properly added in the secondary document. Example: load `web.assets_web` inside an iframe (this use case can happen in `mass_mailing` where we have to wrap some component inside a sandboxed iframe in order to display unsafe content (poorly sanitized), such as emails). The issue is caused by an inconsistent usage of the `globalCache`: `getBundle` adds `bundleName` key to JS and CSS libs, but `computeAssetCaches` adds `url` keys to link or script elements. After this commit: - `globalCache` is only used in `getBundle` to map bundleNames to their libs - `loadCSS` and `loadJS` only use the documents caches to map urls to their element in the respective document. [1]: https://github.com/odoo/odoo/commit/5b1dc282b0f09c0fe6dcf9910a3a29cfd01d66a3
Original PR description
# How to reproduce - Set an employee's work schedule to flexible 40hrs/week with 8hrs of work per day - Create a new attendance for that employee that : - Is the very first attendance of that…
# How to reproduce - Set an employee's work schedule to flexible 40hrs/week with 8hrs of work per day - Create a new attendance for that employee that : - Is the very first attendance of that employee - Is not on a monday (e.g. a Friday) - Create a second attendance for that employee that : - Is atleast one week after the first attendance - Is one of the two days of the week before the day of the week of the first attendance (e.g. a Wednesday or a Thursday) - Go to the settings, update the value for "Tolerance Time In Favor Of Company" and save - Come back to the second attendance # The problem The Extra Hours have changed and are equal to the worked time # Cause When we update the tolerance time, we recompute the overtime of every attendance of every employee. In this recomputation, we compute the `expected_attendance` of every employee and transforms them into a dict of the expected working time for each day : https://github.com/odoo/odoo/blob/281658e86971687656f3235ac1ff8afcb52f2908/addons/hr_attendance/models/hr_attendance.py#L349-L356 Later, if an attendace of the employee was not in their expected working days, then we consider that all hours worked were overtime : https://github.com/odoo/odoo/blob/281658e86971687656f3235ac1ff8afcb52f2908/addons/hr_attendance/models/hr_attendance.py#L381-L384 This makes sense but our issue is that days in the middle of the week are considered "time-off" when they should not. That's because for flexible working schedules, we emulate the expected working hours based on the total hours per week and the maximum hours per day : https://github.com/odoo/odoo/blob/281658e86971687656f3235ac1ff8afcb52f2908/addons/resource/models/resource_calendar.py#L384-L386 For every "week", we start from the first day and continue forward by greedily using all hours for that day until there is no more hours for the week. The problem is that since this PR, we don't start "weeks" on mondays, but on the `start_datime` : https://github.com/odoo/odoo/commit/af36e73108cef4326f6125c3af491b07a51534fe And in our case, `start_datetime` is the very first attendance day of the employee : https://github.com/odoo/odoo/blob/281658e86971687656f3235ac1ff8afcb52f2908/addons/hr_attendance/models/hr_attendance.py#L344 So our expected working days are desynched with the days of the week # Proposed solution We partly revert https://github.com/odoo/odoo/commit/af36e73108cef4326f6125c3af491b07a51534fe opw-6289079