Monday, December 15, 2025
19 changes · saas-18.4
Enhancements to existing features
This update restricts access to version forms within the HR module, ensuring that only HR users and managers can view them. Previously, all users could access these forms, and this change enhances security and streamlines workflows by limiting access based on user roles.
Original PR description
*= hr_payroll, hr_contract_salary Purpose of this PR: - Make version quick access open employee form with selected version if the user has access. - Only HR users/managers can access version form, others can not see quick access. This PR includes: - Added new helper action on hr.version to open the employee form. - Override get_formview_action in payslip and offer models to redirect quick access to employee form with selected version. - Adjusted view fields to restrict version access: - Users with access can open the version from quick access. - Others can see it without the quick access (using no_open option). task-4963805
This update restricts access to employee version quick access based on user roles. HR managers and employees can now directly access the employee version form, while other users will continue to see the standard view. This enhances security and streamlines workflows for HR personnel.
Original PR description
*= hr_payroll Purpose of this PR: - Make version quick access open employee form with selected version if the user has access. - Only HR users/managers can access version form, others can not see quick access. This PR includes: - Added new helper action on hr.version to open the employee form. - Override get_formview_action in payslip and offer models to redirect quick access to employee form with selected version. - Adjusted view fields to restrict version access: - Users with access can open the version from quick access. - Others can see it without the quick access (using no_open option). task-4963805
This update enhances the Point of Sale system by automatically saving log messages to the user's browser for 24 hours. This allows our support team to quickly diagnose and resolve issues by providing clients with easy access to these logs. A download button has been added to simplify the process of sharing these logs with our support team.
Original PR description
Enterprise PR: https://github.com/odoo/enterprise/pull/100183 This commit extends the `logPosMessage` function in the POS to also save each log message to a `Logger` instance (which persists the logs for 24 hours in the browser storage). A download button is added to download these logs, which the client could then send on to the support team. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#236927
This update adds logging to the blackbox communication process, which helps our clients troubleshoot issues more effectively. Combined with a related change to save and download logs, this enhances our ability to diagnose and resolve problems quickly. This improves client support and reduces downtime.
Original PR description
Community PR: https://github.com/odoo/odoo/pull/236927 This commit adds several log messages for the communication with the blackbox. In combination with the associated Community PR to save and download these logs, this should enable easier debugging when clients experience problems. Forward-Port-Of: odoo/enterprise#100183
Resolved issues and error corrections
This update resolves an issue where applying discount codes would cause errors when a loyalty program was archived and then unarchived. The fix ensures the system checks for duplicate discount codes, even when records are archived, preventing conflicting rules and ensuring smooth discount code application.
Original PR description
Currently, an error occurs when a user applies a discount code to the cart. Steps to reproduce: - Install the `website_sale_loyalty` module. - Go to `Discount & Loyalty` and create a new program with…
Currently, an error occurs when a user applies a discount code to the cart. Steps to reproduce: - Install the `website_sale_loyalty` module. - Go to `Discount & Loyalty` and create a new program with `Program Type = Discount Code`. - Under the `Rules & Rewards` tab, add a rule with a `code (e.g., demo)`. - `Archive` the program record. - Repeat `steps 2 and 3`. - `Unarchive` the first record. - Go to `Website` > `Shop`, add a product to the cart, and go to the cart page. - Apply the code `demo`. `ValueError: Expected singleton: loyalty.program(2, 3)` This error occurs when a user creates a sale loyalty program and adds a loyalty rule with a code, then archives that record. If the user creates the same record again and later unarchive the first record, there will be two rules with the same code, resulting in two loyalty programs [1], which raises the error [2]. This commit ensures that the system also checks archived records when unarchiving and verifies that there are no two or more programs with the same code being unarchived, so that no conflicting rules are activated. [1]- https://github.com/odoo/odoo/blob/76a8d6bc28eb5998bd976b3c41bf9772d325c8bf/addons/sale_loyalty/models/sale_order.py#L1351 [2]- https://github.com/odoo/odoo/blob/76a8d6bc28eb5998bd976b3c41bf9772d325c8bf/addons/sale_loyalty/models/sale_order.py#L1371 sentry-6871330244 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#239713 Forward-Port-Of: odoo/odoo#226801
This update fixes an issue where subscription products weren't displaying prices with tax, even when the website setting was enabled for tax-inclusive pricing. The change ensures that the correct company ID is used to determine tax applicability, resulting in accurate tax-inclusive prices for subscriptions.
Original PR description
subscriptions Despite enabling the website setting to display tax-inclusive prices, subscription products show prices without tax when a recurring pricelist is configured. In `_get_sales_prices`, the product’s company ID is compared to the website’s company, but products visible to all have a false company ID, and products assigned to a parent company retain the parent’s company ID. As a result, when the product’s company ID does not match the website’s company ID, no taxes are applied.Instead, _filter_taxes_by_company should be used to determine whether the company can access the product’s tax_id. opw-5222411
This update fixes a confusing issue on the POS receipt in India where all tax columns (CGST, SGST, IGST) were displayed together. Now, the receipt correctly shows only the relevant tax column – either CGST+SGST or IGST – based on the transaction, improving clarity for users and ensuring accurate reporting.
Original PR description
Description of the issue/feature this PR addresses: - The POS receipt shows CGST, SGST, and IGST together, even when IGST is applicable. - This is incorrect because only CGST+SGST or IGST should be…
Description of the issue/feature this PR addresses: - The POS receipt shows CGST, SGST, and IGST together, even when IGST is applicable. - This is incorrect because only CGST+SGST or IGST should be displayed, not all three. Current behavior before PR: - The receipt always displays CGST, SGST, and IGST columns at the same time. <img width="250" height="400" alt="image" src="https://github.com/user-attachments/assets/5c8487c7-c497-4c82-ad80-8cf0e98fbf38" /> Desired behavior after PR is merged: - The receipt shows only the correct tax columns based on the transaction: - Shows CGST and SGST when GST applies. - Shows IGST when IGST applies. <img width="250" height="400" alt="image" src="https://github.com/user-attachments/assets/68d2fb58-9e15-4861-a71f-ccb2d978e544" /> Changes implemented in this commit: - Added `t-if="l10n_in_hsn_summary.has_gst"` to CGST and SGST headers. - Added the same condition to CGST and SGST values in the item rows. task-5268935 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#236243
This update corrects a bug in the l10n_es_edi_tbai module that prevented the correct 'FechaOperacion' field from being generated in TBAI XML invoices when the invoice date and delivery date were set to a past date. This ensures compliance with Spanish tax regulations and accurate invoice generation.
Original PR description
With l10n_es_tbai: - Create an invoice with an `invoice_date` and `delivery_date` that are the same and earlier than today. - In the generated TBAI XML, `FechaOperacion` is missing. In the TBAI XML, `FechaExpedicionFactura` corresponds to the date on which the XML is generated. `FechaOperacion` corresponds to the `delivery_date` and should appear whenever it differs from the issue date. The TicketBAI specs define `FechaOperacion` as: > “Date on which the transaction was carried out, whenever it differs from the issue date.” So when the invoice date and delivery date are equal but set in the past, `FechaOperacion` is not generated, even though it should be. opw-4477135 opw-4477135 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#239189
This update fixes an issue where scanning a lot in a batch transfer would incorrectly update a different line instead of the intended one. Previously, the system prioritized completed lines, leading to inaccurate inventory tracking. This change ensures that scanning a lot updates the correct line, maintaining accurate stock levels.
Original PR description
…f related line is complete ### Steps to reproduce: - In the settings enable Lots & Serials and Batch transfers - On the delivery operation types enable show reserved lots in the barcode tab - Create…
…f related line is complete ### Steps to reproduce: - In the settings enable Lots & Serials and Batch transfers - On the delivery operation types enable show reserved lots in the barcode tab - Create a storable product tracked by lots and put 10 x lot1 in stock - Create and confirm a delivery for 10 units - Create a batch transfer with your delivery - Process your transfer from the barcode app - Scan one unit of LOT1 and put in pack - Toggle sublines select the 0/9 subline without lots nor package - Scan LOT1 #### > The 1/1 LOT1 line with a pack is updated to 2/1 rather than the 0/9 ### Cause of the issue: Since e45249c2f6883d743a4e7d19e736c622e26a3d58 and 27bfb985a29e9f0abe94dec8a76bf6d08560fbc9 an override of the `_findLine` method has been introduced in `BarcodePickingBatchModel` to ensure that scanning a lot referenced by an already existing line of the batch transfer triggers an update of that line rather than an override of the lot of an other line. However, these lines should not priorities a completed line when there is line without a set lot. opw-5340865 Forward-Port-Of: odoo/enterprise#101908 Forward-Port-Of: odoo/enterprise#101611
This update fixes a bug where credit notes weren't properly accounted for when settling invoices. The change ensures credit notes are now correctly processed, allowing them to reduce the total amount settled. This improves the accuracy of financial reporting and reconciliation.
Original PR description
We had a bug when settling invoices and credit notes of a customer. The credit notes where not correctly computed. Steps to reproduce: ------------------- In accounting: * Create and confirm a customer invoice for a total of 10$. * Create and confirm for the same customer a credit note for a total of 2$. In POS: * In a seesion, open the customer selection menu. * In the burger menu at the right of our customer, select Settle invioces. * Select our invoice and credit note. > Observation: The credit note was previously seen as an amount to pay. Why the fix: ------------ Recomputing updates existing credit notes to use the signed residual logic. The domain change allows credit notes with negative pos_amount_unsettled to appear. After these changes, credit notes should appear in the "Settle invoices" dialog with negative amounts, and selecting them will create negative lines that reduce the total. opw-5257884 Forward-Port-Of: odoo/enterprise#101186
This update fixes a calculation error in the MRR evolution dashboard that was causing 'Contraction' figures to be double-counted. The change ensures the dashboard accurately reflects MRR trends by properly incorporating contraction data, which was previously included in the 'Up/Downgrade' calculation. This improves the accuracy of the dashboard's reporting.
Original PR description
…traction **Issue** The formula defined for the "Net new" in the MRR evolution dashboard double counted the "Contraction", as it is already included in the "Up/Downgrade" (cell B6, equal to B4+B5, "Contraction" + "Expansion"). <img width="360" height="354" alt="image" src="https://github.com/user-attachments/assets/0a19a86a-f1b9-462f-812c-71a283f6fe89" /> opw-4925930 Forward-Port-Of: odoo/enterprise#101598 Forward-Port-Of: odoo/enterprise#96878
This update fixes issues where changes to nested card images were incorrectly applied to other cards, or where cards without cover images incorrectly displayed cover image options. The fix ensures that image settings are applied only to the specific card being edited, improving the user experience and consistency.
Original PR description
This commit fixes three issues occurring when editing nested `s_card` snippets. **Problem 1 - Incorrect cover image detection** Issue: An `s_card` without a cover image displayed the cover image…
This commit fixes three issues occurring when editing nested `s_card` snippets. **Problem 1 - Incorrect cover image detection** Issue: An `s_card` without a cover image displayed the cover image option if it contained a child `s_card` with a cover image. Cause: The `querySelector` in `CardImageOption` could detect images inside child snippets. Fix: Now the `querySelector` only searches among direct children of the snippet root element. **Problem 2 - Ratio settings applied to all child cards** Issue: Changing the cover image ratio on an `s_card` applied the setting to all nested cards. Cause: The `we-select` in `s_card` options targeted `.o_card_img_wrapper`, causing the class to apply to all descendants. Fix: The selector is now `>.o_card_img_wrapper`, so the option acts only on the current snippet. **Problem 3 - Parent image positioning leaking to children** Issue: Adjusting the cover image position on a parent `s_card` affected the rendering of all child card images. Cause: CSS rules for `.o_card_img_horizontal` applied to all descendant elements matching `.o_card_img_wrapper`. Fix: The rules now apply only to direct children of `.o_card_img_horizontal`. The same correction was applied to `.o_card_img_ratio_custom`. task-5349540 Forward-Port-Of: odoo/odoo#239503 Forward-Port-Of: odoo/odoo#237587
This update fixes an issue where the system incorrectly processed vendor bills with a zero price in Italian e-invoicing XML. The fix ensures that the system now accurately reflects the zero price from the XML, preventing incorrect pricing calculations and improving compliance with Italian tax regulations. This ensures accurate e-invoicing submissions.
Original PR description
**Steps to reproduce:** * Install the **Italy – E-invoicing (l10n_it_edi)** module. * Create a product with a non-zero cost price. * Create a **vendor bill** for an Italian vendor using the **RC…
**Steps to reproduce:** * Install the **Italy – E-invoicing (l10n_it_edi)** module. * Create a product with a non-zero cost price. * Create a **vendor bill** for an Italian vendor using the **RC fiscal position**. * Add the product with **unit price = 0**, apply **RC tax**, and set the **Origin Document Type**. * Confirm the bill and click **Send to Tax Integration** to generate the XML in the chatter. * Upload the generated XML through **Accounting → Vendors → Bills → Upload**. **Observed behavior:** * The imported bill ignores the XML value **0.00** and uses the product's default price instead. **Cause:** * The XML’s `<PrezzoUnitario>` value is mandatory and may be **0**, but the code skipped it because `0.0` evaluates as falsy in the walrus assignment. **Fix:** * Always set the parsed `PrezzoUnitario` value (including **0.0**) on the invoice line. ref: https://fex-app.com/FatturaElettronica/FatturaElettronicaBody/DatiBeniServizi/DettaglioLinee/PrezzoUnitario opw-5322187 Forward-Port-Of: odoo/odoo#239904 Forward-Port-Of: odoo/odoo#239419
This update ensures that Luxembourg (`l10n_lu`) companies generating FAIA XML reports for their general ledger correctly include the 'PurchaseInvoices' tag, as required by the latest FAIA version 2.01. Previously, vendor bills weren't correctly identified, but this change implements a standardized template to resolve this issue and ensure accurate reporting.
Original PR description
Since version 2.01 of FAIA, it is a requirement to include the `PurchaseInvoices` tag in the FAIA XML. With a `l10n_lu` company: - Create a vendor bill. - In the general ledger, download the FAIA XML report. In the generated XML document, the vendor bill will not appear under `PurchaseInvoices`. The `PurchaseInvoices` section is meant to mirror the `SalesInvoices` section and contains the exact same structure. This PR implements a generic template for both. **Specs and source** (in `FAIA_v2.01_full`): https://pfi.public.lu/dam-assets/backup/FAIA/FAIA/XSD_Files.zip opw-5360572 Forward-Port-Of: odoo/enterprise#101958 Forward-Port-Of: odoo/enterprise#100697
This update fixes an issue where the VAT summary report in the Argentinian localization incorrectly calculated totals when invoices had both VAT (price included) and multiple IIBB taxes. The fix ensures that VAT amounts are counted accurately, matching the totals displayed in the accounting form, preventing inflated totals.
Original PR description
**Issue** When using a VAT tax marked as price included, together with multiple IIBB taxes on the same invoice, the VAT summary report displays an incorrect total. Specifically, the VAT amount is…
**Issue** When using a VAT tax marked as price included, together with multiple IIBB taxes on the same invoice, the VAT summary report displays an incorrect total. Specifically, the VAT amount is counted multiple times, once for each IIBB tax, leading to an inflated total. **Steps to Reproduce** 1. Install the Accounting app and the Argentinian localization (l10n_ar) 2. Set the 21% VAT Purchase tax as Included in Price 3. Create a vendor bill applying the 21% VAT tax and at least two IIBB taxes 4. Open the VAT summary report for that bill Expected Behaviour: The total in the VAT summary should match the total shown in the accounting form view, with each tax counted only once. **Root Cause** The VAT summary report in the Argentinian localization relies on an SQL query to aggregate tax information for each `account.move`. The query joins `account_move_line` with `account_tax`, `account_tax_group`, and the many-to-many relation table `account_move_line_account_tax_rel`. Each `account_move_line` related to a VAT tax line (via `tax_line_id`) is joined with the `account_move_line_account_tax_rel` table. If that base line is related to multiple IIBB taxes, the join multiplies the VAT line once per IIBB tax since multiple matching rows exist. **Fix** The solution separates the logic for computing tax lines and base lines into two distinct subqueries. Each is aggregated independently to prevent duplication caused by one-to-many and many-to-many joins. The results are then joined using the unique `account_move_line.id`, ensuring each tax amount is counted exactly once in the final totals. opw-4776861 Forward-Port-Of: odoo/enterprise#98933 Forward-Port-Of: odoo/enterprise#85873
This update fixes an issue where flexible employee leave durations were incorrectly calculated due to timezone differences. The fix uses date ranges (request_date_from and request_date_to) to ensure accurate duration calculations, regardless of the employee's timezone. This ensures leave requests are processed correctly and accurately reflect the intended working hours.
Original PR description
### Steps to reproduce: - Create an employee with Flexible working schedule - Set the timezone for this employee very far from yours - Create an Unpaid leave with Custom Hours for this employee - Set the hours of the leave from 8 to 21 - Notice the duration is just 8 hours ### Cause: When calculating the duration of the flexible employee leave we check if the date_from and the date_to has the same date and if so we get the difference between the hour_to - hour_from but sometime when the tz is different when we convert it to UTC the dates overlap in two days so the condition sets to false so we get the working hours of the employee. ### Fix: Using the request_date_from and request_date_to in this condition where it will always be accurate in terms of days opw-5118689 Forward-Port-Of: odoo/odoo#239581 Forward-Port-Of: odoo/odoo#230366
This update optimizes how Odoo searches for products based on names, significantly speeding up the process. The change addresses a performance bottleneck caused by how Odoo handles complex search queries, particularly when searching across multiple product tables. This results in faster product searches, especially with large product catalogs.
Original PR description
When doing a name_search with positive operators (=, ilike, in) the resulting query combines domains with the OR operator. This works fine when the leaves are all on the same table (product_product…
When doing a name_search with positive operators (=, ilike, in) the resulting query combines domains with the OR operator. This works fine when the leaves are all on the same table (product_product or product_template) as postgresql uses a Bitmap OR when everything is properly indexed.
When leaves are on multiple tables however postgresql has to plan a Seq Scan. For instance, let's take a simple domain on product.product of the form `['|', ('name', 'ilike', 'test'), ('default_code', 'ilike', 'test')]`. Because `name` is an inherited field via `product_tmpl_id`, the resulting query has the where clause `join_table.name ilike %s OR product_product.default_code ilike %s` with `join_table` the table you get after joining product_product and product_template. Since it's an `OR` condition, postgresql does not know in advance whether a given row will pass this condition. There's no way to filter the tables before the join. The condition moves therefore to a `Join Filter` node and postgresql has to scan the whole join table to fetch the correct tuples.
Same thing when there's a subquery. In case of a where clause `cond OR cond OR subquery`, postgresql does not know in advance whether or not a given row is gonna pass the subquery condition. So it has to scan the whole table.
In both cases this becomes a bottlneck when the number of products increaases. This commit introduces the use of `UNION ALL` instead of `OR`. There's one SubPlan for each individual table in the domain. The results are then appended to get the final products matching the conditions. Thanks to each table having its own SubPlan postgresql can now properly hit indexes for each table, greatly improving the performances.
#### speedup
In a database with 2.5M product_product, the name_search on product with a partner_id in the context and the ilike operator goes from 8s -> 5ms.
In another database with 500k product_template, the name_search on template with a partner_id in the context and the ilike operator goes from 1.8s -> 5ms.
opw-4921944
opw-5103287
opw-5049054
opw-5256691
opw-5221753
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#238901
Forward-Port-Of: odoo/odoo#229275This update resolves an issue in Firefox where scheduling multiple messages would cause the application to freeze. The problem stemmed from an incorrect date sorting algorithm within the chat functionality, leading to an infinite loop. The fix ensures consistent date sorting across browsers, preventing the freeze and improving stability.
Original PR description
**Steps to reproduce:** - (Firefox only) - Go to any record which uses a chatter (e.g. Contact) - Send message > Full composer > click the schedule message icon (lower right corner) - Schedule the…
**Steps to reproduce:**
- (Firefox only)
- Go to any record which uses a chatter (e.g. Contact)
- Send message > Full composer > click the schedule message icon (lower right corner)
- Schedule the message in the future and click send
- You should see now a post in the chatter indicating that the message will be sent
- Now click Send message and repeat the above steps again to schedule a second message
- Whole page will be freezed
- Reloading doesn't help
**Issue:**
Infinite loop in reactive callback on firefox.
The code gets stuck in
```js
for (const callback of [...callbacks]) {
clearReactivesForCallback(callback);
callback();
}
```
because of
```js
const sortProxy2 = reactive(recordProxy, function sortObserver() {
self.requestSort(record, fieldName);
});
this.fieldsSortProxy2.set(fieldName, sortProxy2);
```
which loops over `store._.ADD_QUEUE("sort", record, fieldName);`
(Forcing the `requestSort` only change the infinite loop into a recursion error)
The recomputation seems to be caused by a bad sorting here:
```js
this.scheduledMessages = Record.many("ScheduledMessage", {
sort: (a, b) => {
if (a.scheduled_date === b.scheduled_date) {
return a.id - b.id;
}
return a.scheduled_date < b.scheduled_date ? -1 : 1;
},
```
In the case both datetimes are equal the first condition doesn't properly catches it:
```
> a.scheduled_date - b.scheduled_date
> 0
> a.scheduled_date === b.scheduled_date
> false
> a.scheduled_date < b.scheduled_date
> false
> a.scheduled_date > b.scheduled_date
> false
```
Which make the ordering change on each sort iteration:
```
> Array [ "ScheduledMessage,14", "ScheduledMessage,13" ]
> recordsFullProxy.sort(func);
> Array [ "ScheduledMessage,13", "ScheduledMessage,14" ]
> recordsFullProxy.sort(func);
> Array [ "ScheduledMessage,14", "ScheduledMessage,13" ]
```
Chromium based browsers probably use a different sorting algorithm than Firefox, which seems to prevent the issue.
**Fix:**
Use `compareDatetime` to ensure the ordering is constant for the same datetime values.
opw-5367371
Forward-Port-Of: odoo/odoo#239745
Forward-Port-Of: odoo/odoo#239199This update fixes a problem where loyalty discounts weren't accurately applying based on the quantity of items purchased. By using the quantity on each line, the system now correctly calculates and applies the cheapest line discount, ensuring accurate loyalty program rewards. This resolves issues with maximum discount limits.
Original PR description
Discounts based on the cheapest line were not accounting for the quantity on the line and this was causing issues with the computations when using a maximum discount amount. Changing the discountable value to be a ratio of the quantity on the line allows the cheapest product to be discounted at the correct amount without messing with the discount factor. opw-4998557 Forward-Port-Of: odoo/odoo#239349 Forward-Port-Of: odoo/odoo#222564