Daily updates from Odoo
Navigate
Branch
Wednesday, August 12, 2026
235 changes
16 changes
Enhancements to existing features
Document attachment link calculations have been optimized to reduce unnecessary searches and improve performance. This should make document-related operations feel faster, especially where many attachments are involved, without changing user-facing features.
Original PR description
* Prefetching attachment_ids in sudo allows to limit the scope of the documents search * Removing the location filter on the document, not worth the performance hit. Follow-up of Task-5882406 Forward-Port-Of: odoo/enterprise#127062
Resolved issues and error corrections
A new test verifies that India's GSTR-1 report selects the correct tax rate group when GST and CESS taxes are used together. This helps prevent reporting errors in tax filings for affected Indian businesses.
Original PR description
This PR adds a test case to ensure that the correct tax rate group is selected in the GSTR-1 report when a combination of GST and CESS taxes is used. Community PR - https://github.com/odoo/odoo/pull/280571 Forward-Port-Of: odoo/enterprise#126770
Products created through the Barcode Lookup service now show the image retrieved from the external database. This prevents missing product pictures in the product form and helps users confirm they selected the right item.
Original PR description
Issue before this commit: ========================= When creating a product by adding a barcode using the Barcode Lookup service, the product image was fetched properly but was not displayed in the…
Issue before this commit: ========================= When creating a product by adding a barcode using the Barcode Lookup service, the product image was fetched properly but was not displayed in the UI. Steps to Reproduce: ========================= - Install the stock module. - Enable the Stock Barcode Database. - Add a valid API key for the Barcode Database. - Create a product by adding a barcode available in the Barcode Lookup API. - Notice that the product image is not displayed. Cause of the issue: ========================= This issue was introduced by this [PR](https://github.com/odoo/odoo/pull/244421), which improved the behaviour of **fields.Binary**. As a result, the image returned by the Barcode Lookup API was not converted to the expected binary format, preventing it from being displayed in the UI. With This Commit: ========================= With this commit, convert the fetched image to the expected binary format before assigning it to the product, ensuring that it is displayed correctly in the UI. opw-6434478 Forward-Port-Of: odoo/enterprise#126314
This fix updates how mandatory SSS and Pag-IBIG payroll contributions are calculated for Philippine payroll. It ensures the contribution bases use the correct salary categories, improving payroll accuracy and compliance reporting.
Original PR description
. SSS Mandatory contribution is categories['TAX_CASH_EARNINGS'] . Pag-IBIG Contribution is categories['PH_BASIC'] + categories['ECOLA'] . Update the corresponding tests task-6431960
Belgian payroll calculations now use greater precision when computing ONSS social security contribution amounts. This reduces rounding discrepancies and helps produce more accurate payslips and payroll reporting.
Original PR description
…unt calculation Task: 6431856
Salary offers now correctly display fields that rely on payroll information, even when accessed by HR users with appropriate permissions. The related salary configurator test flow was also updated to reflect real HR user access rather than administrator access.
Original PR description
A field displayed inside the offer should have been computed with sudo as it accesses some payroll field to compute. Also, the salary configurator tour has been adapted to use a HR user instead of an admin Forward-Port-Of: odoo/enterprise#127510
This fix prevents users in multi-company setups from hitting an unsolvable error when creating operation steps without the Quality Control module installed. It ensures quality team email aliases always have an appropriate company value, so manufacturing quality workflows continue smoothly across companies.
Original PR description
This commit actually reverts [1] and manually forwards [2]. Suppose `mrp_workorder` installed and `quality_control` uninstalled. Because of the default value provided by [1], the only existing quality team is linked to the first company. As a result, when using another company, if the user tries to create an operation step (i.e., a QCP), it will raise an error when the onchange tries to load the default team in charge: https://github.com/odoo/enterprise/blob/f9c99f937bd64e5a0acb4bc88b1fc08249250c4e/quality/models/quality.py#L141-L142 However, the `quality` module doesn't provide any view to create such a team. tldr The module raises an error that is actually impossible to solve... Let's avoid it in the above situation. [1] https://github.com/odoo/enterprise/commit/f9c99f937bd64e5a0acb4bc88b1fc08249250c4e [2] https://github.com/odoo/enterprise/commit/8cd5c9322bef7db49a90d4aef844dd0ba267058e Forward-Port-Of: odoo/enterprise#127438 Forward-Port-Of: odoo/enterprise#126364
This fix makes the payroll payrun automated test wait for the page to fully reload before continuing. It reduces false test failures and helps keep payroll quality checks stable without changing user-facing payroll behavior.
Original PR description
Currently in payroll_payrun_tour in hr_payroll module, if we put step_delay as paramater in tour test. the tour test will get fail, after the validation in payslip step. When return to Payrun View Page, the next step to click New Button and Select the Payrun in the Dropdown option. But New Button with dropdown only available in the Payslip steps. The reason it works in runboot before due to race conditions where the test still click new button in Payslip step, expected there is dropdown in this view. The reason it's not work in with step_delay, because step_delay make we have time to change the payrun view, when we trigger the new button, the button is no longer reflected to Payslip step but in PayRun View. In this PR, expected to wait the tour test to fully reload the Payrun View before click the New button, so it will work with or without step_delay. task-6455499
Sales users in Kenya can now open invoices they are allowed to view without being blocked by missing access to local electronic invoicing codes. The change grants employees read-only access to these non-confidential codes, reducing interruptions in sales and invoicing workflows.
Original PR description
The KE codes are used in invoices and when sales people who do not have accounting access, but still can see their own invoices open an invoice, right now they will have an access error because they do not have read access to the codes. So, we should just apply the same logic as is done in edi.documents and give base.group_user read access to those codes, which are not confidential anyways. Forward-Port-Of: odoo/enterprise#126825
Timesheet suggestions now behave correctly when users hold Ctrl and click them. Instead of opening an unwanted new browser window, the suggestion is added to the timesheet form as intended, reducing user confusion.
Original PR description
Currently, when a user use ctrl + click on a suggestion, instead of adding it to the view form, it opens a new window. This is due to the default behavior when ctrl+click is used on a link. Using a button instead of an a href="#" solves this issue. Forward-Port-Of: odoo/enterprise#126293 Forward-Port-Of: odoo/enterprise#126240
Payroll departure processing now correctly updates payslip history when new payslips are added, ensuring departure-related payroll records are generated in the right order. This helps avoid incorrect payroll results at the end of an employee collaboration.
Original PR description
Departure should be generated after payslips
The Helpdesk ticket quick create form now has clearer spacing between the customer field and action buttons. This small layout fix makes the form easier to read and reduces visual crowding for users creating tickets from the kanban view.
Original PR description
This commit add a space between the partner field and the buttons in ticket kanban quickreate. task-6443626 Forward-Port-Of: odoo/enterprise#126901
Subscription products now show discounted recurring prices correctly on shop product tiles. This prevents customers from seeing a price based on the one-time sale price when a discount is meant to apply to the subscription plan.
Original PR description
Steps to reproduce: =================== 1. Create a subscription product, allow one-time sale, sale price 5 2. Add a recurring price 10/month 3. On the pricelist, add an advanced rule: -10% for the…
Steps to reproduce: =================== 1. Create a subscription product, allow one-time sale, sale price 5 2. Add a recurring price 10/month 3. On the pricelist, add an advanced rule: -10% for the monthly plan 4. Open the shop page and look at the product tile Cause: ======= On the /shop page, the subscription price displayed on a product tile is computed by `_get_sales_prices`. The cart has no plan selected yet at that point, so `request.cart.plan_id.id` is empty and was passed as `plan_id` to `_compute_price`. In `product.pricelist.item._compute_base_price`, the recurring base price is only looked up when a `plan_id` is given: if rule_base == 'list_price' and product.recurring_invoice and plan_id: ... # find the recurring rule -> base = recurring price With `plan_id` empty, that branch is skipped and the percentage rule falls back on the product's one-time `list_price` instead of the recurring price. Example: one-time price 5, recurring price 10/month, pricelist rule -10% on the monthly plan. => Tile showed 4.5/month (5 * 0.9) instead of 9/month (10 * 0.9). Solution: ========= The chosen pricing already targets a plan, so pass `pricing.plan_id.id` to `_compute_price`, matching what the product page does in `_get_additionnal_combination_info`. opw-6307398 Forward-Port-Of: odoo/enterprise#124815 Forward-Port-Of: odoo/enterprise#120872
The point-of-sale self-order test was adjusted to match the current behavior where takeaway is selected automatically when it is the only option. This keeps quality checks aligned with the user experience and helps avoid false test failures.
Original PR description
In this commit: - The takeaway preset is now automatically selected when it is the only available option. Remove the explicit "Takeaway" selection step from the tour to match the updated behavior. Task:6217791 Community PR : https://github.com/odoo/odoo/pull/274301 Forward-Port-Of: odoo/enterprise#126889 Forward-Port-Of: odoo/enterprise#122979
The planning overlap warning no longer appears for private tasks that are not linked to a project. This prevents users from seeing irrelevant warnings while drafting tasks and keeps scheduling alerts focused on project-related work.
Original PR description
Steps to reproduce: - - Create a task without a project (do not save) - Set planned_date_begin and date_deadline so it overlaps with another task for the same assignee Issue: - - The overlap warning is shown even though the task has no project. Cause: - - When creating a new record, the overlap warning was shown before saving as there was no check for private tasks (tasks with no project), so the warning could appear even when the task had no project. Solution: - - Add a project check so private tasks never show the warning, and recompute it whenever the project changes. Related PR https://github.com/odoo/enterprise/pull/109988 task-6140800
Payslip CFDIs in Mexican payroll now have their SAT validation status updated correctly in Odoo. This prevents validated payroll documents from incorrectly showing an undefined status, improving compliance visibility for payroll teams.
Original PR description
l10n_mx_hr_payroll_account_edi introduces new l10n_mx_edi.document states (payslip_sent, payslip_sent_failed, payslip_cancel, payslip_cancel_failed) but never extends the two hooks the base l10n_mx_edi module relies on to keep sat_state in sync: - _get_update_sat_status_domains(), which builds the domain used by the SAT-status cron (and manual refresh) to pick documents to poll. Payslip states were missing from it, so their SAT status was never fetched at all. - _update_document_sat_state(), which routes a fetched SAT status to a per-source-document handler. It has no branch for the payslip states, so even a manual poll would silently do nothing. As a result, payslip CFDIs validated in the SAT always appeared as "not_defined" in Odoo. opw-6192651 Forward-Port-Of: odoo/enterprise#126294 Forward-Port-Of: odoo/enterprise#124006
8 changes
Resolved issues and error corrections
Planning managers without HR access can now change the assigned resource on a planning slot without accidentally publishing the shift. The change uses publicly available employee information for the check, avoiding permission-related side effects while keeping the workflow consistent.
Original PR description
For planning manager without HR access, if the user change the resource of the planning slot it will publish it automatically as the employee_ids field cannot be used without HR access. Prefer to use public employee to have better condition without using explicit sudo Caused-by: https://github.com/odoo/enterprise/commit/e88dcd0e545183b3f03e06b62158c52a1e6d2103 Forward-Port-Of: odoo/enterprise#127503
Adds a test to ensure India's GSTR-1 report selects the correct tax rate group when GST and CESS taxes are used together. This helps prevent reporting mistakes in mixed-tax scenarios and supports more accurate compliance checks.
Original PR description
This PR adds a test case to ensure that the correct tax rate group is selected in the GSTR-1 report when a combination of GST and CESS taxes is used. Community PR - https://github.com/odoo/odoo/pull/280571 Forward-Port-Of: odoo/enterprise#126770
The Helpdesk ticket quick create form now has better spacing between the customer field and action buttons. This small layout fix makes the form easier to read and use when creating tickets from the kanban view.
Original PR description
This commit add a space between the partner field and the buttons in ticket kanban quickreate. task-6443626
This fixes an error that could block deliveries when a product was changed into a kit after the transfer had already been confirmed. The Kenya OSCU stock integration now works with the actual component moves created during delivery, helping users complete the process without interruption.
Original PR description
When a stock move's product is turned into a kit after the transfer was confirmed, it explodes it into its component moves and unlinks the original one: https://github.com/odoo/odoo/blob/f59783d43f891fea14d03f67d7c017d7ffbbe5a7/addons/mrp/models/stock_move.py#L358-L363 https://github.com/odoo/odoo/blob/f59783d43f891fea14d03f67d7c017d7ffbbe5a7/addons/mrp/models/stock_move.py#L400 The `_action_done()` override of `l10n_ke_edi_oscu` localisation called `super()` first and then used `self.filtered(...)` on the pre-explosion recordset, which could still reference the now-deleted move, raising a `MissingError`: https://github.com/odoo/enterprise/blob/ee7e6894ed313db844aeff5ba5e19de3ad94898e/l10n_ke_edi_oscu_stock/models/stock_move.py#L96-L99 Use the `super()` return value instead, which reflects the moves that were actually processed. runbot-243291 Forward-Port-Of: odoo/enterprise#127027
Australian payroll now matches unused leave balances to the correct employee when processing multiple payslips at once. This prevents eligible unused leave from being missed, helping final pay and related payroll calculations stay accurate.
Original PR description
`_l10n_au_get_unused_leave_by_type` compared leave allocations to `self.employee_id` while looping payslips. On a multi-recordset that is the whole employee set, so the match never holds and unused leave is skipped. Use `payslip.employee_id` so each payslip keeps its own allocations. task-6458480 Forward-Port-Of: odoo/enterprise#127330
Spreadsheet side panel items now use the same drag-and-drop behavior and visual feedback across list dimensions, sorting rules, pivot dimensions, and global filters. This makes reordering items more predictable and prevents accidental drag actions when using controls like delete buttons or selectors.
Original PR description
Current behavior before PR: - Dragging list dimensions and sorting rules felt visually different from pivot dimensions and global filters in the side panel. - The list side panel used a separate drag-and-drop utility that did not match the consistent UX of other spreadsheet components. Desired behavior after PR is merged: - List dimensions and sorting rules now share the same drag-and-drop behavior and visual feedback as pivot dimensions and global filters. - All reorderable items in the side panel now look and feel the same, providing a consistent user experience across the spreadsheet. Task: [6219600](https://www.odoo.com/odoo/project/2328/tasks/6219600)
Mexican payroll CFDIs now have their SAT validation status updated correctly in Odoo. This prevents validated payslips from incorrectly appearing with an undefined status, improving compliance visibility for payroll teams.
Original PR description
l10n_mx_hr_payroll_account_edi introduces new l10n_mx_edi.document states (payslip_sent, payslip_sent_failed, payslip_cancel, payslip_cancel_failed) but never extends the two hooks the base l10n_mx_edi module relies on to keep sat_state in sync: - _get_update_sat_status_domains(), which builds the domain used by the SAT-status cron (and manual refresh) to pick documents to poll. Payslip states were missing from it, so their SAT status was never fetched at all. - _update_document_sat_state(), which routes a fetched SAT status to a per-source-document handler. It has no branch for the payslip states, so even a manual poll would silently do nothing. As a result, payslip CFDIs validated in the SAT always appeared as "not_defined" in Odoo. opw-6192651 Forward-Port-Of: odoo/enterprise#126294 Forward-Port-Of: odoo/enterprise#124006
This fixes an issue where signatures or other fields could disappear from downloaded signed PDFs when the original document had unusual page positioning. Signed documents should now match the preview more reliably, reducing failed signing workflows and customer confusion.
Original PR description
Steps to reproduce (version 16+): 1) Obtain a pdf with a negative origin point: This can occur when a customer exports a pdf from another software, or it can be made manually using a python script 2) In the sign app, upload the pdf and create a new template, add a signature field to the document. 3) Sign the document. The preview will load correctly and the signature will be visible 4) Download and open the signed pdf. The signature is not on the document Notes: Issue occurs because the signature was added to the pdf outside of the visible area. The preview works because the signature is rendered on top of the unsigned document in the correct location. The issue can be fixed applying a translation to the canvas. Ticket: [6317223](https://www.odoo.com/odoo/project/49/tasks/6317223?debug=assets) Forward-Port-Of: odoo/enterprise#126921 Forward-Port-Of: odoo/enterprise#121960
12 changes
Enhancements to existing features
Budget reports now load much faster by changing how budget lines are matched to accounting and purchase data. This reduces long waits and makes the report usable on databases with large volumes of budget and analytical records.
Original PR description
**Description:** While loading the budget report, the bad queries are created by ```def _get_aal_query()``` and ```def _get_pol_query()``` function, makes the budget report unusable. **Root cause:**…
**Description:**
While loading the budget report, the bad queries are created by
```def _get_aal_query()``` and ```def _get_pol_query()``` function, makes
the budget report unusable.
**Root cause:**
Instead of doing a hash join while searching the record,
the OR statement in the Left Join in the condition
```(%(bl)s IS NULL OR %(a)s = %(bl)s)```
creates a nested for loop that compares everything single aal to bl,
this causes a significant performance issue as the number of the
number of check will be the the number aal * bl,
if a database has a 70k aal and 20k bl, both numbers are not large
but it will cause a 70k * 20k search which is more than a billion.
**Fix**:
There are some refactors made in this PR.
_First_, separate out the Q1.
In order to find the aal that has no bl connects to it.
Doing a search to find the aals that have bl and then subtract them from all aals.
_Second_, Instead of doing a nested loop for by using
```(%(bl)s IS NULL OR %(a)s = %(bl)s)```,
originally we will have do something like
```
JOIN budget_line bl
ON (bl.x_plan2_id IS NULL OR aal.x_plan2_id = bl.x_plan2_id)
AND (bl.x_plan3_id IS NULL OR aal.x_plan3_id = bl.x_plan3_id)
AND (bl.x_plan4_id IS NULL OR aal.x_plan4_id = bl.x_plan4_id)
```
Assuming each bl has three plans ```x_plan2_id```, ```x_plan3_id```, ```x_plan4_id```
Grouping the bl base on whether a specific plan is set, (i.e. shapes)
we can skip the ```IS NULL OR``` because we already know which plan
is null and do the hash join directly.
For example, the shapes will be a dictionary with a key of a tuple of booleans
based on whether a plan is set or not and the value is a list of bl_id.
```
{
(True, False, False): [1, 2],
(False, True, True): [3, 4],
(False, False, False): [5],
}
```
we can end up doing something like
```
JOIN budget_line bl
ON bl.id = ANY(ARRAY[3,4])
AND aal.x_plan3_id = bl.x_plan3_id AND aal.x_plan4_id = bl.x_plan4_id
```
which is way more faster.
---
The benchmark is made locally from this client's database which contains
69k aal, 23k bl, 6829 pol and 3 plans for aal and bl.
|Record count |Time before|Time after|
|--------------------------------------------------|-----------------|---------------|
|69k aal, 23k bl, 6829 pol, 3 plans |70.04s |4.6s |
Dalibo:
Before:
Month-over-month grand total by company:
https://explain.dalibo.com/plan/8h3d4e89aaf9f3d4
Overall grand total by company:
https://explain.dalibo.com/plan/445g1f9caf4923e2
Month-over-month grand total by plan:
https://explain.dalibo.com/plan/53a138ca50b2a7c4
Overall grand total by plan:
https://explain.dalibo.com/plan/hdbe169ddc7g5785
After:
Month-over-month grand total by company:
https://explain.dalibo.com/plan/hcc86c801e6872bf
Overall grand total by company:
https://explain.dalibo.com/plan/69b2421a3581f98h
Month-over-month grand total by plan:
https://explain.dalibo.com/plan/a88f398bbbch3148
Overall grand total by plan:
https://explain.dalibo.com/plan/1gg749ae7ab1553c
opw-6345552
Forward-Port-Of: odoo/enterprise#127405
Forward-Port-Of: odoo/enterprise#124161Resolved issues and error corrections
This update adds a safeguard to verify that Indian GSTR-1 reports choose the correct tax rate group when GST and CESS taxes are used together. It helps reduce the risk of incorrect tax reporting in scenarios involving combined Indian indirect taxes.
Original PR description
This PR adds a test case to ensure that the correct tax rate group is selected in the GSTR-1 report when a combination of GST and CESS taxes is used. Community PR - https://github.com/odoo/odoo/pull/280571
Fixed an error that could occur when users turned the No Follow-Up option on or off for invoices with multiple payment installments. This keeps the Follow-Up Report usable when some installments are already paid and others remain open.
Original PR description
Steps to Reproduce: 1. Configure Payment Term (Accounting > Configuration > Payment Terms) containing multiple installments. 2. Create a Customer Invoice with this Payment Term. 3. Post the invoice.…
Steps to Reproduce:
1. Configure Payment Term (Accounting > Configuration > Payment Terms) containing multiple installments.
2. Create a Customer Invoice with this Payment Term.
3. Post the invoice.
4. Register a payment and fully reconcile one of the installments.
5. Navigate to the customer's Follow-Up Report (Accounting > Reporting > Partner Ledger > Report: Follow-Up Report).
6. Navigate to remaining open installment/account move line for that invoice.
7. Turn On or Off the No Follow-Up toggle for the invoice.
An error occurs when enabling or disabling the No Follow-Up toggle.
Issue:
Enabling or disabling the No Follow-Up toggle on a remaining open installment in the Follow-Up Report raises a server error when the invoice contains multiple installments and one or more installments are already fully reconciled.
Root Cause:
The Follow-Up Report only loads and sends non-fully reconciled account move lines from the JavaScript side through all_line_ids. In action_toggle_no_followup(), when the selected line belongs to an invoice, the code retrieves all receivable/payable lines of the invoice, including fully reconciled installments:
```
move.line_ids.filtered(
lambda line: line.account_type in ('asset_receivable', 'liability_payable'),
)
```
The method then attempts to map every receivable/payable line to a report line ID using aml_id_to_line_id. Since fully reconciled installments are not present in all_line_ids, they are missing from the mapping dictionary, causing a KeyError when accessing:
`aml_id_to_line_id[line.id]
`
Fix:
Restricted the impacted lines to those present in the report by adding a check that the account move line exists in aml_id_to_line_id before performing the mapping:
```
lambda line: line.account_type in ('asset_receivable', 'liability_payable')
and line.id in aml_id_to_line_id
```
opw-6245448
Forward-Port-Of: odoo/enterprise#126785
Forward-Port-Of: odoo/enterprise#126156Users can now open Bank Matching from a working file return even when no bank journal is selected. This prevents an error screen and lets staff continue reconciling bank statement lines from that workflow.
Original PR description
When accessing the reconciliation widget from the working file check, there is no journal to be selected, hence no journal in the context. This was tracebacking since we were trying to send a read query to the server with an undefined id. To reproduce: * create a bank statement line without reconciling * set up the return on the misc journal * open the return, then "Bank Matching" Forward-Port-Of: odoo/enterprise#127421
This update corrects a small issue in the Swiss payroll transmission process where the current date could be calculated without the proper context. It helps avoid errors during payroll-related submissions and keeps Swiss payroll workflows running reliably.
Original PR description
Fix https://github.com/odoo/enterprise/pull/126718 Forward-Port-Of: odoo/enterprise#127535
This fix ensures Mexican payroll CFDI payslips are included when Odoo checks their official SAT status. Businesses will now see the correct validation or cancellation status instead of an undefined status, improving payroll compliance visibility.
Original PR description
l10n_mx_hr_payroll_account_edi introduces new l10n_mx_edi.document states (payslip_sent, payslip_sent_failed, payslip_cancel, payslip_cancel_failed) but never extends the two hooks the base l10n_mx_edi module relies on to keep sat_state in sync: - _get_update_sat_status_domains(), which builds the domain used by the SAT-status cron (and manual refresh) to pick documents to poll. Payslip states were missing from it, so their SAT status was never fetched at all. - _update_document_sat_state(), which routes a fetched SAT status to a per-source-document handler. It has no branch for the payslip states, so even a manual poll would silently do nothing. As a result, payslip CFDIs validated in the SAT always appeared as "not_defined" in Odoo. opw-6192651 Forward-Port-Of: odoo/enterprise#126104 Forward-Port-Of: odoo/enterprise#124006
Tax closing entries now correctly include VAT credit carried over from the previous period. This prevents overstated tax payable amounts and ensures tax return journal entries match the expected carryover without extra user configuration.
Original PR description
### Issue before this commit: When generating a tax closing entry, the VAT credit carryover from the previous period is missing from the journal entry lines. This results in an incorrect net payable…
### Issue before this commit: When generating a tax closing entry, the VAT credit carryover from the previous period is missing from the journal entry lines. This results in an incorrect net payable amount. ### Steps to reproduce the issue: 1. Download Accounting 2. Go to Vendor > Bills 3. Create a vendor bill with date in June and price > 0 (ex. 1000$) and the 15% tax that produce a 150$ VAT tax 4. Go to Customers > Invoices 5. Create an invoice with price > 0 (ex. 9000$), the date in July and the 15% tax that will produce a 1350$ VAT tax 6. Go to Tax Return and validate all opened months up to July and see that for June the balance is -150$ 9. Then go to View Entries of July using the 3 dots next to the "submit" button and see that there is no mentioning of the 150$ carry over of credit from the month before ### Cause of the issue: During a forward-port merge conflict resolution, the code block responsible for retrieving the historical balance from the receivable_account_id was wrongly removed ([diff](https://github.com/odoo/enterprise/compare/b760c1dbee6bfb628bae32041c5b5c7dcaa623a4..4ea95b0c15f5f791d088330596c64ece58effa44)). Consequently, the system only checked the advance_account_id for previous balances, completely ignoring existing credits parked in the standard receivable account. ### Reason to introduce the fix: Restore the dropped logic and the _create_tax_receivable_current_line function. This ensures the tax closing process automatically factors in previous VAT credits from the receivable account, providing accurate closing entries out-of-the-box without requiring extra configuration from the user. opw-6438648
Australian payroll now correctly matches unused leave allocations to each employee when processing multiple payslips at once. This prevents unused leave from being skipped, helping ensure final pay calculations are accurate.
Original PR description
`_l10n_au_get_unused_leave_by_type` compared leave allocations to `self.employee_id` while looping payslips. On a multi-recordset that is the whole employee set, so the match never holds and unused leave is skipped. Use `payslip.employee_id` so each payslip keeps its own allocations. task-6458480 Forward-Port-Of: odoo/enterprise#127330
Fixed an issue where rental returns could fail after using stock transfers for serialized rental products. The system now keeps the pickup and return serial number history correctly, so users can complete later returns without manual errors or blocked workflows.
Original PR description
**Issue** When rental transfers are enabled and rental pickups/returns are processed through stock pickings, it may become impossible to perform a subsequent rental return through the rental return…
**Issue** When rental transfers are enabled and rental pickups/returns are processed through stock pickings, it may become impossible to perform a subsequent rental return through the rental return wizard. **Steps to reproduce** - Activate "Rental Transfers" in the settings - Create a rental product P, tracked by serial number - Create two serial numbers for P - Create and confirm a rental order for 2 units of P - Validate the pickup transfer - Partially validate the return transfer without creating a backorder - Open the rental order and click on "Return" -> The return wizard opens without any available serial number and validation fails with a serial number-related error. **Cause** When clicking on "Return", if there is no pending pickup/return transfer: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/models/sale_order.py#L62-L68 the rental return wizard is opened directly: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/models/sale_order.py#L316 No serial number is prefilled in the wizard because `returned_lot_ids` is empty: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L122-L124 This is because `returnable_lot_ids` is empty as well. `returnable_lot_ids` is computed while generating the wizard lines: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/wizard/rental_processing.py#L38 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/wizard/rental_processing.py#L47-L48 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L99-L106 and `returnable_lots` is empty because both `pickedup_lots` and `returned_lots` are. Those fields are currently only populated through the rental wizard flow: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L42-L43 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L160-L161 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L166-L167 Since this flow uses stock pickings instead of the rental wizard, those fields are never updated, preventing the wizard from determining any returnable serial number. opw-6150305 Forward-Port-Of: odoo/enterprise#126594 Forward-Port-Of: odoo/enterprise#119257
Refunding a POS order linked to Ecuador's generic "Consumidor Final" customer now shows the intended business error message instead of crashing. This helps cashiers understand why the refund cannot be validated and avoids an unexpected interruption at checkout.
Original PR description
When attempting to refund orders that were created with the "Consumidor Final" customer. The refund validation would crash with a TypeError instead of showing the proper error message. Steps to…
When attempting to refund orders that were created with the "Consumidor Final" customer. The refund validation would crash with a TypeError instead of showing the proper error message. Steps to reproduce: ------------------- In POS with l10n_ec_edi module activated: * Create a new order with "Consumidor Final" as customer * Add products and pay the order * Validate the order * Attempt to refund this order > Observation: The refund validation would crash with: TypeError: Cannot read properties of undefined (reading 'add') at OrderPaymentValidation.isOrderValid Why the fix: ------------ The code was trying to access `this.dialog` which is undefined in the OrderPaymentValidation class context. The dialog service should be accessed via `this.pos.dialog`, which is the correct pattern used throughout the base OrderPaymentValidation class. This fix ensures the error dialog is properly displayed when attempting to refund orders for the anonymous final consumer, instead of crashing with a TypeError. opw-6427113 Forward-Port-Of: odoo/enterprise#126308
This fix prevents an error when a product on a confirmed delivery is later changed into a kit. Kenyan OSCU stock reporting now uses the actual component moves processed, so deliveries can be completed without interruption.
Original PR description
When a stock move's product is turned into a kit after the transfer was confirmed, it explodes it into its component moves and unlinks the original one: https://github.com/odoo/odoo/blob/f59783d43f891fea14d03f67d7c017d7ffbbe5a7/addons/mrp/models/stock_move.py#L358-L363 https://github.com/odoo/odoo/blob/f59783d43f891fea14d03f67d7c017d7ffbbe5a7/addons/mrp/models/stock_move.py#L400 The `_action_done()` override of `l10n_ke_edi_oscu` localisation called `super()` first and then used `self.filtered(...)` on the pre-explosion recordset, which could still reference the now-deleted move, raising a `MissingError`: https://github.com/odoo/enterprise/blob/ee7e6894ed313db844aeff5ba5e19de3ad94898e/l10n_ke_edi_oscu_stock/models/stock_move.py#L96-L99 Use the `super()` return value instead, which reflects the moves that were actually processed. runbot-243291 Forward-Port-Of: odoo/enterprise#127027
This fixes an issue where Swiss payroll settings could assign a Swiss contract type to employees outside Switzerland. The change prevents incorrect contract information from appearing and keeps automated checks stable across versions.
Original PR description
[FIX] l10n_ch: fix default contract type This task is runbot error fix that occured from 19.0 to 19.2 Bug reproduction: 1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute…
[FIX] l10n_ch: fix default contract type
This task is runbot error fix that occured from 19.0 to 19.2
Bug reproduction:
1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute test_version_timeline_auto_save_tour tour test 3 - It fails in .o_arrow_button_wrapper[data-tooltip^='Contract:'] step
Bug cause:
1 - When l10n_ch_hr_payroll_account is installed:
1.1 - contract type becomes "Permanent contract with monthly salary"
1.2 - the employee is not swiss but it has this CH contract type
2 - data-tooltip starts with Permanent contract instead of contract
2.1 - Tour fails
3 - contract_type_id is overwritten in swiss modules
3.1 - Default is assigned without looking to the country of self.env
Bug solution:
1 - If the country is not swiss, the default is assigned as False
1.1 -> fixed in l10n_ch_hr_payroll/hr_version
1.2 instead of assigning swiss contract type to the non-swiss emp.
Note: This is fix from saas-18.4 to master.
task-6392040
runbot error: https://runbot.odoo.com/odoo/runbot.build.error/941358
Forward-Port-Of: odoo/enterprise#1265208 changes
Resolved issues and error corrections
This fix prevents an error during delivery processing when a product is changed into a kit after a transfer has already been confirmed. It ensures the Kenya OSCU stock integration uses the correct updated delivery records, helping deliveries complete reliably without unexpected interruptions.
Original PR description
When a stock move's product is turned into a kit after the transfer was confirmed, it explodes it into its component moves and unlinks the original one: https://github.com/odoo/odoo/blob/f59783d43f891fea14d03f67d7c017d7ffbbe5a7/addons/mrp/models/stock_move.py#L358-L363 https://github.com/odoo/odoo/blob/f59783d43f891fea14d03f67d7c017d7ffbbe5a7/addons/mrp/models/stock_move.py#L400 The `_action_done()` override of `l10n_ke_edi_oscu` localisation called `super()` first and then used `self.filtered(...)` on the pre-explosion recordset, which could still reference the now-deleted move, raising a `MissingError`: https://github.com/odoo/enterprise/blob/ee7e6894ed313db844aeff5ba5e19de3ad94898e/l10n_ke_edi_oscu_stock/models/stock_move.py#L96-L99 Use the `super()` return value instead, which reflects the moves that were actually processed. runbot-243291 Forward-Port-Of: odoo/enterprise#127027
Refunding Ecuador POS orders made with the “Consumidor Final” customer now shows the intended warning instead of crashing. This helps cashiers understand why the refund cannot be validated and avoids an unexpected interruption at checkout.
Original PR description
When attempting to refund orders that were created with the "Consumidor Final" customer. The refund validation would crash with a TypeError instead of showing the proper error message. Steps to…
When attempting to refund orders that were created with the "Consumidor Final" customer. The refund validation would crash with a TypeError instead of showing the proper error message. Steps to reproduce: ------------------- In POS with l10n_ec_edi module activated: * Create a new order with "Consumidor Final" as customer * Add products and pay the order * Validate the order * Attempt to refund this order > Observation: The refund validation would crash with: TypeError: Cannot read properties of undefined (reading 'add') at OrderPaymentValidation.isOrderValid Why the fix: ------------ The code was trying to access `this.dialog` which is undefined in the OrderPaymentValidation class context. The dialog service should be accessed via `this.pos.dialog`, which is the correct pattern used throughout the base OrderPaymentValidation class. This fix ensures the error dialog is properly displayed when attempting to refund orders for the anonymous final consumer, instead of crashing with a TypeError. opw-6427113 Forward-Port-Of: odoo/enterprise#126308
This fix corrects how leave intervals are adjusted in the Gantt view for employees using duration-based work schedules. It helps ensure planned absences display with the right timing, reducing confusion for HR teams and managers.
Original PR description
task-id: 6460078 Forward-Port-Of: odoo/enterprise#127487
Swiss payroll no longer assigns a Swiss-specific contract type to employees when the company context is not Switzerland. This prevents automated workflow failures and helps keep employee contract information aligned with the correct country settings.
Original PR description
[FIX] l10n_ch: fix default contract type This task is runbot error fix that occured from 19.0 to 19.2 Bug reproduction: 1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute…
[FIX] l10n_ch: fix default contract type
This task is runbot error fix that occured from 19.0 to 19.2
Bug reproduction:
1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute test_version_timeline_auto_save_tour tour test 3 - It fails in .o_arrow_button_wrapper[data-tooltip^='Contract:'] step
Bug cause:
1 - When l10n_ch_hr_payroll_account is installed:
1.1 - contract type becomes "Permanent contract with monthly salary"
1.2 - the employee is not swiss but it has this CH contract type
2 - data-tooltip starts with Permanent contract instead of contract
2.1 - Tour fails
3 - contract_type_id is overwritten in swiss modules
3.1 - Default is assigned without looking to the country of self.env
Bug solution:
1 - If the country is not swiss, the default is assigned as False
1.1 -> fixed in l10n_ch_hr_payroll/hr_version
1.2 instead of assigning swiss contract type to the non-swiss emp.
Note: This is fix from saas-18.4 to master.
task-6392040
runbot error: https://runbot.odoo.com/odoo/runbot.build.error/941358
Forward-Port-Of: odoo/enterprise#126520This fix corrects an internal module dependency for the Belgian point of sale black box setup with HR features. It helps ensure the right related module is installed and avoids configuration or automated test failures caused by the previous dependency mismatch.
Original PR description
Before this commit, the dependency of the module l10n_be_pos_blackbox_hr_pos_blackbox_be was set to pos_hr, which is not totally correct. The correct dependency should be l10n_be_pos_blackbox_hr. runbot-error: 941561 Forward-Port-Of: odoo/enterprise#124814
This fixes an issue where unused leave could be missed when processing payslips for multiple employees at once. Each payslip now uses the correct employee’s leave allocations, helping ensure Australian payroll amounts are calculated accurately.
Original PR description
`_l10n_au_get_unused_leave_by_type` compared leave allocations to `self.employee_id` while looping payslips. On a multi-recordset that is the whole employee set, so the match never holds and unused leave is skipped. Use `payslip.employee_id` so each payslip keeps its own allocations. task-6458480 Forward-Port-Of: odoo/enterprise#127330
Fixes an issue where using AI to update website SEO could fail when the AI agent relied on certain document-generated files, such as invoice PDFs. The AI feature can now correctly use those document sources, reducing interruptions for users optimizing website content.
Original PR description
### Problem When an AI agent includes a document source whose underlying `ir.attachment` has `res_field` set (e.g., an invoice PDF generated from a Sale Order), triggering **Update With AI** from…
### Problem
When an AI agent includes a document source whose underlying `ir.attachment`
has `res_field` set (e.g., an invoice PDF generated from a Sale Order),
triggering **Update With AI** from **Website → Site → Optimize SEO**
raises a `KeyError` in `_build_rag_context`.
### Steps to Reproduce
1. Open the **AI** app.
2. Configure the **Odoo Agent**.
3. Add a source → **Add From Documents**.
4. Select a document whose underlying `ir.attachment` has `res_field` set
(e.g., an invoice PDF generated from a Sale Order).
5. Go to **Website → Site → Optimize SEO**.
6. Click **Update With AI**.
7. Observe the following error:
```
KeyError: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
```
[Video](https://drive.google.com/file/d/1AAg0AvC3TRQzMLhI9hWFuSarOTHzQE-b/view?usp=sharing)
### Root Cause
In `ai/models/ai_agent.py`, `_build_rag_context()` retrieves the
`ai.agent.source` records corresponding to the embeddings by searching on the
attachment checksum:
```python
agent_sources = self.env["ai.agent.source"].search([
("attachment_id.checksum", "in", embeddings_attachment_checksums),
("agent_id", "=", self.id),
])
```
This domain traverses `attachment_id.checksum`, which internally calls
`ir.attachment._search()`.
As part of the standard attachment search behavior,
`ir.attachment._search()` automatically injects a
`('res_field', '=', False)` filter unless:
- `skip_res_field_check=True` is set in the context,
- the domain explicitly references `id` or `res_field`, or
- `bypass_access` is enabled.
```python
domain = Domain(domain)
if (
not self.env.context.get("skip_res_field_check")
and not any(d.field_expr in ("id", "res_field") for d in domain.iter_conditions())
and not bypass_access
):
disable_binary_fields_attachments = True
domain &= Domain("res_field", "=", False)
```
[Reference](https://github.com/odoo/odoo/blob/19.0/odoo/addons/base/models/ir_attachment.py#L630)
Because of this implicit filter, attachments with `res_field` set are excluded
from the search. Consequently, `agent_sources` does not contain all the sources
corresponding to the retrieved embeddings.
Later, `_build_rag_context()` builds a checksum-to-source mapping:
```python
source_map = {
source.attachment_id.checksum: source
for source in agent_sources
}
for embedding in similar_embeddings:
checksum = embedding.attachment_id.checksum
agent_source = source_map[checksum]
```
Since `source_map` is built from the incomplete `agent_sources` recordset, it is
missing entries for attachments filtered by `ir.attachment._search()`.
However, `similar_embeddings` still contains embeddings for those attachments.
As a result, the lookup:
```python
agent_source = source_map[checksum]
```
raises a `KeyError`.
### Solution
Bypass the implicit `res_field` filter when searching `ai.agent.source`:
```python
agent_sources = (
self.env["ai.agent.source"]
.with_context(skip_res_field_check=True)
.search([
("attachment_id.checksum", "in", embeddings_attachment_checksums),
("agent_id", "=", self.id),
])
)
```
This ensures that all `ai.agent.source` records matching the requested
attachment checksums are returned, including those referencing attachments with
`res_field` set. As a result, `source_map` contains all expected entries and
`_build_rag_context()` no longer raises a `KeyError`.
opw-6379816French VAT reimbursement declaration 3519 now includes the bank account holder name in the account details section. This helps meet declaration requirements and reduces the risk of rejected or incomplete reimbursement submissions.
Original PR description
For reimbursement declarations, the name of the holder of the account is required This commits adds holder's name to the account data zone no-task-id Forward-Port-Of: odoo/enterprise#127631 Forward-Port-Of: odoo/enterprise#127554
2 changes
Resolved issues and error corrections
French VAT reimbursement declaration 3519 now includes the name of the bank account holder in the account information section. This helps ensure the declaration contains the required banking details and reduces the risk of rejected or incomplete reimbursement submissions.
Original PR description
For reimbursement declarations, the name of the holder of the account is required This commits adds holder's name to the account data zone no-task-id Forward-Port-Of: odoo/enterprise#127554
This fix prevents cancelled point-of-sale refunds from being counted when creating Mexican global invoices. Businesses can now generate the invoice correctly when an order has both a cancelled refund attempt and a completed refund, avoiding erroneous negative amounts.
Original PR description
Steps to reproduce: ------------------- 1. Install `l10n_mx_edi_pos` and set the company to Mexico. 2. In PoS, make an order with one product and pay it. 3. Open the order in the backend, click…
Steps to reproduce: ------------------- 1. Install `l10n_mx_edi_pos` and set the company to Mexico. 2. In PoS, make an order with one product and pay it. 3. Open the order in the backend, click "Return Products" to make a refund, but don't pay it, cancel it instead. 4. From the same order, click "Return Products" again to make a second refund, and pay it normally. 5. Go to the orders list, select the main order and the paid refund (not the cancelled one), then Actions > Create Global Invoice. -> Observation: error in the global invoice. In the CFDI tab of the main order the line is "Send Global In Error", and hovering on it the detail says "Failed to distribute some negative lines". Why: ---- When we make the global invoice, we remove the refunds from the order. A cancelled refund was never paid, so we should not count it. But we were counting it too. So we removed the refund amount twice in our case, one for the paid refund, and one for the cancelled one, and we end up with an order with negative amount that cannot be distributed. The fix: -------- We now skip the cancelled orders when we search the refunds, the same way it is done above when we collect the refunded orders. opw-6261404 Forward-Port-Of: odoo/enterprise#127454 Forward-Port-Of: odoo/enterprise#120996
5 changes
New functionality added to Odoo
A new FedEx certified delivery module adds the API changes required to meet FedEx certification guidelines. This helps businesses continue using FedEx shipping services with an approved integration and updated branding/configuration support.
Original PR description
For the certification process of FedEx there were some changes needed in the delivery_fedex_rest module. This modules made those changes according to the FedEx guidelines. Task-id: 6164275 Forward-Port-Of: odoo/enterprise#122663
Resolved issues and error corrections
The Dutch tax reporting status process now skips or handles records that are missing their linked closing entry instead of crashing. This helps keep Digipoort tax return status updates running even when one record has incomplete data.
Original PR description
The `l10n_nl_reports_sbr_status_info` contains the `l10n_nl_reports_sbr.status.service` class. The class is responsible for fetching the status of sent Digipoort tax returns. The status is then posted as a chatter message to the tax return's closing entry. Issues can arise when one of the status service records is, for whatever reason, missing a closing entry. In such case, the message cannot be posted, resulting in an exception being raised. Since the records are processed in a loop without a try-catch, this causes the whole action to fail. This can lead to one broken record effectively shutting down the whole module's functionality. This PR adds some if-else checks to gracefully handle the case where the closing entry is missing. Related tickets: opw-5901446 and opw-6410082 Forward-Port-Of: odoo/enterprise#127389 Forward-Port-Of: odoo/enterprise#125996
French VAT reimbursement declarations now include the bank account holder's name in the required account information. This helps ensure declaration 3519 contains the information needed for successful processing by authorities.
Original PR description
For reimbursement declarations, the name of the holder of the account is required This commits adds holder's name to the account data zone no-task-id Forward-Port-Of: odoo/enterprise#127554
Users can now interact with Search More dialogs from document fields without the dialog unexpectedly closing. This prevents interruptions when choosing related records such as owners or customers in the Documents app.
Original PR description
Steps to reproduce: 1. Install Documents 2. In the Documents list view, select a document to display the inspector. 3. Edit a field such as Owner or Customer which uses a Many2one widget. 4. In the…
Steps to reproduce: 1. Install Documents 2. In the Documents list view, select a document to display the inspector. 3. Edit a field such as Owner or Customer which uses a Many2one widget. 4. In the field dropdown, click "Search More..." to open a modal dialog. 5. Click inside the "Search More..." modal (e.g., to sort columns or resize headers). Issue: - The modal dialog immediately closes, and the contact cannot be selected. Root cause: - When an inspector field is edited, the record row is put into edit mode. While in edit mode, the documents list renderer listens for global clicks. Clicking inside the "Search More..." modal dialog targets elements that have `.o_list_renderer` (since the modal dialog renders a list view). Because the click target is within a list renderer but is not a document row, `DocumentsListRenderer.onGlobalClick` executes and clears the selection of the main list view. Clearing the selection unmounts the edited field in the inspector, thereby destroying the modal dialog stack. Solution: - Modify DocumentsListRenderer.onGlobalClick to scope click handling to the current Documents list renderer. Ignore clicks outside this.root.el, so interactions in nested UI such as Search More... do not clear the main selection and destroy the inspector field. opw-6253360 Forward-Port-Of: odoo/enterprise#126614 Forward-Port-Of: odoo/enterprise#119262
Submitting Australian Single Touch Payroll records without payslips or employees now shows a clear validation message instead of causing an unexpected error. This helps payroll users understand what information is required before sending data to the ATO.
Original PR description
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module -…
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module - Switch to ``My australian Company`` - Go to Payroll > Configuration > Settings > In Australian Localization, Set BMS ID > Set STP Responsible and his date of birth - Go to Payroll > Reporting > Single Touch Payroll > Create a new record > Set Payment Date > Submit to ATO > Sign & Submit to ATO Traceback: ```py IndexError: tuple index out of range ``` https://github.com/odoo/enterprise/blob/b0e48baaf99bdc4faefd2ffdd3bd5637fb548593/l10n_au_hr_payroll_account/models/l10n_au_stp.py#L228-L233 The traceback occurs because ``_get_fiscal_year_start()`` assumes that the STP record always contains at least one payslip or one employee. When these recordsets are empty, indexing the first element raises an IndexError. Solution: This commit validates that the required payslips or employees are present before the submission and raises a validation error instead of a traceback. Forward-Port-Of: odoo/enterprise#124096
37 changes
New functionality added to Odoo
Adds Schedule III Balance Sheet and Profit and Loss reports for Indian localization. This helps Indian businesses prepare statutory financial statements in the required format more directly within Odoo.
Original PR description
WIP task-2381149
A new DHL shipping connector is being added using DHL’s recommended MyDHL REST API, replacing the older XML-based approach that DHL is retiring. This helps keep DHL shipping services compatible with current provider standards and reduces future disruption risk for businesses using DHL delivery.
Original PR description
This new module should replace the existing implementation for DHL integration which uses XML and is no longer recommended by DHL: https://developer.dhl.com/dhl-express-xml-developer-portal-sunset. The new integration uses ["MyDHL API"](https://developer.dhl.com/api-reference/dhl-express-mydhl-ap) which is based on REST. Upgrade PR: odoo/upgrade#6090 Task-3759205
This adds a new USPS shipping integration that uses USPS's current REST API instead of the older XML-based approach. Businesses using USPS delivery can benefit from alignment with USPS's recommended technology, improving long-term compatibility and supportability.
Original PR description
This new module should replace the existing implementation for USPS integration which uses XML which is not the recommended API currently by USPS. The new integration uses USPS's latest RESTful APIs: https://developer.usps.com/apis. Task-3759325
Enhancements to existing features
The Peru localization tests were updated to match revised default accounts introduced for smoother onboarding. This helps keep automated checks aligned with the current setup and reduces false failures during validation.
Original PR description
Purpose: Default accounts were updated for an improved onboarding process, which caused some tests to be outdated. Update the tests to align with the account changes. task-6221374
Indian GSTR-1 report exports now handle large accounting datasets much faster and with far less memory. This reduces the risk of export failures for high-volume businesses and makes compliance reporting more reliable.
Original PR description
Current Implementation: ======================= The current implementation of _get_l10n_in_gstr1_json relies on multiple iterations over ORM recordsets. Since the ORM loads multiple fields rather…
Current Implementation: ======================= The current implementation of _get_l10n_in_gstr1_json relies on multiple iterations over ORM recordsets. Since the ORM loads multiple fields rather than only the required fields, memory consumption grows significantly for large datasets (around 700 MB for 150K account move lines). Additionally, the method builds a single large dictionary from _get_tax_details that is tailored for the Indian GST reporting logic. Constructing and holding this intermediate data structure further increases memory usage. The combination of repeated Python loops, ORM overhead, and the large intermediate dictionary results in high execution time and memory consumption, causing the process to exceed the available time and memory limits for large exports. Solution: ========= Instead of processing tax details through the ORM, create a temporary table containing the GST tax details and query this subset directly for each GSTR-1 subsection. This approach bypasses the ORM, fetching only the required columns instead of entire records. Eliminates the need to build the large _get_tax_details dictionary. Reduces the number of Python-side iterations and intermediate data structures. Pushes the data aggregation and filtering to SQL, where it is more efficient. Restricts Python's responsibility to formatting the final JSON output. This significantly reduces memory usage, improves execution speed, and makes the implementation simpler and easier to maintain. Benchmark Performance Results: ============================== ```text +-----------+-------------+----------------------+------------------+ | Size | Parameter | Current Version | IMPROVED SQL + | | | | | Indian Reports | +-----------+-------------+----------------------+------------------+ | 150K AMLs | Time | 28.19s | 2.18s | | +-------------+----------------------+------------------+ | | Peak Memory | 711 MB | 34.7 MB | +-----------+-------------+----------------------+------------------+ | 250K AMLs | Time | 64s | 3.68s | | +-------------+----------------------+------------------+ | | Peak Memory | 1.4 GB | 58.5 MB | +-----------+-------------+----------------------+------------------+ | 500K AMLs | Time | 208s | 7.33s | | +-------------+----------------------+------------------+ | | Peak Memory | 2.7 GB | 114.8 MB | +-----------+-------------+----------------------+------------------+ | 1M AMLs | Time | Memory Limit (7 GB+) | 15.07s | | +-------------+----------------------+------------------+ | | Peak Memory | Memory Limit (7 GB+) | 230.7 MB | +-----------+-------------+----------------------+------------------+ | 2M AMLs | Time | Memory Limit (7 GB+) | 28.20s | | +-------------+----------------------+------------------+ | | Peak Memory | Memory Limit (7 GB+) | 461.4 MB | +-----------+-------------+----------------------+------------------+ ``` ref - https://drive.google.com/drive/folders/10I8gJmGgZVAMW8te_GFg5lleTUW1Nku1?usp=drive_link -------------------------- task-3941950 Community PR - https://github.com/odoo/odoo/pull/274381
The Master Production Schedule forecast wizard is now easier to use when updating forecasts for one or many products. Users can start with the current period prefilled, see all forecasting basis options, and apply the same update settings across multiple selected products at once.
Original PR description
This commit improves the Master Production Schedule forecast suggestion wizard with the following enhancements: - Prefill current period when opening wizard from product - Show all "Based On" options even when a specific period is selected (Previously hidden when period was set) - Replace "Toggle Indirect Demand" with "Update Forecast" in Actions menu - Add multi-product "Update Forecast" wizard for bulk forecast updates - Shows product count instead of product selector - Preview calculation based on first product - Applies settings to all selected products simultaneously
Starting a work order from the list view now records time under the employees assigned to that work order instead of always using the currently logged-in user. If no employee is assigned, the system still falls back to the logged-in user, helping keep production time records accurate without disrupting existing workflows.
Original PR description
This commit changes the behavior of starting a work order from the `mrp_workorder` tree view in terms of the employee(s) who perform(s) the time logs of the workorder. Previosuly, the logged in user was always used to perform these time logs, irrespective of the assigned employees of the workorder. This commit uses the assigned employees instead and fallbacks to the logged-in user in case there was no assigned employee. Task-4105643
Saudi payroll now allows companies to set a threshold for unpaid leave days that should be excluded from end-of-service benefit calculations. This improves compliance and accuracy by ensuring extended unpaid absences are handled consistently in employee benefit reports.
Original PR description
[IMP] l10n_sa_hr_payroll: exclude unpaid days from EOS New field is added to company and company settings l10n_sa_unpaid_leave_eos_threshold, unpaid holidays above this threshold should be excluded from EOS calculation Instead of using function _l10n_sa_get_eosb_compensation in salary rule python amount compute, we put the function directly to the salary rule's itself. EOS benefit wizard is changed because it was using the function _l10n_sa_get_eosb_compensation and now it uses the salary rule directly. Test is written to test the implemented functionality by testing the EOS benefit report for different scenarios. task - 6393974
Belgian payroll now automatically carries forward and recovers negative net salary amounts through payslip rules instead of relying on manual reporting. This reduces manual follow-up for payroll teams and adds targeted warnings when unrecovered amounts remain at year-end or employee departure.
Original PR description
Previously, payslips with negative net amounts relied on a manual reporting action (`action_report_negative_net_amount`) and a generic dashboard warning. This commit removes the legacy negative net reporting mechanism and replaces it with an automated salary-rule-based net recovery process in Belgian payroll: - Removed legacy `action_report_negative_net_amount`, warning helper, and `hr_payroll_warning_negative_net_to_report` record from `hr_payroll`. - Added `NET_TO_RECOVER` and `NET_ALREADY_RECOVERED` salary rules to automatically offset negative net salary and deduct prior debt. - Added `_get_net_to_recover_amount` helper method on `hr.payslip` to calculate and apply accumulated debt recovery across payslips. - Overrode `action_payslip_done` to automatically mark payslips with net amount <= 0 as 'paid'. - Added a Belgian payroll warning for December or departure payslips when an unrecovered net amount remains. Task: 6413612
Indian GST reporting now lets businesses with turnover below 5 crore choose whether to include HSN details for B2C transactions. A new setting allows users to turn this reporting on or off, helping them align reports with the updated GSTIN rules.
Original PR description
The GSTIN has updated the rules for B2C HSN reporting. Now it has become optional for businesses having a turnover of less than 5 Cr. This improvement aims to integrate this change into our system by providing a boolean in settings. The user can switch on/off the reporting mechanism using this boolean. task-6097595 Community PR - https://github.com/odoo/odoo/pull/269014
Map route calculations are no longer enabled by default across field service planning views. Routing is now limited to the Maps and Live Map menus, helping reduce unnecessary Mapbox token usage and related customer costs.
Original PR description
Currently, the map view calculates routing by default whenever Mapbox is enabled. This ends up consuming unnecessary tokens (which cost the customer money) in views where routing isn't actually needed or relevant. To prevent this waste, we are turning off the default routing on the main map view. Moving forward, the routing feature is only explicitly enabled in the "Maps" and "Live Map" menus, where seeing the route actually makes sense for the user. task-6351070
Resolved issues and error corrections
Opening Bank Matching from a working file now works even when no bank journal is selected. This prevents an error that interrupted users handling unreconciled bank statement lines and returns.
Original PR description
When accessing the reconciliation widget from the working file check, there is no journal to be selected, hence no journal in the context. This was tracebacking since we were trying to send a read query to the server with an undefined id. To reproduce: * create a bank statement line without reconciling * set up the return on the misc journal * open the return, then "Bank Matching" Forward-Port-Of: odoo/enterprise#127421
This fixes an internal test so it correctly accounts for archived call activity records before deleting an activity type. The change helps prevent false test failures and keeps quality checks stable without affecting day-to-day user functionality.
Original PR description
test_create_call_activity attempts to delete any 'phonecall' activity types. This is so it can test the functionality of create_call_activity when there is no existing 'phonecall' activity type. However, demo data inside voip creates an archived activity with the type mail_activity_data_call. https://github.com/odoo/enterprise/blob/cc4456ac16aeee59830db08505a27877e149f3a7/voip/demo/voip_call.xml#L4-L13 When searching for phonecall_activities the test only gets active activities. We need to alter this to fetch all. Otherwise, the test will then try to delete the activity type when there are still records using the type. opw-6443475 runbot-242850 Forward-Port-Of: odoo/enterprise#126540
Fixes a server error that could occur when users turned the No Follow-Up option on or off for invoices paid in multiple installments. This makes follow-up reporting more reliable when some installments are already settled and others remain open.
Original PR description
Steps to Reproduce: 1. Configure Payment Term (Accounting > Configuration > Payment Terms) containing multiple installments. 2. Create a Customer Invoice with this Payment Term. 3. Post the invoice.…
Steps to Reproduce:
1. Configure Payment Term (Accounting > Configuration > Payment Terms) containing multiple installments.
2. Create a Customer Invoice with this Payment Term.
3. Post the invoice.
4. Register a payment and fully reconcile one of the installments.
5. Navigate to the customer's Follow-Up Report (Accounting > Reporting > Partner Ledger > Report: Follow-Up Report).
6. Navigate to remaining open installment/account move line for that invoice.
7. Turn On or Off the No Follow-Up toggle for the invoice.
An error occurs when enabling or disabling the No Follow-Up toggle.
Issue:
Enabling or disabling the No Follow-Up toggle on a remaining open installment in the Follow-Up Report raises a server error when the invoice contains multiple installments and one or more installments are already fully reconciled.
Root Cause:
The Follow-Up Report only loads and sends non-fully reconciled account move lines from the JavaScript side through all_line_ids. In action_toggle_no_followup(), when the selected line belongs to an invoice, the code retrieves all receivable/payable lines of the invoice, including fully reconciled installments:
```
move.line_ids.filtered(
lambda line: line.account_type in ('asset_receivable', 'liability_payable'),
)
```
The method then attempts to map every receivable/payable line to a report line ID using aml_id_to_line_id. Since fully reconciled installments are not present in all_line_ids, they are missing from the mapping dictionary, causing a KeyError when accessing:
`aml_id_to_line_id[line.id]
`
Fix:
Restricted the impacted lines to those present in the report by adding a check that the account move line exists in aml_id_to_line_id before performing the mapping:
```
lambda line: line.account_type in ('asset_receivable', 'liability_payable')
and line.id in aml_id_to_line_id
```
opw-6245448
Forward-Port-Of: odoo/enterprise#126785
Forward-Port-Of: odoo/enterprise#126156The Timesheets Assistant now ignores the current user's own email address when matching Gmail emails to customers. This prevents irrelevant task or project suggestions when the user's own contact is listed as a customer.
Original PR description
Before this commit, the Timesheets Assistant resolved every address found in a read or composed email to a partner, then matched the event to a task or project having that partner as its customer. The current user is a recipient of every email they receive, so their own address is present in the "To" or "Cc" fields of every `reading_email` event. As a result, any task whose customer was the current user could be suggested for those emails. This commit excludes the current user's partner from that lookup. task-6438374 Forward-Port-Of: odoo/enterprise#127422 Forward-Port-Of: odoo/enterprise#126448
Shifts for employees with flexible schedules and no fixed start or end times are now included consistently in Planning and Timesheets reports. This prevents planned work from being missing in analysis views, giving managers a more accurate view of allocated time.
Original PR description
## Behavior Before the PR When an employee did not have explicit `hours_from` and `hours_to` values defined, their shift was in the **Schedule by X** pivot view but was not included in the **Planning…
## Behavior Before the PR When an employee did not have explicit `hours_from` and `hours_to` values defined, their shift was in the **Schedule by X** pivot view but was not included in the **Planning / Timesheets Analysis** report. ## Steps to Reproduce 1. Create an employee with a Flexible Working Schedule in the Employee form, or configure working hours where both `Hour from` and `Hour to` are left unset. 2. Add a shift for this employee linked to a project and a task. 3. Publish the shift. 4. Navigate to **Planning → Schedule → By Project**, switch to the pivot view, and observe that the shift created in step 2 appears and is counted. 5. Navigate to **Planning → Reporting → Planning / Timesheets Analysis**, switch to the pivot view, and observe that the same shift does not appear. ## Behavior After the PR When an employee does not have explicit `hours_from` and `hours_to` values, their shift is now considered valid in both the **Schedule by X** views and the **Planning / Timesheets Analysis** report. ## Additional Notes - In earlier versions of Odoo, the `Work From` and `Work To` fields were mandatory. With a change to flexible working schedules and the option to define only the total number of hours per day, these fields may now be left empty. This change exposed the underlying issue addressed by this fix. task-[5969788](https://www.odoo.com/odoo/project/4105/tasks/5969788) Forward-Port-Of: odoo/enterprise#127300 Forward-Port-Of: odoo/enterprise#110606
Users who have both Partner Commissions access and Purchase User access can now create and view purchase orders as expected. This prevents commission-related restrictions from accidentally blocking normal purchasing work, while keeping commission-only users limited appropriately.
Original PR description
## Current behavior: The user Partner Commissions access rights as All Documents or Own Documents and Purchase access rights as User. With this configuration, the user is unable to create new…
## Current behavior: The user Partner Commissions access rights as All Documents or Own Documents and Purchase access rights as User. With this configuration, the user is unable to create new Purchase Orders, and existing Purchase Orders are also not visible in the Purchase module. ## Expected behavior: The expected behavior is that the user should be able to create and view Purchase Orders with these access rights. Additionally, clarification is required regarding the purpose of the new Partner Commissions access group. ## Steps to reproduce: - Go to user and assign Partner Commission rights as All or own document. - On Purchase, select group as User. ## Cause of the issue: partner_commission adds commission-specific purchase order record rules, but purchase users have no matching purchase-order rule in that module. For mixed-role users, the commission rule ends up restricting standard purchase orders as well. ## Fix: Apply the module's explicit all-purchase rule to purchase users so mixed users keep base procurement access while commission-only users remain restricted by the commission rules. opw-6366074 Forward-Port-Of: odoo/enterprise#127188 Forward-Port-Of: odoo/enterprise#126003
Products created through Barcode Lookup now correctly show the image returned by the service. This helps users verify newly created products visually and avoids manual image updates after scanning or entering barcodes.
Original PR description
Issue before this commit: ========================= When creating a product by adding a barcode using the Barcode Lookup service, the product image was fetched properly but was not displayed in the…
Issue before this commit: ========================= When creating a product by adding a barcode using the Barcode Lookup service, the product image was fetched properly but was not displayed in the UI. Steps to Reproduce: ========================= - Install the stock module. - Enable the Stock Barcode Database. - Add a valid API key for the Barcode Database. - Create a product by adding a barcode available in the Barcode Lookup API. - Notice that the product image is not displayed. Cause of the issue: ========================= This issue was introduced by this [PR](https://github.com/odoo/odoo/pull/244421), which improved the behaviour of **fields.Binary**. As a result, the image returned by the Barcode Lookup API was not converted to the expected binary format, preventing it from being displayed in the UI. With This Commit: ========================= With this commit, convert the fetched image to the expected binary format before assigning it to the product, ensuring that it is displayed correctly in the UI. opw-6434478 Forward-Port-Of: odoo/enterprise#126314
This update fixes a payroll-related issue by removing outdated or unnecessary behavior covered by the payroll run test flow. It helps keep payroll processes reliable and reduces the chance of confusion from obsolete steps.
Original PR description
task-6455499
A spreadsheet sharing update was incorrectly running during every page load, sometimes disrupting navigation state in other parts of Odoo. This fix limits that behavior to spreadsheet pages only, reducing unexpected page navigation issues.
Original PR description
BUG:
To make make spreadsheet backend shareabable, a patch to the router was done, and ran on *every* page load. The code looks harmless (it already had a `if (pathParts.at(-2) !== "spreadsheet")` early return, but because of the implementation of replaceState, this we had global impact regardless.
Indeed the real problem is that `router.replaceState` routes through doPush(), which replaces `history.state` disregarding the previous history completly (with a debounce, explaining the indeterminism)
In our case the builder stored `{skipRouteChange: true}` in `history.state` which was sometimes wiped by the `replaceState` debounce
FIX:
As a quick fix (JPP is on holidays), we amend the code to make spreadsheet shareable only run if the targetted app is spreadsheet
runbot-error: https://runbot.odoo.com/odoo/error/945518
breaking PR: https://github.com/odoo/enterprise/pull/114484This fix ensures vendor price list entries always include a unit of measure, preventing incomplete purchasing data. It helps avoid downstream errors or confusion when products are planned, ordered, or priced using supplier information.
Several older icon references were replaced with their supported Material Symbols equivalents across affected apps. This prevents icons from disappearing when the legacy compatibility layer is removed and keeps the product aligned with current quality checks.
Original PR description
__Problem__ A few `fa`/`fa-*` icons survived the migration to Material Symbols. They still render today thanks to the compatibility mapping between the two sets, but will stop doing so once it is removed. They are also caught by the new `test_lint` icons check. __Quick fix__ Replace them by their Material Symbols equivalent, set through the `data-icon` attribute, the sizing and filling classes being kept through their `oi` counterparts (`fa-lg` → `oi-lg`, `fa-fw` → `oi-fw`, ...). Community PR: odoo/odoo#279361
Preparation tickets in self-ordering now follow the language set for the default self-order user. This helps kitchen or preparation staff receive tickets in the expected language, reducing confusion in multilingual setups.
Original PR description
Before this commit the preparation ticket wasn't using the lang of the default pos_self_order user. Now it will use it. Forward-Port-Of: odoo/enterprise#127113 Forward-Port-Of: odoo/enterprise#126903
A spreadsheet sharing update was unintentionally affecting navigation data across the system on every page load. This fix limits that behavior to spreadsheet pages only, reducing unexpected navigation issues in other apps.
Original PR description
BUG:
To make make spreadsheet backend shareabable, a patch to the router was done, and ran on *every* page load. The code looks harmless (it already had a `if (pathParts.at(-2) !== "spreadsheet")` early return, but because of the implementation of replaceState, this we had global impact regardless.
Indeed the real problem is that `router.replaceState` routes through doPush(), which replaces `history.state` disregarding the previous history completly (with a debounce, explaining the indeterminism)
In our case the builder stored `{skipRouteChange: true}` in `history.state` which was sometimes wiped by the `replaceState` debounce
FIX:
As a quick fix (JPP is on holidays), we amend the code to make spreadsheet shareable only run if the targetted app is spreadsheet
runbot-error: https://runbot.odoo.com/odoo/error/945518
breaking PR: https://github.com/odoo/enterprise/pull/114484The payroll validation flow now correctly opens any required follow-up step, such as a wizard for missing employee information. This prevents the Validate button from appearing unresponsive and helps users understand what needs to be fixed before completing a payslip.
Original PR description
action_validate() called action_payslip_done() without returning its result. When action_payslip_done() returns a client action (e.g. a wizard to fix missing employee data instead of raising), that action was lost and the Validate button appeared to do nothing, with no error or warning shown. task-6373549
Generating public holidays now works consistently outside Belgium by applying the same automatic public holiday time type behavior to all localizations. This prevents errors when users load public holidays and improves the out-of-the-box payroll experience.
Original PR description
Purpose: generating Public Holidays fails with an error on all localizations except Belgium, preventing users from loading public holidays. This is because the Belgium localization includes a dedicated Public Holiday time type, which is automatically selected when creating public holidays. Extending this behavior to all localizations will make the feature work out of the box and provide a consistent user experience. - removed the inheritance for `load.public.holiday.wizard.line` as it's implemented generally in `hr_holidays` task-id: 6448261
Creating an employee in Belgian payroll with a subtype but no active contract no longer triggers an error. This prevents interruptions during employee setup and makes public holiday allocation handling more reliable.
Original PR description
Step to reproduce: -> Go to employee -> Create an employee with a sub type but without a running contract You will have a traceback Reason: We will take the minimum start date between all versions but version without contract date start are not supported. task-6455669
Payroll users can now send several payslips to off-cycle processing at once without encountering an error. This makes bulk payroll corrections smoother and avoids interruptions when working from the payslip list.
Original PR description
Steps to reproduce: - Open payslip list view - Select multiple payslips - Select "Send to Off-cycle" action Issue: A traceback occurs with ValueError: Expected singleton when the action is executed on multiple payslips. Reason: - 'action_move_to_off_cycle()' assumes a singleton and directly accesses self.version_id.id - When multiple payslips are selected from list view then self contains several payslips and self.version_id returns multiple versions, causing the singleton error. Solution: - Iterate over each payslip individually when processing the off-cycle action and use the corresponding version for each record, allowing the action to work correctly in multi-record mode task-6320059 Forward-Port-Of: odoo/enterprise#125284
Spreadsheet sharing logic now only runs when users are actually opening a spreadsheet. This prevents unrelated pages from losing navigation state, reducing intermittent page behavior and improving reliability across the app.
Original PR description
BUG:
To make make spreadsheet backend shareabable, a patch to the router was done, and ran on *every* page load. The code looks harmless (it already had a `if (pathParts.at(-2) !== "spreadsheet")` early return, but because of the implementation of replaceState, this we had global impact regardless.
Indeed the real problem is that `router.replaceState` routes through doPush(), which replaces `history.state` disregarding the previous history completly (with a debounce, explaining the indeterminism)
In our case the builder stored `{skipRouteChange: true}` in `history.state` which was sometimes wiped by the `replaceState` debounce
FIX:
As a quick fix (JPP is on holidays), we amend the code to make spreadsheet shareable only run if the targetted app is spreadsheet
runbot-error: https://runbot.odoo.com/odoo/error/945518
breaking PR: https://github.com/odoo/enterprise/pull/114484This fix prevents access errors when displaying salary offer details that depend on payroll information. It also updates the salary configurator test flow to reflect use by an HR user rather than an administrator, helping ensure the feature works for normal HR staff.
Original PR description
A field displayed inside the offer should have been computed with sudo as it accesses some payroll field to compute. Also, the salary configurator tour has been adapted to use a HR user instead of an admin Forward-Port-Of: odoo/enterprise#127510
A new test verifies that India GSTR-1 reporting selects the correct tax rate group when GST and CESS taxes are combined. This helps reduce the risk of incorrect tax reporting for Indian businesses using these tax combinations.
Original PR description
This PR adds a test case to ensure that the correct tax rate group is selected in the GSTR-1 report when a combination of GST and CESS taxes is used. Community PR - https://github.com/odoo/odoo/pull/280571 Forward-Port-Of: odoo/enterprise#126770
This fix prevents users in multi-company setups from hitting an unavoidable error when creating quality-related operation steps. It ensures the default quality team works correctly with the current company, reducing blocked manufacturing or quality workflows.
Original PR description
This commit actually reverts [1] and manually forwards [2]. Suppose `mrp_workorder` installed and `quality_control` uninstalled. Because of the default value provided by [1], the only existing quality team is linked to the first company. As a result, when using another company, if the user tries to create an operation step (i.e., a QCP), it will raise an error when the onchange tries to load the default team in charge: https://github.com/odoo/enterprise/blob/f9c99f937bd64e5a0acb4bc88b1fc08249250c4e/quality/models/quality.py#L141-L142 However, the `quality` module doesn't provide any view to create such a team. tldr The module raises an error that is actually impossible to solve... Let's avoid it in the above situation. [1] https://github.com/odoo/enterprise/commit/f9c99f937bd64e5a0acb4bc88b1fc08249250c4e [2] https://github.com/odoo/enterprise/commit/8cd5c9322bef7db49a90d4aef844dd0ba267058e Forward-Port-Of: odoo/enterprise#127438 Forward-Port-Of: odoo/enterprise#126364
Code cleanup and technical improvements
The field service attendance menu was updated to use the newer OWL3 approach for managing location tracking when employees check in or out. This keeps the feature compatible with the latest framework while preserving the existing user experience.
Original PR description
Replaced `useLayoutEffect` with OWL3 `useEffect` because `useLayoutEffect` is deprecated in OWL3. The effect reacts to `this.state.checkedIn` to start/stop the geolocation watch. OWL3 `useEffect` auto-tracks reactive values read inside the callback, so the plain `this.state.checkedIn` access subscribes automatically — no deps array needed. The code refactored is functionnaly tested, see https://runbot.odoo.com/runbot/batch/2596694/build/114854534
This update renames an internal frontend helper to better match its purpose, without changing how the affected business features work. It improves code clarity and consistency across several Odoo apps, helping future maintenance while keeping user-facing behavior unchanged.
Original PR description
This commit replaces the `plugin` imports by `usePlugin` which is the same function but with a correct hook name.
This update modernizes part of the timesheet timer interface to stay compatible with the next version of Odoo's web framework. It also corrects a small internal issue so the timer form continues to apply configured minimums, rounding, and basic actions reliably.
Original PR description
Replaced `useLayoutEffect` with `useEffect` because `useLayoutEffect` is deprecated in OWL3. `descriptionFieldRef` is already a `signal.ref()` field (bound in the template via `t-ref`), so…
Replaced `useLayoutEffect` with `useEffect` because `useLayoutEffect` is deprecated in OWL3. `descriptionFieldRef` is already a `signal.ref()` field (bound in the template via `t-ref`), so `useEffect` is the idiomatic choice: it auto-tracks the signal and re-runs whenever the element enters the DOM. The `!el` guard handles the eager pre-mount call (the ref is `null` before the node appears). This also fixes a latent bug: the original `if (this.descriptionFieldRef)` tested the always-truthy signal function rather than its value. The useLayoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - @timesheet_grid/timesheet_systray/Timer applies configured minimum - @timesheet_grid/timesheet_systray/Timer applies configured rounding - @timesheet_grid/timesheet_systray/Basic systray actions Those tests were run against all three states of the code: - Passed with previous useLayoutEffect. - Failed with previous useLayoutEffect commented. - Passed with our OWL3 replacement. see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2681606/build/120351199 The timer subclass `TimesheetTimerInlineForm` was also updated: its `onPatched` hook read `this.descriptionFieldRef.el`, which broke after the base t-ref migration converted the field from `useRef` to `signal.ref()` (no `.el` property). Fixed by calling `this.descriptionFieldRef()` instead — no `?.` needed since the ref is always set when `onPatched` fires.
This update removes use of an outdated internal rendering method in spreadsheet-related tests and components. It helps keep the Enterprise spreadsheet experience compatible with the next version of Odoo’s web framework without changing business functionality.
Original PR description
- community: https://github.com/odoo/odoo/pull/281942 See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update simplifies internal accounting screen code by removing unused or unnecessary shared settings. It should make the feature easier to maintain without changing how users interact with accounting workflows.
Original PR description
This commit removes two `useSubEnv`. The function `skipKanbanRestoreNeeded` given to the env was never used. The function `setPopout` given in the env was used by a direct child component. This function is now given by props instead of by env.
10 changes
Resolved issues and error corrections
Australian payroll now correctly matches unused leave balances to the employee on each payslip. This helps ensure termination or leave-related payouts are not missed when payroll is processed for multiple employees at once.
Original PR description
`_l10n_au_get_unused_leave_by_type` compared leave allocations to `self.employee_id` while looping payslips. On a multi-recordset that is the whole employee set, so the match never holds and unused leave is skipped. Use `payslip.employee_id` so each payslip keeps its own allocations. task-6458480
French VAT reimbursement declaration 3519 now includes the bank account holder name in the account information section. This helps meet the required declaration details and reduces the risk of reimbursement submissions being rejected or incomplete.
Original PR description
For reimbursement declarations, the name of the holder of the account is required This commits adds holder's name to the account data zone no-task-id Forward-Port-Of: odoo/enterprise#127554
This fixes an internal module dependency so the Belgian POS Blackbox HR integration loads the correct related component. It helps prevent installation or automated test failures without changing day-to-day point-of-sale behavior.
Original PR description
Before this commit, the dependency of the module l10n_be_pos_blackbox_hr_pos_blackbox_be was set to pos_hr, which is not totally correct. The correct dependency should be l10n_be_pos_blackbox_hr. runbot-error: 941561
This fix improves how time-off intervals are calculated for employees using duration-based work schedules. It helps ensure the Gantt planning view shows leave durations correctly, reducing confusion for managers and HR teams.
Original PR description
task-id: 6460078
When warehouse staff scan multiple lot numbers during a receipt, new lot lines now keep the putaway destination already assigned by the receipt. This prevents items from appearing in the wrong stock location and keeps barcode receiving aligned with warehouse putaway rules.
Original PR description
Steps to reproduce --- 1. Enable Storage Locations and Lots & Serial Numbers. 2. Add a putaway rule sending a lot-tracked product from WH/Stock to WH/Stock/Shelf 1. 3. Confirm a receipt reserving 2…
Steps to reproduce --- 1. Enable Storage Locations and Lots & Serial Numbers. 2. Add a putaway rule sending a lot-tracked product from WH/Stock to WH/Stock/Shelf 1. 3. Confirm a receipt reserving 2 units of that product; putaway sets the reserved move line destination to WH/Stock/Shelf 1. 4. In the Barcode app, scan a first lot, then a second lot. The second lot lands on a separate line at WH/Stock instead of WH/Stock/Shelf 1. Issue --- The first lot reuses the reserved line and keeps its Shelf 1 destination. The second lot cannot reuse it because its tracking number differs, so `_findLine` returns nothing and `_getNewLineDefaultValues` builds a new line with `location_dest_id` set to `_defaultDestLocation()`, the picking's default destination (WH/Stock). https://github.com/odoo/enterprise/blob/314a79b774f30dc9377b2971492576c4b84483e1/stock_barcode/static/src/models/barcode_picking_model.js#L1591-L1601 Putaway relocates the destination on the move line at reservation, never on the picking, so only the reserved line carries Shelf 1. Since `groupKey` includes `location_dest_id`, the new line does not group with the first lot and shows separately at WH/Stock. This is not a regression: new lines have always defaulted to the operation destination. https://github.com/odoo/enterprise/blob/314a79b774f30dc9377b2971492576c4b84483e1/stock_barcode/static/src/models/barcode_picking_model.js#L239-L241 The new line now inherits the selected line's `location_dest_id`, already relocated by putaway, instead of the default. opw-6317077
This pull request combines several business-facing fixes and improvements across Odoo Enterprise, including cleaner tax return screens, corrected rental availability checks, restored POS preparation ticket printing, and more accurate localized accounting reports. It also adds Romania's D390 EC Sales report support, helping Romanian companies meet electronic tax filing requirements.
Account transfer journal entries now stay balanced when destination percentages are below 100%. This prevents one-cent discrepancies caused by rounding across multiple source accounts, reducing posting errors and manual correction needs.
Original PR description
Before this commit, _get_transfer_move_lines_values computed the amount for the last destination line from the global transferred balance, instead of reusing the amount already removed from the source accounts. The two values are rounded independently and can differ by a cent whenever the removed amount comes from more than one rounded source, producing an unbalanced journal entry. Removing that condition the last destination line always absorbs the remainder fixes it. Steps to reproduce: 1. Transfer model with 2 source accounts and 1 destination line at 15%. 2. Post moves for the period: account A balance 395.88, account B balance 252.16 (total 648.04). 3. Run `action_perform_auto_transfer()`. Before: source lines -59.38 (395.88 * 15%) and -37.82 (252.16 * 15%), destination line +97.21 (648.04*15% rounded) -> entry off by 0.01. After: destination line takes the exact remainder, 97.20 -> balanced. OPW-6443928
The Helpdesk Stock workflow now keeps the Replace button visible even when no customer has been selected. This makes the ticket interface more consistent with related actions and reduces confusion for support teams handling stock replacements.
Original PR description
Adjust the `invisible` condition to make the button visible even if no customer is selected, for consistency with other buttons --- task-6103996
This fix prevents Swiss payroll settings from assigning a Swiss contract type to employees or environments that are not Swiss. It avoids test failures and helps ensure payroll contract defaults stay appropriate for the employee context.
Original PR description
[FIX] l10n_ch: fix default contract type This task is runbot error fix that occured from 19.0 to 19.2 Bug reproduction: 1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute…
[FIX] l10n_ch: fix default contract type
This task is runbot error fix that occured from 19.0 to 19.2
Bug reproduction:
1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute test_version_timeline_auto_save_tour tour test 3 - It fails in .o_arrow_button_wrapper[data-tooltip^='Contract:'] step
Bug cause:
1 - When l10n_ch_hr_payroll_account is installed:
1.1 - contract type becomes "Permanent contract with monthly salary"
1.2 - the employee is not swiss but it has this CH contract type
2 - data-tooltip starts with Permanent contract instead of contract
2.1 - Tour fails
3 - contract_type_id is overwritten in swiss modules
3.1 - Default is assigned without looking to the country of self.env
Bug solution:
1 - If the country is not swiss, the default is assigned as False
1.1 -> fixed in l10n_ch_hr_payroll/hr_version
1.2 instead of assigning swiss contract type to the non-swiss emp.
Note: This is fix from saas-18.4 to master.
task-6392040
runbot error: https://runbot.odoo.com/odoo/runbot.build.error/941358
Forward-Port-Of: odoo/enterprise#126520An accounting test was updated to align with a related platform fix in how grouped data is read. This helps keep automated checks accurate and reduces the risk of false test failures during accounting development.
Original PR description
The fix at https://github.com/odoo/odoo/pull/281911 adds bin_size: tru in the web_read_group. This commit adpats an accounting test as a consequence
1 change
Resolved issues and error corrections
Fixed an issue where exporting the Deferred Revenue Report to XLSX could fail when the report included annotations. This helps accounting users reliably export annotated reports without encountering a server error.
Original PR description
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Start Date** and **End Date** fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to…
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Start Date** and **End Date** fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to **Accounting → Reports → Deferred Revenue Report**. * Add an annotation to a deferred revenue line by clicking the **annotate** from three dots next to the account. * Export the report in **XLSX** format. **Observed behavior:** * The export fails with a server error: `UnboundLocalError: cannot access local variable 'annotations_x_offset' where it is not associated with a value` **Cause:** * The variable `annotations_x_offset` is assigned inside the `for header_level_index, header_level in enumerate(options['column_headers'])` loop, which writes the "Annotations" column header for each header level. * The Deferred Revenue Report produces an empty `column_headers` list, so the loop body never executes and `annotations_x_offset` is never assigned. * When the code later tries to write annotation data for each report line, it references the unassigned variable, causing Python to raise `UnboundLocalError`. **Fix:** * Introduce a boolean flag `annotations_header_written = False` before the header loop to explicitly track whether the "Annotations" column header has already been written. * Inside the header loop, set `annotations_header_written = True` after writing the header. * After writing all individual column headers (where `x_offset` already points to the first free column after all data columns), add a fallback: if `report_annotations` is set but `annotations_header_written` is still `False`, assign `annotations_x_offset` from the current `x_offset` and write the "Annotations" header. opw-6354473
1 change
Resolved issues and error corrections
This fix prevents Swiss payroll settings from automatically assigning a Swiss contract type to employees outside Switzerland. It avoids incorrect contract labels and helps keep automated HR/payroll checks reliable across localized setups.
Original PR description
[FIX] l10n_ch: fix default contract type This task is runbot error fix that occured from 19.0 to 19.2 Bug reproduction: 1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute…
[FIX] l10n_ch: fix default contract type
This task is runbot error fix that occured from 19.0 to 19.2
Bug reproduction:
1 - Go to version 19.0, install l10n_ch_hr_payroll_account 2 - Execute test_version_timeline_auto_save_tour tour test 3 - It fails in .o_arrow_button_wrapper[data-tooltip^='Contract:'] step
Bug cause:
1 - When l10n_ch_hr_payroll_account is installed:
1.1 - contract type becomes "Permanent contract with monthly salary"
1.2 - the employee is not swiss but it has this CH contract type
2 - data-tooltip starts with Permanent contract instead of contract
2.1 - Tour fails
3 - contract_type_id is overwritten in swiss modules
3.1 - Default is assigned without looking to the country of self.env
Bug solution:
1 - If the country is not swiss, the default is assigned as False
1.1 instead of assigning swiss contract type to the non-swiss emp.
Note: I started to fix it from 17.0 BUT:
. in above versions field overwrite might be in different CH modules . fix all in the above versions
task-6392040
runbot error: https://runbot.odoo.com/odoo/runbot.build.error/941358