Monday, August 4, 2025
18 changes · saas-18.4
New functionality added to Odoo
Adds Cambodia-specific financial reporting so businesses can generate a balance sheet, profit and loss report, and WT003 withholding tax export in Odoo. This helps Cambodian companies meet local reporting needs more directly from the accounting system.
Original PR description
Adds basic reporting module for Cambodia, including: - Balance sheet - Profit & loss - WT003 export task-4383330 Forward-Port-Of: odoo/enterprise#91592 Forward-Port-Of: odoo/enterprise#89831
Enhancements to existing features
Restaurant self-order users can now access a Get QR Codes button directly from the floor plan view. The button opens a prefilled Odoo.com form, making it easier to order engraved QR codes for tables and streamline self-order setup.
Original PR description
Add a `Get QR Codes` button on the floor plan view TaskID: 4814164 Forward-Port-Of: odoo/odoo#221546 Forward-Port-Of: odoo/odoo#218164
Resolved issues and error corrections
Future leave balances now stay correct when unused days carry over for a limited period. This helps HR teams and employees see reliable vacation entitlements after carryover expires, avoiding misleading zero or partial balances.
Original PR description
### Steps to reproduce: - Create an accrual plan with the following rule: — The employee has 20 days off in the first year. Total 20. — The employee has 21 days off in the second year and an…
### Steps to reproduce: - Create an accrual plan with the following rule: — The employee has 20 days off in the first year. Total 20. — The employee has 21 days off in the second year and an additional 5 days off if available from the previous year, which can be taken until 6 months. Total 21 + 5 = 26 — The employee has 22 days off in the third year and an additional 5 days off if available from the previous year, which can be taken until 6 months. Total 22 + 5 = 27 — The employee has 23 days off in the fourth year and an additional 5 days off if available from the previous year, which can be taken until 6 months. Total 23 + 5 = 28 - Create an accrual allocation with the created plan - Check future allocation data using 'Balance at the' - Notice the following behaviour: — until 31/12/2025 it CORRECTLY shows 20 days available. — from 01/01/2026 to 30/06/2026 it CORRECTLY shows 26 days (21 days for renewal and 5 days not used in 2025) — from 01/07/2026 it INCORRECTLY shows no days available. — from 01/01/2027 to 30/06/2027 it CORRECTLY shows 27 days (22 days for renewal and 5 days not used in 2026) — from 01/07/2027 it INCORRECTLY shows 5 days. — from 01/01/2028 to 30/06/2028 it CORRECTLY shows 28 days (23 days for renewal and 5 days not used in 2027) — from 01/07/2028 it INCORRECTLY shows no days available. — from 01/01/2029 it CORRECTLY shows 28 days again. — In the following years, after 6 months, one year shows 5 days and the next shows nothing. ### Cause: The first cause here is that when we have validity for the carryover then we will have two calls in each year one at the start of the year and another at the expiration date of the carryover. So, when we add the days to the allocation we don't consider the second call in the condition and we only check if the allocation.actual_lastcall is equal to one of the start dates for each year https://github.com/odoo/odoo/blob/3fb37cbc59adc2caace8efcdae418d2466a9b750/addons/hr_holidays/models/hr_leave_allocation.py#L588 The second cause where each two years one of them shows the number of carryover days from the previous year, this is happening because when we remove the expiring days for the first year we set the number of days to 0 https://github.com/odoo/odoo/blob/3fb37cbc59adc2caace8efcdae418d2466a9b750/addons/hr_holidays/models/hr_leave_allocation.py#L516-L517 And it will be 0 until we loop again and add the days to allocation https://github.com/odoo/odoo/blob/3fb37cbc59adc2caace8efcdae418d2466a9b750/addons/hr_holidays/models/hr_leave_allocation.py#L521-L522 and since this is happening after we already set the expiring days which in this year will be 0 we won't remove those expiring days from the year's allocation data ### Fix: We add a condition to check if the actual_lastcall is either a date in the start of the allocation or one of the expiration dates for the carryover. Also, before we set the value of the expiring_carryover_days we call _add_days_to_allocation to calculate on the correct number of days for the plan level we are checking. opw-4606886 Forward-Port-Of: odoo/odoo#221433 Forward-Port-Of: odoo/odoo#209669
The Point of Sale no longer loads all customer invoice records upfront when settling dues. This reduces memory use and startup delays, making the PoS interface faster and more reliable for users.
Original PR description
Before this commit, all account.move records were loaded into the PoS interface, even though they were not used immediately. This caused significant performance issues, increasing memory usage and loading times. opw-4986727 Forward-Port-Of: odoo/enterprise#91515
This update brings the spreadsheet engine to its latest 18.4 version and fixes several visible issues. Users should see more reliable chart behavior, better handling of transparent colors, and fewer interface layering problems in the spreadsheet top bar.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/358931f33 [REL] 18.4.5 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/358931f33 [REL] 18.4.5 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/8ab8485e4 [FIX] Color: Support colors with alpha in colorScale helpers [Task: 4951926](https://www.odoo.com/odoo/2328/tasks/4951926) https://github.com/odoo/o-spreadsheet/commit/808a34539 [IMP] demo: Add error handler [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/d2e91ea45 [FIX] chart: chartJS extensions loaded too late [Task: 4954034](https://www.odoo.com/odoo/2328/tasks/4954034) https://github.com/odoo/o-spreadsheet/commit/b6d9f269a [FIX] Topbar: Fix Z-index [Task: 4981390](https://www.odoo.com/odoo/2328/tasks/4981390) Co-authored-by: Anthony Hendrickx (anhe) <anhe@odoo.com> Co-authored-by: Alexis Lacroix (laa) <laa@odoo.com> Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com> Co-authored-by: Dhrutik Patel (dhrp) <dhrp@odoo.com> Co-authored-by: Adrien Minne (adrm) <adrm@odoo.com> Co-authored-by: Mehdi Rachico (mera) <mera@odoo.com> Co-authored-by: Florian Damhaut (flda) <flda@odoo.com> Co-authored-by: Rémi Rahir (rar) <rar@odoo.com> Co-authored-by: Pierre Rousseau (pro) <pro@odoo.com> Co-authored-by: Vincent Schippefilt (vsc) <vsc@odoo.com>
Payment providers are now filtered consistently by the current website across checkout, saved payment methods, and payment link flows. This prevents customers from seeing or using payment options that are not meant for the site they are visiting, reducing confusion and transaction issues.
Original PR description
In a multi-website environment, payment providers are often configured specifically for each website using the `website_id` field. While the checkout page (`/shop/payment`) correctly filters providers by the current website, other routes such as `/my/payment_method` or `/payment/pay` flows do not apply this filtering consistently. This patch ensures that the `website_id` constraint on payment providers is respected across all relevant flows, improving consistency and preventing users from seeing or using providers that are not available for their current website. Without this patch, users may see or select payment providers that are not intended for their site, leading to potential confusion, incorrect transactions, or access to providers that are not supported on the current website. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#218985 Forward-Port-Of: odoo/odoo#218089
Fixes an error that could block users from completing subcontracted purchase receipts when they choose not to create a backorder for a small remaining quantity. The system now correctly cancels the remaining manufacturing order instead of trying to set it to zero, improving reliability for subcontracting workflows.
Original PR description
Steps to reproduce the bug: - unarchive the subcontracting route - Create a storable product C1 with the following route: - Buy + Resupply Subcontractor on Order - Create a storable product P1 with:…
Steps to reproduce the bug:
- unarchive the subcontracting route
- Create a storable product C1 with the following route:
- Buy + Resupply Subcontractor on Order
- Create a storable product P1 with:
- BoM type: Subcontracting - Type: subcontracting - Subcontractor: Azure Interior - Component: C1
- Create a purchase order for 20 units of P1
- Confirm the purchase order
- Validate the resupply transfer
- Go to the receipt of P1
- Record 19.8 units of the component (ignore the remaining 0.2)
- Validate the receipt with no backorder
Problem:
A user error is raised:
```
The operation cannot be completed: The quantity to produce must
be positive!
```
When clicking No Backorder, the `process_cancel_backorder` method is
called:
https://github.com/odoo/odoo/blob/18.0/addons/stock/wizard/stock_backorder_confirmation.py#L75-L77
This triggers the validation of the picking, so updates the subcontract
order quantity:
https://github.com/odoo/odoo/blob/16a1d9b19b8b07435a9c4b4db2cad3c1e37e4e17/addons/mrp_subcontracting/models/stock_picking.py#L53
At this stage, we check whether it should reduce the MO quantity or
cancel the order entirely. However, the logic compares the quantity to
remove against the initial order quantity without using `float_compare`,
which leads to minor rounding differences. This results to update the
MO quantity to zero instead of canceling it, which then triggers an SQL
constraint error because the MO quantity cannot be zero:
https://github.com/odoo/odoo/blob/e7e2a088495eed3c2886a69054af689c01628f32/addons/mrp_subcontracting/models/stock_move.py#L304-L311
https://github.com/odoo/odoo/blob/29d1f637d3ec6f3ebb218d103001a6182af1b8a4/addons/mrp/models/mrp_bom.py#L93-L95
opw-4905031
Forward-Port-Of: odoo/odoo#221451
Forward-Port-Of: odoo/odoo#219650The activity counter in the systray now updates correctly when activities are changed, archived, rescheduled, created, or deleted in batches. This helps users see an accurate count of pending activities without needing to refresh or wait for unrelated changes.
Original PR description
Currently the systray counter is only updated at: - create - unlink - write, but only if the user changes We want to detect changes such as activities being archived or due dates being updated to properly reflect the changes as the user applies them. We now do a separate check for activity count per user before and after a write call that modifies these fields. Additionally since we now have a count we provide that as part of the bus notification so that it can be updated accurately when modifying/creation/deleting activities in batch. Common activity test utils are updated to avoid false negatives. task-4862215 Forward-Port-Of: odoo/odoo#220642 Forward-Port-Of: odoo/odoo#215880
Users can now merge stock picking batches even when some batches do not have a scheduled date, avoiding an unexpected error. The system also clearly warns users when they try to merge only one batch, since that action has no practical effect.
Original PR description
Issue Before This Commit: ============================ - Merging a batch that lacks a `scheduled_date` causes a traceback: `TypeError: '<' not supported between instances of 'datetime.datetime' and…
Issue Before This Commit: ============================ - Merging a batch that lacks a `scheduled_date` causes a traceback: `TypeError: '<' not supported between instances of 'datetime.datetime' and 'bool'.` - Merging a single batch does nothing but still proceeds silently, even though merging a single record has no practical effect. Steps to Reproduce: ============================ - Install the `stock_picking_batch` module. - Create two batches, one with a scheduled_date, one without. - Try merging only one batch → it proceeds silently, which makes no sense. - Try merging both; a traceback error occurs due to a missing scheduled date. With This Commit: ============================ - Raise a proper UserError when the user tries to merge fewer than two batches. - Prevent traceback by filtering out batches without a scheduled date before finding the earliest one. This commit ensures that users can proceed with the batch merging process without encountering a traceback when one or more batches have no scheduled date. It also introduces a UserError when attempting to merge only a single batch, similar to the behaviour in purchase order merging. Since merging a single record has no practical effect.
Past-date inventory reports now avoid counting internal warehouse transfers as customer outgoing stock. This prevents inflated on-hand quantities for products using multi-step delivery routes, giving businesses more reliable historical stock reporting.
Original PR description
Before this commit, the available quantity was incorrect when using the "Inventory At" feature with a past date in the inventory report For products using multi-step delivery routes, the…
Before this commit, the available quantity was incorrect when using the "Inventory At" feature with a past date in the inventory report For products using multi-step delivery routes, the `_compute_quantities_dict()` method incorrectly treated internal moves as outgoing moves As a result, the same outgoing quantity was added multiple times, leading to an overestimation of the available stock This commit adds a filter to the `domain_move_out_done` domain used for past dates, excluding internal moves based on `location_dest_usage`` ## Steps to reproduce: - Create a new product - Active the multi-step routes in Settings - Set the Warehouse's Outgoing Shipments to Pick, Pack, then Deliver - Create a RFQ for 100 products and Receive Products - Create a Quotation for 20 products - Validate each delivery steps - Go to Inventory -> Report -> Stock - Click on Inventory At - Set the date to 2025-01-01 - Search for your product - The `In Hand` quantity should be 0 but is 40 before the fix opw-4848473 Forward-Port-Of: odoo/odoo#217732
The website event pages now show the “Registered” banner consistently based on the visitor’s actual registration state. This prevents customers from seeing misleading event registration status when browsing event lists or pages in different sessions.
Original PR description
We had an inconsistent display of the Registered banner for events on the website. The banner would appear or disappear randomly, regardless of whether the user was logged in or not. Steps to reproduce: ------------------- - start the server - log in as a user that does not have access to website editor - get a ticket for an event - go to the event list -> event is marked register - go to the event page in a new browser session (incognito) -> event is still marked register > Observation: On refresh, Registered green banner on events appear and disappear randomly Why the fix: ------------ Keys that are not stored on the table of event should be added to the cache key to force a re-render when they change, or t-nocache should be used opw-4819021 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#221637 Forward-Port-Of: odoo/odoo#220053
Malaysian e-invoices now use the classification code chosen on each invoice line before falling back to the product default. This helps ensure submitted e-invoices reflect line-specific choices and reduces reporting errors when a product needs a different classification on a particular invoice.
Original PR description
Description of the issue/feature this PR addresses: Prioritizes the Malaysian classification code from the invoice line over the one from the product. This ensures that line-specific override or manual selection of the code is correctly used when submitting e-invoices. Adds one unit test to verify this priority logic. Current behavior before PR: Submission of e-invoice uses products' classification code and ignores invoice lines' code. Desired behavior after PR is merged: Submission of e-invoice uses invoice lines' classificatio`n code. If the code is not available, the submission uses products' classification code. Task-4945679 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The French POS inalterability check report now processes large volumes of orders much faster by loading only the data needed for verification. This reduces delays and memory pressure for businesses running compliance checks on high transaction volumes.
Original PR description
### Problem: Pos inalterability Check report is specific to French localization. It verifies whether POS orders have been modified by computing a hash of the order data and comparing it to the previously stored hash. _compute_string_to_hash method is computationally expensive and leads to significant performance and memory issues when processing more than 50,000 orders. ### Benchmark Before: | Orders | Time | Memory | |--------|---------|--------| | 1k | 15s | 10MB | | 10k | 77s | 81MB | | 20k | 102s | 110MB | | 40K | timeout | 256MB | After: | Orders | Time | Memory | |--------|------|--------| | 1k | 5s | 7MB | | 10k | 9s | 42MB | | 40K | 20s | 174MB | | 100k | 42s | 550MB | | 330k | 126s | 1.2GB | ### Solution: Fetching only required fields to compute _compute_string_to_hash opw-4901994 Forward-Port-Of: odoo/odoo#221218 Forward-Port-Of: odoo/odoo#217348
This fix prevents WinBooks file imports from being blocked by validation issues related to payable tax accounts, missing journals, or accounts marked for deprecation. Businesses can import legacy accounting data more reliably without manual cleanup for these cases.
Original PR description
When importing a winbooks file the following issues and or inconsistencies may be found **Issue 1** We may import an account with CENTRALID 'V03' and code 45100000 Having this centralID means that it…
When importing a winbooks file the following issues and or inconsistencies may be found **Issue 1** We may import an account with CENTRALID 'V03' and code 45100000 Having this centralID means that it will be set as tax payable account id according to https://github.com/odoo/enterprise/blame/d8d4812414dba8825a1c785c29d00f7d0fd98360/account_winbooks_import/wizard/import_wizard.py#L174 However, this means it needs to be a `liability_payable` account with reconcile enable, in order to comply with the following check https://github.com/odoo/odoo/blame/ad6c9001b447f5ffebafe1581512f48708c7d746/addons/account/models/account_tax.py#L80 *Note* Even if we set it as liability_payable, the import may fail later on in case the same account is used in a sales move where those types of account are not allowed https://github.com/odoo/odoo/blame/1b657cf1e1ce43874a3ede307b2f8ad68216aa56/addons/account/models/account_move_line.py#L1247 A solution is to skip the `_check_payable_receivable` check for winbooks lines **Issue 2** Move line data may reference an unkown journal, causing a validation error because no journal is retrieved from the database and a move always need a journal **Issue 3** Account created during import may be marked for deprecation, which occurs at the end of the import process. However, if the account has been used in a tax repartition line, trying to set it as deprecated will raise an error. https://github.com/odoo/odoo/blame/2cdc41c012f637849ba030989ce928b6b1152e7e/addons/account/models/account_account.py#L1028 opw-4850314 Forward-Port-Of: odoo/enterprise#89426
Payment links for already invoiced recurring sales orders now use the next invoice amount instead of including past transactions. This prevents customers from seeing incorrect payment amounts when renewing or paying for subscription periods.
Original PR description
Before this commit,when a payment link was generated for a recurring SO already invoiced, the default values of amount and amiunt_max would take into account all previous transactions. As a result, the amount would be badly computed as recurring order have many transactions (at least once or each period). This commit ensure to use the next invoice amount. taskid: 4352396 Forward-Port-Of: odoo/enterprise#83934
Barcode scanning on iOS is made more reliable by preventing unsupported or blocked scan sounds from causing an error. Users can continue scanning even if their browser cannot play the selected sound or does not allow audio playback.
Original PR description
Issue ----- On iOS 18.5, users can get a `NotSupportedError` when trying to scan a barcode from the (barcode) main menu. Steps to reproduce ----- - Open barcode - Click the center scan button - Scan…
Issue ----- On iOS 18.5, users can get a `NotSupportedError` when trying to scan a barcode from the (barcode) main menu. Steps to reproduce ----- - Open barcode - Click the center scan button - Scan a barcode --> Traceback Discussion ----- There are 2 issues occuring here. 1. We play either an ogg or mp3 file. However, the method to know if the format is supported by the browser returns one of 'probably', 'maybe', ''. https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType#return_value This means that when we do https://github.com/odoo/enterprise/blob/70e5013ea022ed04ff27db71ea3ecccb55ae1f70/stock_barcode/static/src/main_menu/main_menu.js#L37 We might end up using ogg even if the browser doesn't actually support it, as 'maybe' is truthy. To reduce the risk of this happening, we can specify the codec as "vorbis" (all ogg files of Odoo are vorbis). This is already done in mail: https://github.com/odoo/odoo/blob/cd4c1d599ea9403ce3791e239ad765d946446a47/addons/mail/static/src/core/common/sound_effects_service.js#L46 2. The browser might not have the permission to play the sound. In such cases, the best we can do is try to play the sound and log potential errors. ----- Ticket: opw-4820022 Forward-Port-Of: odoo/enterprise#91158
Manufacturing users who are not HR users can now open the Shop Floor app without encountering an access rights error. The app now looks up the relevant employee barcode only when needed, avoiding restricted employee data access while keeping barcode identification working.
Original PR description
**PROBLEM** If a user is in the mrp.group_mrp_user group, but does not belong to hr.group_hr_user, he can't access the shop floor app. **STEP TO REPRODUCE** 1. connect with a user which is a user of manufactring, but not a user of hr. 2. try to go on the shop floor app and notice there is an access right error. **CAUSE** When connecting to the shop floor app, we are trying to get the barcode field on all employee (because we need them if we want to identify an employee on the shop floor app using their barcode). This was added in this commit: https://github.com/odoo/enterprise/commit/b3fb0073a15adcc799a5681284f0cfd2308764b8 The barcode field is only accessible to member of hr.group_hr_user. **FIX** Instead of getting the barcode of all employee using `get_all_employee()`, we do a rpc call to query the employee the barcode belong to. opw-4905206 Forward-Port-Of: odoo/enterprise#89436
Rejecting an UrbanPiper order in Point of Sale now completes without causing an error. This keeps staff workflows stable when declining test or real delivery orders and ensures the POS screen resets correctly afterward.
Original PR description
Steps to reproduce: --- - Configure UrbanPiper in any POS configuration. - Open this POS and place a test order. - Attempt to reject the order. Issue: --- - A traceback occurs when rejecting the order. Cause: --- - The `removeOrder` function was being called unnecessarily, even though it is already handled by `deleteOrders`. Fix: --- - Removed the redundant call to `removeOrder`. - Additionally, called `afterOrderValidation` and `setSelectedOrder` to properly reset the state after rejection. task-4965076 Forward-Port-Of: odoo/enterprise#91116