Friday, April 3, 2026
16 changes · 19.0
Resolved issues and error corrections
Multi-day half-day time off requests for employees with flexible schedules now create the correct daily timesheet entries instead of a single undercounted entry. This helps keep absence tracking, project reporting, and payroll-related time records accurate.
Original PR description
Steps to reproduce: ------------------- 1. Install Timesheets and Time Off. 2. Create a new Time Off type with duration type "Half Day" (disable "Require allocation" to skip allocations). 3. Enable…
Steps to reproduce: ------------------- 1. Install Timesheets and Time Off. 2. Create a new Time Off type with duration type "Half Day" (disable "Require allocation" to skip allocations). 3. Enable "Timesheets" in Timesheets > Configuration. 4. Ensure the employee is configured with a "Flexible" working schedule. 5. Create a multi-day Time Off request (2 days) using this type and approve it. 6. Check the timesheet entries for the employee. Issue: ------ When a multi-day time off request is submitted for a "Half Day" time off type, the system fails to generate individual daily timesheet entries. Instead, it generates a single timesheet entry with a duration calculated as calendar.hours_per_day / 2, regardless of the actual number of days requested. (e.g., if hours_per_day is 8, it generates one entry of 4 hours for a 2-day leave), Cause: ------ After this commit 9512832, multi-day requests were allowed for time off types where the **request_unit** is "half day" or "hours". However, the logic in `_generate_timesheets` for flexible calendars was not updated to account for this. Previously, `request_unit_half` was computed as: https://github.com/odoo/odoo/blob/feb3cd520d7a736996621f7765184edca6ac390c/addons/hr_holidays/models/hr_leave.py#L319-L323 But now, the condition is: https://github.com/odoo/odoo/blob/14ccd1f54e21c07ac68593c8dec7682371f8663c/addons/hr_holidays/models/hr_leave.py#L467-L470 Since `request_unit_half` now stays **True** regardless of the request duration (as long as the Type is 'half_day'), the following condition in `_generate_timesheets`: https://github.com/odoo/odoo/blob/14ccd1f54e21c07ac68593c8dec7682371f8663c/addons/project_timesheet_holidays/models/hr_leave.py#L39 always evaluates to **True**. This traps multi-day requests in the "single-day" logic, preventing the code from reaching `_list_work_time_per_day`. Solution: --------- Update the condition to strictly check if the request is a single day before applying the simplified single-entry logic. If the request spans multiple days, it will now correctly fall into the else block, utilizing `_list_work_time_per_day` to generate one timesheet entry per day of the leave. opw-5715197 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Public shoppers could see an access error when viewing product pages with review ratings enabled, especially around dynamic product snippets such as alternatives. This fix allows those ratings to load correctly, preventing a broken shopping experience for anonymous visitors.
Original PR description
**Steps to produce:** - Install the `Ecommerce` module. - Create a product. - In the Sales tab, set an alternative product and ensure both are published. - Open the product page on the website and enable `reviews` from the editor. - Open the same product page in incognito mode. **Issue:** ``` AccessError: You do not have enough rights to access the field "rating_avg" on Product Variant (product.product). ``` Root cause: --- - Currently, product records in dynamic snippets to be fetched without superuser privileges. Since the `rating_avg` field is restricted to internal users, public visitors encounter an `AccessError` when viewing snippets with ratings enabled. - Similar approach used [here]. [here]: https://github.com/odoo/odoo/commit/12bb994da4c3222e8c7fb2df95c202a6c45a28b0 opw-6065319 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#256570
Fixed an issue that could break translation editing on appointment detail pages when guest invitations were enabled. This helps website editors translate appointment pages reliably across languages without errors.
Original PR description
When we are at the appointment details page, and have the option allow_guests turned on, and go to the editor for translation, we encounter the issue. Steps To Reproduce: 1. Create an appointment. 2.…
When we are at the appointment details page, and have the option allow_guests turned on, and go to the editor for translation, we encounter the issue. Steps To Reproduce: 1. Create an appointment. 2. Go to the "Options" tab, and click on "Allow Guests". 3. Go to the web page for the appointment, select the data and time. 4. Now, on the details page, go to any other language than the default, and click on edit/translate. 5. The issue occurs. The issue occurs when the regex tries to match the placeholder where the guests are added, which is enabled by the allow_guests. It contains strings with newline characters. The regex fails to take into consideration for these newlines and breaks causing the issue to appear. To fix the issue, we'll use regex to account for the new lines. Also the fix adapts [this commit](https://github.com/odoo/odoo/commit/bc30d2592d4a7913eddf30bac8be2d94b6c22ad4) to work with the [website refactoring](https://github.com/odoo/odoo/commit/9fe45e2b7ddbbfd0445ffe25a859e67a316d02b2) opw-5412775 Forward-Port-Of: odoo/odoo#249195
Delivery slips now show the correct ordered and delivered quantities when products are handled in packaging units such as packs. This prevents confusing or inflated quantities on customer-facing warehouse documents.
Original PR description
Currently, when a user prints a delivery slip for items with different packaging units, the report shows the wrong quantity. ## Steps to replicate: - Install Purchase and Inventory with demo data -…
Currently, when a user prints a delivery slip for items with different packaging units, the report shows the wrong quantity.
## Steps to replicate:
- Install Purchase and Inventory with demo data
- Settings > Enable 'Units of Measure & Packagings' and 'Packages'
- Products > Desk Pad > Purchase > Add a line > Set unit to pack of 6 and set a vendor.
- Create new RFQ with the same vendor for 'Desk pad' having quantity 10
- Confirm RFQ > Go to receipt > Details
- Create and Set Destination Package to
- LOT A 5 pack of 6
- LOT B 5 pack of 6
- Validate Delivery Order and Print the Delivery Slip
## Observed Behavior:
Both the ordered and delivered quantities are showing 30.0 (Pack of 6), but this is incorrect.
The correct quantity ordered and delivered should be 5 (Pack of 6).
## Root cause:
This unintentional behavior occurs after commit [1].
When printing the delivery slip, function [2] is triggered. The packaging quantity is calculated using `move_line.product_uom_id`. In this case, the unit of measure is `pack of 6`, because the user selected a different UoM when setting the Destination Packaging.
As a result, when `_compute_quantity` is called, it reaches condition [3], where it checks whether the unit of measure provided as `self` matches `to_unit` Since both are `pack of 6`, no conversion is performed.
Because of this, the packaging quantity is not converted as expected, and the quantity is set to 30 instead of 5.
[2]-
https://github.com/odoo/odoo/blob/9c9ed6ef00b796d7428e4df6e5f96abb5b95287a/addons/stock/models/stock_move_line.py#L860-L945
[3]-
https://github.com/odoo/odoo/blob/9c9ed6ef00b796d7428e4df6e5f96abb5b95287a/addons/uom/models/uom_uom.py#L87-L88
## Solution:
Use the uom variable instead, as it reflects the unit of measure for the product applied directly on the receipt. This ensures that the unit-of-measure conversion for packaging quantities is handled correctly.
**Before:**
<img width="824" height="244" alt="image" src="https://github.com/user-attachments/assets/ce0ae06b-7cba-46e0-929b-a51aadc0c199" />
**After:**
<img width="833" height="244" alt="image" src="https://github.com/user-attachments/assets/dff563ef-e05c-4b86-bd89-99e89378d152" />
[1]:
https://github.com/odoo/odoo/commit/fa606530235ac413d17dd3d58bdb0921bd811d28
opw-5930343
Forward-Port-Of: odoo/odoo#256766
Forward-Port-Of: odoo/odoo#249779When a confirmed purchase order is updated with another subcontracted product, Odoo now adds the needed components to the existing resupply transfer instead of creating a duplicate one. This keeps subcontractor replenishment cleaner and reduces extra warehouse documents for the same purchase order and destination.
Original PR description
Steps to reproduce: 1- Install Inventory, Purchase and Manufacturing 2- Enable 'multi-step routes' in the settings 3- Create Product A and create a Bill of Materials (BoM type: subcontracting,…
Steps to reproduce: 1- Install Inventory, Purchase and Manufacturing 2- Enable 'multi-step routes' in the settings 3- Create Product A and create a Bill of Materials (BoM type: subcontracting, Component A) 4- Repeat the same for Products [B,C] with components [B,C] correspondingly. 5- Assign the same subcontractor to all of them 6- Create a Purchase Order for both Product A and Product B with vendor as the subcontractor and confirm it 7- Add a new order line with Product C and save Description of issue: A second resupply picking is created Expected behavior: Should group the new product's component with the existing picking Why this happens: When assigning the resupply picking for the new product's component, the search domain for the existing picking includes production_group_id, which is different for the added product. This prevents merging of components into a single resupply picking despite sharing the same destination and purchase order Fix: We ignore production_group_id since it is not necessary in the resupply stock moves domain. opw-5906451
This fixes incorrect pricing for self-order combo meals when a free combo choice had a zero price alongside extra paid quantities. Customers now see and pay the correct combo price, reducing billing errors in self-order flows.
Original PR description
In a specific scenario where a combo had combo choice with free quaitites and combo choice with only extra quantities and the price of the combo choice with free quantities was 0, the price of the combo product was distributed on the "free" lines and on the "extra" lines, which was causing the price to be wrong. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix makes failures in email template rendering easier to diagnose by identifying the affected template when possible. It also reduces oversized logs and error messages by showing only relevant snippets, helping administrators and support teams troubleshoot faster without unnecessary server bloat.
Original PR description
This is mainly a backport of an IMP done at https://github.com/odoo/odoo/pull/252455 Given it's potential to reduce server bloat and increase of QOL for sys admins and support agents, backporting (a…
This is mainly a backport of an IMP done at https://github.com/odoo/odoo/pull/252455 Given it's potential to reduce server bloat and increase of QOL for sys admins and support agents, backporting (a sligthly modified version) seemed adequate. Summary: When a QWeb template fails to render, the current logic logs the entire template source and raises a generic UserError. This leads to significant log bloat and makes it difficult for developers and support staff to identify the specific failing template or the root cause of the error. This commit improves the error handling in `mail.render.mixin` and `mail.template` by: - mail.render.mixin: Added logic to identify the failing template's name and ID if it belongs to a `mail.template` or `mail.compose.message` (mass mailing). - Log Truncation: Implemented truncation for identified templates, showing only a snippet (first and last 500 chars) in logs and UserErrors to prevent log/UI bloat while keeping full source logging as a fallback for unidentified templates. OPW-5980295 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#257104
This fixes an issue where delivery tracking references were not passed from one warehouse step to the next when carrier propagation was enabled. Businesses using multi-step deliveries can now keep shipment tracking information consistent across picking, packing, and delivery operations, even when no carrier is assigned.
Original PR description
Steps to reproduce:
- Enable multi-step routes in Inventory settings
- Go to Warehouse Management → Operation Types
- Set Delivery to 3 steps
- Open the 3-step delivery routes and enable “Propagate carrier” on any rule
- Create a storable product P1
- Create a sales order with 1 unit of P1
- Confirm the sales order
- Open the generated picking
- Go to the Additional Info tab
- Set Tracking Reference = 123
- Confirm the picking
- Open the next picking (Pack operation)
Problem:
The tracking reference is not propagated to the next picking, even though the rule has “Propagate carrier” enabled.
Expected behavior:
The tracking reference should be propagated to the subsequent picking when carrier propagation is enabled on the rule. Even if no carrier set.
opw-6052930Inventory at Date reports now calculate average product costs using the correct historical move values. This prevents overstated inventory costs for average-cost products, helping users see accurate stock valuation figures for a chosen date.
Original PR description
When we open the Stock report at date, we filter out moves anterior to that date and, if the cost method is AVCO, Odoo recompute the `avg_cost` up to that point of time with `_run_average_batch`. However, when iterating over the moves, `move._get_value(at_date)` might return a value calculated from the current standard_price if the move is not associated with any accounting entry or PO/SO. Steps to reproduce the issue: 1. Create a new product with AVCO cost method 2. On the product form, set the cost to 5$ 3. Manually adjust the inventory to 5 units 4. Create a PO and receive 5 products at a unit cost of 10$ > Total value: 75$ > Total quantity: 10 units > avg_cost: 7.5$ 5. Navigate to Stock report and run "Inventory at Date" at current time 6. avg_cost is 8.75$ instead of 7.5$ Ticket: opw-5951072
This fix stops the website editor from adding extra paragraph or block containers when users paste inline content into buttons, links, or similar elements. It helps preserve the intended page layout and avoids unexpected visual changes while editing website content.
Original PR description
Since [website builder refactor], the editor wraps inline elements at the root of an editable boundary. This is causing issues in website builder when the root element is not supposed to contain `p` or `div` elements (added to wrap the inline elements). This behavior can be configured globally with `allowInlineAtRoot`. And since 6bc5946796a364634cb5eb217e61a5b882a1b6b2, it can be configured per-element with a "predicate" resource. This commit adds a predicate to allow inline at root of editable when the root is (according to its tag) not supposed to contain `p` or `div` elements. Steps to reproduce: - Open website builder on a product page - Select text in "Add to cart" button - Copy - Paste - Bug: a `p` element is created (on master) - Open website builder - Select "Company" below footer - Copy - Paste - Bug: a `p` element is created [website builder refactor]: 9fe45e2b7ddbbfd0445ffe25a859e67a316d02b2 task-5868460 Forward-Port-Of: odoo/odoo#247231
This update corrects errors in the generation of XML files for commercial events in the Co-DIAN integration. Previously, incorrect naming conventions and data extraction led to validation failures. Now, commercial events are generated using the same XML format as invoices, ensuring accurate data transmission to the Dian authorities.
Original PR description
When POS support was added [1], XML rendering was refactored to use dict_to_xml. Commercial events were partially migrated: the body used the new mechanism, but extensions and signing still went through the deprecated _dian_sign_xml(). That method calls _add_invoice_config_vals() which sets vals['name'] to invoice.name (e.g. "BILL/2026/0001"). For commercial events the name should be the event ID (e.g. "SETP9900130771"). SoftwareSecurityCode is computed as sha384(software_id + security_code + name), so the wrong name produced a bad hash: Regla: AAB27b, Rechazo: Huella no corresponde a un software autorizado para este OFE. _dian_sign_xml() also extracted uuid from the rendered XML's <cbc:UUID/>, which is the event's own CUDE. But the QR code should reference the original invoice's CUFE, not the event's. We now render commercial events like how invoices are rendered. [1] odoo/enterprise#107170 opw-6065701
This update resolves an issue where manufacturing orders weren't correctly incorporating components from intercompany purchase orders with 'never variant' products. The fix ensures that component data is accurately retrieved from the purchase order, enabling proper manufacturing order creation. This improves the reliability of intercompany transactions.
Original PR description
In a multicompany setting, when buying product with intercompany rule, the never variant attribute was lost. Steps to reproduce: ------------------- * Enable intercompany transaction * Enable variant…
In a multicompany setting, when buying product with intercompany rule, the never variant attribute was lost.
Steps to reproduce:
-------------------
* Enable intercompany transaction
* Enable variant grid entry
* Enable multistep routes
* Unarchive MTO
* Settings>Users & Companies>Companies
* Enable Generate Sales Orders in company A
* Create a product:
- Never variant with at least two values
- MTO and manufacture
* Create a bom,
- Company : company B
- Add a component with apply on variant: choose one of the variants
* Create and confirm a purchase order, for a never variant of the product, in company A with vendor as company B
* Confirm the sales order in company B
-> The manufacture order does not include the components that are applied on variant
Observation:
-------------
When creating a sale order for an intercompany rule, button_approve is overwritten and it calls the function "inter_company_create_sale_order.
That function will create the sale order from the data of the purchase order:
https://github.com/odoo/enterprise/blob/273528ba462f2f2b5768bf29dbdb697713a8e619/sale_purchase_inter_company_rules/models/purchase_order.py#L63-L64
When preparing the value for each order line, the attribute value for the never variant will not be retrieved:
https://github.com/odoo/enterprise/blob/273528ba462f2f2b5768bf29dbdb697713a8e619/sale_purchase_inter_company_rules/models/purchase_order.py#L63-L64
Since the attribute value is lost, it will not be retrived by the mto since it should get the value from the PO.
opw-5438723This update resolves an issue where the LPP (Labor Pension Plan) was incorrectly applied to employee salaries in the Swiss payroll module when employees were not covered by insurance. The fix ensures that LPP contributions are only applied to insured employees, aligning with Swiss tax regulations and improving payroll accuracy.
Original PR description
Forward-Port-Of: odoo/enterprise#112824
This update fixes an issue where amounts with thousand separators (like 1,334.00) were incorrectly parsed, leading to potential errors in reconciliation reports. The change introduces a new function to intelligently split amounts, ensuring accurate conversion to decimal values and improving the reliability of financial reporting.
Original PR description
When extracting amounts using a regex with a single capturing group, values containing thousand separators such as 1.334,00 or 1,334.00 were not correctly converted to floats. This could lead to…
When extracting amounts using a regex with a single capturing group, values containing thousand separators such as 1.334,00 or 1,334.00 were not correctly converted to floats. This could lead to incorrect amounts being interpreted in reconciliation models.
Added a new function `split_amount_str`in utils which will give
integer and decimal part for different number formats.
This is a heuristic approach, meaning it aims to provide the best
possible result for valid inputs. Invalid or ambiguous formats are
not guaranteed to be parsed correctly and may result in ('0', '0').
For the two capturing groups case, the first group is treated as the
integer part and the second as the decimal part, allowing users to
Explicitly split amounts like 9065 into 90.65 by using two groups
in their regex.
Examples:
EU format: 1.334,15 → 1334.15
US format: 1,334.15 → 1334.15
Implicit decimals: uid 01870912 0000009065 → 90.65 (using two groups)
Additional tests were added to ensure amounts with thousand separators
are correctly parsed.
Task [link](https://www.odoo.com/odoo/project/967/tasks/6026748)
task-6026748This update corrects an issue where the Master Production Schedule (MPS) wasn't accurately accounting for safety stock levels when calculating indirect demand. The change ensures that demand forecasts are adjusted to include safety stock, leading to more reliable production planning and reduced stockouts. This improves inventory management efficiency.
Original PR description
Steps to reproduce: ------------------- * Enable "Master Production Schedule" in Inventory settings * Create tracked Product "Child" and set up a vendor * Create tracked Product "Parent" and set up a…
Steps to reproduce: ------------------- * Enable "Master Production Schedule" in Inventory settings * Create tracked Product "Child" and set up a vendor * Create tracked Product "Parent" and set up a bom as component "Child" and Lead Time: 2 days * Create tracked Product "GParent" and set up a bom as component "Parent" and Lead Time: 2 days * Open MPS and add your three products: - Child, Parent: activate indirect demand - Parent: Safety Stock Target of 10 * Add 1 in the forecast demand for "Gparent" on third column -> Will have 20 Indirect Demand Forecast of Child in the first column and -9 on the second Observation: ------------- Usefull comment form the function : https://github.com/odoo/enterprise/blob/b332af45a46b2295797a5096f68b7953554a495b/mrp_mps/models/mrp_mps.py#L424-L447 When creating a demand from the MPS, it will always take the first date of the interval (ex: Week 10 (2-8/Mar), it will create the demand for the 2 of Mars) When calculating the production schedule. we wil we calculate each product for each date_range: https://github.com/odoo/enterprise/blob/ea805995f66e007c0aef6b473a2b16dbe54d73bc/mrp_mps/models/mrp_mps.py#L488 https://github.com/odoo/enterprise/blob/ea805995f66e007c0aef6b473a2b16dbe54d73bc/mrp_mps/models/mrp_mps.py#L509 When calculating the values for a product, we will set the indirect demand qty for it component The demand will created the demand in function of the date of when the parent need and the lead time (it will for the previous date range because of the lead time): https://github.com/odoo/enterprise/blob/ea805995f66e007c0aef6b473a2b16dbe54d73bc/mrp_mps/models/mrp_mps.py#L554 https://github.com/odoo/enterprise/blob/ea805995f66e007c0aef6b473a2b16dbe54d73bc/mrp_mps/models/mrp_mps.py#L555 If the demand is not equal to the resplensih_qty we will create another demand to compensate, it will use the first date of range minus the lead time it will send it to the previous date range: https://github.com/odoo/enterprise/blob/ea805995f66e007c0aef6b473a2b16dbe54d73bc/mrp_mps/models/mrp_mps.py#L556-L560 In our case this will create the issue, since it will try to compensate each time on the previous week. opw-5413838 Forward-Port-Of: odoo/enterprise#112811 Forward-Port-Of: odoo/enterprise#107671
This update corrects a bug where discounts were applied twice to service tasks, resulting in incorrect pricing. The fix ensures discounts are applied correctly based on the sales order settings, preventing over-discounting and ensuring accurate pricing for service tasks.
Original PR description
Currently, when the user creates a task for a customer with a discount pricelist, the discount is applied twice for the service. <h2>Steps to produce:</h2> * Install `industry_fsm_sale` and enable…
Currently, when the user creates a task for a customer with a discount pricelist, the discount is applied twice for the service. <h2>Steps to produce:</h2> * Install `industry_fsm_sale` and enable `Discounts` and `Pricelists` in settings. * Create a pricelist with a price rule of type discount that applies 10 percent discount to every product. * Go to Customers > Acme Corporation > Sales & Purchase and set the pricelist. * Go to Field Service > Create a Task, and set `Customer` to Acme Corporation. * Add a timesheet with Time Spent 1 > Mark the task as Done > Sale Order <h2>Observed behavior:</h2> The discount is applied twice to the product on SO: **Product**: Service on Timesheets **Unit Price**: `$40` (excluding tax) **First discount:** The 10 percent discount on the unit price of the product. Product unit price is set from `$40 -> $36 ` **Second discount:** The 10 percent discount on the SO line itself. `$36 -> $32.4 ` The untaxed amount is: `$32.40` which should be `$36.00` <h2>Root cause:</h2> This happens because, at line [1], the unit price is already set to the final price from the pricelist when the sale order line is created. Since discounts are enabled, [2] applies an additional discount to that same price, causing the discount to be applied twice. <h2>Solution:</h2> When creating the sales order: * **Discount setting is on:** use list price so the discount is applied from the sales order. * **Discount setting is off:** set the product unit price to the discounted price. [1]- https://github.com/odoo/enterprise/blob/224d2453cc975a3e333825370beaf30d27d89f10/industry_fsm_sale/models/project_task.py#L658 [2]- https://github.com/odoo/odoo/blob/76717e588bfd012b42e859bfc829257d899c6165/addons/sale/models/sale_order_line.py#L788 opw-5432088 Forward-Port-Of: odoo/enterprise#112761 Forward-Port-Of: odoo/enterprise#103950