Daily updates from Odoo
Tuesday, June 23, 2026
132 changes
14 changes
Resolved issues and error corrections
This update resolves a critical issue where VoIP registration would fail due to a delayed response when a user left a session open and inactive. The fix ensures a new registration attempt is made when the initial request times out, preventing error dialogs and restoring VoIP functionality. It improves the reliability of the VoIP service for users.
Original PR description
Leaving a session open and idle (page open, no activity at all) eventually pops an error dialog: UncaughtPromiseError > RequestPendingError REGISTER request already in progress, waiting for final…
Leaving a session open and idle (page open, no activity at all) eventually pops an error dialog:
UncaughtPromiseError > RequestPendingError
REGISTER request already in progress, waiting for final response
at Registerer.register (sip.js)
at Registerer.register (registerer.js)
at UserAgent.attemptReconnection (user_agent_service.js)
When the WebSocket transport drops while a REGISTER is in flight (which happens on an idle tab: SIP.js sends a periodic re-REGISTER before the registration expires, and the socket may be closed by an idle timeout or by the machine going to sleep in the meantime), the final response never comes back. SIP.js only clears its internal `waiting` flag from the REGISTER response callbacks (onAccept/onReject/onRedirect); it is never reset on transport loss or request timeout. The Registerer is then stuck `waiting` forever, and every subsequent register() rejects with a RequestPendingError.
On top of that, our wrapper's register() did not return the SIP.js promise, and attemptReconnection() called it without awaiting, so the rejection escaped the surrounding try/catch and surfaced as an unhandled promise rejection. Worse, the WebSocket error was resolved right after, so the user appeared reconnected while VoIP registration was actually dead until the page was reloaded.
This commit makes register() recreate the underlying SIP.js Registerer when it is stuck `waiting` (a clean instance starts with waiting=false), and return the promise so callers can await it. attemptReconnection() now awaits it, so any rejection goes through the existing retry/back-off logic instead of bubbling up as an uncaught error.
The recreation is intentionally conditional: disposing a healthy registerer would send an unregister (REGISTER expires=0) racing with the fresh register (expires=600) and could leave us unregistered, so we only recreate when a request is actually stuck.
Forward-Port-Of: odoo/enterprise#120487
Forward-Port-Of: odoo/enterprise#119701This update resolves an issue where manually adding serial-tracked by-products to manufacturing orders caused errors when closing production. The fix ensures that all move lines, including those with manually assigned serial numbers, are correctly processed within the shopfloor workflow, preventing user error messages.
Original PR description
**Issue** Adding a serial-tracked by-product manually on a Manufacturing Order whose BOM does not define it, can lead to inconsistencies when assigning serial numbers in the shopfloor application.…
**Issue** Adding a serial-tracked by-product manually on a Manufacturing Order whose BOM does not define it, can lead to inconsistencies when assigning serial numbers in the shopfloor application. **Steps to reproduce** - Activate by-product in the settings - Create a product with an empty BOM (final product) - Create another product tracked by serial number (by-product) - Create and confirm a MO for the final product with 1 unit of the by-product - Go to Miscellaneaous -> operation Type -> shopfloor - Activate the option "Pre fill lot/serial numbers in shop floor" - Return to the MO and open the shopfloor view - Click on the '+' button next to the by-product and assign a serial number - Try to close the production -> A user error is raised stating that the by-product requires a serial number. **Cause** When the by-product is added manually on the MO, a stock move is created with an initial move line that does not contain any serial number. Later, when assigning a serial number from the shopfloor view: https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/mrp_workorder/models/stock_move.py#L121-L122 a new move line containing the serial number is created: https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/mrp_workorder/models/stock_move.py#L116-L119 However, the original empty move line is not removed (the issue): https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/mrp_workorder/models/stock_move.py#L124-L125 Because `self.picking_type_prefill_shop_floor_lots` is True, but `self.byproduct_id` is an empty recordset since: https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/mrp/models/mrp_production.py#L1304-L1311 https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/mrp/models/mrp_production.py#L1279 Indeed, `byproduct_id` is only populated from BOM-defined by-products. As a result, while confirming the production, there is 2 sml and among them, the original one without SN, which triggers the error: https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/stock/models/stock_move_line.py#L590 https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/stock/models/stock_move_line.py#L634-L635 https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/stock/models/stock_move_line.py#L658-L659 https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/stock/models/stock_move_line.py#L661-L669 opw-6223158 Forward-Port-Of: odoo/enterprise#120493 Forward-Port-Of: odoo/enterprise#118792
This update fixes an issue where preparation times weren't correctly calculated when order stages changed and ensured the preparation time report only displayed data for the active company. This improves the accuracy of order processing times and reporting, leading to better business insights.
Original PR description
Issues: - Preparation time for order lines was not computed when the preparation order stage changed. - Preparation time report aggregated orders across all companies instead of showing records for the active company only. Fixes: - Ensure preparation time is properly recomputed when the order stage changes. - Add company domain filtering to the preparation time report. Task-6250974 Forward-Port-Of: odoo/enterprise#118738
This update significantly speeds up appointment scheduling, particularly when managing multiple resources like tables in a restaurant. The change optimizes how the system checks resource availability, resulting in faster loading times and quicker auto-assignment processes. This improves the overall user experience and efficiency.
Original PR description
In the current code, for each slot, and for each "available" resource, we check if the resource is available on the slot, based on availability values. Then, we check the remaining capacity of that…
In the current code, for each slot, and for each "available" resource, we check if the resource is available on the slot, based on availability values. Then, we check the remaining capacity of that resource. Also, linked resources information is added when computing the original resource remaining capacity. If many linked resources exist, this will be done several times and is not useful. This commit makes that loop disappear. We now check all resources at once in terms of availability, and linked resources that could be selected (in the appointment resources, in the slot resources (if any restricted resource)) at the same time. Then, the total capacity is the sum of the resource remaining capacity and the ones of available linked resources. Therefore, _slot_availability_is_resource_available is renamed to _slot_available_resources, as it now takes more than one resource and returns all resources among 'resources' that are valid on the slot, based on the availability_values, slot restrictions and booking lines. A noticeable difference is mainly seen when using many resources (and linked resources). For instance, a restaurant with a lot of small tables will have their slot availability check much shorter. BENCHMARK, LOCAL (time only, as number of requests does not change) Only appointment installed For a restaurant with - 10 tables of 2 - 5 tables of 2 linked, 2 times - 10 tables of 4 - 2 table of 2 - time then auto assign On loading /appointment/id: ~ 3.1s -> ~ 1.6s On selecting any number of people (1 to 10): [2s, 2.5s] -> [0.6s, 0.8s] Task-4144524 Forward-Port-Of: odoo/enterprise#121212 Forward-Port-Of: odoo/enterprise#107711
This update fixes an issue where Odoo was incorrectly selecting unavailable couriers from Shiprocket. The change now filters out 'blocked' couriers, ensuring only serviceable options are considered for rate calculations and shipment selection. Additionally, the system is more robust to handle potential errors in Shiprocket's data, preventing shipment delays.
Original PR description
Shiprocket provides an odablock flag in the courier serviceability response. Couriers with odablock=True are not serviceable for the requested route and should not be considered for rate calculation or selection. Before this change, Odoo selected the first courier returned by Shiprocket regardless of its ODA status. As a result, unavailable couriers could be proposed to users and selected for shipments. The fix filters out ODA-blocked couriers before evaluating available services, ensuring that only serviceable couriers are considered. Additionally, freight charge parsing is hardened to gracefully handle non-numeric values returned by Shiprocket, preventing errors during AWB assignment and price computation. FYI: Shiprocket uses odablock=False for serviceable routes and odablock=True for routes that are blocked for a given courier. opw-6288768,6152279 Forward-Port-Of: odoo/enterprise#120374
This update fixes a problem where self-order receipts lacked important company information like the logo, address, and contact details. Now, all relevant company and PoS settings are included on self-order receipts, improving customer experience and providing consistent branding.
Original PR description
Before this commit: ---------------- - Order receipts generated from self-orders were missing several company and PoS configuration details, such as the company logo, receipt address, phone number, email, and website. After this commit: ---------------- - Order receipts generated from self-orders now include all relevant company and PoS configuration details. Task-6271261 Forward-Port-Of: odoo/odoo#268789
This update fixes issues where mass email campaigns were failing due to incorrect server selections. Specifically, personal email servers were being inadvertently used, causing campaigns to get stuck in the queue. The changes ensure that personal servers are excluded from mass mailing selections, improving campaign delivery reliability.
Original PR description
A personal outgoing mail server is an `ir.mail_server` that belongs to one user. The system only lets that user send through it. Mass mailings do not always respect this, which can cause a few…
A personal outgoing mail server is an `ir.mail_server` that belongs to one user. The system only lets that user send through it. Mass mailings do not always respect this, which can cause a few problems: 1. Admins cannot duplicate a personal server. The copy keeps the same owner, and the rule that says one user can own only one server stops the save. 2. In *Email Marketing > Settings*, the "Dedicated Server" picker offers every server, even personal ones. If an admin picks a personal one, all campaigns get stuck. The cron job runs as Odoobot, the personal server rejects it, and the mailing stays in the queue. 3. When no dedicated server is set, the fallback selection can still land on a personal server (for example because its `from_filter` matches the sender). The cron sends through it and gets rejected. One commit per problem: 1. **mail**: duplicating a personal server now produces a copy with no owner. 2. **mass_mailing**: the picker in the settings hides personal servers. Setting an owner on a server that is already used for mass mailing now raises a clear error that names the campaign blocking the change. 3. **mass_mailing**: personal servers are skipped when the fallback selection runs, so only shared servers are considered. opw-6086077 Forward-Port-Of: odoo/odoo#271115 Forward-Port-Of: odoo/odoo#261537
This fix resolves an issue where extra prices were incorrectly added to POS orders when using 'always' attributes for products. The change ensures that extra prices are now set on the combo creation page for 'always' attributes, aligning with the intended product variant behavior and preventing double-counting.
Original PR description
## Steps to reproduce - Create an attribute A, of type always, with 2 values, one should have an extra price - Create an attribute B, of type never, with 2 values - Create a product that has both…
## Steps to reproduce - Create an attribute A, of type always, with 2 values, one should have an extra price - Create an attribute B, of type never, with 2 values - Create a product that has both those attributes - Create a combo with that product with both values for A - Go to the PoS and order that combo with the value that has an extra price for A - The extra price is added ## Why the fix: For variants of type always, a product is created, meaning we can chose which products of this variants to have in our combo. As we can chose this, it means that we can and should chose the extra price on the combo creation page, not on the attribute page. It does not make sense to take the attribute extra price into account, as we do not take the unit price of combo items into account, so this extra price should be set on the combo page and we should ignore the attribute's extra price if the type is "always". The variants are then considered as different products, as they should in this case. If the type of the attribute is never, we can't chose which one gets an extra price on the combo page, so we should still take the attribute's extra price in this situation, as we have no other way to set it. We need to have both an always and a never attribute in order to reproduce this bug because if we only have "always" values, the configuration of the combo item is bypassed and is undefined, so **attribute_value_ids** will be undefined in this code and we won't get any value for the extra price in this code: https://github.com/odoo/odoo/blob/c09e8b2fc24ee75495fc947924e29cf5c601506f/addons/point_of_sale/static/src/app/models/utils/compute_combo_items.js#L44-L49 We now ignore the attribute's extra price if it's type is always, otherwise, it the behavior stays the same. opw-6262431 Forward-Port-Of: odoo/odoo#270894 Forward-Port-Of: odoo/odoo#268567
This update resolves an issue where recurring plans would disappear when updating a subscription product's quantity. The fix ensures that the selected plan is correctly recomputed and displayed after changes, improving the user experience for subscription management. It addresses a conflict arising from checks related to one-time purchase options.
Original PR description
# Introduction note This PR fixes two bugs introduced by the same commit : https://github.com/odoo/enterprise/commit/106d70a1ef0ddbd61a74b7cac82dfce1e316beaa The original commit fixed multiple issues…
# Introduction note This PR fixes two bugs introduced by the same commit : https://github.com/odoo/enterprise/commit/106d70a1ef0ddbd61a74b7cac82dfce1e316beaa The original commit fixed multiple issues regarding the display of recurring plans when the One-time purchase option was enabled, but it also introduced new ones. Theses new issues are due to multiple new checks on `allow_one_time_sale`, but this variable only indicates that the One-time purchase option is available to the user, not that it is actually selected. So the fixes of the original commit works when first loading the page, but fails when the content of the page is updated. # Shared steps - Activate Subscriptions & eCommerce modules - Create a subscription product, enable 'Accept One-Time' and publish it on the website # Bug 1 ## How to reproduce - Add atleast two recurring plans to the product - Go to the product page on the website - Select one of the recurring plans - Increase the quantity of the product ## The problem The recurring plan selection is removed ## Cause The condition `!combination_info.allow_one_time_sale` was added on the `t-att-checked` of the recurring plan selection display. This correctly fixed the issue when first loading the page, but when the user changes the price or the variant, the recurring plan are recomputed and rerendered : https://github.com/odoo/enterprise/blob/0b408acbadb2cfcbc844521f3244a06b7ae7be22/website_sale_subscription/static/src/interactions/product_page.js#L37-L40 When that is the case, that condition blocks the proper display of the selected recurring plan. ## Proposed Solution When loading the recurring plan selection, what defines wich plan is selected is the `subscription_default_pricing_plan_id` variable, which is based on the `plan_id` value given in the request to the server : https://github.com/odoo/enterprise/blob/0b408acbadb2cfcbc844521f3244a06b7ae7be22/website_sale_subscription/models/product_template.py#L222 We make it so if no `plan_id` is sent to the server and `allow_one_time_sale` is enabled, then the server does not give back any `subscription_default_pricing_plan_id` opw-6131532 # Bug 2 ## How to reproduce - Add an attribute with values A & B for the product - Define atleast two recurring plans for the variant with attribute B - Publish the product - Go to the product page - Select the variant with attribute B ## The problem The recurring plan is not displayed. If the order of the attribute is reversed, then it works as expected. ## Cause The pricings are correcly sent to the front-end but they are not added to selection because of the check on `allow_one_time_sale` : https://github.com/odoo/enterprise/blob/0b408acbadb2cfcbc844521f3244a06b7ae7be22/website_sale_subscription/static/src/interactions/product_page.js#L42-L50 opw-6132160 Forward-Port-Of: odoo/enterprise#120873 Forward-Port-Of: odoo/enterprise#115446
This update corrects errors in how appointment invitations are sent, ensuring they're only triggered for 'booked' or 'requested' appointments. Previously, invitations were sent regardless of appointment status, leading to unnecessary emails and incorrect notifications. This ensures accurate and timely appointment confirmations for users.
Original PR description
This PR fix three issues related to the sending of the appointment invitations. Each one has its own commit: - Commit 1 sends invitations only if the event either "booked" or "request". Previously they were sent even if the appointment was cancelled. - Commit 2 prevents the sending of regular invitations and always sends appointment invitation to new attendees of existing booked appointments. - Commit 3 sent appointment invitations if the status of an existing event is set "request". It also add the status change in the log as it would have been if it was done at the creation. Community PR: https://github.com/odoo/odoo/pull/260073 Task-6139036 Forward-Port-Of: odoo/enterprise#121213 Forward-Port-Of: odoo/enterprise#114304
A recent update caused the Point of Sale system to incorrectly add the 'S' variant when scanning a barcode for the 'M' variant of a product with dynamic attributes. This fix ensures that the correct variant is added based on the scanned barcode, improving the accuracy of sales transactions. The change corrects a logic error in how the system handles product variants with dynamic attributes.
Original PR description
Steps to reproduce ------------------ 1. Create a product with two attributes: - Size with values S and M (Variants Creation: "Instantly") - a second attribute with a single value (Variants Creation: "Dynamically") 2. Set a different barcode on the S and the M variant. 3. Open PoS, scan the barcode of M. -> The S variant is added instead. Why the issue ------------- In 390b48a1ba24, when a product has a single-value attribute set to "dynamic", we look for the first variant that has this value and use it instead of the preselected variant. This is wrong when several variants share this value: in our case both S and M have it, so scanning M is overridden by the first variant, S. The fix ------- We now keep the preselected variant if it already has this value, and only look for or create one otherwise. opw-6272739 Forward-Port-Of: odoo/odoo#268590
This update corrects a bug where reordering rules were incorrectly creating purchase orders linked to sales orders. Now, reordering rules will always generate new, separate purchase orders, ensuring accurate inventory management and preventing duplicate purchase orders. This improves order fulfillment efficiency.
Original PR description
Steps to reproduce the bug: - Go to contact: - azure interior: - Group RFQ: On Order - Create two storable products P1 and P2, both with the Buy route and Azure interior as vendor - Confirm a sale…
Steps to reproduce the bug:
- Go to contact:
- azure interior: - Group RFQ: On Order
- Create two storable products P1 and P2, both with the Buy route and Azure interior as vendor
- Confirm a sale order with P1 (MTO+Buy):
- a purchase order PO1 is created, linked to the sale order via reference_ids
- Create a reordering rule for P2 and trigger it
Problem:
The reordering rule procurement for P2 was merged into PO1 (the sale order's purchase order) instead of creating a new separate PO.
In _make_po_get_domain (purchase_stock/models/stock_rule.py), when group_rfq == 'default' (On Order), the domain only adds a reference_ids filter when the procurement carries reference_ids. When the procurement comes from a reordering rule (no sale order, no reference_ids), no filter was added, so the search matched any draft PO from that vendor, including PO1, which has reference_ids pointing to the sale order.
Solution:
When group_rfq == 'default' and the procurement has no reference_ids, add ('reference_ids', '=', False) to the domain so the search only matches POs that are also not linked to any sale order.
opw-6167835
Forward-Port-Of: odoo/odoo#270735This update resolves a bug where overtime was incorrectly generated when using timing rules with employer tolerances. The fix ensures that attendance limits are properly considered during overtime calculations, preventing unnecessary overtime charges. This improves accuracy and reduces potential payroll discrepancies.
Original PR description
**Version:** - 19.0 **Steps to reproduce:** - Create a rule of Timing type. - Add a tolerance for the employer. - Set the ruleset on the employee. - Add an attendance of less than the tolerance. **Issue:** - When using a Timing type rule with employer tolerance, overtime is still created even if the attendance is below the tolerance limit. **Cause:** - The timing rule calculation was missing the tolerance check that exists in the quantity rule calculation. **Fix:** - Added the missing tolerance check in the timing rule calculation. - Removed employee tolerance from view for timing rules. **Task-6064081** Forward-Port-Of: odoo/odoo#257079
This update ensures that the chatter within Odoo accurately reflects the employee who made changes to tracked orders. Previously, the system incorrectly attributed changes to the original order cashier. This fix uses the current session employee to provide accurate tracking, improving order management and reporting.
Original PR description
**Steps to reproduce:** - Enable "Track orders edits" in the settings - Enable "Log in with Employees" - Go to the Restaurant, log in with employee A - Go to a table, order 3 Sushis - Go back to the…
**Steps to reproduce:** - Enable "Track orders edits" in the settings - Enable "Log in with Employees" - Go to the Restaurant, log in with employee A - Go to a table, order 3 Sushis - Go back to the floor plan and change to employee B - Go back to the table and change the qty of 3 Sushis to 2 Sushis - Go to the order in the backend and check the chatter - It will indicate that employee A did the change, but it was employee B **Why the fix:** We always used the cashier set on the order to determine who should be put in the chatter, regardless of who is actually connected at that point. We now use the session's current employee to write who did the change in the chatter. We do not change the order's employee, because it will be done once the order has been paid. In the case where we are not logged in but pos_hr is installed, the employee_id might be the id of a res.user, and browsing it might return the wrong value. To avoid this, we check if the value exists as a hr.employee before assigning the name. The way we return the value has been changed because the linter wasn't happy about it. opw-6213504 Forward-Port-Of: odoo/odoo#270768 Forward-Port-Of: odoo/odoo#265582
14 changes
New functionality added to Odoo
This update streamlines connections to remote SaaS databases for users created through the Databases module. Now, users will automatically authenticate upon connecting, eliminating the need for manual login screens and improving the overall user experience.
Original PR description
## [IMP] databases: SSO smooth connection and setup The aim of this commit is to allow databases_user to be directly connected to any remote SaaS database to which they have access. When they click…
## [IMP] databases: SSO smooth connection and setup
The aim of this commit is to allow databases_user to be directly connected to
any remote SaaS database to which they have access.
When they click the "connect" button, they will bypass the login screen and be
authenticated automatically.
To achieve this, when a user tries to connect to an accessible SaaS database, we
quickly write their `oauth_uid` to that remote database right before the
connection is initiated.
Before this commit:
A user that was created in the remote db using the create user feature from the
databases module wouldn't get automatically authenticated through the Odoo
OAuth SSO feature.
After this commit:
Users attempting to connect to a SaaS database will be directly connected if the
settings was activated.
task-id: 6071808
## TODO:
- [x] check if we always have oauth_uid for saas db
- [x] think about making the oauth module autoinstall (make a bridge module? or overkill?)
- We can avoid that and have everything work in place directly, avoiding an inheritance nightmare at installation time.
- [x] handle cases where it isn't there on both the remote db and the managing one
- [x] write some tests to ensure the code is free from traceback
- [x] add a feature allowing to:
- [x] add it to all server on which the user has access
- [x] add it to a specific server (may require the db list view on `res.users`
- [x] remove the previous and do everything when the user click on "connect"
- [x] would be better to put the code in a new module with auto install => people get auto-install + no "hacky" code.
- The "hacky" code is not so hacky and with that we can directly advertise the installation of `auth_oauth` in an action
- [x] add a config in the settings
Forward-Port-Of: odoo/enterprise#112369Resolved issues and error corrections
This update prevents users from incorrectly increasing refund quantities when processing gift card or e-wallet orders in the ticket screen. Previously, clicking these orderlines would lead to unintended quantity adjustments. This change ensures accurate refund processing and improves the overall reliability of the point-of-sale system.
Original PR description
Before this commit: =================== - Clicking an e-wallet or gift card orderline in the ticket screen increased the refund quantity. After this commit: ================== - Gift card and e-wallet products are now restricted from refund quantity increments in the ticket screen. Task - 6200888
This update fixes an issue where preparation times weren't accurately calculated when order stages changed and where the preparation time report incorrectly included data from all companies. The changes now ensure preparation times are correctly updated and that reports only show data for the active company, improving the accuracy of order preparation tracking.
Original PR description
Issues: - Preparation time for order lines was not computed when the preparation order stage changed. - Preparation time report aggregated orders across all companies instead of showing records for the active company only. Fixes: - Ensure preparation time is properly recomputed when the order stage changes. - Add company domain filtering to the preparation time report. Task-6250974 Forward-Port-Of: odoo/enterprise#118738
This update resolves an issue that prevented efficient processing of invoices with multiple related documents (specifically those related to Mexican tax filings - CFDI). By using a specialized index, the system now handles complex cancellation scenarios and large volumes of data more effectively, ensuring smoother invoice workflows.
Original PR description
The field `l10n_mx_edi_cfdi_origin` can contain a large number of associated UUIDs, especially in complex cancellation scenarios. The default B-tree index fails when this field exceeds 2704 bytes, which occurs after approximately 20 UUIDs. By switching to a trigram index, we avoid the entry size limit of PostgreSQL's B-tree nodes. This ensures that invoices with many related documents can be processed while maintaining efficient search performance for partial matches on this field. **Video before the fix:** https://youtu.be/24u0HbxwIH8 **Video after the fix:** https://youtu.be/sUelv1HZMvI Forward-Port-Of: odoo/enterprise#118868
This update corrects a previous issue where Odoo was incorrectly selecting unavailable couriers from Shiprocket. The fix now filters out 'blocked' couriers, ensuring only service-eligible options are considered for shipping rates and selections. Additionally, the system is more robust to handle potential errors in Shiprocket's data.
Original PR description
Shiprocket provides an odablock flag in the courier serviceability response. Couriers with odablock=True are not serviceable for the requested route and should not be considered for rate calculation or selection. Before this change, Odoo selected the first courier returned by Shiprocket regardless of its ODA status. As a result, unavailable couriers could be proposed to users and selected for shipments. The fix filters out ODA-blocked couriers before evaluating available services, ensuring that only serviceable couriers are considered. Additionally, freight charge parsing is hardened to gracefully handle non-numeric values returned by Shiprocket, preventing errors during AWB assignment and price computation. FYI: Shiprocket uses odablock=False for serviceable routes and odablock=True for routes that are blocked for a given courier. opw-6288768,6152279 Forward-Port-Of: odoo/enterprise#120374
This fix resolves an issue where extra prices were incorrectly applied to products with 'always' attributes when creating point-of-sale combos. The update ensures that extra prices are now set on the combo creation page for 'always' attributes, aligning with how the system should calculate prices for these product variations.
Original PR description
## Steps to reproduce - Create an attribute A, of type always, with 2 values, one should have an extra price - Create an attribute B, of type never, with 2 values - Create a product that has both…
## Steps to reproduce - Create an attribute A, of type always, with 2 values, one should have an extra price - Create an attribute B, of type never, with 2 values - Create a product that has both those attributes - Create a combo with that product with both values for A - Go to the PoS and order that combo with the value that has an extra price for A - The extra price is added ## Why the fix: For variants of type always, a product is created, meaning we can chose which products of this variants to have in our combo. As we can chose this, it means that we can and should chose the extra price on the combo creation page, not on the attribute page. It does not make sense to take the attribute extra price into account, as we do not take the unit price of combo items into account, so this extra price should be set on the combo page and we should ignore the attribute's extra price if the type is "always". The variants are then considered as different products, as they should in this case. If the type of the attribute is never, we can't chose which one gets an extra price on the combo page, so we should still take the attribute's extra price in this situation, as we have no other way to set it. We need to have both an always and a never attribute in order to reproduce this bug because if we only have "always" values, the configuration of the combo item is bypassed and is undefined, so **attribute_value_ids** will be undefined in this code and we won't get any value for the extra price in this code: https://github.com/odoo/odoo/blob/c09e8b2fc24ee75495fc947924e29cf5c601506f/addons/point_of_sale/static/src/app/models/utils/compute_combo_items.js#L44-L49 We now ignore the attribute's extra price if it's type is always, otherwise, it the behavior stays the same. opw-6262431 Forward-Port-Of: odoo/odoo#270894 Forward-Port-Of: odoo/odoo#268567
This update resolves an issue where recurring plans would disappear from the website when a product's quantity was increased. The original fix only worked on the initial page load, but this change ensures the recurring plan selection remains accurate even after updates to the product's price or variant. This improves the user experience for subscription customers.
Original PR description
# Introduction note This PR fixes two bugs introduced by the same commit : https://github.com/odoo/enterprise/commit/106d70a1ef0ddbd61a74b7cac82dfce1e316beaa The original commit fixed multiple issues…
# Introduction note This PR fixes two bugs introduced by the same commit : https://github.com/odoo/enterprise/commit/106d70a1ef0ddbd61a74b7cac82dfce1e316beaa The original commit fixed multiple issues regarding the display of recurring plans when the One-time purchase option was enabled, but it also introduced new ones. Theses new issues are due to multiple new checks on `allow_one_time_sale`, but this variable only indicates that the One-time purchase option is available to the user, not that it is actually selected. So the fixes of the original commit works when first loading the page, but fails when the content of the page is updated. # Shared steps - Activate Subscriptions & eCommerce modules - Create a subscription product, enable 'Accept One-Time' and publish it on the website # Bug 1 ## How to reproduce - Add atleast two recurring plans to the product - Go to the product page on the website - Select one of the recurring plans - Increase the quantity of the product ## The problem The recurring plan selection is removed ## Cause The condition `!combination_info.allow_one_time_sale` was added on the `t-att-checked` of the recurring plan selection display. This correctly fixed the issue when first loading the page, but when the user changes the price or the variant, the recurring plan are recomputed and rerendered : https://github.com/odoo/enterprise/blob/0b408acbadb2cfcbc844521f3244a06b7ae7be22/website_sale_subscription/static/src/interactions/product_page.js#L37-L40 When that is the case, that condition blocks the proper display of the selected recurring plan. ## Proposed Solution When loading the recurring plan selection, what defines wich plan is selected is the `subscription_default_pricing_plan_id` variable, which is based on the `plan_id` value given in the request to the server : https://github.com/odoo/enterprise/blob/0b408acbadb2cfcbc844521f3244a06b7ae7be22/website_sale_subscription/models/product_template.py#L222 We make it so if no `plan_id` is sent to the server and `allow_one_time_sale` is enabled, then the server does not give back any `subscription_default_pricing_plan_id` opw-6131532 # Bug 2 ## How to reproduce - Add an attribute with values A & B for the product - Define atleast two recurring plans for the variant with attribute B - Publish the product - Go to the product page - Select the variant with attribute B ## The problem The recurring plan is not displayed. If the order of the attribute is reversed, then it works as expected. ## Cause The pricings are correcly sent to the front-end but they are not added to selection because of the check on `allow_one_time_sale` : https://github.com/odoo/enterprise/blob/0b408acbadb2cfcbc844521f3244a06b7ae7be22/website_sale_subscription/static/src/interactions/product_page.js#L42-L50 opw-6132160 Forward-Port-Of: odoo/enterprise#120873 Forward-Port-Of: odoo/enterprise#115446
This update fixes a bug in the stock valuation calculation that incorrectly displayed product values when multiple companies and currencies were involved. The fix ensures that values are accurately converted to the main company's currency (USD) for a correct total value calculation. This impacts how stock values are reported across different company setups.
Original PR description
**Steps to reproduce:** - make sure your main company (company 1) has dollars as its main currency - create second company (company 2) and a warehouse in this second company - set euro has the main…
**Steps to reproduce:** - make sure your main company (company 1) has dollars as its main currency - create second company (company 2) and a warehouse in this second company - set euro has the main currency in the company 2 From company 1: - set an exchange rate of 1$ = 0.5 eur on the euro currency - create a storable product with a cost of 10$ and an on-hand quantity of 1 From company 2: - set the cost to 10 eur and set an on-hand quantity of 1 with both company selected and company 1 as the main company selected: - open the stock view and look for your product **Current behavior:** the total value is 20$ **Expected behavior:** with conversion rate, it should be 30$ **Cause of the issue:** when computing the total value we do not apply a conversion rate from the value of the company to the main company selected https://github.com/odoo/odoo/blob/8759429547e42e9f63b15a7c80475be46ef437e2/addons/stock_account/models/product.py#L273 opw-6280108 Forward-Port-Of: odoo/odoo#270575
A recent update caused the Point of Sale system to incorrectly add the 'S' variant when scanning a barcode for the 'M' variant of a product with dynamic attributes. This fix ensures that the correct variant is always added, improving the accuracy of sales transactions. The change corrects a logic error in how the system handles product variants with dynamic attributes.
Original PR description
Steps to reproduce ------------------ 1. Create a product with two attributes: - Size with values S and M (Variants Creation: "Instantly") - a second attribute with a single value (Variants Creation: "Dynamically") 2. Set a different barcode on the S and the M variant. 3. Open PoS, scan the barcode of M. -> The S variant is added instead. Why the issue ------------- In 390b48a1ba24, when a product has a single-value attribute set to "dynamic", we look for the first variant that has this value and use it instead of the preselected variant. This is wrong when several variants share this value: in our case both S and M have it, so scanning M is overridden by the first variant, S. The fix ------- We now keep the preselected variant if it already has this value, and only look for or create one otherwise. opw-6272739 Forward-Port-Of: odoo/odoo#268590
This update fixes an issue where reordering rules were incorrectly creating purchase orders linked to sales orders. Now, reordering rules will always generate new, separate purchase orders, ensuring accurate inventory management and preventing duplicate purchase orders. This improves order fulfillment efficiency.
Original PR description
Steps to reproduce the bug: - Go to contact: - azure interior: - Group RFQ: On Order - Create two storable products P1 and P2, both with the Buy route and Azure interior as vendor - Confirm a sale…
Steps to reproduce the bug:
- Go to contact:
- azure interior: - Group RFQ: On Order
- Create two storable products P1 and P2, both with the Buy route and Azure interior as vendor
- Confirm a sale order with P1 (MTO+Buy):
- a purchase order PO1 is created, linked to the sale order via reference_ids
- Create a reordering rule for P2 and trigger it
Problem:
The reordering rule procurement for P2 was merged into PO1 (the sale order's purchase order) instead of creating a new separate PO.
In _make_po_get_domain (purchase_stock/models/stock_rule.py), when group_rfq == 'default' (On Order), the domain only adds a reference_ids filter when the procurement carries reference_ids. When the procurement comes from a reordering rule (no sale order, no reference_ids), no filter was added, so the search matched any draft PO from that vendor, including PO1, which has reference_ids pointing to the sale order.
Solution:
When group_rfq == 'default' and the procurement has no reference_ids, add ('reference_ids', '=', False) to the domain so the search only matches POs that are also not linked to any sale order.
opw-6167835
Forward-Port-Of: odoo/odoo#270735This update corrects a scheduling issue in manufacturing orders where operations with dependencies were not always processed in the correct order. The fix ensures operations are planned based on their dependencies, preventing delays and improving production efficiency. This resolves a conflict when planning operations with shared blockers.
Original PR description
Bug introduced in: https://github.com/odoo/odoo/commit/cfc5c998035b4268c36f5097782888e18e21b4fe Steps to reproduce the bug: - Create a product with a BoM with operation dependencies enabled - Add 4…
Bug introduced in: https://github.com/odoo/odoo/commit/cfc5c998035b4268c36f5097782888e18e21b4fe
Steps to reproduce the bug:
- Create a product with a BoM with operation dependencies enabled
- Add 4 operations on the same workcenter:
- opA: no blocker
- opB: blocked by opA
- opC: blocked by opA
- opD: blocked by opC
- Confirm a manufacturing order from this BoM
- Click Plan
Problem:
opA was scheduled after opB, violating the dependency.
`_plan_workorders` starts planning from the "leaf" workorders (those
with no dependents). Given the structure above, the initial set is
[opB, opD]. Processing opB first correctly plans opA then opB. But
processing opD triggers a recursive chain opD→opC→opA which calls
`action_unplan(opA)` and replans it from scratch. By then, opB already
occupies the workcenter slot that opA originally held, so opA ends up
scheduled after opB.
Solution:
Add `and not wo.is_planned` to the filter on `blocked_by_workorder_ids` in the recursive call inside `_plan_workorders`. Workorders that are already planned are skipped instead of being unplanned and replanned, preserving the correct order.
opw-6299179This update resolves a bug where clicking gift cards, e-wallets, or discount order lines in the ticket screen incorrectly increased refund quantities. Now, these product types are properly restricted from quantity increments during refunds, ensuring accurate transaction processing.
Original PR description
pos*: point_of_sale, pos_loyalty, pos_discount Before this commit: =================== - Clicking an e-wallet, gift card, discount order line in the ticket screen increased the refund quantity. After this commit: ================== - Gift card, e-wallet and discount products are now restricted from refund quantity increments in the ticket screen. Task-6200888 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves a crash that occurred when users tried to view Instagram videos within Odoo. The fix now displays the video link instead of attempting to render the video as an image, ensuring a stable preview experience. This improves usability and prevents disruptions for users accessing Instagram content.
Original PR description
Purpose ======= When we have a real on Instagram, we try to show the video as an image. When clicking on the broken image, the previewer crash. To fix that issue, we know show the link of the video in the message. Task-5491124 Forward-Port-Of: odoo/enterprise#121176 Forward-Port-Of: odoo/enterprise#113487
This update corrects a bug where the invoice status cron job only processed invoices for the main company. Now, it accurately retrieves and updates the status of invoices across all companies within the Odoo system. This ensures accurate reporting and compliance for all business entities.
Original PR description
The invoice status cron was only fetching the main company's invoices. Fetch all companies' invoice statuses. Reference: https://github.com/odoo/odoo/pull/267144#discussion_r3441968099 no-task Forward-Port-Of: odoo/odoo#271227
8 changes
New functionality added to Odoo
This update streamlines connections to remote SaaS databases for users created through the Odoo Databases module. Now, users automatically authenticate upon connecting, eliminating the need for manual login steps and improving the overall user experience. This enhancement ensures seamless access to data for users managing SaaS databases.
Original PR description
## [IMP] databases: SSO smooth connection and setup The aim of this commit is to allow databases_user to be directly connected to any remote SaaS database to which they have access. When they click…
## [IMP] databases: SSO smooth connection and setup
The aim of this commit is to allow databases_user to be directly connected to
any remote SaaS database to which they have access.
When they click the "connect" button, they will bypass the login screen and be
authenticated automatically.
To achieve this, when a user tries to connect to an accessible SaaS database, we
quickly write their `oauth_uid` to that remote database right before the
connection is initiated.
Before this commit:
A user that was created in the remote db using the create user feature from the
databases module wouldn't get automatically authenticated through the Odoo
OAuth SSO feature.
After this commit:
Users attempting to connect to a SaaS database will be directly connected if the
settings was activated.
task-id: 6071808
## TODO:
- [x] check if we always have oauth_uid for saas db
- [x] think about making the oauth module autoinstall (make a bridge module? or overkill?)
- We can avoid that and have everything work in place directly, avoiding an inheritance nightmare at installation time.
- [x] handle cases where it isn't there on both the remote db and the managing one
- [x] write some tests to ensure the code is free from traceback
- [x] add a feature allowing to:
- [x] add it to all server on which the user has access
- [x] add it to a specific server (may require the db list view on `res.users`
- [x] remove the previous and do everything when the user click on "connect"
- [x] would be better to put the code in a new module with auto install => people get auto-install + no "hacky" code.
- The "hacky" code is not so hacky and with that we can directly advertise the installation of `auth_oauth` in an action
- [x] add a config in the settings
Forward-Port-Of: odoo/enterprise#112369Resolved issues and error corrections
This update fixes an issue where preparation times weren't accurately calculated when order stages changed and where the preparation time report incorrectly included data from all companies. The changes now ensure preparation times are correctly updated and the report displays data specific to the active company, improving reporting accuracy.
Original PR description
Issues: - Preparation time for order lines was not computed when the preparation order stage changed. - Preparation time report aggregated orders across all companies instead of showing records for the active company only. Fixes: - Ensure preparation time is properly recomputed when the order stage changes. - Add company domain filtering to the preparation time report. Task-6250974 Forward-Port-Of: odoo/enterprise#118738
This update resolves an issue that prevented efficient processing of invoices with multiple related documents (specifically those involving Mexican tax cancellations). By using a different database index, the system now handles a greater volume of invoices without performance slowdowns, ensuring smoother operations for our Mexican customers. This change improves the reliability of the l10n_mx_edi module.
Original PR description
The field `l10n_mx_edi_cfdi_origin` can contain a large number of associated UUIDs, especially in complex cancellation scenarios. The default B-tree index fails when this field exceeds 2704 bytes, which occurs after approximately 20 UUIDs. By switching to a trigram index, we avoid the entry size limit of PostgreSQL's B-tree nodes. This ensures that invoices with many related documents can be processed while maintaining efficient search performance for partial matches on this field. **Video before the fix:** https://youtu.be/24u0HbxwIH8 **Video after the fix:** https://youtu.be/sUelv1HZMvI Forward-Port-Of: odoo/enterprise#118868
This update corrects a previous issue where Odoo was incorrectly selecting unavailable couriers from Shiprocket. The change now filters out 'blocked' couriers, ensuring only valid options are considered for shipping rates and selections. Additionally, the system is more robust to handle unexpected data from Shiprocket, preventing errors in pricing.
Original PR description
Shiprocket provides an odablock flag in the courier serviceability response. Couriers with odablock=True are not serviceable for the requested route and should not be considered for rate calculation or selection. Before this change, Odoo selected the first courier returned by Shiprocket regardless of its ODA status. As a result, unavailable couriers could be proposed to users and selected for shipments. The fix filters out ODA-blocked couriers before evaluating available services, ensuring that only serviceable couriers are considered. Additionally, freight charge parsing is hardened to gracefully handle non-numeric values returned by Shiprocket, preventing errors during AWB assignment and price computation. FYI: Shiprocket uses odablock=False for serviceable routes and odablock=True for routes that are blocked for a given courier. opw-6288768,6152279 Forward-Port-Of: odoo/enterprise#120374
A recent update caused the Point of Sale system to incorrectly add the 'S' variant when scanning a barcode for the 'M' variant of a product with dynamic attributes. This fix ensures that the correct variant is added based on the scanned barcode, improving the accuracy of sales transactions. The change corrects a logic error in how the system handles product variants with dynamic attributes.
Original PR description
Steps to reproduce ------------------ 1. Create a product with two attributes: - Size with values S and M (Variants Creation: "Instantly") - a second attribute with a single value (Variants Creation: "Dynamically") 2. Set a different barcode on the S and the M variant. 3. Open PoS, scan the barcode of M. -> The S variant is added instead. Why the issue ------------- In 390b48a1ba24, when a product has a single-value attribute set to "dynamic", we look for the first variant that has this value and use it instead of the preselected variant. This is wrong when several variants share this value: in our case both S and M have it, so scanning M is overridden by the first variant, S. The fix ------- We now keep the preselected variant if it already has this value, and only look for or create one otherwise. opw-6272739 Forward-Port-Of: odoo/odoo#268590
This update corrects a bug where reordering rules were incorrectly creating purchase orders linked to sales orders. Now, reordering rules will always generate new, separate purchase orders, ensuring accurate inventory management and preventing duplicate purchase orders. This improves order fulfillment efficiency.
Original PR description
Steps to reproduce the bug: - Go to contact: - azure interior: - Group RFQ: On Order - Create two storable products P1 and P2, both with the Buy route and Azure interior as vendor - Confirm a sale…
Steps to reproduce the bug:
- Go to contact:
- azure interior: - Group RFQ: On Order
- Create two storable products P1 and P2, both with the Buy route and Azure interior as vendor
- Confirm a sale order with P1 (MTO+Buy):
- a purchase order PO1 is created, linked to the sale order via reference_ids
- Create a reordering rule for P2 and trigger it
Problem:
The reordering rule procurement for P2 was merged into PO1 (the sale order's purchase order) instead of creating a new separate PO.
In _make_po_get_domain (purchase_stock/models/stock_rule.py), when group_rfq == 'default' (On Order), the domain only adds a reference_ids filter when the procurement carries reference_ids. When the procurement comes from a reordering rule (no sale order, no reference_ids), no filter was added, so the search matched any draft PO from that vendor, including PO1, which has reference_ids pointing to the sale order.
Solution:
When group_rfq == 'default' and the procurement has no reference_ids, add ('reference_ids', '=', False) to the domain so the search only matches POs that are also not linked to any sale order.
opw-6167835
Forward-Port-Of: odoo/odoo#270735This update fixes an error in the generation of CFDI documents when payments are made in foreign currencies. Previously, the CFDI document incorrectly displayed the payment rate. The fix ensures the correct payment amount and rate are reflected in the generated CFDI document, improving accuracy for Mexican businesses.
Original PR description
The rate and payment amount shown on the CFDI document generated after updating payments was wrong when the payment was made in a foreign currency. Steps to reproduce: ------------------- * Create a journal that use USD as currency and set the rate to 20 MXN for 1 USD * Create an invoice in MXN and make sure it is set to PPD * Add any product to the invoice for 300$ and post it * Send the invoice to CFDI (a first document should be generated) * Create a payment of 15 USD in the new journal and reconcile it with the invoice * Go back to the invoice and click on "Update payments" to generate the second CFDI document > Observation: The payment document shows an amount of 300 USD with a rate of 1 instead of 15 USD with a rate of 20. Why the fix: ------------ We make sure to use the amount from the statement line when there is one. opw-5974519 Forward-Port-Of: odoo/enterprise#120934 Forward-Port-Of: odoo/enterprise#115779
This update resolves an issue where the invoice status cron job only processed invoices for the primary company within Odoo. The fix ensures that all companies within an Odoo instance are now correctly updated, improving invoice tracking and reporting accuracy. This change was made to align with best practices for multi-company environments.
Original PR description
The invoice status cron was only fetching the main company's invoices. Fetch all companies' invoice statuses. Reference: https://github.com/odoo/odoo/pull/267144#discussion_r3441968099 no-task Forward-Port-Of: odoo/odoo#271227
4 changes
Resolved issues and error corrections
This update fixes an issue where preparation times weren't accurately calculated and reports incorrectly combined data across all companies. Now, preparation times are correctly updated when order stages change, and reports only show data for the active company, leading to more reliable and accurate order management.
Original PR description
Issues: - Preparation time for order lines was not computed when the preparation order stage changed. - Preparation time report aggregated orders across all companies instead of showing records for the active company only. Fixes: - Ensure preparation time is properly recomputed when the order stage changes. - Add company domain filtering to the preparation time report. Task-6250974 Forward-Port-Of: odoo/enterprise#118738
This update fixes an issue where Odoo was incorrectly selecting unavailable couriers from Shiprocket. The change now filters out ‘blocked’ couriers, ensuring only serviceable options are considered for rate calculation and shipment selection. Additionally, the system is more robust to handle potential errors in Shiprocket’s data, preventing shipment delays.
Original PR description
Shiprocket provides an odablock flag in the courier serviceability response. Couriers with odablock=True are not serviceable for the requested route and should not be considered for rate calculation or selection. Before this change, Odoo selected the first courier returned by Shiprocket regardless of its ODA status. As a result, unavailable couriers could be proposed to users and selected for shipments. The fix filters out ODA-blocked couriers before evaluating available services, ensuring that only serviceable couriers are considered. Additionally, freight charge parsing is hardened to gracefully handle non-numeric values returned by Shiprocket, preventing errors during AWB assignment and price computation. FYI: Shiprocket uses odablock=False for serviceable routes and odablock=True for routes that are blocked for a given courier. opw-6288768,6152279 Forward-Port-Of: odoo/enterprise#120374
This update resolves a crash that occurred when users tried to view Instagram videos within Odoo. The fix now displays the video link instead of attempting to render the video as an image, ensuring a stable preview experience. This improves usability for Instagram integration.
Original PR description
Purpose ======= When we have a real on Instagram, we try to show the video as an image. When clicking on the broken image, the previewer crash. To fix that issue, we know show the link of the video in the message. Task-5491124 Forward-Port-Of: odoo/enterprise#121176 Forward-Port-Of: odoo/enterprise#113487
This update fixes an error in the generation of CFDI documents for payments made in foreign currencies. Previously, the rate used was incorrect, leading to inaccurate amounts displayed on the CFDI. The fix ensures the correct payment amount and rate are used, improving the accuracy of financial reporting for Mexican businesses.
Original PR description
The rate and payment amount shown on the CFDI document generated after updating payments was wrong when the payment was made in a foreign currency. Steps to reproduce: ------------------- * Create a journal that use USD as currency and set the rate to 20 MXN for 1 USD * Create an invoice in MXN and make sure it is set to PPD * Add any product to the invoice for 300$ and post it * Send the invoice to CFDI (a first document should be generated) * Create a payment of 15 USD in the new journal and reconcile it with the invoice * Go back to the invoice and click on "Update payments" to generate the second CFDI document > Observation: The payment document shows an amount of 300 USD with a rate of 1 instead of 15 USD with a rate of 20. Why the fix: ------------ We make sure to use the amount from the statement line when there is one. opw-5974519 Forward-Port-Of: odoo/enterprise#120934 Forward-Port-Of: odoo/enterprise#115779
6 changes
Resolved issues and error corrections
This update corrects a previous issue where Odoo was incorrectly selecting unavailable couriers from Shiprocket due to a lack of filtering. The change now ensures only serviceable couriers are considered, improving shipment accuracy and preventing errors in rate calculations. Additionally, the system is now more robust in handling potential errors from Shiprocket's data.
Original PR description
Shiprocket provides an odablock flag in the courier serviceability response. Couriers with odablock=True are not serviceable for the requested route and should not be considered for rate calculation or selection. Before this change, Odoo selected the first courier returned by Shiprocket regardless of its ODA status. As a result, unavailable couriers could be proposed to users and selected for shipments. The fix filters out ODA-blocked couriers before evaluating available services, ensuring that only serviceable couriers are considered. Additionally, freight charge parsing is hardened to gracefully handle non-numeric values returned by Shiprocket, preventing errors during AWB assignment and price computation. FYI: Shiprocket uses odablock=False for serviceable routes and odablock=True for routes that are blocked for a given courier. opw-6288768,6152279 Forward-Port-Of: odoo/enterprise#120374
This update resolves an issue where E-Way Bill amounts were incorrectly calculated when sales prices included tax. The fix ensures that tax is handled correctly, producing accurate amounts in both the printed E-Way Bill and the JSON data. This ensures compliance with Indian tax regulations.
Original PR description
`*` = `ewaybill_Stock, sale_stock, purchase_stock` **Steps to reproduce:** * Install `l10n_in_ewabill_stock` and `l10n_in_sale_Stock`. * Set the Default Tax Price Setting to "Tax Included". * Create…
`*` = `ewaybill_Stock, sale_stock, purchase_stock` **Steps to reproduce:** * Install `l10n_in_ewabill_stock` and `l10n_in_sale_Stock`. * Set the Default Tax Price Setting to "Tax Included". * Create a Sales Order (e.g. unit price 300, qty 600, 18% GST) and confirm the Delivery Challan/Delivery Order. * Generate an E-Way Bill from the Delivery Challan. **Observed behavior:** * The Taxable Amount and Total Invoice Amount are displayed incorrectly in the generated E-Way Bill, including both the printed document and the JSON. * The `ewaybill_price_unit` shows the tax-excluded price (e.g. 254.24) instead of the original tax-included price (300), leading to a double tax exclusion when `compute_all` processes it. **Cause:** * `_l10n_in_get_product_price_unit` in both `l10n_in_sale_stock` and `l10n_in_purchase_stock` unconditionally used `price_subtotal / qty` to compute the E-Way Bill price unit. `price_subtotal` is always tax-excluded, so for tax-included prices, the tax was already stripped. * `_l10n_in_tax_details_by_stock_move` then passed this already tax-excluded price to `compute_all` with taxes that have `price_include=True`, causing `compute_all` to strip the tax a second time (e.g. 254.24 / 1.18 = 215.46 instead of the correct 254.24). **Fix:** * Check whether any of the line's taxes have `price_include` set. If so, use `price_total / qty` (which preserves the tax-included price) so that `compute_all` can correctly extract the tax. Otherwise, continue using `price_subtotal / qty` as before. opw-6273101 Forward-Port-Of: odoo/odoo#271264 Forward-Port-Of: odoo/odoo#268504
This update resolves an issue where the due date calculation for French payroll was incorrect, specifically returning a month of 0 for November transactions. It also corrects a technical error that prevented the system from properly processing empty recordsets, improving data reliability. This ensures accurate reporting and compliance for French businesses using this module.
Original PR description
- Fix due date calculation (returned month 0 if move date was in November) - Fix ensure_one error, avoid calling _deduce_country_code() on an empty recordset opw-6293701 Forward-Port-Of: odoo/odoo#270003
This update significantly speeds up the calculation of future timesheets based on public holidays. The previous process was slow and inefficient, especially when many holidays were defined. This change optimizes the calculation, resulting in faster timesheet generation and improved system performance.
Original PR description
**Problem:** When creating a new employee, the future timesheets due to public holidays are computed. If the number of public holidays is large (i.e. if the user creates them for each year, several…
**Problem:** When creating a new employee, the future timesheets due to public holidays are computed. If the number of public holidays is large (i.e. if the user creates them for each year, several years in the future), then it takes excessively long and the action may not complete. **Cause:** The pytz method `localize` and comparing times with non-static timezones is done repeatedly and unnecessarily which becomes costly with more records. **Solution:** Only localize the time when absolutely necessary (determining the date of the leave in the calendar timezone). **Performance Stats:** |Record count|Time before|Queries before|Time after|Queries after| |------------|-----------|--------------|----------|-------------| |100 |3.1s |393 |0.8s |117 | |1,000 |22.3s |2,090 |1.5s |183 | |10,000 |Timeout |N/A |6.7s |541 | opw-6087422 Forward-Port-Of: odoo/odoo#269876 Forward-Port-Of: odoo/odoo#263953
This update resolves an issue where Android 14 users couldn't access their camera when uploading images through the Odoo web interface. The fix ensures users can now select photos from their device, improving usability on this popular operating system. This enhancement addresses a compatibility problem identified by Google and other developers.
Original PR description
Since Android 14 we don't have option to take a photo on clicking on file input in Chrome.
This for example will allow only images but no option "Camera"
```html
<input type="file" accept="image/*/>
```
A workaround is to use a dummy mimetype (`*/*`), example `dummy/allowAndroidCamera` The fix will be applied on image widget in addition to the original `acceptedFileExtensions` to not override the existing `accept` attribute
Linked url
- https://blog.addpipe.com/html-file-input-accept-video-camera-option-is-missing-android-14-15/
- https://stackoverflow.com/questions/77876374/html-input-type-file-not-working-to-pull-up-camera-for-pixel-android-14-comb/79163998#79163998
- https://issues.chromium.org/issues/40937303
opw-6040375
backport of https://github.com/odoo/odoo/pull/265750
Forward-Port-Of: odoo/odoo#268584
Forward-Port-Of: odoo/odoo#266850This update resolves a problem where the kitchen printer was incorrectly sending duplicate orders after merging table orders. Specifically, when identical products were combined, the system would re-send quantities that had already been printed. This fix ensures that quantities are accurately reflected in the kitchen printouts, improving order fulfillment efficiency.
Original PR description
When transferring an order to a table that already has an open order, identical products are merged into a single line. If both orders were already sent to the kitchen printer, the merged line was incorrectly marked as new and had to be sent again. Steps to reproduce: ------------------- * Open table 1, add product A (2 units) and product B, send to kitchen * Open table 2, add product A (3 units) and product C, send to kitchen * On table 2, transfer/merge the order to table 1 > Observation: product A shows 2 units as new and must be sent to the kitchen printer again, although all quantities were already sent. Why the fix: ------------ When merging preparation history for identical lines, handlePreparationHistory overwrote the destination sent quantity with the source one instead of summing both. The kitchen diff then treated the missing quantity as new changes. A unit test will be added in 18.3. opw-6246470 Forward-Port-Of: odoo/odoo#267915
2 changes
Resolved issues and error corrections
This update corrects a previous issue where Odoo was selecting unavailable couriers from Shiprocket due to a lack of filtering. The change now excludes 'blocked' couriers, ensuring only service-eligible options are considered for shipping rates and selections. Additionally, the system is more robust to handle potential errors in Shiprocket's data.
Original PR description
Shiprocket provides an odablock flag in the courier serviceability response. Couriers with odablock=True are not serviceable for the requested route and should not be considered for rate calculation or selection. Before this change, Odoo selected the first courier returned by Shiprocket regardless of its ODA status. As a result, unavailable couriers could be proposed to users and selected for shipments. The fix filters out ODA-blocked couriers before evaluating available services, ensuring that only serviceable couriers are considered. Additionally, freight charge parsing is hardened to gracefully handle non-numeric values returned by Shiprocket, preventing errors during AWB assignment and price computation. FYI: Shiprocket uses odablock=False for serviceable routes and odablock=True for routes that are blocked for a given courier. opw-6288768,6152279 Forward-Port-Of: odoo/enterprise#120374
This update resolves an issue preventing sales users with 'Own Documents Only' access from adding components to production orders. The fix adjusts security rules to grant necessary read access, ensuring sales users can correctly manage production orders created within their sales documents.
Original PR description
### Steps to reproduce: - Ensure `sale_stock_renting` is installed - Enable Multi-Steps Routes > Unarchive MTO - Create a product P with a BoM and the routes MTO + manufacture - Create anc confirm a…
### Steps to reproduce: - Ensure `sale_stock_renting` is installed - Enable Multi-Steps Routes > Unarchive MTO - Create a product P with a BoM and the routes MTO + manufacture - Create anc confirm a sale order for A unit of P - Log in with an other user with with mrp User rights and sales User: Own Documents Only (he should not have access to the SO) - Open the MO, add a component line and save #### > Access Error: Blame the following rule: - Personal Order ### Cause of the issue: Writing on the `move_raw_ids` will trigger a call of the `_autoconfirm_production` in order to confirm the newly created move: https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/mrp/models/mrp_production.py#L990-L991 https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/mrp/models/mrp_production.py#L1422-L1423 During this confirmation process, one calls the `_merge_moves` method in order to merge this new move (if relevant) to any already existing one. https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/stock/models/stock_move.py#L1575-L1576 Now, the issue is that, `sale_stock_renting` module overrides the method `_prepare_merge_moves_distinct_fields` determining the fields relevant to the merge by requiring a read access to the `is_rental_order` compute field of the `sale_order` linked to the MO: https://github.com/odoo/enterprise/blob/b66097122ba3a758734ac6fb2b26579c35cb72c2/sale_stock_renting/models/stock_move.py#L34-L40 However, due to the 'Personal Orders' ir.rule, the user does not have a read access to this record: https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/sale/security/ir_rules.xml#L44-L49 Community: https://github.com/odoo/odoo/pull/271017 opw-6275658 Forward-Port-Of: odoo/enterprise#121135
35 changes
New functionality added to Odoo
This update adds support for popular food delivery services like Talabna, Mandoob, and DiDi Food, expanding Odoo's reach to new markets. The changes also include backporting integrations for existing delivery providers, enhancing the platform's capabilities for restaurants and delivery businesses. This improves the user experience by offering more delivery options.
Original PR description
In this commit: - We are introducing new delivery providers like Talabna, Mandoob, Snoonu, DiDi Food and Zyada for different countries and backporting Radyes, ToYou, The Chefz, InstaShop and Smiles. Task-6263289,6263272,6263203,6263165,6310690 Forward-Port-Of: odoo/enterprise#121229 Forward-Port-Of: odoo/enterprise#119537
This update adds support for Belgium's new payroll regulations by mapping key codes (DMFA, eGov3, and salary categories) to the correct work entry types within the Odoo system. This ensures accurate and compliant payroll processing for Belgian businesses using the Enterprise edition.
Original PR description
Map DMFA codes, daily eGov3 codes, and salary categories to the new work entry types. Task: 6275946
This update consolidates SMS functionality into a new 'frontdesk_sms' module, improving organization and maintainability. It moves key SMS-related data and logic, and introduces a helper function to prevent code duplication, streamlining the frontdesk visitor management process.
Original PR description
In this PR we have moved all the sms related stuffs from **frontdesk** to **frontdesk_sms** Task-6068563
Enhancements to existing features
This update simplifies the process of creating company cars within the Odoo Enterprise system. It now automatically transfers information from the employee's existing car details to the company car creation form, eliminating a manual step. Furthermore, the quick create option has been removed, ensuring only authorized users can create and edit company car records.
Original PR description
This PR expected to pass input value from inventory car field in Employee Form to license plate field in create company car form and also remove quick create, only allowed create & edit task:6307500
This update implements the required NSSO reduction for elderly employees in Belgium (Brussels and Wallonia), aligning with recent regulations and ONSS guidelines. The changes improve the accuracy of these deductions, particularly regarding part-time worker calculations and wage caps. The update also addresses a critical issue with the µ calculation, ensuring it aligns with ONSS instructions for structural and target-group reductions.
Original PR description
Implements the NSSO elderly-worker reduction for Brussels (codes 7320) and Wallonia (8320/8321/8322), including the Wallonia 2023 reform and the 2026-04-01 hire-date sub-rule. Adds: * A monthly…
Implements the NSSO elderly-worker reduction for Brussels (codes
7320) and Wallonia (8320/8321/8322), including the Wallonia
2023 reform and the 2026-04-01 hire-date sub-rule.
Adds:
* A monthly salary rule producing an estimation of the quarterly G1
reduction prorated on the current slip, for payslip visibility.
* Dated hr.rule.parameter records holding the per-region bracket tables
(age_min, age_max, dmfa_code, G), the quarterly wage caps, and the
βg breakpoints.
* DMFAOccupationDeductionElderly in hr_dmfa.py: P = G × µ × βg per
matching bracket per occupation, with µ from declared service hours
and βg from the worker-level µ_global.
* Tests covering region/age/hire-date branching, the wage cap, part-time
µ rounding, and payslip-vs-DMFA parity.
Payslip estimation takes shortcuts that make it informational only: it
sums all worked-days hours instead of filtering DMFA service codes,
extrapolates one month × 3 instead of aggregating the real quarter,
uses the slip's own µ as µ_global, ignores multi-occupation aggregation,
checks the wage cap on ONSS_BASE × 3 instead of the proper ss_quarter,
and prorates the quarterly result flatly across months.
Shared bracket / βg / age helpers live on hr.payslip rather than in
hr_dmfa.py because the salary rule needs them at slip computation time
(before any DMFA export exists)
task - 6131498This update introduces a new NISS (National Identification Number) field to the Belgium salary configurator, aligning with local regulations. Previously, the identification_id field was removed, and now the system accepts an empty NISS value during validation. This ensures accurate employee data matching within the Odoo system for Belgian payroll.
Original PR description
[IMP] l10n_be_hr_contract_salary: NISS in salary configurator
1 - For Belgium salary configurator, identification_id field is deleted and NISS field is added
1.1 - NISS field is added to the version of l10n_be_hr_payroll as a related field (from employee), salary configurator applies on version and makes the matching
2 - Empty NISS in validation is accepted as well now (in the UI of salary configurator)
task - 6147359This update enhances the Odoo Enterprise mail system by incorporating new syntax for OWL 3 (part 3) properties. This improves the system's ability to handle complex data and relationships within Odoo's various modules, particularly those related to documents, accounting, and HR. It’s an important update to ensure continued compatibility and functionality.
Original PR description
Enterprise counter-part. task-6255532 https://github.com/odoo/odoo/pull/270123
This update improves the user experience by automatically notifying users via email and Odoo notifications when a document request is fulfilled. This ensures users are promptly informed about the status of their document requests, streamlining workflows and improving transparency.
Original PR description
When a document is requested from any user/partner, it is helpful to be notified when the document is uploaded. This commit does the same. The requester is notified with email/push notification when the document request is fulfilled. Some tests are also modified to verify the behaviour. Task-5446939
This update allows users to group and filter POS orders based on their DIAN transmission status, which was previously unavailable. Previously, it was difficult to identify rejected or failed orders, hindering visibility into the daily synchronization process. This change enhances reporting and provides better insights into POS order health.
Original PR description
The DIAN transmission status (l10n_co_edi_pos_dian_state) is a non-stored computed field, so it could not be used to group, filter or sort the POS Orders list: users had no way to isolate rejected or failed orders, nor to get an overview of daily sync health. Provide a compute_sql for the field so the ORM can express it in SQL, making it groupable/searchable/sortable without storing it. This avoids a schema change while keeping the value derived from the most recent DIAN document. task-6273842 Forward-Port-Of: odoo/enterprise#120929
This update removes the outdated 'reception report' feature and integrates changes from the community to improve barcode scanning and product allocation tracking. Specifically, it highlights unusual product locations and adds a button to print operation reports for allocated items, ensuring accurate inventory management.
Original PR description
*: industry_fsm_stock, stock_barcode, stock_barcode_picking_batch This commit adapts code to changes made in community: - Remove `stock.group_reception_report`; - Set `auto_show_reception_report` in picking type if needed. task-4894566 **Community PR:** odoo/odoo#264299 **Upgrade PR:** odoo/upgrade#10320
This update streamlines the loading process for Odoo's registry, resulting in a 7% performance improvement. The change removes an unnecessary check that slowed down loading times, particularly for the planning module. This translates to a quicker startup experience for the system.
Original PR description
has_group for superuser during module loading is slow and unnecessary (``@api.depends(lambda self: self._display_name_fields())``) This commit bypasses the check and improves the loading time by 7% for the registry (assume all modules are loaded in other registries) <img width="1504" height="382" alt="image" src="https://github.com/user-attachments/assets/94da0b4a-f728-4783-8883-5d7925dcb34b" />
This update streamlines the process for filing the 273S report, aligning with government regulations. It introduces a clear lifecycle for reports and proactive warnings to ensure accurate data submission, reducing potential errors and improving compliance.
Original PR description
This commit introduces a comprehensive management system for the 273S report, enhancing its lifecycle, data integrity, and user experience. It's important to note that filing a 237S report can…
This commit introduces a comprehensive management system for the 273S report, enhancing its lifecycle, data integrity, and user experience. It's important to note that filing a 237S report can involve one of the following declarations: 1. Initial declaration 2. Modification declaration 3. Cancellation declaration **After contacting the Service Public Federal (SPF) Finances, we have clarified that only Initial declarations are used in practice, and that modification and cancellation declarations are not used.** **Initial Declarations are used to modify reports that have already been declared** Ideally, a maximum of 12 Initial declarations should be used, but since modifications can also happen, a system is implemented to report the payslips of the year using the minimal amount of declared and corrected reports possible throughout the year by reporting each payslip that's not included in any ready/done report that exists in the period starting from the beginning of the year until the end of the month of the report. **Lifecycle & Structure** * 273S reports are now persistent documents with a clear lifecycle (Draft, Ready, Done, Cancelled) rather than transient pop-ups. * In the draft state, all fields are editable except Year and Month in the type `correction` since they are inherited from the original report. The original report is a required field for the correction type. Payslips are auto-populated if any of the fields (Year, Month, Original, Type) are updated. Populating a report differs based on its type; if it's an original declaration, then the report is populated by all payslips that are in a ready/done state that were issued starting from the current year and until the end of the declared month; if it's a correction report, then it's populated with payslips that aren't in a **finalised report**. **A finalised report is a report that is in a ready/done state and not one of its parent correction reports. Once the report has payslips in it, a button appears to generate the PDF (for the user) and XML (to be submitted) files.** * Once generated, the report moves to the Ready state, allowing users to review the data before final submission. In this state, all fields become non-editable except for the Reference field, which should be used to add the reference of the declaration received from the government after submission. The report can be set back to draft if any changes are needed. If a report that needs to be corrected was set to draft, it will no longer be considered in the first warning type since its `is_correction_needed` will be set to False. * Done state is the next state after Ready, which is achieved by the action `Mark as done` and requires the Reference field to be filled. Since the Reference field is important for the traceability of the declaration report, it's set to be tracked in the chatter. Done state and Ready state are alike except for the fact that Done state is for reports that are already declared to the government and have the reference of the declaration while Ready state is for reports that are generated but not yet declared to the government that's why a `Set to draft` action is allowed for Ready state and the Done state cannot be reached without filling the Reference field. The action `Correct` is shown for Done reports to allow creating a new correction report with the same period and payslips as the original report. * Cancelled state is the last state in the lifecycle and can be reached from any of the previous states. Once a report is cancelled, it cannot be set back to any other state, and all its data becomes non-editable except the Reference field. **UI & Proactive Warnings** * Two warnings are also added to the dashboard to alert the user when some reports are outdated and need to be corrected, or when some payslips are missing from the declaration of the previous year. * For the first warning, a report is considered outdated when one of its payslips has been cancelled after the report was generated. * For the second warning, a payslip is considered missing from last year's declaration when it belongs to the previous year and is not included in any ready/done report of the previous year. Missing payslips will be declared in December's Initial Declaration report of the previous year or a correction report if December's report is already declared. The warning for missing payslips of only one previous year is shown. Task: 5473528
This update enhances the accuracy of withholding tax calculations for Belgian employees. The changes incorporate more detailed criteria, such as residency status and employment duration, to ensure compliance with Belgian tax regulations and improve the precision of tax deductions.
Original PR description
In this commit, we improved the bareme computation in withholding tax, by taking into consideration more conditions (Resident, Frontalier, contract covering the full year, works in belgium for >= 75%, ..) task-6231497
This update allows administrators to directly adjust the total amounts for individual lines within payroll calculations. Previously, these totals were fixed, leading to potential discrepancies. This change improves payroll accuracy and provides greater control for financial teams.
Original PR description
Task: 6292521
This update enhances the timesheet assistant by allowing administrators to precisely control which employees receive suggestions based on new 'Applies To' settings. It also introduces a threshold feature, ensuring activity suggestions are only displayed when a specific usage level is reached, optimizing efficiency. This change improves the relevance and usability of the timesheet assistant.
Original PR description
- Replace the "Shared With" mechanism with an "Applies To" field to control which employees a rule applies to. - Add threshold support so activity suggestions are only displayed when the configured threshold is reached. task-6186073
This update enhances employee record management by adding a certificate column to employee profiles, allowing easy viewing and download. Additionally, uploaded certificates are now automatically stored in the Documents folder, streamlining the process for both new and existing certificates.
Original PR description
This PR includes some changes related to the certificates in hr_skills. First of all, we add a column in the list view found in the Certificates tab on the employee profile that shows the certificate that has been uploaded. This also allows the downloading of the certificate. Secondly, we make it so that if documents is installed, the uploaded certificates are uploaded to the Certificate folder in Documents. Task: 6210153
This update enhances the visual design of the call debrief transcription layout, making it more user-friendly. Specifically, it adds an 'active' state to the timeline markers, providing clearer visual cues for key moments during the call. This improves clarity and usability of the call debrief feature.
Original PR description
This commit refines the design of the call debrief transcription layout. It also adds an active state to the timeline markers. task-6119464 Requires: - https://github.com/odoo/odoo/pull/271103 --- |…
This commit refines the design of the call debrief transcription layout. It also adds an active state to the timeline markers. task-6119464 Requires: - https://github.com/odoo/odoo/pull/271103 --- | Header | Header | |--------|--------| | <img width="955" height="440" alt="Screenshot 2026-06-19 at 16 38 12" src="https://github.com/user-attachments/assets/114819c7-8bec-4a65-af13-9f834e692053" /> | <img width="947" height="820" alt="Screenshot 2026-06-19 at 16 39 24" src="https://github.com/user-attachments/assets/62374140-6819-4557-8181-6fd36b006cc5" /> | | <img width="960" height="247" alt="Screenshot 2026-06-19 at 16 38 28" src="https://github.com/user-attachments/assets/b25368c8-b545-4fc7-8211-907faed28926" /> | <img width="954" height="368" alt="Screenshot 2026-06-19 at 16 39 45" src="https://github.com/user-attachments/assets/1836c801-c383-43cb-aa11-ef2ec3e496cb" /> | | <img width="955" height="449" alt="Screenshot 2026-06-19 at 16 38 49" src="https://github.com/user-attachments/assets/983dd118-a3dd-4055-8af4-703217047e8b" /> | <img width="957" height="614" alt="Screenshot 2026-06-19 at 16 40 08" src="https://github.com/user-attachments/assets/5b22f3e4-9af7-4ce9-b3fd-b997964c5794" /> |
Resolved issues and error corrections
A recent payroll upgrade introduced an error preventing users from accessing the Wage Types configuration in Odoo. This change required restoring the action's update functionality to ensure the system correctly reflects the latest payroll structure settings. This fix resolves a critical issue impacting Swiss payroll functionality.
Original PR description
The Wage Types action record salary rules belonging to the CHMONTHLYELM payroll structure. During the payroll refactoring, salary rules were changed to support multiple payroll structures. in the…
The Wage Types action record salary rules belonging to the CHMONTHLYELM payroll structure.
During the payroll refactoring, salary rules were changed to support multiple payroll structures. in the 19.4 version here c2f18f3
Where struct_id M20 field is changes to [M2m](https://github.com/odoo/upgrade/pull/10294/changes#diff-541246af074f8ac598b0a274ef9861f5fe974e6ded22e906c3d35adecb284e8cR51) struct_ids
Opening Payroll > Configuration > Company > Wage Types will cause the issue as the action has not updated which Failes the [ci/upgrade_enterprise](https://runbot.odoo.com/runbot/batch/2598248/build/115031148)
Steps to reproduce.
- Create a database on saas-19.3.
- Install l10n_ch_hr_payroll.
- Upgrade the database to master.
- Open Payroll > Configuration > Company > Wage Types.
- Error raise error(message % (*args, self.field_expr, self.operator, self.value)) ValueError: Invalid field hr.salary.rule.struct_id in condition
('struct_id.code', '=', 'CHMONTHLYELM')
The issue will directly reproduce in the runbot maste too installed the l10n_ch_hr_payroll module and access the wage type.
```
Adding menu ('l10n_ch_hr_payroll.menu_l10n_ch_wage_types', 1598, 'Payroll > Configuration > Company > Wage Types', 2337) to the failing menus
Traceback (most recent call last):
File "[/data/build/odoo/odoo/orm/domains.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/domains.py#L964)", line 964, in __get_field
field = model._fields[field_name]
~~~~~~~~~~~~~^^^^^^^^^^^^
KeyError: 'struct_id'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "[/data/build/upgrade/migrations/base/tests/test_mock_crawl.py](https://github.com/odoo/upgrade/blob/07bec6a1031093cf001642f8df21e40421cce3be/migrations/base/tests/test_mock_crawl.py#L346)", line 346, in crawl_menu
self.mock_action(action_vals)
File "[/data/build/upgrade/migrations/base/tests/test_mock_crawl.py](https://github.com/odoo/upgrade/blob/07bec6a1031093cf001642f8df21e40421cce3be/migrations/base/tests/test_mock_crawl.py#L377)", line 377, in mock_action
return self.mock_act_window(action)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/upgrade/migrations/base/tests/test_mock_crawl.py](https://github.com/odoo/upgrade/blob/07bec6a1031093cf001642f8df21e40421cce3be/migrations/base/tests/test_mock_crawl.py#L537)", line 537, in mock_act_window
mock_method(model, view, fields_list, domain, group_by)
File "[/data/build/upgrade/migrations/base/tests/test_mock_crawl.py](https://github.com/odoo/upgrade/blob/07bec6a1031093cf001642f8df21e40421cce3be/migrations/base/tests/test_mock_crawl.py#L675)", line 675, in mock_view_list
return self.mock_view_tree(model, view, fields_list, domain, group_by)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/upgrade/migrations/base/tests/test_mock_crawl.py](https://github.com/odoo/upgrade/blob/07bec6a1031093cf001642f8df21e40421cce3be/migrations/base/tests/test_mock_crawl.py#L688)", line 688, in mock_view_tree
self.mock_web_search_read(model, view, [domain], fields_list)
File "[/data/build/upgrade/migrations/base/tests/test_mock_crawl.py](https://github.com/odoo/upgrade/blob/07bec6a1031093cf001642f8df21e40421cce3be/migrations/base/tests/test_mock_crawl.py#L722)", line 722, in mock_web_search_read
data = model.search_read(domain=domain, fields=fields_list, limit=80, order=filter_order(model))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/odoo/odoo/orm/models.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/models.py#L5187)", line 5187, in search_read
records = self.search_fetch(domain or [], fields, offset=offset, limit=limit, order=order)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/odoo/odoo/orm/models.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/models.py#L1462)", line 1462, in search_fetch
query = self._search(domain, offset=offset, limit=limit, order=order or self._order)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/odoo/odoo/orm/models.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/models.py#L4773)", line 4773, in _search
domain = domain.optimize_full(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/odoo/odoo/orm/domains.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/domains.py#L472)", line 472, in optimize_full
return self._optimize(model, OptimizationLevel.FULL)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/odoo/odoo/orm/domains.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/domains.py#L486)", line 486, in _optimize
previous, domain = domain, domain._optimize_step(model, next_level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/odoo/odoo/orm/domains.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/domains.py#L670)", line 670, in _optimize_step
children = self._flatten(child._optimize(model, level) for child in self.children)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/odoo/odoo/orm/domains.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/domains.py#L628)", line 628, in _flatten
for child in children:
File "[/data/build/odoo/odoo/orm/domains.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/domains.py#L670)", line 670, in <genexpr>
children = self._flatten(child._optimize(model, level) for child in self.children)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/odoo/odoo/orm/domains.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/domains.py#L486)", line 486, in _optimize
previous, domain = domain, domain._optimize_step(model, next_level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/odoo/odoo/orm/domains.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/domains.py#L988)", line 988, in _optimize_step
field, property_name = self.__get_field(model)
^^^^^^^^^^^^^^^^^^^^^^^
File "[/data/build/odoo/odoo/orm/domains.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/domains.py#L966)", line 966, in __get_field
self._raise("Invalid field %s.%s", model._name, field_name)
File "[/data/build/odoo/odoo/orm/domains.py](https://github.com/odoo/odoo/blob/2fb276668c824d6fe759a7c51f9ef10677532508/odoo/orm/domains.py#L951)", line 951, in _raise
raise error(message % (*args, self.field_expr, self.operator, self.value))
ValueError: Invalid field hr.salary.rule.struct_id in condition ('struct_id.code', '=', 'CHMONTHLYELM')
2026-06-22 12:02:29 [ERROR](https://github.com/odoo/upgrade-util/blob/f3431df77099e3df9299b9d6fb1ea001796c176c/src/testing.py#L483)
FAIL: TestCrawler.test_check
Traceback (most recent call last):
File "[/data/build/upgrade-util/src/testing.py](https://github.com/odoo/upgrade-util/blob/f3431df77099e3df9299b9d6fb1ea001796c176c/src/testing.py#L483)", line 483, in test_check
self.check(value)
File "[/data/build/upgrade/migrations/base/tests/test_mock_crawl.py](https://github.com/odoo/upgrade/blob/07bec6a1031093cf001642f8df21e40421cce3be/migrations/base/tests/test_mock_crawl.py#L230)", line 230, in check
self.assertFalse(diff, msg)
AssertionError: [('l10n_ch_hr_payroll.menu_l10n_ch_wage_types', 1598, 'Payroll > Configuration > Company > Wage Types', 2337)] is not false : At least one menu or view working before upgrade is not working after upgrade.
```
Soln:- Update the action with the correct field.
ref :- https://runbot.odoo.com/runbot/batch/2598248/build/115031148This update fixes a bug where rental order PDFs didn't show the pickup and return dates. The fix adds the necessary date fields to the PDF report, ensuring consistent information between the portal and the printed sales orders. This improves clarity for customers receiving rental order details.
Original PR description
**Problem:** On a rental order, the sales order / quotation PDF no longer shows the pickup and return dates. The line description only displays the rental duration (e.g. "2 Days"), so the actual…
**Problem:** On a rental order, the sales order / quotation PDF no longer shows the pickup and return dates. The line description only displays the rental duration (e.g. "2 Days"), so the actual dates are missing from the printout. **Steps to reproduce:** 1. Create a rental order with a rentable product and pickup/return dates 2. Print the order (Print > Quotation / Order) 3. Observe the PDF shows only the duration, with no pickup/return dates **Current behavior:** Neither the rental dates (removed from the description) nor any pickup/return field appear on the PDF. **Expected behavior:** The pickup and return dates are shown on the rental order PDF. **Cause of the issue:** The rental line description was intentionally reduced to only the duration (`_get_rental_duration_description`), the actual dates being meant to appear as dedicated Pickup/Return fields. This was added to the customer portal (`sale_rental_portal_details` inherits `sale.sale_order_portal_content`) but the equivalent was never added to the `sale.report_saleorder_document` PDF report, so the dates disappeared from the printout. **Fix:** Inherit the sale order report to render the order-level pickup and return dates for rental orders, mirroring the existing portal presentation so the PDF and the portal stay consistent. opw-6268640 Forward-Port-Of: odoo/enterprise#119736
This update fixes an issue preventing users from accessing payslip lists within the employee departure process. The changes include making fields read-only to prevent unintended modifications and relocating currency data to improve data handling. This ensures accurate payslip access and avoids errors.
Original PR description
Bug 1: In the departure tab of the Employee, you can't open the payslip list Fix: Added a check to get the correct departure id depending on the model we are in Bug 2: You can select payslips for other employees than the departing employee and the payslips list is not affected Fix: made fields `l10n_be_payslip_n_ids` and `l10n_be_payslip_n1_ids` readonly so they can't be modified in the UI without being saved Bug 3: You get an error because you can't read `currency_id` when opening n payslips (happens when the monetary fields are shown in the list) Fix: moved the `currency_id` to be inside the list instead of the parent form task-id: 6265648 Forward-Port-Of: odoo/enterprise#119402
This update resolves an issue preventing the 'Send to SII' option from appearing on Chilean vendor bills. The fix adjusts internal settings to correctly display this functionality, ensuring accurate electronic invoice submission for Chilean businesses. This ensures compliance with local tax regulations.
Original PR description
**Steps to reproduce:** * Install the **l10n_cl_edi** module. * Go to **Accounting → Configuration → CAFs**, create a new CAF, and upload a valid CAF…
**Steps to reproduce:** * Install the **l10n_cl_edi** module. * Go to **Accounting → Configuration → CAFs**, create a new CAF, and upload a valid CAF [XML](https://www.odoo.com/mail/message/1097235975) file. * Create a new **Purchase Journal** with **Use Documents** enabled. * Create a vendor bill using this journal. * Set the **Document Type** to **46 - Liquidación-Factura Electrónica**. * Confirm the vendor bill. **Observed behavior:** * The Send button is not visible on the confirmed vendor bill despite the DTE being generated and `l10n_cl_dte_status` being set to `not_sent`. **Cause:** * `_compute_display_send_button` in `account` only returns `True` for sale documents (`is_sale_document()`), so the "Send" button — which opens the Send & Print dialog containing the "Send to SII" option — was never shown on vendor bills. * `_get_move_constraints` in `account.move.send` unconditionally adds a `not_sale_document` constraint for non-sale documents, blocking the Send & Print dialog from processing vendor bills even if the button were visible. * The cron's `cron_run_sii_workflow` only processes moves with `l10n_cl_dte_status = 'ask_for_status'`, skipping moves still in `not_sent` state. **Fix:** * Override `_compute_display_send_button` in `l10n_cl_edi` to also show the "Send" button on posted moves with `l10n_cl_dte_status == 'not_sent'`, matching the pattern used by `l10n_br_edi`. * Override `_get_move_constraints` in `l10n_cl_edi` to remove the `not_sale_document` constraint for Chilean purchase documents with `not_sent` status, matching the pattern used by `l10n_br_edi`. **REF** During this [refactor](https://github.com/odoo/enterprise/pull/103427/changes/f5617ecf7584cf019897408df94b002622f48d9d), these two methods were inadvertently missed and were not overridden opw-6300571 Forward-Port-Of: odoo/enterprise#121233 Forward-Port-Of: odoo/enterprise#120818
This update significantly speeds up how Odoo retrieves document access permissions, particularly for the 'my counters' route. By switching to a subquery, the system now utilizes an index more efficiently, resulting in a much faster response time for users accessing documents. This improves overall performance and user experience.
Original PR description
The '/my/counters' route is hit a lot of times on big databases like odoo.com One thing it does is a `self.env['documents.document].search_count([])` With this commit, we use a subquery for the…
The '/my/counters' route is hit a lot of times on big databases like odoo.com
One thing it does is a `self.env['documents.document].search_count([])`
With this commit, we use a subquery for the folder access instead of the current LEFT JOIN.
This ok since the number of folders is typically small compared to regular documents and the query is fast since it can use the index on 'type'
Before as portal user
------
2x Seq Scan
```
Aggregate (cost=1900290.73..1900290.74 rows=1 width=8) (actual time=282.271..282.276 rows=1 loops=1)
Buffers: shared hit=66629
-> Hash Left Join (cost=41649.94..1900044.55 rows=98472 width=0) (actual time=184.202..282.267 rows=3 loops=1)
Hash Cond: (documents_document.folder_id = documents_document__folder_id.id)
Filter: ((hashed SubPlan 2) OR ((documents_document.owner_id = 6) AND ((documents_document.shortcut_document_id IS NULL) OR (documents_document.shortcut_document_owner_id = 6))) OR (((documents_document.access_via_link)::text = ANY ('{edit,view}'::text[])) AND (documents_document.folder_id IS NOT NULL) AND ((hashed SubPlan 4) OR ((documents_document__folder_id.owner_id = 6) AND ((documents_document__folder_id.shortcut_document_id IS NULL) OR (documents_document__folder_id.shortcut_document_owner_id = 6)))) AND (documents_document.is_access_via_link_hidden IS NOT TRUE)))
Rows Removed by Filter: 28085
Buffers: shared hit=66629
-> Seq Scan on documents_document (cost=0.00..1857903.54 rows=187073 width=26) (actual time=0.022..109.288 rows=28088 loops=1)
Filter: ((active IS TRUE) AND ((hashed SubPlan 2) OR ((owner_id = 6) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 6))) OR (((access_via_link)::text = ANY ('{edit,view}'::text[])) AND (folder_id IS NOT NULL) AND (is_access_via_link_hidden IS NOT TRUE))))
Rows Removed by Filter: 342576
Buffers: shared hit=33313
SubPlan 2
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.008..0.009 rows=0 loops=2)
Buffers: shared hit=6
-> Index Scan using documents_access__partner_id_index on documents_access (cost=0.43..105.55 rows=103 width=9) (actual time=0.008..0.008 rows=0 loops=2)
Index Cond: (partner_id = 7)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 10:16:38'::timestamp without time zone))
Buffers: shared hit=6
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id (cost=0.42..2.44 rows=1 width=9) (never executed)
Index Cond: (id = documents_access.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access.role)::text = ANY ('{view,edit}'::text[])))
-> Hash (cost=37016.64..37016.64 rows=370664 width=16) (actual time=164.521..164.521 rows=370664 loops=1)
Buckets: 524288 Batches: 1 Memory Usage: 17824kB
Buffers: shared hit=33310
-> Seq Scan on documents_document documents_document__folder_id (cost=0.00..37016.64 rows=370664 width=16) (actual time=0.005..100.491 rows=370664 loops=1)
Buffers: shared hit=33310
SubPlan 4
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.003..0.003 rows=0 loops=1)
Buffers: shared hit=3
-> Index Scan using documents_access__partner_id_index on documents_access documents_access_1 (cost=0.43..105.55 rows=103 width=9) (actual time=0.002..0.003 rows=0 loops=1)
Index Cond: (partner_id = 7)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 10:16:38'::timestamp without time zone))
Buffers: shared hit=3
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id_1 (cost=0.42..2.44 rows=1 width=9) (never executed)
Index Cond: (id = documents_access_1.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access_1.role)::text = ANY ('{view,edit}'::text[])))
Planning:
Buffers: shared hit=69
Planning Time: 1.708 ms
Execution Time: 282.344 ms
```
After as portal user
-----
Only 1x Seq Scan
```
Aggregate (cost=2004948.33..2004948.34 rows=1 width=8) (actual time=116.161..116.165 rows=1 loops=1)
Buffers: shared hit=37942
-> Seq Scan on documents_document (cost=145660.16..2004490.36 rows=183187 width=0) (actual time=24.635..116.155 rows=3 loops=1)
Filter: ((active IS TRUE) AND ((hashed SubPlan 2) OR ((owner_id = 6) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 6))) OR (((access_via_link)::text = ANY ('{edit,view}'::text[])) AND (hashed SubPlan 5) AND (is_access_via_link_hidden IS NOT TRUE))))
Rows Removed by Filter: 370661
Buffers: shared hit=37942
SubPlan 2
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.008..0.009 rows=0 loops=1)
Buffers: shared hit=3
-> Index Scan using documents_access__partner_id_index on documents_access (cost=0.43..105.55 rows=103 width=9) (actual time=0.008..0.008 rows=0 loops=1)
Index Cond: (partner_id = 7)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 10:15:10'::timestamp without time zone))
Buffers: shared hit=3
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id (cost=0.42..2.44 rows=1 width=9) (never executed)
Index Cond: (id = documents_access.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access.role)::text = ANY ('{view,edit}'::text[])))
SubPlan 5
-> Index Scan using documents_document__type_index on documents_document documents_document_1 (cost=0.42..145625.73 rows=13772 width=4) (actual time=11.688..11.689 rows=0 loops=1)
Index Cond: ((type)::text = 'folder'::text)
Filter: ((hashed SubPlan 4) OR ((owner_id = 6) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 6))))
Rows Removed by Filter: 28198
Buffers: shared hit=4629
SubPlan 4
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.002..0.002 rows=0 loops=1)
Buffers: shared hit=3
-> Index Scan using documents_access__partner_id_index on documents_access documents_access_1 (cost=0.43..105.55 rows=103 width=9) (actual time=0.001..0.002 rows=0 loops=1)
Index Cond: (partner_id = 7)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 10:15:10'::timestamp without time zone))
Buffers: shared hit=3
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id_1 (cost=0.42..2.44 rows=1 width=9) (never executed)
Index Cond: (id = documents_access_1.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access_1.role)::text = ANY ('{view,edit}'::text[])))
Planning:
Buffers: shared hit=56
Planning Time: 1.544 ms
Execution Time: 116.216 ms
```
Before as internal user
--------
```
Aggregate (cost=1902165.43..1902165.44 rows=1 width=8) (actual time=332.919..332.925 rows=1 loops=1)
Buffers: shared hit=69223 read=370
-> Hash Left Join (cost=41649.94..1901908.04 rows=102955 width=0) (actual time=176.179..332.325 rows=10040 loops=1)
Hash Cond: (documents_document.folder_id = documents_document__folder_id.id)
Filter: ((hashed SubPlan 2) OR ((documents_document.owner_id = 1054906) AND ((documents_document.shortcut_document_id IS NULL) OR (documents_document.shortcut_document_owner_id = 1054906))) OR (((documents_document.access_internal)::text = ANY ('{view,edit}'::text[])) AND ((documents_document.company_id = 1) OR (documents_document.company_id IS NULL))) OR (((documents_document.access_via_link)::text = ANY ('{view,edit}'::text[])) AND (documents_document.folder_id IS NOT NULL) AND ((hashed SubPlan 4) OR ((documents_document__folder_id.owner_id = 1054906) AND ((documents_document__folder_id.shortcut_document_id IS NULL) OR (documents_document__folder_id.shortcut_document_owner_id = 1054906))) OR (((documents_document__folder_id.access_internal)::text = ANY ('{view,edit}'::text[])) AND ((documents_document__folder_id.company_id = 1) OR (documents_document__folder_id.company_id IS NULL)))) AND (documents_document.is_access_via_link_hidden IS NOT TRUE)))
Rows Removed by Filter: 27228
Buffers: shared hit=69223 read=370
-> Seq Scan on documents_document (cost=0.00..1859756.86 rows=190950 width=35) (actual time=15.029..155.718 rows=37268 loops=1)
Filter: ((active IS TRUE) AND ((hashed SubPlan 2) OR ((owner_id = 1054906) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 1054906))) OR (((access_internal)::text = ANY ('{view,edit}'::text[])) AND ((company_id = 1) OR (company_id IS NULL))) OR (((access_via_link)::text = ANY ('{view,edit}'::text[])) AND (folder_id IS NOT NULL) AND (is_access_via_link_hidden IS NOT TRUE))))
Rows Removed by Filter: 333396
Buffers: shared hit=33931 read=370
SubPlan 2
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.155..7.920 rows=148 loops=2)
Buffers: shared hit=1612 read=370
-> Index Scan using documents_access__partner_id_index on documents_access (cost=0.43..105.55 rows=103 width=9) (actual time=0.110..3.448 rows=200 loops=2)
Index Cond: (partner_id = 1800102)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 12:17:29'::timestamp without time zone))
Buffers: shared hit=192 read=190
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id (cost=0.42..2.44 rows=1 width=9) (actual time=0.022..0.022 rows=1 loops=400)
Index Cond: (id = documents_access.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access.role)::text = ANY ('{view,edit}'::text[])))
Rows Removed by Filter: 0
Buffers: shared hit=1420 read=180
-> Hash (cost=37016.64..37016.64 rows=370664 width=25) (actual time=157.822..157.823 rows=370664 loops=1)
Buckets: 524288 Batches: 1 Memory Usage: 21336kB
Buffers: shared hit=33310
-> Seq Scan on documents_document documents_document__folder_id (cost=0.00..37016.64 rows=370664 width=25) (actual time=0.005..96.730 rows=370664 loops=1)
Buffers: shared hit=33310
SubPlan 4
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.019..0.372 rows=148 loops=1)
Buffers: shared hit=991
-> Index Scan using documents_access__partner_id_index on documents_access documents_access_1 (cost=0.43..105.55 rows=103 width=9) (actual time=0.005..0.078 rows=200 loops=1)
Index Cond: (partner_id = 1800102)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 12:17:29'::timestamp without time zone))
Buffers: shared hit=191
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id_1 (cost=0.42..2.44 rows=1 width=9) (actual time=0.001..0.001 rows=1 loops=200)
Index Cond: (id = documents_access_1.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access_1.role)::text = ANY ('{view,edit}'::text[])))
Rows Removed by Filter: 0
Buffers: shared hit=800
Planning:
Buffers: shared hit=69 read=8
Planning Time: 2.116 ms
Execution Time: 333.013 ms
```
After as internal user
--------
```
Aggregate (cost=2006950.17..2006950.18 rows=1 width=8) (actual time=157.117..157.121 rows=1 loops=1)
Buffers: shared hit=39918
-> Seq Scan on documents_document (cost=145798.74..2006482.26 rows=187165 width=0) (actual time=16.595..156.590 rows=10040 loops=1)
Filter: ((active IS TRUE) AND ((hashed SubPlan 2) OR ((owner_id = 1054906) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 1054906))) OR (((access_internal)::text = ANY ('{view,edit}'::text[])) AND ((company_id = 1) OR (company_id IS NULL))) OR (((access_via_link)::text = ANY ('{view,edit}'::text[])) AND (hashed SubPlan 5) AND (is_access_via_link_hidden IS NOT TRUE))))
Rows Removed by Filter: 360624
Buffers: shared hit=39918
SubPlan 2
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.019..1.016 rows=148 loops=1)
Buffers: shared hit=991
-> Index Scan using documents_access__partner_id_index on documents_access (cost=0.43..105.55 rows=103 width=9) (actual time=0.012..0.262 rows=200 loops=1)
Index Cond: (partner_id = 1800102)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 12:16:29'::timestamp without time zone))
Buffers: shared hit=191
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id (cost=0.42..2.44 rows=1 width=9) (actual time=0.004..0.004 rows=1 loops=200)
Index Cond: (id = documents_access.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access.role)::text = ANY ('{view,edit}'::text[])))
Rows Removed by Filter: 0
Buffers: shared hit=800
SubPlan 5
-> Index Scan using documents_document__type_index on documents_document documents_document_1 (cost=0.42..145763.43 rows=14124 width=4) (actual time=0.429..14.916 rows=4625 loops=1)
Index Cond: ((type)::text = 'folder'::text)
Filter: ((hashed SubPlan 4) OR ((owner_id = 1054906) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 1054906))) OR (((access_internal)::text = ANY ('{view,edit}'::text[])) AND ((company_id = 1) OR (company_id IS NULL))))
Rows Removed by Filter: 23573
Buffers: shared hit=5617
SubPlan 4
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.007..0.390 rows=148 loops=1)
Buffers: shared hit=991
-> Index Scan using documents_access__partner_id_index on documents_access documents_access_1 (cost=0.43..105.55 rows=103 width=9) (actual time=0.003..0.074 rows=200 loops=1)
Index Cond: (partner_id = 1800102)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 12:16:29'::timestamp without time zone))
Buffers: shared hit=191
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id_1 (cost=0.42..2.44 rows=1 width=9) (actual time=0.001..0.001 rows=1 loops=200)
Index Cond: (id = documents_access_1.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access_1.role)::text = ANY ('{view,edit}'::text[])))
Rows Removed by Filter: 0
Buffers: shared hit=800
Planning:
Buffers: shared hit=56
Planning Time: 1.569 ms
Execution Time: 157.171 ms
```
portal user
before https://explain.dalibo.com/plan/e1e755fg7bb26a21
after https://explain.dalibo.com/plan/hb5fa1d201ff164g
internal user with few documents access
before https://explain.dalibo.com/plan/f753bf2aa244dg63
after https://explain.dalibo.com/plan/538dg5ecb120ch84
internal user with *lots* of documents access
before https://explain.dalibo.com/plan/cf76h84537f7ge4a
after https://explain.dalibo.com/plan/45317a5e3168c5bc
Forward-Port-Of: odoo/enterprise#120991This update resolves an issue impacting how Odoo calculates sick leave payments, specifically related to the 'DPV' (days of paid vacation) calculation for employees with extended absences. The fix ensures accurate assimilation of sickness periods, particularly when transitioning between long and partial absences, improving payroll accuracy and compliance. The changes primarily affect the Be payroll module.
Original PR description
Forward-Port-Of: odoo/enterprise#121086 Forward-Port-Of: odoo/enterprise#120868
This update resolves an issue where manually added by-products on manufacturing orders caused errors when closing production in the shopfloor view. The fix ensures that serial numbers are correctly handled for by-products created outside of the standard BOM definition, preventing user errors and improving production workflow.
Original PR description
**Issue** Adding a serial-tracked by-product manually on a Manufacturing Order whose BOM does not define it, can lead to inconsistencies when assigning serial numbers in the shopfloor application.…
**Issue** Adding a serial-tracked by-product manually on a Manufacturing Order whose BOM does not define it, can lead to inconsistencies when assigning serial numbers in the shopfloor application. **Steps to reproduce** - Activate by-product in the settings - Create a product with an empty BOM (final product) - Create another product tracked by serial number (by-product) - Create and confirm a MO for the final product with 1 unit of the by-product - Go to Miscellaneaous -> operation Type -> shopfloor - Activate the option "Pre fill lot/serial numbers in shop floor" - Return to the MO and open the shopfloor view - Click on the '+' button next to the by-product and assign a serial number - Try to close the production -> A user error is raised stating that the by-product requires a serial number. **Cause** When the by-product is added manually on the MO, a stock move is created with an initial move line that does not contain any serial number. Later, when assigning a serial number from the shopfloor view: https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/mrp_workorder/models/stock_move.py#L121-L122 a new move line containing the serial number is created: https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/mrp_workorder/models/stock_move.py#L116-L119 However, the original empty move line is not removed (the issue): https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/mrp_workorder/models/stock_move.py#L124-L125 Because `self.picking_type_prefill_shop_floor_lots` is True, but `self.byproduct_id` is an empty recordset since: https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/mrp/models/mrp_production.py#L1304-L1311 https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/mrp/models/mrp_production.py#L1279 Indeed, `byproduct_id` is only populated from BOM-defined by-products. As a result, while confirming the production, there is 2 sml and among them, the original one without SN, which triggers the error: https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/stock/models/stock_move_line.py#L590 https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/stock/models/stock_move_line.py#L634-L635 https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/stock/models/stock_move_line.py#L658-L659 https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/addons/stock/models/stock_move_line.py#L661-L669 opw-6223158 Forward-Port-Of: odoo/enterprise#120493 Forward-Port-Of: odoo/enterprise#118792
This update resolves an issue where the system wasn't properly validating partner banks when creating SEPA direct debit mandates. The change adds a constraint to ensure the correct bank is associated with each mandate, improving data accuracy and preventing potential errors in payment processing. This enhances the reliability of our SEPA direct debit functionality.
Original PR description
Forward-Port-Of: odoo/enterprise#121236 Forward-Port-Of: odoo/enterprise#120901
This update corrects a previous issue where Odoo was incorrectly selecting unavailable couriers from Shiprocket. The fix now filters out ‘blocked’ couriers, ensuring only serviceable options are considered for rate calculations and shipment selection. Additionally, the system is now more robust in handling potential errors from Shiprocket’s data.
Original PR description
Shiprocket provides an odablock flag in the courier serviceability response. Couriers with odablock=True are not serviceable for the requested route and should not be considered for rate calculation or selection. Before this change, Odoo selected the first courier returned by Shiprocket regardless of its ODA status. As a result, unavailable couriers could be proposed to users and selected for shipments. The fix filters out ODA-blocked couriers before evaluating available services, ensuring that only serviceable couriers are considered. Additionally, freight charge parsing is hardened to gracefully handle non-numeric values returned by Shiprocket, preventing errors during AWB assignment and price computation. FYI: Shiprocket uses odablock=False for serviceable routes and odablock=True for routes that are blocked for a given courier. opw-6288768,6152279 Forward-Port-Of: odoo/enterprise#120374
This update optimizes how the system searches for documents, specifically addressing a slow and complex query when filtering by 'not SHARED'. The change aligns with the production database's approach, resulting in faster and more efficient searches. This improves overall user experience and system responsiveness.
Original PR description
Searching for "not 'SHARED'" results in a very complex query. Our own production DB prefers this implementation, also easier to read. credit: https://github.com/odoo/enterprise/pull/105915#discussion_r2745148099 Task-5893183 Forward-Port-Of: odoo/enterprise#121070 Forward-Port-Of: odoo/enterprise#120870
This update fixes a bug where changes to employee data didn't correctly update past payslips. The fix ensures that all affected payslips are accurately corrected when a user manages them, preventing discrepancies in payroll calculations. This improves data accuracy and payroll processing reliability.
Original PR description
Steps to reproduce: 1. Make sure you have an employee with a contract 2. Create 2 payslips for this employee 3. Change any field of the employee (ex: job position) 4. Go to one of the payslips…
Steps to reproduce: 1. Make sure you have an employee with a contract 2. Create 2 payslips for this employee 3. Change any field of the employee (ex: job position) 4. Go to one of the payslips created before 5. Click on the "Manage Payslips" link appearing because of the change of data Problem: When the data of an employee has been modified and past payslip are affected, the popup currently states 0 payslip has been affected. When clicking the "Correct" button, the correct amount briefly shows before we are sent to the payslip page where only one payslip gets corrected. Source of the problem: - The `employee_id` field was missing from the wizard form view. Since it was not referenced anywhere in the view, the web client did not include it in the initial payload / default_get calls. As a result, the wizard was initialized without `employee_id`, causing the payslip computation to use an empty employee and return a count of 0. - The window action did not explicitly call the intended wizard form view. Odoo therefore selected an unintended inherited view (salary increase wizard) due to view resolution rules (inheritance and priority ordering). This inherited view specifically replaces the description and the correction choice with nothing, which explains why it didn't show before. Fix: - Add an invisible `employee_id` field in the form view to ensure it is included in the initial form payload and properly initialized from context defaults. - Explicitly specify the correct view in the `views` parameter of the window action to prevent fallback to an inherited or unintended view. - Add an explicit priority on the salary increase wizard view to avoid ambiguous view selection in the future. Task-6304311
This update strengthens the testing process for the AI call debrief feature in Odoo Enterprise. Previously, the test relied on a quick trigger, which wasn't reliable due to the time it takes for browsers to complete audio seeking. This fix adds a deliberate wait, ensuring the test accurately reflects real-world scenarios and improves the overall stability of the AI call debrief functionality.
Original PR description
Before (in the test), we trigger the media loading by manually dispatching the loadeddata event. Once loadeddata runs, our component updates the <audio> element with the new time and triggers the seek. But because the actual seek in the browser takes time, we cannot just do a simple animationFrame(). We must explicitly wait for the browser to finish seeking and that's what we do in this fix. task-6321435 **community counter-part** https://github.com/odoo/odoo/pull/271300
This update corrects a bug where RCM entries for service imports were missing from the GSTR2B report. The team added a necessary section to the report's domain, ensuring accurate reporting of import service charges as required by Indonesian tax regulations. This ensures compliance and accurate financial reporting.
Original PR description
In commit https://github.com/odoo/odoo/commit/16c0ef65b3b755ddb8256914d8f16ecf48e36409, a new section purchase_imp_services_rcm was introduced, but it was not added to the GSTR2B domain. As a result, RCM entries for import of services were missing from the GSTR2B report. This commit adds the new section to the GSTR2B report line domain.
This update prevents users who aren't designated approvers from directly accepting or rejecting approval requests through the system's activity interface. Previously, this allowed unintended actions, creating a potential security risk. This change ensures that approval workflows remain controlled and secure.
Original PR description
Currently when a user submits an approval request, an activity is created for the approver who can validate or refuse the request directly from the activity, however these options are also visible to other users who will trigger an error if interacting with the options. This commit removes these options for users who are not the approver. **Steps to reproduce:** - Log in as admin - Go to approvals - Select dropdown menu of General Approval and Edit - Change documents to optionnal - Make sure admin is in the approvers list - Log in as demo - Go to approvals -> General Approval -> New Request - Submit the request - You'll see an activity be created for admin, with Accept and Refuse options - If you select any of these options you will get an access error opw-5423528 Forward-Port-Of: odoo/enterprise#120767 Forward-Port-Of: odoo/enterprise#109047
This update improves the security of ESG management by separating ESG user access from accounting data. Previously, ESG users automatically had full accounting access, creating potential risks. Now, ESG users have restricted access, allowing organizations to control data visibility and adhere to confidentiality requirements.
Original PR description
Purpose: In some corporate structures, the ESG manager should not have the rights to access all details in the accounting apps (bank journals, invoices etc), for reasons of confidentiality. The idea is to let the user decide whether the ESG manager should have all rights (then put him as ESG Administrator) or restricted/read only rights (then put him as ESG User). Before this PR, once a user got the ESG user role, they also got the accounting user role, which gave them access to all the accounting features. This was not ideal, as it could lead to security issues. After this PR, the ESG user role no longer inherits from the accounting user role by default. It involves that we make some adjustments to the ESG dashboard and emissions views to ensure that they still work correctly without the accounting user role. task-6127245
This update resolves an issue where recurring plans were incorrectly removed from the website when updating product quantities. The fix ensures that recurring plan selections remain active even after changes to the product's price or variant, improving the subscription experience for users. This was caused by a misinterpretation of the 'allow_one_time_sale' flag.
Original PR description
# Introduction note This PR fixes two bugs introduced by the same commit : https://github.com/odoo/enterprise/commit/106d70a1ef0ddbd61a74b7cac82dfce1e316beaa The original commit fixed multiple issues…
# Introduction note This PR fixes two bugs introduced by the same commit : https://github.com/odoo/enterprise/commit/106d70a1ef0ddbd61a74b7cac82dfce1e316beaa The original commit fixed multiple issues regarding the display of recurring plans when the One-time purchase option was enabled, but it also introduced new ones. Theses new issues are due to multiple new checks on `allow_one_time_sale`, but this variable only indicates that the One-time purchase option is available to the user, not that it is actually selected. So the fixes of the original commit works when first loading the page, but fails when the content of the page is updated. # Shared steps - Activate Subscriptions & eCommerce modules - Create a subscription product, enable 'Accept One-Time' and publish it on the website # Bug 1 ## How to reproduce - Add atleast two recurring plans to the product - Go to the product page on the website - Select one of the recurring plans - Increase the quantity of the product ## The problem The recurring plan selection is removed ## Cause The condition `!combination_info.allow_one_time_sale` was added on the `t-att-checked` of the recurring plan selection display. This correctly fixed the issue when first loading the page, but when the user changes the price or the variant, the recurring plan are recomputed and rerendered : https://github.com/odoo/enterprise/blob/0b408acbadb2cfcbc844521f3244a06b7ae7be22/website_sale_subscription/static/src/interactions/product_page.js#L37-L40 When that is the case, that condition blocks the proper display of the selected recurring plan. ## Proposed Solution When loading the recurring plan selection, what defines wich plan is selected is the `subscription_default_pricing_plan_id` variable, which is based on the `plan_id` value given in the request to the server : https://github.com/odoo/enterprise/blob/0b408acbadb2cfcbc844521f3244a06b7ae7be22/website_sale_subscription/models/product_template.py#L222 We make it so if no `plan_id` is sent to the server and `allow_one_time_sale` is enabled, then the server does not give back any `subscription_default_pricing_plan_id` opw-6131532 # Bug 2 ## How to reproduce - Add an attribute with values A & B for the product - Define atleast two recurring plans for the variant with attribute B - Publish the product - Go to the product page - Select the variant with attribute B ## The problem The recurring plan is not displayed. If the order of the attribute is reversed, then it works as expected. ## Cause The pricings are correcly sent to the front-end but they are not added to selection because of the check on `allow_one_time_sale` : https://github.com/odoo/enterprise/blob/0b408acbadb2cfcbc844521f3244a06b7ae7be22/website_sale_subscription/static/src/interactions/product_page.js#L42-L50 opw-6132160 Forward-Port-Of: odoo/enterprise#120873 Forward-Port-Of: odoo/enterprise#115446
This update resolves a crash that occurred when creating payslips for employees in Belgium with overtime. The issue stemmed from a data structure mismatch during payslip generation, specifically related to overtime calculations. The fix removes a problematic function and corrects the data handling to ensure accurate overtime pay processing.
Original PR description
When creating a payslip for an employee in the Belgian localization with an hourly wage and an attendance-based work entry source contract, a traceback occurs if there is an attendance with overtime.…
When creating a payslip for an employee in the Belgian localization with an hourly wage and an attendance-based work entry source contract, a traceback occurs if there is an attendance with overtime. This happens because the overridden `_preprocess_work_hours_data_split_half` method in `l10n_be_hr_payroll_attendance` attempts to unpack `work_entries` assuming it is a list of triplets, but it is passed as a `defaultdict` with composite keys instead. This data structure mismatch results in a `ValueError: not enough values to unpack (expected 3, got 2)`. Even if updated to handle the `defaultdict` structure, `_preprocess_work_hours_data_split_half` would improperly delete the overtime line hours without adding them back elsewhere (the code responsible for adding them back seems to have been removed). Since this function serves no purpose anymore, we omit the call to it. However, because `saas-19.2` is a stable version Task Id: 6253707 Forward-Port-Of: odoo/enterprise#119177 Forward-Port-Of: odoo/enterprise#118676
This update resolves a problem where validating rental orders for kit products (specifically, products with a component BOM) would trigger an error. The fix ensures that the system correctly handles the explosion of the kit BOM during validation, preventing the 'record does not exist' error. This ensures rental orders involving kit products function as expected.
Original PR description
### Steps to reproduce: - Enable rental transfer - Create a rentable product R - Create and confirm a rental order for 1 unit of R - Create a kit bom for R: 1 x COMP - Validate the delivery of your…
### Steps to reproduce:
- Enable rental transfer
- Create a rentable product R
- Create and confirm a rental order for 1 unit of R
- Create a kit bom for R: 1 x COMP
- Validate the delivery of your unit of R
#### > Missing Error: Record does not exist or has been deleted.
### Cause of the issue:
Confirming your rental order will generate a confirm moves of R. However, since at this point the product was not a kit, these will not be exploded. Now, the issue is that at validation The move will be exploded and deleted in the super call:
https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/sale_mrp_renting/models/stock_move.py#L10-L13 https://github.com/odoo/odoo/blob/0f2f222a431627a672daf10c86ec2578a27f97bb/addons/mrp/models/stock_move.py#L550-L555 https://github.com/odoo/odoo/blob/0f2f222a431627a672daf10c86ec2578a27f97bb/addons/mrp/models/stock_move.py#L591-L593 However, since the overrides of the sale_{mrp,stock}_renting modules call self rather than the result of the super call, they still expect to work with the original move rather than its exploded result: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/sale_mrp_renting/models/stock_move.py#L10-L13 https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/sale_stock_renting/models/stock_move.py#L61-L65
opw-6191841
Forward-Port-Of: odoo/enterprise#120866
Forward-Port-Of: odoo/enterprise#1200518 changes
Resolved issues and error corrections
This update fixes an issue where preparation times weren't accurately calculated when order stages changed and where reports incorrectly included data from all companies. The changes ensure preparation times are correctly updated and that reports now only display data for the active company, improving reporting accuracy and efficiency.
Original PR description
Issues: - Preparation time for order lines was not computed when the preparation order stage changed. - Preparation time report aggregated orders across all companies instead of showing records for the active company only. Fixes: - Ensure preparation time is properly recomputed when the order stage changes. - Add company domain filtering to the preparation time report. Task-6250974 Forward-Port-Of: odoo/enterprise#118738
This update resolves an issue where processing invoices with multiple related documents (especially cancellations) was slow due to a database index limitation. Switching to a different index type allows the system to handle complex scenarios efficiently and maintain fast search performance for finding invoices.
Original PR description
The field `l10n_mx_edi_cfdi_origin` can contain a large number of associated UUIDs, especially in complex cancellation scenarios. The default B-tree index fails when this field exceeds 2704 bytes, which occurs after approximately 20 UUIDs. By switching to a trigram index, we avoid the entry size limit of PostgreSQL's B-tree nodes. This ensures that invoices with many related documents can be processed while maintaining efficient search performance for partial matches on this field. **Video before the fix:** https://youtu.be/24u0HbxwIH8 **Video after the fix:** https://youtu.be/sUelv1HZMvI Forward-Port-Of: odoo/enterprise#118868
This update corrects a previous issue where Odoo was selecting unavailable couriers from Shiprocket due to a lack of filtering. The change now ensures only serviceable couriers are considered, preventing incorrect rate calculations and shipment selections. Additionally, the system is more robust to handle potential errors in Shiprocket's data.
Original PR description
Shiprocket provides an odablock flag in the courier serviceability response. Couriers with odablock=True are not serviceable for the requested route and should not be considered for rate calculation or selection. Before this change, Odoo selected the first courier returned by Shiprocket regardless of its ODA status. As a result, unavailable couriers could be proposed to users and selected for shipments. The fix filters out ODA-blocked couriers before evaluating available services, ensuring that only serviceable couriers are considered. Additionally, freight charge parsing is hardened to gracefully handle non-numeric values returned by Shiprocket, preventing errors during AWB assignment and price computation. FYI: Shiprocket uses odablock=False for serviceable routes and odablock=True for routes that are blocked for a given courier. opw-6288768,6152279 Forward-Port-Of: odoo/enterprise#120374
This update resolves a bug where Odoo failed to correctly retrieve lot numbers from GS1 barcodes containing leading zeros (like '10'). The fix ensures accurate lot number identification when scanning these barcodes, preventing errors and improving inventory management. This ensures accurate tracking of products by lot.
Original PR description
When we scan a gs1 barcode that has in his lot a special character and start with 10, odoo will not be able to retrieve it from the db. **Steps to reproduce** * In settings activate: - Lots & Serial…
When we scan a gs1 barcode that has in his lot a special character and start with 10, odoo will not be able to retrieve it from the db. **Steps to reproduce** * In settings activate: - Lots & Serial Numbers - Units of Measure & Packagings - Storage Locations - Barcode Scanner : GS1 nomenclature * Create a Product tracked by lot with - barcode: 00001234567895 * Add on hand quantity: - 100 kg in lot : 10002002303-4 - 100 kg in lot : 11002002303-4 * Go to barcode>Operation>Internal Transfer>New * Scan 02000012345678951010002002303-4#3100000100 meaning: - 02 following 14 characters are the product barcode - 10 following characters are the lot number - "#" separator - 3100: means the units are kilograms, - 00100 means 100 units. -> if you check with the edit button the lot was not found (if you click on validate it will trigger an UserError for missing lot) **Observation** When scanning the GS1 barcode it will call onBarcodeSubmitted->onBarcodeScanned where we will execute processBarcode: https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/stock_barcode/static/src/components/main.js#L387 Where we will deconstruct the barcode into his component en retrieve from the db the relevant data: https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/stock_barcode/static/src/models/barcode_model.js#L709-L717 - First the barcode is parsed, identifiers are erased and each section is separated, the variable with our lot number only has the lot number in it, the identifier (10) is not included, BarcodeObject.forBarcode(bc) -> new BarcodeObject -> parser.parse_barcode: https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/stock_barcode/static/src/barcode_object.js#L14 - Check if the data is in the cache, if not, set it to retrieve after - Retrieve missing data getMissingRecords : https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/stock_barcode/static/src/lazy_barcode_cache.js#L349 From here we will get a call to get_specific_barcode_data for each element: https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/stock_barcode/controllers/stock_barcode.py#L176 In the case of the stock.lot since it has a symbol and it's not only digit it will skip the gs1 nomenclature domain converter (it will not become 'ilike' and stay with 'in'): https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/stock_barcode/controllers/stock_barcode.py#L182-L197 We will do the search: https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/stock_barcode/controllers/stock_barcode.py#L205 during which we will retrieve specific query from the stock.lot module : https://github.com/odoo/odoo/blob/8d14665af5acf1bd391d05a5048dc701986e8b15/odoo/orm/models.py#L1408 Where, since it's a GS1 nomenclature, we will preprocess the agrs: https://github.com/odoo/enterprise/blob/8030b105d3fce1eef9b8965a2bfc37195f71723c/stock_barcode/models/stock_lot.py#L14 -> Since our barcode start with a 10, it will erase it, which lead to a miss in the search. It will also avoid further searches since we avoid multiple search on the same elements (added in missingBarcodeKeyCache in getMissingRecords). https://github.com/odoo/enterprise/blob/c6d18a7a92092ffdf96f4569a70e95bdc276441c/stock_barcode/static/src/lazy_barcode_cache.js#L294-L298 opw-6207120
This update resolves an issue where changing a task's deadline by shrinking its right edge in the Gantt chart view caused a server error. The fix addresses a situation where tasks with no successors resulted in an empty date list, triggering a ValueError. This ensures the Gantt chart's deadline adjustment functionality is now consistently reliable.
Original PR description
## Current behavior: In the Project's app, switch to Gantt chart's view, when changing the deadline of a single task by shrinking its right edge, the server throws `ValueError: max() iterable…
## Current behavior: In the Project's app, switch to Gantt chart's view, when changing the deadline of a single task by shrinking its right edge, the server throws `ValueError: max() iterable argument`` is empty when calling end_date = max(candidates.mapped(stop_date_field_name)). ## Steps to reproduce: 1. In version 19.0 and above, install Project app 2. Create a project and only 1 single task 3. Switch to Gantt chart view 4. Try changing the deadline of a task by dragging its right edge 5. Observe that extending the task's deadline by dragging to the right works fine, but shrinking the deadline by dragging to the left will cause server to throw RPC_ERROR: Odoo Server Error and ValueError: max() iterable argument is empty. ## Cause of the issue: - A task with NO successors will cause candidates gathered via dependency_inverted_field_name to be empty. - The empty candidates recordset then get called by max(candidates.mapped(stop_date_field_name)), which is the reason causing error message ValueError: max() iterable argument is empty. opw-6283566
This update resolves an issue where international UPS shipments were failing due to incorrect commercial invoice address information. The fix initially used the delivery address, but caused further problems. Now, the system defaults back to the delivery address if country codes don't match, with a warning displayed to the user to ensure accurate invoice details.
Original PR description
Issue ----- When making an international delivery to a partner with different invoice and delivery addresses, we send the delivery address as the `Sold To` address as well. Problematic case 1 ----- -…
Issue ----- When making an international delivery to a partner with different invoice and delivery addresses, we send the delivery address as the `Sold To` address as well. Problematic case 1 ----- - Create a belgian company - Setup UPS - Create a French customer - Add a different french delivery address - Create a product (with some weight) - Create a SO (with UPS delivery) to the customer & confirm - Validate the transfer > Commercial invoice `Sold To` uses the delivery address Solution for case 1 ----- Use the delivery address' `commercial_partner_id`. This leads to another issue in some edge cases... Problematic case 2 (caused by case 1 fix) ----- - Create a belgian company - Setup UPS - Create a French customer - Add a delivery address in Switzerland - Create a product (with some weight) - Create a SO (with UPS delivery) to the customer & confirm - Validate the transfer > UPS error `The Sold To party's country code must be the same as the Ship To party's country code with the exception of Canada and satellite countries.` Solution for case 2 ----- Default back to delivery address for the `Sold To` field when countries don't match, as this is a limitation of the UPS API. Warn the user, either on the SO or the transfer itself (if no SO). Warning looks like this (on SO): <img width="1914" height="716" alt="image" src="https://github.com/user-attachments/assets/f7aa73c4-f24c-42da-8f3e-6a58765ef020" /> ----- Ticket: opw-6200263 Forward-Port-Of: odoo/enterprise#120592 Forward-Port-Of: odoo/enterprise#118031
This update fixes an error in the CFDI invoice generation process when payments are made in foreign currencies (like USD). Previously, the CFDI document incorrectly displayed the payment amount and rate. The fix ensures the correct USD amount and corresponding MXN rate are used, accurately reflecting the payment details on the CFDI document.
Original PR description
The rate and payment amount shown on the CFDI document generated after updating payments was wrong when the payment was made in a foreign currency. Steps to reproduce: ------------------- * Create a journal that use USD as currency and set the rate to 20 MXN for 1 USD * Create an invoice in MXN and make sure it is set to PPD * Add any product to the invoice for 300$ and post it * Send the invoice to CFDI (a first document should be generated) * Create a payment of 15 USD in the new journal and reconcile it with the invoice * Go back to the invoice and click on "Update payments" to generate the second CFDI document > Observation: The payment document shows an amount of 300 USD with a rate of 1 instead of 15 USD with a rate of 20. Why the fix: ------------ We make sure to use the amount from the statement line when there is one. opw-5974519 Forward-Port-Of: odoo/enterprise#120934 Forward-Port-Of: odoo/enterprise#115779
This update corrects a bug that caused overtime intervals to overlap, particularly during overnight shifts. The fix ensures accurate back-projection of work entries by preventing calculated start times from falling outside the intended timeframe. This improves the reliability of time tracking for employee hours.
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
6 changes
Resolved issues and error corrections
This update addresses slow response times in the Point of Sale UI caused by prolonged network requests. By adding timeouts and optimizing font loading, the system now reacts faster to network changes, preventing delays in operations like receipt printing and synchronization. This enhances the overall user experience and system stability.
Original PR description
Currently, requests from the PoS UI are sent without any timeout, which can lead to indefinite waiting when the system is connected to a network but lacks internet access. Examples: - `sync_from_ui`…
Currently, requests from the PoS UI are sent without any timeout, which can lead to indefinite waiting when the system is connected to a network but lacks internet access. Examples: - `sync_from_ui` can take more than 2 minutes to fail. - Font CDN requests during receipt printing can take over 4 minutes to fail. - In some cases, this causes receipt printing failure as well, even after several minutes (4-5 min) of delay. This commit introduces a timeout for PoS UI requests to prevent such delays and improve responsiveness. Additionally, font declarations are extracted from `web` into `point_of_sale`, and only the required fonts are included. This avoids unnecessary requests to missing CDN resources. Additionally, this PR backports the following commits required to support this fix: - https://github.com/odoo/odoo/pull/215130 - https://github.com/odoo/odoo/pull/220954 Ensures the system continuously checks network connectivity and resumes synchronization once the connection is restored. - https://github.com/odoo/odoo/pull/225743 Prevents receipt printing from being blocked by logo loading issues and ensures the logo is displayed gracefully in such scenarios. Task-6053404 | Font CDN request delay (~ 4 min) | `sync_from_ui` long request (> 2 min) | | --------------------------------- | --------------------------------------------------------------------------------------------------------- | | <img width="400" src="https://github.com/user-attachments/assets/8ea8b3e4-7ffe-44bf-a4d0-7975f43a8f68" /> | <img width="400" src="https://github.com/user-attachments/assets/5f899cab-b022-4ed2-aa82-12e54ea34ea7" /> |
This update corrects a bug in how Odoo calculates the Cost of Goods Sold (COGS) for sale orders involving kits. Previously, archived components were excluded, leading to inaccurate journal entries. Now, all components, including archived ones, are correctly included in the COGS calculation, ensuring accurate inventory valuation and invoicing.
Original PR description
### Issue: When invoicing a sale order for a kit, components tracked by quantity that are archived are excluded from the Cost of Goods Sold (COGS) calculation As a result, the journal items for…
### Issue: When invoicing a sale order for a kit, components tracked by quantity that are archived are excluded from the Cost of Goods Sold (COGS) calculation As a result, the journal items for "Expenses" and "Stock Interim (Delivered)" are undervalued on the invoice, creating a mismatch with the inventory valuation which correctly includes the archived components' costs Odoo natively allows the delivery and usage of archived components when they are part of a BoM ### Cause: The Bill of Materials (BoM) explosion correctly bypasses the active check using `with_context(active_test=False)` However, during the invoice posting, `_stock_account_get_anglo_saxon_price_unit()` filters the kit's components using a standard `search()`, but without disabling the active test Consequently, archived components tracked by quantity are ignored when computing the final anglo-saxon price unit ### To reproduce the issue: - Install `account_accountant`, `sale_management` and `mrp` - Create a product category PC (Inventory Valuation: Automated) - Create 3 Products: - Kit (Tracked: Quantity, Product Category: PC) - Kit_Comp01 (Tracked: Quantity, Product Category: PC, Cost: 10$) - Kit_Comp02 (Tracked: Quantity, Product Category: PC, Cost: 20$) - Set Kit_Comp01 and Kit_Comp02 on hand's quantity to 1 - Create a Bill of Materials (Product: Kit, Type: Kit, Components: 1x Kit_Comp01, 1x Kit_Comp02) - Archive Kit_Comp02 - Create and Confirm a Sale Order for 1x Kit - Process the related delivery - Create and Post the Invoice - Check the Journal Items tab Before the fix, the lines `Expenses` and `Stock Interim (Delivered)` are 10$ instead of 30$ opw-6204621
This update corrects a previous issue where Odoo was incorrectly selecting unavailable couriers from Shiprocket. The change now filters out ‘blocked’ couriers, ensuring only service-eligible options are considered for shipping rates and selections. Additionally, the system is now more robust to handle unexpected data from Shiprocket, preventing errors in shipment pricing.
Original PR description
Shiprocket provides an odablock flag in the courier serviceability response. Couriers with odablock=True are not serviceable for the requested route and should not be considered for rate calculation or selection. Before this change, Odoo selected the first courier returned by Shiprocket regardless of its ODA status. As a result, unavailable couriers could be proposed to users and selected for shipments. The fix filters out ODA-blocked couriers before evaluating available services, ensuring that only serviceable couriers are considered. Additionally, freight charge parsing is hardened to gracefully handle non-numeric values returned by Shiprocket, preventing errors during AWB assignment and price computation. FYI: Shiprocket uses odablock=False for serviceable routes and odablock=True for routes that are blocked for a given courier. opw-6288768,6152279 Forward-Port-Of: odoo/enterprise#120374
This update fixes an issue where partial dropship quantities weren't accurately reflected in stock valuation reports. The change ensures that SVL quantities and associated debit/credit amounts align with the actual partial dropship quantities, improving inventory accuracy. This impacts the financial reporting related to dropshipping operations.
Original PR description
**Problem:** partial quantities in a dropship picking is not taken into account for the svl quantity (it's always the full initial quantity) **Steps to reproduce:** - create a storable product with…
**Problem:** partial quantities in a dropship picking is not taken into account for the svl quantity (it's always the full initial quantity) **Steps to reproduce:** - create a storable product with dropship route - set the category as avco auto - set a vendor in the purchase tab with a price of 10 - confirm a SO for a quantity of 2 - confirm the related PO with a unit price of 10 - on the dropship picking change the quantity to 1 - validate without backorder - click on the valuation smart button **Current behavior:** - the svls have quantities of 2 and -2 - the related amls have debit/credit of 20 **Expected behavior:** - the svls should have quantities of 1 and -1 - the related amls should have debit/credit of 10 **Cause of the issue:** when creating the svls we use the move's product_qty instead of its quantity https://github.com/odoo/odoo/blob/c97629d5efb82aed191de211593c539686cae65b/addons/stock_account/models/stock_move.py#L290 **fix:** product_qty is expressed in the uom of the product and quantity in the uom of the move so we need to add a uom conversion to the fix opw-6113031
This update resolves an issue where creating new contacts with CUIT values containing special characters (like hidden characters) would cause an error and prevent contact creation. The fix uses regular expressions to extract the numeric part of the VAT number, allowing for correct CUIT validation regardless of these special characters.
Original PR description
Avoid traceback when there is special hidden characters on the VAT numer, compact() method from stdnum does not process it. We use regex to get only the number part for all the doc types ###…
Avoid traceback when there is special hidden characters on the VAT numer, compact() method from stdnum does not process it. We use regex to get only the number part for all the doc types ### Description of the issue/feature this PR addresses: 1. Create new contact 2. add cuit value (in the vat field). This one is copy from an external program with special hidden characteres ### Current behavior before PR: There is a traceback and the user can not create the contact ``` Traceback (most recent call last): ... File "/home/odoo/src/odoo/addons/l10n_ar/models/res_partner.py", line 123, in _get_id_number_sanitize res = int(stdnum.ar.cuit.compact(self.vat)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ValueError: invalid literal for int() with base 10: '\u206030717808599' The above server error caused the following client error: RPC_ERROR: Odoo Server Error RPC_ERROR at makeErrorFromResponse (https://brunetti.adhoc.ar/web/assets/1/debug/web.assets_web.js:30061:19) at XMLHttpRequest.<anonymous> (https://brunetti.adhoc.ar/web/assets/1/debug/web.assets_web.js:30124:27) ``` ### Desired behavior after PR is merged: Will let us to create the contact and validate the cuit no matter if it has or not an special character --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where GSTR-2B reports incorrectly flagged foreign currency vendor bills as 'Partially matched'. The fix ensures accurate reconciliation by comparing GSTR-2B amounts (in INR) with the bill's values, regardless of the bill's currency.
Original PR description
**Steps to reproduce:** * Install the **l10n_in_reports** module. * Go to **Accounting → Configuration → Settings**, and enable **Multi-Currencies**. * Activate a foreign currency (e.g., USD) and set…
**Steps to reproduce:** * Install the **l10n_in_reports** module. * Go to **Accounting → Configuration → Settings**, and enable **Multi-Currencies**. * Activate a foreign currency (e.g., USD) and set an exchange rate. * Create a new vendor bill for an Indian vendor, setting the currency to USD. * Add lines to the bill and apply IGST/GST taxes, then confirm the bill. * Go to **Accounting → Reporting → GST Return Period** and initiate GSTR-2B matching for the period corresponding to the bill (using a valid JSON payload where the amounts are correctly reported in INR). **Observed behavior:** * The vendor bill is incorrectly marked as "Partially matched" instead of "Fully matched", accompanied by an exception stating that the total amount as per GSTR-2B does not match. **Cause:** * The GSTR-2B data fetched from the GST portal always reports values in the company's base currency (INR). * The `match_bills` method was directly comparing the GSTR-2B INR amounts ( `bill_total` and `bill_taxable_value`) against the bill's `amount_total` and `amount_untaxed` fields. * Because these fields return values in the document's foreign currency (e.g., USD), the mismatch triggers an exception and flags the bill as partially matched. **Fix:** * Modified the matching logic to compare GSTR-2B values against `abs(amount_total_signed)` and `abs(amount_untaxed_signed)`. * This ensures that the amounts evaluated during reconciliation are always correctly converted and compared in the company's base currency (INR). opw-6311097 Forward-Port-Of: odoo/enterprise#120967
3 changes
Enhancements to existing features
This update adjusts Odoo's tax settings to reflect a VAT change in Austria. Starting July 1, 2026, the standard VAT rate for certain food categories will shift from 10% to 4.9%. This change impacts tax calculations, chart of accounts, and tax reporting within the Odoo system.
Original PR description
From first of July 2026, the VAT will change from 10% to 4.9% for some food categories. Adapt the taxes, the CoA and the tax return accordingly. task-6273259 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
This update resolves an issue where foreign currency vendor bills were incorrectly flagged as 'Partially matched' during GSTR-2B reporting. The fix ensures that GSTR-2B data, always in INR, is accurately compared against the bill's amounts, regardless of the currency setting. This improves the reliability of GSTR-2B reconciliation.
Original PR description
**Steps to reproduce:** * Install the **l10n_in_reports** module. * Go to **Accounting → Configuration → Settings**, and enable **Multi-Currencies**. * Activate a foreign currency (e.g., USD) and set…
**Steps to reproduce:** * Install the **l10n_in_reports** module. * Go to **Accounting → Configuration → Settings**, and enable **Multi-Currencies**. * Activate a foreign currency (e.g., USD) and set an exchange rate. * Create a new vendor bill for an Indian vendor, setting the currency to USD. * Add lines to the bill and apply IGST/GST taxes, then confirm the bill. * Go to **Accounting → Reporting → GST Return Period** and initiate GSTR-2B matching for the period corresponding to the bill (using a valid JSON payload where the amounts are correctly reported in INR). **Observed behavior:** * The vendor bill is incorrectly marked as "Partially matched" instead of "Fully matched", accompanied by an exception stating that the total amount as per GSTR-2B does not match. **Cause:** * The GSTR-2B data fetched from the GST portal always reports values in the company's base currency (INR). * The `match_bills` method was directly comparing the GSTR-2B INR amounts ( `bill_total` and `bill_taxable_value`) against the bill's `amount_total` and `amount_untaxed` fields. * Because these fields return values in the document's foreign currency (e.g., USD), the mismatch triggers an exception and flags the bill as partially matched. **Fix:** * Modified the matching logic to compare GSTR-2B values against `abs(amount_total_signed)` and `abs(amount_untaxed_signed)`. * This ensures that the amounts evaluated during reconciliation are always correctly converted and compared in the company's base currency (INR). opw-6311097
This update ensures that sales orders with recurring products always have a valid subscription plan. Previously, adding a recurring product without a subscription plan didn't trigger a warning, leading to potential errors. This fix introduces a consistent validation process for both manual and catalog product additions, improving order accuracy.
Original PR description
Steps to reproduce: --------------------------------------- 1. Install Subscription Module 2. Create and Confirm SO with no recurring plan and a non-recurring product 3. Add a recurring product >…
Steps to reproduce: --------------------------------------- 1. Install Subscription Module 2. Create and Confirm SO with no recurring plan and a non-recurring product 3. Add a recurring product > Save SO > Observe the User Error 4. Now add the same recurring product through Catalog View Observation: --------------------------------------- No User Error raised stating 'You cannot save a sale order with recurring product and no subscription plan.' Issue: --------------------------------------- When you manually add a line and click 'Save', the constraint (`_constraint_subscription_plan`) is triggered and raised `UserError` https://github.com/odoo/enterprise/blob/434d88960abb5e424fdc1106fc93935d328bff78/sale_subscription/models/sale_order.py#L176-L177 When you add a product via the catalog view, it calls `_update_order_line_info` which directly creates/updates order lines, Which do not trigger the python constraint. https://github.com/odoo/odoo/blob/ef9772bba1515bdaf5410c3af5a3e395f562d513/addons/sale/models/sale_order.py#L1926-L1933 Solution: --------------------------------------- Two private helpers are introduced: * `_is_exempt_from_subscription_plan_check`: single source of truth for all exempt states (draft, cancelled, upsell, and legacy upgrade orders). * `_check_recurring_plan_mismatch`: raises a `UserError` when the order has or will have a recurring product but no subscription plan, reusing the exemption helper so both call sites stay in sync. `_constraint_subscription_plan` is refactored to delegate to these helpers, and `_update_order_line_info` is overridden to call `_check_recurring_plan_mismatch` before the catalog update is applied, ensuring consistent validation across both entry points. opw-6194865