Tuesday, July 14, 2026
31 changes · saas-19.2
Enhancements to existing features
Mexican payroll now follows the latest CFDI payroll validation rules for taxable and exempt perception amounts and employment subsidy limits. This helps companies reduce payroll XML rejection risks and stay aligned with updated compliance requirements.
Original PR description
**. Perceptions – ImporteGravado / ImporteExento (XML Nodes)** For each Perception node, validate that: If ImporteExento = 0, then ImporteGravado > 0. If ImporteGravado = 0, then ImporteExento > 0. Both values cannot be 0 at the same time. These validations must be applied per Perception node, not at an aggregated level. **. TipoPercepcion = "038" (Other Salary Income) (XML Nodes)** When TipoPercepcion = "038": ImporteExento must always be 0. The amount must be recorded only in ImporteGravado. **. SubsidioCausado (XML Nodes)** Update the validation logic for the SubsidioCausado attribute based on NumDiasPagados: If NumDiasPagados ≤ 31, SubsidioCausado ≤ 628.00 If NumDiasPagados > 31, SubsidioCausado ≤ NumDiasPagados × 0.206 task-5412728 Forward-Port-Of: odoo/enterprise#121304
This update strengthens marketing automation by adding broader test coverage and correcting edge cases in campaign synchronization, scheduling, and failed or bounced message handling. It helps ensure customers receive the right follow-up actions at the right time, especially across email, SMS, and WhatsApp campaigns.
Original PR description
RATIONALE In order to prepare upcoming improvements for marketing automation application, as well as performance improvements, some tests are added to improve coverage and cover some synchronization…
RATIONALE
In order to prepare upcoming improvements for marketing automation
application, as well as performance improvements, some tests are added
to improve coverage and cover some synchronization use cases.
SPECIFICATIONS
Add some tests improve coverage of synchronization, as we recently
discovered limitations
* "opposite" triggers when checking brother traces to skip in
'action_update_participants' (which synchronizes traces): sub
addons (sms, whatsapp) is not taken into account;
* 'schedule_date' is not correct for user-based activities (e.g.
mail_open, mail_click, ...) when new activities are added to
a campaign. They should not have scheduled dates, as it depends
on user action. Date is correct for activities when participants
enter child activities but not when doing the synchronize;
* add some checks on participant state;
* globally try to improve some corner cases coverage;
Add some tests to improve coverage of bounce / fail behavior with
various activities, as we want to make it clearer how MA should
behave when dealing with issue. First step is to assert current
behavior and fix some odd bits.
Notably in some cases trace update is missing, notably with SMS
sending with does not call trace update method, which means some
triggers are not processed.
Various fixes are included in this branch, spotted by newly added tests.
See commits for more details.
Task-4224152: [marketing_automation] Performance / Scalability
Forward-Port-Of: odoo/enterprise#124126This update improves the performance and reliability of our website's image galleries by upgrading the Owl library to the latest version (2.8.4). Specifically, it fixes a bug that caused image renders to be lost and adds support for running the library with Node.js, enhancing flexibility.
Original PR description
- [FIX] runtime: don't lose coalesced renders - [IMP] loadable with nodejs See https://github.com/odoo/owl/commits/owl-2.x/ for more details 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#275568
This update enhances the testing framework for Odoo's mass mailing functionality. Specifically, it improves the tools used to simulate user interactions (like email opens and replies) to accurately verify the scheduling and execution of marketing campaigns. This ensures marketing automation processes are reliable and perform efficiently.
Original PR description
Improve (mass_)mailing asserts and tools, notably to use their usage in marketing automation where simulating user actions (open emails, reply, ...) is necessary to check marketing activities scheduling and execution. Task-4224152: [marketing_automation] Performance / Scalability Forward-Port-Of: odoo/odoo#275964
Resolved issues and error corrections
This fix ensures the barcode app correctly assigns the existing stock owner when scanning non-tracked products for delivery. It prevents Odoo from creating or updating the wrong stock record, helping businesses keep consignment inventory accurate.
Original PR description
### Steps to reproduce: - In the settings enable: "Storage Locations" and "Consignment" - Create a storable product and put 1 unit in stock with a set owner - Go to the barcode app > Operations >…
### Steps to reproduce: - In the settings enable: "Storage Locations" and "Consignment" - Create a storable product and put 1 unit in stock with a set owner - Go to the barcode app > Operations > Delivery Orders > New - Scan your product and validate #### > The owner was not set on the stock move line so that a new quant was created and updated in stock rather than using the available unit. ### Cause of the issue: The mechanism of prefilling an owner or a package in the barcode app is currently gate-kept behind the existence of a lot name: https://github.com/odoo/enterprise/blob/0be4f71de3420fb9b72fd4e70d48c6cbbbc0ecb4/stock_barcode/static/src/models/barcode_model.js#L1382-L1407 However, the option also make sense for none tracked products. ### Note: Performing the flow form the backend and adding quantity will generate the move line by setting the owner if possible since the quantity of a move is set via the back end, move lines are generated by looking at the existing quant data's: https://github.com/odoo/odoo/blob/5d61c03b33c9a915684dd59656f8be7612956dd1/addons/stock/models/stock_move.py#L2364 https://github.com/odoo/odoo/blob/5d61c03b33c9a915684dd59656f8be7612956dd1/addons/stock/models/stock_move.py#L2328-L2330 Setting the same owner on the new move line as on the quant we are going to reserve: https://github.com/odoo/odoo/blob/5d61c03b33c9a915684dd59656f8be7612956dd1/addons/stock/models/stock_move.py#L2337 https://github.com/odoo/odoo/blob/5d61c03b33c9a915684dd59656f8be7612956dd1/addons/stock/models/stock_move.py#L1715 Additional subtelties appearing when prefilling for non tracked product: 1. Currently the available quantity is not taken into account to determine if the the value provided to the prefilled is actually relevant, in particular if there is a quant with an available quantity of 0, it will be used as a valid value to prefill and it will parasit the prefill that could be done by other quants. 2. The location source used to determine the quants taken into account is not set on the first scan since the scan is performed without any existing line: https://github.com/odoo/enterprise/blob/4f0d25f9fe4ca8ff1b0ecd7900899a2a246ba888/stock_barcode/static/src/models/barcode_model.js#L1387 > This was not problematic with respect to tracked product since the product needs to be scanned prior to the lot, hence there is always a current line when the the lot is scanned. opw-6050657 Forward-Port-Of: odoo/enterprise#123173 Forward-Port-Of: odoo/enterprise#115021
Fixed an issue where subscription product pages could fail when a discount was applied directly to a recurring plan without a pricelist. Customers can now view the product page normally and see the correct discounted recurring price.
Original PR description
**Problem:** On the website, a subscription product page returns a 500 error when a discount is set directly on the recurring plan (a time-based pricing rule with a plan but no pricelist). **Steps to…
**Problem:** On the website, a subscription product page returns a 500 error when a discount is set directly on the recurring plan (a time-based pricing rule with a plan but no pricelist). **Steps to reproduce:** 1. Create a subscription product with a recurring plan. 2. Add a recurring price rule for that plan with no pricelist, set as a percentage discount (base = sales price). 3. Open the product page on the website. **Current behavior:** The page fails with a 500: Internal Server Error during price computation. **Expected behavior:** The page loads and shows the discounted recurring price. **Cause of the issue:** For a recurring price rule based on the sales price, `_compute_base_price` looks up "the no-pricelist rule for the plan" to use as its base, via `_get_applicable_rules_domain(plan_id=...)`. When the discount is set directly on the plan, the rule being computed has no pricelist itself, so that search returns the very same rule and calls `_compute_price` on it again, leading to infinite recursion. **Fix:** Excluding the rule itself from the base-rule lookup lets a no-pricelist plan rule resolve its base from the product's sales price (the super() fallback) instead of re-entering its own computation. A rule applied through a pricelist is unaffected, since its no-pricelist base rule is a different record. opw-6306105 Forward-Port-Of: odoo/enterprise#121466
The Czech VIES XML export now matches tax authority requirements more closely by removing an email field and adding missing taxpayer city and representative name details for individuals. This helps companies submit valid VIES reports and avoid rejection or manual corrections when filing.
Original PR description
**PROBLEM** For VIES report, the xml should not contains the email. The city of the tax payer is missing, and while it's not strictly require, it can modify the tax regime of the payer, so we need to include it in the xml. There is missing fields in the case the company is an individual (zast_jmeno, zast_prijmeni). **STEP TO REPRODUCE** 1. Create an invoice to a EU partner, don't forget to set the transaction code on the invoice line (unhide the field). 2. Go to the VIES reports, and generate the xml. 3. Upload it to https://mojedane.gov.cz/pmd/epo to validate and see the errors. documentation: https://mojedane.gov.cz/dpr/adis/idpr_pub/epo2_info/popis_struktury_detail.faces?zkratka=DPHSHV opw-6190983 Forward-Port-Of: odoo/enterprise#123367 Forward-Port-Of: odoo/enterprise#117698
Invoice tax recomputations using Avatax now refresh the pre-tax base amount each time, instead of keeping an older cached value. This helps prevent incorrect invoice line totals when Avatax returns updated base amounts during recalculation.
Original PR description
Previously, when recomputing taxes via Avatax, `manual_tax_amounts` was cleared and repopulated from the fresh API response, but `manual_total_excluded_currency` was only set if it was None. This meant that after the first Avatax call, the pre-tax base amount was never refreshed from subsequent API responses, even though the tax amounts were. This inconsistency could cause stale pre-tax base amounts to persist on invoice lines across recomputations, even when Avatax returned a different base amount. By resetting `manual_total_excluded_currency` to `None` at the start of each recomputation, mirroring what is already done for `manual_tax_amounts`, we ensure that the pre-tax base is always taken from the current Avatax response rather than a previously cached value. opw-6235597 Forward-Port-Of: odoo/enterprise#123802
Accounting report XLSX exports now store date and date-time columns as real Excel date values instead of plain text. This makes exported reports easier to sort, filter, format, and use in spreadsheet calculations, while also preventing a crash when exporting real date-time values.
Original PR description
Before this commit, columns with figure_type 'date'/'datetime', General Ledger's Date column, but also Partner Ledger, Aged Partner Balance, Bank Reconciliation and Customer Statement. were exported…
Before this commit, columns with figure_type 'date'/'datetime', General Ledger's Date column, but also Partner Ledger, Aged Partner Balance, Bank Reconciliation and Customer Statement. were exported to XLSX as plain text strings instead of real Excel date values. _get_cell_type_value, which decides whether a cell must be written as a date or as text, only recognized a cell as a date when its 'class' contained 'date'. _build_column_dict, used by every report to build its column cells, never set that key, so the check always failed and cells fell back to text, even though figure_type was correctly set to 'date' on them. _build_column_dict now also sets 'class': 'date' on date datetime columns, the same convention already used by hand-built cells in account_followup This in turn revealed a second, so-far dormant issue: once real datetime values started reaching the XLSX writer, _set_xlsx_cell_sizes crashed while estimating the column width, as it unconditionally tried float(value) to shorten long numbers and only guarded against value errors and overflow errors, not the TypeError raised by float() on a datetime object. It now skips that numeric-shortening step for date/datetime values, like it already did for None. opw-6276398 Forward-Port-Of: odoo/enterprise#121668
Creating a new planning slot now shows the default start and end times in the company's timezone instead of applying an extra timezone offset. This prevents schedules from starting or ending at the wrong time for companies and users outside UTC.
Original PR description
Issue: ---------------------------------------- When creating a new slot, no resrouces are set so we use the calendar of the company but the hours are offset because of the timezone. Steps to reproduce: ---------------------------------------- - Have planning Installed - Have an hour based calendar, from 8 to 16 each day for example - Have the company timezone in UTC+2, same for you the user - Go in Planning "Schedule By Resource" view - Click "New" - The default start and end time are 10am and 6pm (2h offset) Cause: ---------------------------------------- `default_get()` calls `_company_working_hours()` to get the company calendar hours. But they are returned in UTC, so when displaying them they are converted to the user timezone and are offsetted. Solution: ---------------------------------------- `_company_working_hours()` should return the compny hours in the company timezone. opw-6333993
Fixed an issue where appointment booking pages could show an empty month after visitors navigated forward, even though available days existed. This ensures customers see accurate appointment availability when minimum booking delays push the first bookable slot into a later month.
Original PR description
On the website booking page, moving to a later month can show no available times even though the weekly schedule clearly has some. ### Steps to reproduce - Install Appointments. - Create a recurring…
On the website booking page, moving to a later month can show no available times even though the weekly schedule clearly has some. ### Steps to reproduce - Install Appointments. - Create a recurring appointment type available on a single weekday (say Monday), with a user or resource assigned and a date range spanning a few months. - Set `Allow bookings at least` (the minimum booking delay) so that the current time plus the delay falls after this month's last Monday. Close to the end of a month, a day or two of delay is enough. - Open the booking page: the first month shown is next month, because the delay skipped this month's last slot. - Click the arrow to move forward one more month. => the reached month shows no slots, even though it has Monday availability. ### Cause The calendar computes availability one month at a time. It builds a list of months, and the browser refers to each month by its position in that list (0, 1, 2, ...). Clicking the next arrow sends that position back to the server. The server turns the position into a real month by adding it to a start month, which it computes as `now` plus the minimum booking delay. But the list shown to the visitor does not start there: it starts at the month of the first slot that can actually be booked. These two are usually the same, so the position lines up. They stop matching when the delay moves the earliest bookable time past the last availability day of the current month. In the steps above, `now` plus the delay lands after the month's last Monday, so the first bookable slot is a Monday in the next month. The visitor's list then starts one month later than the server assumes, every position points one month too early, and the server computes availability for a month the visitor is not looking at. The reached month comes back empty. ### Fix Count the visitor's month position from the same first bookable slot the list starts from, instead of from `now` plus the delay. The navigation offset is passed to the slot computation and resolved against that slot, so the filled month always matches the month the visitor sees. opw-6353569 Forward-Port-Of: odoo/enterprise#123994 Forward-Port-Of: odoo/enterprise#122494
The Documents app now keeps the Actions menu working when users select more than one document. This prevents a stuck menu button and preserves the correct selected-document count after uploads, making bulk document actions reliable again.
Original PR description
***Issue:*** Since https://github.com/odoo/enterprise/commit/8baaad621a1555680cd77ab514f626137b5b584d the div holding the selection box and the Actions menu carries t-key="targetRecords.length" in…
***Issue:*** Since https://github.com/odoo/enterprise/commit/8baaad621a1555680cd77ab514f626137b5b584d the div holding the selection box and the Actions menu carries t-key="targetRecords.length" in the documents list and kanban views, so every change of the selection count destroys and recreates everything inside it. Ticking a document checkbox updates both the selection and the focused record, and with these two updates the recreation goes wrong: the new ActionMenus component ends up destroyed while its button is still in the page. The dropdown click listeners are removed with the component, so clicking Actions does nothing until the selection changes again. That t-key was added because the selection box shows a stale count after a file upload. The real problem is that SelectionBox caches this.root once in setup. The upload flow reloads the model, which replaces the root record list, and the box keeps counting the selection of the old one. ***Fix:*** Remove the t-key from documents_list_controller.xml and documents_kanban_controller.xml and make DocumentsSelectionBox read the current props.root instead of the value cached by the parent setup. The count follows the new record list after an upload without remounting anything, and the Actions menu is not recreated so its dropdown keeps working. The upload scenario stays covered by the existing multi_view.test.js test, a new test checks that the Actions menu opens with two selected documents. ***Steps to reproduce:*** 1. Open the Documents app 2. Switch to the list view 3. Tick the checkboxes of two documents 4. Click the Actions button next to the "2 selected" box => the Actions dropdown does not open Ticket [link](https://www.odoo.com/odoo/project.task/6365618) opw-6365618 Forward-Port-Of: odoo/enterprise#123986 Forward-Port-Of: odoo/enterprise#123575
Rental pickup and return receipts now include the separate invoicing and shipping address details when customer addresses are enabled. This ensures printed rental documents show the right address information for customers and operations teams.
Original PR description
**Steps to Reproduce:** 1. Install sale_renting and enable "Customer Addresses" in the settings 2. Confirm a rental order with shipping address and invoice address 3. Print the Pickup and Return Receipt **Issue:** Only the general partner address is printed; the invoicing/shipping `information_block` is missing **Why this happens:** The 19.2 layout rework (abf18ba250bae2f390f93f70abef1d7fb601c524) switched `web.external_layout` calls to accept macro arguments (e.g. `address="address"`). report_rental_order_document was only partially migrated: `address` was set above the t-call and passed as an argument, but `information_block` was left as a t-set inside the call body, which was the old convention. Once external_layout is called with explicit arguments, content t-set nodes in the body no longer populate the callee's scope, so address_layout's `t-if="information_block"` never triggers. opw-6366091
Luxembourg payroll now uses the correct official salary index values for contracts starting from May 2025 and June 2026. This prevents incorrect contract signature index values and helps keep payroll calculations aligned with current legal parameters.
Original PR description
## Issue When creating or browsing an existing contract in a Luxembourgish company, the current index shown is the one from September 2023 (which was up-to-date until Mai 2025). If the contract is…
## Issue
When creating or browsing an existing contract in a Luxembourgish company, the current index shown is the one from September 2023 (which was up-to-date until Mai 2025). If the contract is created after Mai 2025, the "Index on Contract Signature" field is also wrong.
## Steps to reproduce
1. Install *Luxembourg - Payroll* (`l10n_lu_hr_payroll`)
2. Using a Luxembourgish company, create a new contract for an employee
- *Contract Start Date*: Any date after 05/01/2025 (Mai 1st 2025)
3. __The *Index on Contract Signature* shows `944.43`, which is the index from September 2023. It does not match with the most recent indices.__
## Cause
The two most recent indices are missing from the [`rule_parameter_lu_index`](https://github.com/odoo/enterprise/blob/885edbc270a86ab76e0a6eff4acb5767c0fe29d1/l10n_lu_hr_payroll/data/rule_parameters/general_rules_data.xml#L4-L58). These indices are:
- `968.04` from 2025-05-01 (Mai 1st 2025)
- `992.24` from 2026-06-01 (June 1st 2026)
These values were taken from [here](https://salary.lu/en/tools/social-parameters/indexation-of-salaries) and double-checked [here](https://lustat.statec.lu/?lc=en&tm=DF_C1201&pg=0&snb=1).
## Tests modification
Updating the latest index had an impact on the tests from the `l10n_lu_hr_payroll_account` (testing the salary rules). In fact, the current index (`l10n_lu_current_index`) is [used to compute the indexed wage](https://github.com/odoo/enterprise/blob/7892d035ddb968d67a3e8da0daf91292bd8fb499/l10n_lu_hr_payroll/models/hr_contract.py#L24-L33) (`l10n_lu_indexed_wage`), which is then used to compute most lines in the payslip (e.g., the `WAGE_SUPPLEMENT_70`).
https://github.com/odoo/enterprise/blob/7892d035ddb968d67a3e8da0daf91292bd8fb499/l10n_lu_hr_payroll/data/salary_rules/hr_salary_rule_data.xml#L70-L74
Since the latest index is not the same as when those tests were written, the values are not correct anymore. To prevent this, time was frozen to 01/01/2024 to use the expected index (944.43, from September 2023).
opw-6330790
Forward-Port-Of: odoo/enterprise#122147This update resolves a bug where employee working schedules weren't consistently updating with new version changes, leading to inaccurate attendance visualizations. The fix ensures schedules are synchronized between employee and resource records, preventing issues like incorrect unavailable time slots in the Attendance Gantt view. This improves data accuracy for employee scheduling.
Original PR description
Steps to reproduce: 1. Create a new version on an employee with a future start date 2. Ensure the new version has a different working schedule 3. After the new version becomes active, observe that…
Steps to reproduce: 1. Create a new version on an employee with a future start date 2. Ensure the new version has a different working schedule 3. After the new version becomes active, observe that the working schedule on the employees record is different from the one on the employee's resource record Every employee has an associated resource record associated with them. Normally, the employee's working schedule (`hr_employee.resource_calendar_id`) should always be in sync with their associated resource record (`hr_employee.resource_id.calendar_id`). When we update the employee's working schedule through the UI on a currently active version, it will also update their associated resource record with the same working schedule. However, if we change the working schedule for a future version, when `_cron_update_current_version_id()` runs and changes the active version, there is no mechanism to update the associated resource with the new working schedule. This change will ensure we keep the working schedules in sync, as if they are not, strange behaviors can occur. One side effect of this problem: When a new version becomes active, and working schedules become de-synced, this can cause the Attendance gannt view to display incorrect unavailable intervals for an employee (this appears as a grayed-out time slot). This is because `_attendance_intervals_batch()` pulls from the working schedule of an employee's associated resource record, rather than the employee record itself. This is what occurred on the linked ticket. [opw-6352770](https://www.odoo.com/odoo/my-tasks/6352770?debug=assets) Forward-Port-Of: odoo/odoo#275430
This update resolves an issue where Odoo was incorrectly sending duplicate capture requests to Stripe for EFTPOS payments in Australia. This resulted in payment failures and incomplete orders. The fix ensures that payments processed through EFTPOS are captured only once, improving reliability and order completion rates.
Original PR description
In Australia, Terminal payments using `payment_method_options.card_present.capture_method=manual_preferred` are not always captured later. When a payment is processed on the `eftpos_au` network, Stripe authorizes and captures it in a single step. However, the POS Stripe flow only skipped the extra capture based on the card brand instead of the processed network. As a result, payments such as `brand = visa` and `card_present.network = eftpos_au` were treated as capturable, and Odoo sent a second capture request. Stripe then rejected it with `payment_intent_unexpected_state` because the PaymentIntent had already been captured, leaving the POS order unfinished. This patch skips the extra capture call when the payment was processed on `card_present.network = eftpos_au`. opw-6228977 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271609 Forward-Port-Of: odoo/odoo#270293
This update resolves an issue where duplicate stock availability messages were appearing on product pages when using mega menus. The fix ensures that stock messages are correctly cleared and updated, providing a consistent and accurate display of product availability to customers. This improves the user experience and prevents confusion.
Original PR description
Steps to reproduce: - Add an `s_add_to_cart` snippet inside a mega menu - Open a product detail page for a storable product - Change the product variant several times - Stock availability messages…
Steps to reproduce:
- Add an `s_add_to_cart` snippet inside a mega menu
- Open a product detail page for a storable product
- Change the product variant several times
- Stock availability messages keep appending under `availability_messages` instead of replacing the previous one
`_onChangeCombinationStock` removed existing messages with `document.querySelector('.oe_website_sale').querySelectorAll(...)`, but appended the new message with
`this.el.querySelector('div.availability_messages').append(...)`.
`document.querySelector('.oe_website_sale')` only returns the first `.oe_website_sale` element in the document. When a mega menu contains an `s_add_to_cart` snippet, that element appears before the product page container, so the removal step runs on the wrong subtree and never clears the messages on the product page.
Fix by scoping the removal to `this.el`, the current `WebsiteSale` interaction root, so both removal and insertion target the same product page container.
Forward-Port-Of: odoo/odoo#276007
Forward-Port-Of: odoo/odoo#274928This update fixes a problem where background and image shape colors on the website weren't automatically updating when the overall theme color was changed. Now, changes to the theme color presets will correctly reflect in the shape colors used within website snippets and images. This ensures a consistent and visually aligned user experience.
Original PR description
[*]=website 1. Sync background shape color with color preset. Steps to reproduce: 1. Go to the website and enter edit mode. 3. Drop any snippet. 4. Add a background shape. 5. Set the background shape…
[*]=website
1. Sync background shape color with color preset.
Steps to reproduce:
1. Go to the website and enter edit mode.
3. Drop any snippet.
4. Add a background shape.
5. Set the background shape color to "o-color-1".
6. Go to theme tab.
7. Change the value of theme color 1 from theme preset.
Issue:
The background shape color is not updated when the theme color changes.
Reason:
The background shape color is embedded in the URL of the "**background-image**" style attribute. When the theme color value changes, this URL is not updated. Additionally, the URL uses color variables rather than resolved hexadecimal color values as parameters. As a result, even when an updation occurs, the URL itself remains unchanged, preventing the background shape color from being updated.
2. Sync image shape color with color preset.
Steps to reproduce:
1. Go to the website and enter edit mode.
2. Drop any snippet.
4. Click on the image and add a shape.
5. Set the image shape color to "o-color-1".
6. Go to theme tab.
7. Change the value of theme color 1 from theme preset.
Issue:
The image shape color is not updated when the theme color changes.
Reason:
When the theme color value changes, the SVGs are not re-fetched. Additionally, the image "**shapeColors**" dataset stores the hexadecimal value of the theme color instead of the corresponding CSS variable. As a result, there is no way to determine which theme color was selected (for example, whether `o-color-1` or `o-color-2`), since only the hex value is available.
task-5438314
Forward-Port-Of: odoo/odoo#272952
Forward-Port-Of: odoo/odoo#241968This update resolves an issue where Odoo was unnecessarily building internal registries, leading to increased CPU usage on the gevent server. By adapting a key component, this fix prevents over-registry creation and optimizes server performance. This results in a smoother and more responsive Odoo experience.
Original PR description
In [1], the need to build a registry for outgoing messages was removed, but `acquire_cursor` wasn't adapted. As a result, we might end up building more registries than needed, blocking the gevent server CPU. This commit fixes this issue. [1]: https://github.com/odoo/odoo/pull/235746 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
This update fixes a discrepancy in the default tax date obligation for Serbian VAT invoices. Previously, the system defaulted to a 'By Issuance Date' setting, which wasn't compliant with Serbian law. Now, it correctly defaults to 'By Delivery Date' as mandated by Article 16 of the Serbian VAT Law, ensuring accurate tax reporting.
Original PR description
According to[ Article 16 of Serbia's VAT Law](https://www.paragraf.rs/propisi/law-on-value-added-tax.html#:~:text=of%20Tax%20Obligation-,Article%2016,-A%20tax%20obligation), the tax obligation arises at the time of delivery of goods/services by default. 'By Issuance Date' only applies to a narrow set of services under Article 16(2a) Before: l10n_rs_tax_date_obligations_code defaulted to '3' (By Issuance Date) After: defaults to '35' (By Delivery Date) Upgrade: odoo/upgrade#10657 task-6348377 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273608
This update corrects an issue where reverting inventory adjustments with packages resulted in negative quantities appearing within those packages. The fix ensures that quantities are accurately restored after reverting, preventing inconsistencies in package inventory levels. This improves data reliability and simplifies inventory management.
Original PR description
Currently when the user reverts an inventory adjustment move line with a package the package contains extra line showing negative quantity of the product. ## Steps to produce: - Install Inventory…
Currently when the user reverts an inventory adjustment move line with a package the package contains extra line showing negative quantity of the product.
## Steps to produce:
- Install Inventory without demo data
- Settings Enable 'Packages'
- Create a product:
- Cheese burger
- On hand > Create a new quant
- Package: 'Burgerbox' and 'On Hand Quantity`: 1 and save
- Set the On Hand quantity to zero and save
- History > Revert the Inventory adjustment line from WH/stock to Inventory adjustment by selecting it and reverting via actions.
- Products > Packages > BurgerBox
## Observed Behaviour:
After reverting an inventory adjustment that set the product's physical quantity to 0, the package contains two lines for the same product with quantities 1 and -1.
This is inconsistent because a package should not contain a product with a negative quantity.
The package should be restored to its original state and contain only the expected positive quantity.
## Root cause:
When the user reverts the move line, `action_revert_inventory` is called. This method creates the revert move and then marks that move as done at [1].
Marking the move as done subsequently marks all related move lines as done at [2]. During this process, the system first unreserves the quantity from the virtual location / inventory adjustment and then removes the quantity from that location (resulting in a -1 quantity move line at that location). This is performed through `_synchronize_quant`, which is responsible for synchronizing the physical inventory with the move line at [3].
The `_synchronize_quant` method uses the move line's `package_id` when updating the corresponding quant at [4]. As a result, `_update_available_quantity` creates a new quant with the following values at [5]:
```
{
'product_id': 1,
'location_id': 14,
'lot_id': stock.lot(),
'package_id': 1,
'owner_id': res.partner(),
'in_date': datetime.datetime(2026, 6, 22, 12, 42, 11),
'quantity': -1.0,
}
```
This creates a quant with a negative quantity that is linked to the package because `package_id` is set on the newly created quant. Consequently, the move line with the negative quantity becomes associated with the package.
[1]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move_line.py#L1016-L1035
[2]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move.py#L1956 [3]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move_line.py#L662-L666
[4]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move_line.py#L678-L687
[5]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_quant.py#L1130-L1143
## Solution:
Remove the source `package_id` when creating revert moves for inventory adjustment locations.
When an inventory adjustment sets a product's quantity to 0, the adjustment is completed without a destination package, meaning the product is effectively removed from the package. Therefore, the corresponding revert move should not retain the package as its source. Keeping the package as the source is inconsistent because package information should not exist on a virtual inventory adjustment location, and the original inventory adjustment removes the product from the package (there is no destination package).
By removing the source `package_id` from the revert move, the system avoids creating negative quants associated with the package during quant synchronization. This also ensures that, after the inventory adjustment is reverted, the quantities of products inside the package are restored correctly and match their state prior to the adjustment.
opw-6285739
Forward-Port-Of: odoo/odoo#274167
Forward-Port-Of: odoo/odoo#271440This update resolves an issue where users couldn't update company names through the portal, and new companies were incorrectly created as contacts. Now, company names can be updated correctly, and commercial fields are editable for customer addresses with a single direct child company, streamlining business processes.
Original PR description
### [FIX] portal: fix parent company handling Before this commit, users could not update the company name from the portal, and creating a company resulted in a regular contact instead of a company. This happened because the additional_values passed to mark the parent as is_company=True were overridden to False when the customer did not have a VAT number. This commit sets is_company after creating the company, ensuring the parent contact is always created as a company. ### [FIX] portal: make commercial fields editable Before this commit, there was no way to edit commercial fields after a user entered a company name in the address form. Setting a company name created a parent company, and editing commercial fields was blocked because the customer had a parent record. This commit allows commercial fields to be edited again for customer addresses whose parent company has only a single direct child. Forward-Port-Of: odoo/odoo#275207
This update ensures that all invoices sent via Peppol are regularly checked for validity, regardless of whether they are sent in batches or individually. Previously, this check was only performed manually, leading to potential issues with Peppol compliance. This change improves the reliability and accuracy of our Peppol invoice processing.
Original PR description
If you have a partner that wasn't on Peppol. If you only do batch sending, we never re-check its validity. You need to do it by hand, or open explicitely the send&print for an invoice for this customer. We should simply do that check in every case, in batch or in manual sending. task-6296017 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273121
This update fixes an issue where the amount to invoice was incorrectly calculated when products were ordered using a unit of measure (UoM) like 'pack of 6'. The change ensures accurate invoice amounts are generated for purchase orders and sales orders that utilize UoMs, improving financial reporting accuracy. This resolves a discrepancy in the billing process.
Original PR description
**PROBLEM** amount_to_invoice_at_date is not calculated correctly when using UoM. **STEP TO REPRODUCE** 1. Create a product tracked by unit. 2. Create a purchase order with a UoM of pack of 6 (or some multiples of the Units UoM). 3. Confirm the PO and receive the products. 4. Go to the accounting app, reviews>bill to receive 5. Notice the po line on bill to receive as an incorrect amount. opw-6305324 Forward-Port-Of: odoo/odoo#275385 Forward-Port-Of: odoo/odoo#270327
This update resolves a critical issue where the purchase catalog feature crashed when accessed on mobile devices. The problem stemmed from a configuration error that prevented the catalog from properly displaying. This fix ensures the purchase catalog functions correctly on all device views, improving usability for mobile users.
Original PR description
Currently, th purchase catalog crashes in mobile view. Steps to reproduce: ------------------- * Open purchase order form on desktop * From the devtools put window size to mobile (don't refresh) * Select catalog > Traceback: Cannot find the definition of component "Dropdown" Why the fix: ------------ PurchaseSuggestCatalogSearchPanel extends AccountProductCatalogSearchPanel which also extends AccountProductCatalogSearchPanel. Components were completely overridden and not inherited. opw-6219505 Forward-Port-Of: odoo/odoo#271449
This update ensures that the Point of Sale system always uses a fiscal position that is both allowed and suitable for a customer, regardless of order of preference. Previously, the system could unintentionally use an unauthorized fiscal position, leading to potential errors. This fix improves data accuracy and prevents issues related to tax calculations during sales transactions.
Original PR description
**Steps to reproduce:** - Create a fiscal position T1, with detect automatically - Create another one T2, without the detect automatically - When looking at the fiscal positions list, make sure T1 is…
**Steps to reproduce:** - Create a fiscal position T1, with detect automatically - Create another one T2, without the detect automatically - When looking at the fiscal positions list, make sure T1 is on top, followed by T2 - Go to the PoS settings, check flexible taxes - Put T2 as default and in allowed, don't put T1 in allowed - Go to the PoS, chose a customer - The fiscal position is T1 even though it's not allowed **Why the fix:** Currently, the fiscal position is chosen like this in order: - A FP specified on the customer's profile - A FP detected with the detect automatically setting - The default FP from the PoS settings When we have a tie, it's the first one in the fiscal positions list that is chosen. Before this commit, we did not check that the fiscal position was allowed to be used in the PoS, so we just fetched whatever fiscal position fit the best for a given customer and didn't check if we could actually use it. We now make sure that the fiscal position we try to use is allowed in the current PoS, and if it's not we fall back to the default one. opw-6032031 Forward-Port-Of: odoo/odoo#271343
This update resolves an issue where customers were not appearing in the POS list when using the Taiwan localization. The fix updates the Chart of Accounts to correctly display customer accounts, ensuring all customers are visible within the POS interface for Taiwan companies. This improves the user experience for Taiwanese businesses using Odoo POS.
Original PR description
## Current behavior: Currently, when we go into POS using l10n_tw localization, none of the customers appear on the list. ## Expected behavior: All customers should be shown when using Taiwan localization ## Steps to reproduce: 1. Install l10n_tw and POS modules 2. Use the default US company, observe the customer list in POS. All of them are shown 3. Create and switch to a Taiwan company, go back to POS 4. Observe that no customers are shown ## Cause of the issue: Since 19.0, there is a check where if the default payable or receivable account set on the partner is non-trade, those accounts do not appear ## Fix: - Updated AR accounts in COA template file - Added migration script to version 1.1 opw-6298634 Forward-Port-Of: odoo/odoo#270738
This update fixes a glitch that allowed customers to repeatedly top up their loyalty program balances using eWallet top-up products, effectively creating an unlimited credit. The fix now correctly prevents applying eWallets when an order consists solely of top-up products, ensuring accurate discount calculations and preventing abuse.
Original PR description
### Steps to reproduce: - Download 'Sales' application - From 'Configuration' > 'Settings', enable 'Promotions, Loyalty & Gift Card' - From 'Products' > 'Gift cards & eWallet', Configure an eWallet…
### Steps to reproduce:
- Download 'Sales' application
- From 'Configuration' > 'Settings', enable 'Promotions, Loyalty & Gift Card'
- From 'Products' > 'Gift cards & eWallet', Configure an eWallet program with a top-up product
- Have a customer with an existing eWallet balance
- Create a new sale order for that customer and add the eWallet top-up product
- Pay the order using the customer's eWallet
> The order gets discounted by the eWallet, effectively allowing the user to top up their balance
using the balance itself (infinite money glitch).
### Cause of Issue:
When computing the discountable amount for payment programs (like eWallets and gift cards), `_discountable_order` includes the total order amount. However, it did not exclude the program's own top-up products (`trigger_product_ids`) from the discountable lines.
### Fix:
If an order consists solely of top-up products, attempting to apply the eWallet now correctly raises a `UserError` ("There is nothing to discount").
opw-6341410
Forward-Port-Of: odoo/odoo#273419This update resolves an issue where batch payment sequences were incorrectly created when a new company was initially set up. The change ensures sequences are properly associated with the correct company during creation, preventing errors in payment processing. This improves the reliability of batch payments.
Original PR description
Previously, batch payment sequence will be created by simply select to create new company due to having lambda in default. Hence, the created sequence does not have a correct company_id set as company hasn't yet created. Switch to creating sequence in ``create`` function to avoid this issue. Also use ``range_year`` for payment prefix because it was set to use date range. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273852 Forward-Port-Of: odoo/odoo#268689
The barcode check-in process in kiosk mode was previously inaccurate, with location data off by several kilometers. This update fixes the issue by utilizing the browser's geolocation to provide more precise location data, improving the accuracy of check-in times.
Original PR description
**Issue** Check-in and check-out performed in kiosk mode via the barcode scanner were less accurate than those made via the manual selection. The reported inacurracy between the actual and real locations was several kilometers. **Cause** `attendance_barcode_scanned` was called without a location coming from the browser's geolocation API. In that case, the location was determined by the geoip database https://github.com/odoo/odoo/blob/51f59a293de1e86f66f30257f8fc0c419463d18c/addons/hr_attendance/controllers/main.py#L69-L70 which is generally not as accurate as the location provided by the browser. opw-5889102 Forward-Port-Of: odoo/odoo#273044 Forward-Port-Of: odoo/odoo#251478
This update resolves an issue where web assets weren't correctly loaded within iframes, particularly in scenarios like displaying emails. The change ensures assets are properly added to secondary documents, improving functionality in complex use cases.
Original PR description
Commit [1] introduces the concept of "global" cache for optimization. However when loading a bundle inside a secondary document such as an iframe, containing source files that are already loaded in…
Commit [1] introduces the concept of "global" cache for optimization. However when loading a bundle inside a secondary document such as an iframe, containing source files that are already loaded in the main document, those source files are not properly added in the secondary document. Example: load `web.assets_web` inside an iframe (this use case can happen in `mass_mailing` where we have to wrap some component inside a sandboxed iframe in order to display unsafe content (poorly sanitized), such as emails). The issue is caused by an inconsistent usage of the `globalCache`: `getBundle` adds `bundleName` key to JS and CSS libs, but `computeAssetCaches` adds `url` keys to link or script elements. After this commit: - `globalCache` is only used in `getBundle` to map bundleNames to their libs - `loadCSS` and `loadJS` only use the documents caches to map urls to their element in the respective document. [1]: https://github.com/odoo/odoo/commit/5b1dc282b0f09c0fe6dcf9910a3a29cfd01d66a3