Daily updates from Odoo
Navigate
Branch
Thursday, August 13, 2026
255 changes
14 changes
Resolved issues and error corrections
The Planning menu now appears in the intended order when Field Service is installed. This keeps navigation consistent for users without changing the standard Planning menu setup when Field Service is not installed.
Original PR description
Ensure the Planning menus are displayed in the correct order when Field Service is installed, without affecting the standard Planning menu structure. task-6443397
The Timesheets Assistant now ignores the current user's own contact when matching Gmail email recipients to customers. This prevents unrelated emails from suggesting tasks or projects simply because the user's address appears in the message.
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
Accounting read-only users can now see the General section on the Accounting tab of contact records when they have the proper access rights. This restores visibility of bank account details that were accidentally hidden by a view configuration issue.
Original PR description
Problem: The General group of the Accounting tab of the partner form view is not visible to some users, even if they have the access rights to see it. Steps to reproduce: 1. Create a user or edit an existing one, giving them Accounting Read-Only access rights. 2. Log in with that user. 3. Go to Contacts and select a partner. 4. Open the Accounting tab 5. Notice how the General group (with the bank account details) is not visible. Cause: In the account_accountant module, the partner form view is inherited in one of the views to add additional groups to the General group of the Accounting tab. However, it doesn't add the new group, but instead replaces the existing groups with the new one. opw-6413683 Forward-Port-Of: odoo/enterprise#126679
This fix prevents small rounding differences from creating unbalanced journal entries when account transfer rules send less than 100% to a destination. Businesses using automated transfers can now rely on the generated accounting entries to balance correctly, avoiding one-cent posting errors.
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 Forward-Port-Of: odoo/enterprise#126877
The payroll validation button now correctly opens any needed follow-up prompt, such as a wizard to complete missing employee information. This prevents users from clicking Validate and seeing no response when additional data is required.
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
Customers can now use Order Again for rental products even when their cart already has a rental period. The cart reuses the existing rental dates, preventing a false conflict that previously stopped the item from being added.
Original PR description
Steps to reproduce: --- - Install the `website_sale_renting` module. - Create a rental product, place an order for it with customer as `Administrator`, and confirm the order. - Open the order preview…
Steps to reproduce: --- - Install the `website_sale_renting` module. - Create a rental product, place an order for it with customer as `Administrator`, and confirm the order. - Open the order preview and click `Order Again`. - In the cart, modify the rental period. - Go to My Account > Your Orders, open the sales order, and click `Order Again` again. Issue: --- - Clicking Order Again a second time does nothing and - The following error is logged in the terminal: `You cannot mix different rental periods in the same order.` Root cause: --- - When the user clicks `Order Again`, the `/my/orders/reorder` route calls `add_to_cart`[1], which in turn invokes `_cart_add`[2]. If no rental dates are provided, `_cart_add` computes default rental dates based on the product's rental periodicity [3]. - However, when the current cart already has a rental period set, these computed dates differ from the cart's existing rental period. As a result, the rental consistency check detects the mismatch and prevents the product from being added to the cart. Solution: --- - When the current sale order already has a rental period set, reuse those dates instead of computing default ones. This ensures the product is added using the existing cart rental period and avoids the false conflict. [1]: https://github.com/odoo/odoo/blob/bb9fcbb062887ab6b1c4c17870201d789afa9dbc/addons/website_sale/controllers/reorder.py#L63-L76 [2]: https://github.com/odoo/odoo/blob/bb9fcbb062887ab6b1c4c17870201d789afa9dbc/addons/website_sale/controllers/cart.py#L134-L141 [3]: https://github.com/odoo/enterprise/blob/a39da12a4a85d749235d59a05ebd67b91f9867b0/website_sale_renting/models/sale_order.py#L60-L64 opw-6357001 ---
This fixes an incorrect value used when reporting Swiss withholding tax changes in payroll declarations. It helps ensure employee payroll data is submitted with the expected official classification, reducing the risk of rejected or inaccurate declarations.
Original PR description
task-6116327 Forward-Port-Of: odoo/enterprise#127745
VoIP contact searches now recognize phone numbers even when the user's input includes an automatic country code and the saved contact number is stored differently. This makes keypad suggestions and contact tab searches more reliable, while showing a readable formatted phone number to users.
Original PR description
Before this fix, the keypad's callee suggestions only matched the search term against the raw `phone` field of contacts. When the user input was automatically prefixed with a country code (e.g. +86), the match could fail if the stored phone number lacked the international prefix. Now `phone_sanitized` is also sent to the frontend via the Store, and the callee suggestion matching falls back to the E164 sanitized number when the raw phone field does not match. Task-6290760 compr https://github.com/odoo/odoo/pull/278018 Forward-Port-Of: odoo/enterprise#127466 Forward-Port-Of: odoo/enterprise#124797
Fixed an issue in Payroll where saving an employee declaration without selecting an employee caused an error. Users can now create or save these records without being blocked by a traceback, improving reliability in the declaration workflow.
Original PR description
When creating an employee declaration without selecting an employee, a traceback occurs. Steps to reproduce the error: - Install ``l10n_be_hr_payroll`` module with demo data - Switch to Belgian…
When creating an employee declaration without selecting an employee, a traceback occurs. Steps to reproduce the error: - Install ``l10n_be_hr_payroll`` module with demo data - Switch to Belgian company - Go to Payroll > Reporting > Individual Accounts > Create a new Individual Account > Click on Eligible Employees > Create a new employee declaration without employee > Save Traceback: ```py ValueError: Expected singleton: hr.employee() ``` https://github.com/odoo/enterprise/blob/000544c3d5b93e194264e15bb73d9599525106e3/hr_payroll/models/hr_payroll_employee_declaration.py#L71 The ``_compute_version_id()`` method calls ``_get_version()``. When ``employee_id`` is empty, ``_get_version()`` is invoked on an empty ``hr.employee`` record, and its ``ensure_one()`` call raises the above traceback at [1]. [1]: https://github.com/odoo/odoo/blob/3c358ae2badad69b125695a97b4a14e8ab77fccd/addons/hr/models/hr_employee.py#L745-L750 sentry-7625826444 Forward-Port-Of: odoo/enterprise#125175
Australian payroll now correctly includes each employee's unused leave when payslips are processed together. This prevents leave payouts or balances from being skipped in multi-employee payroll runs.
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
The Helpdesk Stock flow now shows the Replace button even when no customer is selected. This keeps the ticket interface consistent with related actions and reduces confusion for support teams handling 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 Forward-Port-Of: odoo/enterprise#124467
Accounting users can now export Spanish VAT record books that include Point of Sale data without needing separate POS access. This prevents access errors during tax reporting while still using POS information only internally to build the report.
Original PR description
Steps to reproduce:
- With an ES Company
- Open a POS session, add product with tax and pay
- As a user with only accounting access
- Go to Accouting > Reporting > Tax report
- Select Generic Tax report
- Print "VAT record Books"
Issue:
An AccessError will raise
```
Access Error
You are not allowed to access 'Point of Sale Session' (pos.session) records.
This operation is allowed for the following groups:
- Point of Sale/User
Contact your administrator to request access if necessary.
```
Analysis:
Vat Record Books handler for POS needs to read pos.session and pos.order records. Currently, the action is performed with the rights of the user running the report, so accounting-only user face an error.
As POS records are only read internally to build the report, we add sudo call to get the data.
opw-5862529
Forward-Port-Of: odoo/enterprise#126590
Forward-Port-Of: odoo/enterprise#125980Belgian payroll now calculates fictitious remuneration for departure holiday attestations and December double holiday regularization using the salary that applied during each absence period. This prevents employees with mid-year salary changes from having those absences valued at the wrong wage, improving payroll accuracy.
Original PR description
### Problem - The fictitious remuneration used for departure holiday attest and December double holiday regularization was computed using the salary applicable at the end of the previous year for all…
### Problem - The fictitious remuneration used for departure holiday attest and December double holiday regularization was computed using the salary applicable at the end of the previous year for all assimilated absence periods. **For an employee with:** - 20 days of assimilated absence in February with a salary of 2,000. - A salary increase to 3,000 in June. - Another 20 days of assimilated absence in November. ``` The previous computation was: (40 × 3,000) × (3 / 13 / 5) ``` - where all assimilated absence days were valued using the wage applicable on the last day of the previous year. - Instead, the remuneration should be computed using the wage applicable ``` during each assimilated absence period: ((20 × 2,000) + (20 × 3,000)) × (3 / 13 / 5) ``` - Compute the fictitious remuneration using the contract wage applicable to each payslip period so that each assimilated absence is valued with the correct monthly salary before applying the holiday formula. task-5932817
Belgian payroll now reports the correct mobility budget balance when it is paid after an employee's contract no longer includes a mobility budget. This prevents the DMFA declaration from showing zero and helps ensure accurate social security reporting.
Original PR description
When the mobility budget balance is paid on a contract that no longer carries a mobility budget, fall back to the previous quarter's contract to declare the correct amount instead of 0. Task-6384786 Forward-Port-Of: odoo/enterprise#127318
13 changes
Resolved issues and error corrections
A test was adjusted to match improved spacing in plain-text tracking messages. This keeps automated checks aligned with the expected mobile notification output and helps prevent false test failures.
Original PR description
The enterprise commit adds a span in the tracking values template which adds a space between the values when converted to plaintext. This is a side-effect, but it's a good one. task-6456370
Users with Accounting Read-Only access can now see the General section in the Accounting tab of contact records, including bank account details. This fixes a visibility issue caused by a view customization that accidentally replaced existing access groups instead of adding the intended one.
Original PR description
Problem: The General group of the Accounting tab of the partner form view is not visible to some users, even if they have the access rights to see it. Steps to reproduce: 1. Create a user or edit an existing one, giving them Accounting Read-Only access rights. 2. Log in with that user. 3. Go to Contacts and select a partner. 4. Open the Accounting tab 5. Notice how the General group (with the bank account details) is not visible. Cause: In the account_accountant module, the partner form view is inherited in one of the views to add additional groups to the General group of the Accounting tab. However, it doesn't add the new group, but instead replaces the existing groups with the new one. opw-6413683 Forward-Port-Of: odoo/enterprise#126679
This update adjusts an internal automated test for mobile mail notifications after a tracking template change. It helps keep quality checks reliable without changing the user-facing product experience.
Original PR description
Task-6424104
Automatic account transfers now keep journal entries balanced when destination percentages are below 100%. This prevents small rounding differences, such as one-cent mismatches, from blocking or distorting transfer postings.
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 Forward-Port-Of: odoo/enterprise#126877
The Point of Sale UrbanPiper ticket screen now shows the order info button on mobile as well as desktop. This ensures staff using mobile devices can access order details consistently, reducing friction during order handling.
Original PR description
Before this commit: ------------ - The order info button was not visible on the ticket screen in the mobile UI. After this commit: ------------ - Display the order info button in both the mobile and desktop views of the ticket screen. Related: - Community: https://github.com/odoo/odoo/pull/276568 Task-6388045
Belgian payroll now automatically applies an employee's default private-use fuel card amount when creating a payslip, as long as the employee has no company car or mobility budget. This prevents the taxable benefit from being missed and keeps payslips aligned with the employee's payroll settings.
Original PR description
Steps to reproduce: - Set a "Fuel Card - Private use" default on the employee's payroll tab (fuel_card_personal_use), with no company car. - Generate/compute a monthly payslip for that employee. - The FUEL_CARD_PRIV salary rule never fires, so the private-use benefit-in-kind stays at 0 and is missing from the payslip. FUEL_CARD_PRIV is a property_input salary rule, so its amount comes from the payslip's property inputs, but nothing ever copied the employee's fuel_card_personal_use default into them. Seed FUEL_CARD_PRIV from that default in _compute_input_line_ids(), gated on fuel_card, no company car (transport_mode_car) and no mobility budget, matching this version's own benefit view visibility conditions. Added tests covering the default, each exclusion case, and manual payslip overrides. Task 6469003
This fix ensures Belgian payroll declarations report the correct mobility budget balance when an employee's current contract no longer includes a mobility budget. The system now uses the previous quarter's contract information so the declared amount is not incorrectly set to zero.
Original PR description
When the mobility budget balance is paid on a contract that no longer carries a mobility budget, fall back to the previous quarter's contract to declare the correct amount instead of 0. Task-6384786
The Helpdesk Stock workflow now shows the Replace button even when no customer is selected. This keeps the ticket interface consistent with related actions and helps users access the replacement process without unnecessary data entry first.
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 Forward-Port-Of: odoo/enterprise#124467
This fixes an issue where the signing process could fail when an empty value was used without an automatic fallback value. Users should now be able to complete affected signing workflows without encountering an unexpected error.
This fixes an incorrect status value used in Swiss withholding tax mutation declarations. The change helps ensure employee payroll updates are reported with the right classification, reducing the risk of rejected or inaccurate declarations.
Original PR description
task-6116327 Forward-Port-Of: odoo/enterprise#127745
The timesheet menu has been adjusted to display more cleanly on mobile devices. This makes it easier for users to enter and manage timesheets from smaller screens without dealing with a clunky layout.
Original PR description
In this commit, we improve the display of the timesheet systray in mobile view as it was clunky. task-6332208
This fix prevents Swiss payroll settings from being applied automatically to employees outside Switzerland. It helps avoid incorrect employee contract information and keeps payroll-related screens and automated checks working as expected.
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 fixes an issue where Belgian SODA file imports could fail for users who do not have Analytic Accounting access. The import can now continue normally when Analytic Accounting is disabled, reducing unnecessary blockers in accounting workflows.
Original PR description
**Description of the issue/feature this PR addresses:** When importing a SODA XML file, users without the Analytic Accounting group encounter an access rights error. This occurs because the import…
**Description of the issue/feature this PR addresses:** When importing a SODA XML file, users without the Analytic Accounting group encounter an access rights error. This occurs because the import wizard reads the `analytic_account_id` field on the `soda.analytic.mapping` model to build an internal dictionary of departments. Because this field is restricted to the Analytic Accounting group, the evaluation of this field crashes the import for users even when the Analytic Accounting feature is disabled. This commit prevents the crash by using `.sudo()` when reading the analytic account ID. This safely bypasses the field-level group restriction, allowing the dictionary to be built with False values without interrupting the core import process. **Steps to reproduce:** - Log in as Mitchell Admin, change company to “My Belgian Company” - Settings > Users & Companies > Users > Mitchell Admin > Access Rights > Extra Rights > ensure “Analytic Accounting” is unchecked - Also ensure Mitchell Admin is not part of the “Analytic Accounting” group - Accounting Dashboard > remove “Favorites” from filter > drag & drop a SODA XML file to “Miscellaneous Operations” > save > observe Access Error **Current behavior before PR:** - Users who don't belong to the Analytic Accounting group encounter an access error when attempting to import SODA XML files, even when the Analytic Accounting feature isn't enabled **Desired behavior after PR is merged:** - Those users no longer receive an access error opw-6376039
2 changes
Resolved issues and error corrections
Account transfers now keep journal entries balanced when destination percentages do not add up to 100%. This prevents rare one-cent discrepancies caused by rounding across multiple source accounts, reducing posting errors for automated transfers.
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 Forward-Port-Of: odoo/enterprise#126877
Users with Accounting Read-Only access can now see the General section in the Accounting tab of partner records as intended. This restores visibility of bank account details and prevents confusion for finance users reviewing contact information.
Original PR description
Problem: The General group of the Accounting tab of the partner form view is not visible to some users, even if they have the access rights to see it. Steps to reproduce: 1. Create a user or edit an existing one, giving them Accounting Read-Only access rights. 2. Log in with that user. 3. Go to Contacts and select a partner. 4. Open the Accounting tab 5. Notice how the General group (with the bank account details) is not visible. Cause: In the account_accountant module, the partner form view is inherited in one of the views to add additional groups to the General group of the Accounting tab. However, it doesn't add the new group, but instead replaces the existing groups with the new one. opw-6413683 Forward-Port-Of: odoo/enterprise#126679
10 changes
Resolved issues and error corrections
Users without accounting permissions could be prevented from confirming sales orders when a Studio approval rule referenced certain customer follow-up fields. This fix lets the approval check evaluate those rules correctly, avoiding unnecessary access errors while preserving the approval process.
Original PR description
continuation of [PR](https://github.com/odoo/enterprise/pull/121856) Issue: Inside _get_approval_spec filtered_domain is called a few times and due to a related field that calls an access rights group that the user who used the action isnt apart of is blocked by the filtered_domain. To Replicate: 1) Install studio, sale, Accounting and make sure "account_followup" is installed 2) create a related field on the sales.order form related to "customer -> follow up status" 3) Save 4) Create a "Studio Approval Rule" (studio.approval.rule) with a domain using the new related studio field -> method : "action_confirm" -> approver:admin 5)create a test user with no accounting access rights 6) in an incognito browser try and create a sales order, and then confirm it. it will throw the access rights error Solution: Go one up the stack where _get_approval_spec is called and add a syudo for those calls opw-6316069 Forward-Port-Of: odoo/enterprise#127412
The Replace button in helpdesk stock workflows now remains visible even when no customer is selected. This keeps the ticket interface consistent with related actions and prevents users from missing the replacement option.
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 Forward-Port-Of: odoo/enterprise#124467
This update adjusts an automated accounting test to match a recent underlying fix in how grouped data is read. It helps keep the accounting module's quality checks accurate and prevents false test failures during validation.
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 Forward-Port-Of: odoo/enterprise#127638
Users with read-only accounting access can now see the General section in the Accounting tab of contact records, including bank account details. This fixes a view configuration issue that accidentally hid information users were already allowed to access.
Original PR description
Problem: The General group of the Accounting tab of the partner form view is not visible to some users, even if they have the access rights to see it. Steps to reproduce: 1. Create a user or edit an existing one, giving them Accounting Read-Only access rights. 2. Log in with that user. 3. Go to Contacts and select a partner. 4. Open the Accounting tab 5. Notice how the General group (with the bank account details) is not visible. Cause: In the account_accountant module, the partner form view is inherited in one of the views to add additional groups to the General group of the Accounting tab. However, it doesn't add the new group, but instead replaces the existing groups with the new one. opw-6413683 Forward-Port-Of: odoo/enterprise#126679
When receiving lot-tracked products with putaway rules, the Barcode app now keeps the correct destination shelf for each scanned lot. This prevents extra lots from being placed on the general stock location by mistake, improving warehouse accuracy.
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 Forward-Port-Of: odoo/enterprise#125309
Global invoice creation for Mexican point-of-sale orders now ignores cancelled refunds, so only completed refunds affect the invoice totals. This prevents valid invoices from failing when a cancelled refund exists alongside a paid refund.
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#127560 Forward-Port-Of: odoo/enterprise#120996
Automated account transfers now balance correctly when destination percentages are below 100%. This prevents one-cent rounding differences from creating unbalanced journal entries, improving reliability for accounting workflows.
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 Forward-Port-Of: odoo/enterprise#126877
The UK CIS report now correctly shows payments for receipts that include CIS tax, not just vendor bills. This helps businesses keep CIS reporting complete and accurate across more purchase document types.
Original PR description
With the l10n_uk_reports_cis module installed: - Create a vendor bills and add a CIS tax --> This vendor's bills appear correctly in the report. - Create a receipt and add a CIS tax --> This type of bill appears in the report, but the payment is not showing up. opw-6282548 Forward-Port-Of: odoo/enterprise#124043
This fix corrects an incorrect enumeration used in Swiss withholding tax mutation declarations. It helps ensure payroll declaration data is categorized properly when sent or prepared for Swiss reporting requirements.
Original PR description
task-6116327 Forward-Port-Of: odoo/enterprise#127745
This fixes an issue where signatures could disappear from downloaded signed PDFs when the original document used unusual page positioning from another PDF tool. Users can now trust that signatures visible during preview will also appear correctly in the final downloaded document.
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#121960
5 changes
Resolved issues and error corrections
Submitting an Australian Single Touch Payroll record with no payslips or employees now shows a clear validation message instead of crashing. This helps payroll users understand what information is missing 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#127584 Forward-Port-Of: odoo/enterprise#124096
Deferred Revenue Report exports no longer fail when annotations are included. This prevents a server error and lets accounting users reliably download annotated XLSX reports.
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 Forward-Port-Of: odoo/enterprise#122768
The Dutch tax reporting status process now skips or handles tax return status records that are missing their related closing entry. This prevents one incomplete record from blocking status updates for other Digipoort tax returns.
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#127597 Forward-Port-Of: odoo/enterprise#125996
This fix ensures users with Accounting Read-Only access can see the General section in the Accounting tab on contact records, including bank account details. It corrects a view configuration issue that accidentally hid existing access groups instead of adding the new one.
Original PR description
Problem: The General group of the Accounting tab of the partner form view is not visible to some users, even if they have the access rights to see it. Steps to reproduce: 1. Create a user or edit an existing one, giving them Accounting Read-Only access rights. 2. Log in with that user. 3. Go to Contacts and select a partner. 4. Open the Accounting tab 5. Notice how the General group (with the bank account details) is not visible. Cause: In the account_accountant module, the partner form view is inherited in one of the views to add additional groups to the General group of the Accounting tab. However, it doesn't add the new group, but instead replaces the existing groups with the new one. opw-6413683 Forward-Port-Of: odoo/enterprise#126679
This fix corrects an incorrect status value used in Swiss withholding tax mutation declarations. It helps ensure payroll declaration data is reported accurately and reduces the risk of rejected or incorrect submissions.
Original PR description
task-6116327 Forward-Port-Of: odoo/enterprise#127745
5 changes
Security fixes and vulnerability patches
Odoo Sign now prevents users from linking a signature request to records they are not allowed to view. This closes a data exposure gap where manually changing the linked record could reveal information from restricted records.
Original PR description
Version: saas-18.3 Reported issue: 1. Marc Demo creates a sign request from a template whose fields are automatically populated from the linked record. 2. It is sent to himself. He does not have…
Version: saas-18.3 Reported issue: 1. Marc Demo creates a sign request from a template whose fields are automatically populated from the linked record. 2. It is sent to himself. He does not have access to all records of a referenced model (e.g. Sales Orders). 3. The "Linked To" (reference_doc) field is edited afterwards to point to a record the signer does not have access to. By the time it's signed, the value of that record becomes visible - so a user can, simply by changing the linked record, see the value of a record they were never authorized to access. Even a Sign Manager could link a request to a record they have no access to and later see its value through it. Issue: `reference_doc` could be set or changed to any record of any allowed model with no validation that the acting user actually has access to it. In the interface, you can only create a signature request from a record you can see, but editing `reference_doc` manually (via write(), RPC, etc.) was not held to the same rule, making it an easy way to leak information about records outside your normal access. Cause: The only restriction was cosmetic, enforced client-side by the record picker widget filtering its search results. Nothing on the server validated the value being written to `reference_doc`. Fix: `write()` now checks that the acting user has read access to the target record before allowing `reference_doc` to be set, raising a ValidationError otherwise, bringing manual edits in line with what the interface already enforces when creating a request.
Resolved issues and error corrections
Annotated Deferred Revenue Reports can now be exported to XLSX without triggering a server error. This prevents disruption for accounting users who need to download reports that include notes or annotations.
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 Forward-Port-Of: odoo/enterprise#122768
This fix corrects an incorrect category value used when reporting Swiss withholding tax employee changes. It helps ensure payroll declarations are accepted and accurately reflect employee tax mutations.
Original PR description
task-6116327 Forward-Port-Of: odoo/enterprise#127745
This update prevents Swiss payroll settings from automatically applying a Swiss contract type to employees outside Switzerland. It helps avoid incorrect employee contract data and prevents related automated checks from failing.
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
Forward-Port-Of: odoo/enterprise#126507Acerta payroll exports for Belgian employees now include weekend days when certain leave periods, such as sick leave, overlap a weekend. This prevents missing leave information in reports and helps ensure payroll files match Acerta’s expected format.
Original PR description
## Steps to reproduce: - Install l10n_be_hr_payroll_acerta - Create an employee in a belgian company - Create a sick time off for the created employee that overlaps with a weekend - Export acerta report for the employee - Notice the weekend that overlaps with the time off is not present in the report ## Cause: While exporting the report file we only loop over the created work entries' dates and since weekends doesn't have work entries we don't consider them in the report. ## Fix: When generating the line of a leave's start date we check if the leave overlaps with a WE, we fetch the WE's date and we generate a line for each day of the WE. According to Acerta this is the correct behavior for their reports for specific types of leaves. **opw-6313534** Forward-Port-Of: odoo/enterprise#124500
20 changes
New functionality added to Odoo
Adds official Guatemala VAT book reporting for sales and purchases, helping companies prepare required period filings from FEL documents. The report includes legal PDF output and CSV export with document-level details and summaries for easier compliance review.
Original PR description
Guatemala requires two legal VAT books, the Libro de Ventas and the Libro de Compras y Servicios Recibidos, filed per period from the FEL documents. Add them as a single account.generic_tax_report variant with a Tax Type selector switching between the sales and the purchase book, so it sits alongside the standard tax report and matches the printed book layout. The detail engine produces one row per posted FEL document, reading the move lines with TableSQL rather than the ORM, which is too slow at book volumes; each document is split into goods vs services and taxable vs exempt, with the IVA and the combined specific taxes alongside, and a summary table aggregates them by bucket. The legal PDF opens on the SAT header, carrying the company identification and the reporting period, and closes on the document count, the total tax debit or credit and the summary table. A CSV export provides the flat data companion. task-6015093
This update adds Telnyx-based PBX capabilities to VoIP, including incoming call handling, phone ringing, user call forwarding, queues, and call groups. Businesses can route calls more flexibly and manage how calls are distributed or forwarded when users are busy or unavailable.
This update improves Odoo VoIP by adding early support for buying phone numbers and ringing phones through PBX integration, while also fixing issues with incoming calls, call groups, and phone number formatting. It should make business calling workflows more reliable and prepare the VoIP module for broader phone service capabilities.
Enhancements to existing features
This update improves Belgian payroll handling for Joint Committee 302 employees who are paid through tips. It adds the related payroll rules, employee and contract settings, warnings, reporting data, and validation coverage so payroll teams can process these cases more accurately.
Original PR description
Task: 6037567
VoIP calls now coordinate across open browser tabs so that when a call is answered or brought forward, other tabs automatically place their sessions on hold. This helps prevent overlapping calls or audio conflicts and makes the calling experience more reliable for users working with multiple tabs.
Original PR description
Put sessions on hold in other tabs when a call is accepted or promoted. The shared worker now tracks connected clients and assigns each tab a unique userAgentKey. When a session is promoted to front, the worker broadcasts HOLD_ALL_SESSIONS to every tab. The receiving tab ignores broadcasts matching its own userAgentKey. task-5973023
Payroll rules and related country-specific payroll modules were updated to remove an outdated paid amount setting. This simplifies payroll configuration and helps keep payslip calculations consistent across localizations.
Original PR description
task-6186326
Belgian payroll now avoids applying flat-rate withholding tax to double holiday pay and 13th month payslips when the employee's regular monthly tax situation indicates no tax is due. This helps prevent over-withholding in eligible cases while keeping the tax calculation aligned with normal payslip rules.
Original PR description
This commit adds an exemption that skips the flat-rate professional withholding tax on double holiday and 13th month payslips when two conditions both hold: no cumulated PP from regular monthly payslips this year, and the theoretical monthly tax on base salary plus 1/12 of the exceptional gross works out to zero. That theoretical tax is simulated the same way as a real monthly payslip, including the flat-rate professional fees and transport tax deductions, so it does not overstate what the employee actually owes. It also pulls the bareme bracket logic into its own method so both the standard and theoretical paths can share it. task-6322148
Belgian payroll cash register settings now appear when the selected employer category allows Joint Committee 302, instead of depending on whether an employee is already assigned to that committee. This makes the settings available earlier and keeps payroll configuration aligned with the employer category setup.
Original PR description
Cash register settings are currently displayed only when the company has an employee assigned to Joint Committee 302. This makes their availability depend on the employee configuration. The employer category already defines the allowed joint committees. Base the visibility on whether the selected category allows Joint Committee 302, making the settings available as soon as the relevant payroll configuration is selected. Task: 6395308
Users can still add appointment events to external calendars such as Google, Outlook, Apple, and iCal, but the responsibility is now handled by the Calendar app instead of Appointment. This centralizes the feature so calendar links can be reused more consistently across appointment-related communications.
Original PR description
Moving the possibility for users to add a calendar event to their iCal/Outlook/Apple or Google calendars from appointment to calendar. Task-6218949
Turkish payroll now calculates severance pay and provisions based on an employee's departure date and reason, rather than whether the employee record is archived. Several internal salary rule lines are hidden from display, and manual deduction/addition labels are renamed to clearer business terms.
Original PR description
- Severance Pay and Severance Provision now trigger on the employee's departure date and departure reason instead of the employee being archived. - Set visibility to NEVER for: Previous Months Gross, Previous Months Paid Tax, Gross From Net, SSI Company Contribution, SSI (unemployment) Company Contribution, Taxable Salary, Current Month Actual Deducted Tax (Pre Exempt), Expected Net Salary. - Rename Manual Deductions -> Other Deductions, Manual Additions -> Other Allowances. task-6459874
Resolved issues and error corrections
Planning overlap warnings are now hidden for tasks that are not linked to a project. This prevents users from seeing irrelevant alerts while creating private tasks and keeps scheduling feedback focused on project 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 Forward-Port-Of: odoo/enterprise#122222
Sales users can now view invoices that include Kenyan electronic invoicing codes without needing accounting access. This removes an unnecessary access error while keeping the information available only for standard internal users.
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#127443 Forward-Port-Of: odoo/enterprise#126825
The Helpdesk ticket quick create form in kanban view now has clearer spacing between the customer field and action buttons. This small visual fix makes the form easier to read and use when creating tickets quickly.
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
Users can now Ctrl-click a timesheet suggestion without accidentally opening a new browser window. The suggestion is added to the form as intended, reducing confusion and keeping timesheet entry smoother.
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#127230 Forward-Port-Of: odoo/enterprise#126240
Belgian payroll users can now generate 274.xx tax XML reports even when the accounting payroll add-on is not installed. The required SME exemption setting has been moved into the core Belgian payroll configuration, preventing an error and making the report available in more setups.
Original PR description
[FIX] l10n_be_hr_payroll: fix 274.xx xml generation (without accounting)
Bug reproduction:
1 - Install only l10n_be_hr_payroll (without accounting) 2 - Belgium company → create new employee
3 - Create payslip with employee validate it
4 - Payroll → Reporting → 274.XX → Generate XML
5 - Traceback about exemption_sme_status is there
Bug cause:
1 - Field exemption_sme_status is defined in l10n_be_hr_payroll_account
1.1 - It can be defined in l10n_be_hr_payroll instead
2 - When there is only l10n_be_hr_payroll installed
2.1 - It cannot find the mentioned field
Bug solution:
1 - Move field From l10n_be_hr_payroll_account to l10n_be_hr_payroll
task-6422367This fixes an issue where closing entries from German point-of-sale sessions were not being recorded in the Fiskaly portal. The certification module now uses the updated accounting validation process, helping ensure compliant register closures after sales sessions.
Original PR description
Steps to reproduce: =================== - In a Fiskaly-enabled German company, open a PoS session and make some transactions. - Close the register. Issue: ====== - The closing register entry is not registered in the Fiskaly portal. Cause: ====== - `l10n_de_pos_cert` calls the _validate_session method. - After the PoS accounting refactor, `_validate_session` was replaced by `_validate_session_accounting`. Fix: ==== - Update the method call to use `_validate_session_accounting`. task-6455319
Mexican payroll now clearly separates Integrated Daily Wage for severance from Base Contribution Salary for Social Security, reducing confusion and improving confidence in payroll results. The Social Security salary calculation now uses actual accrued days from the prior two-month period, excluding unpaid absences, to better align with Mexican legal requirements.
Original PR description
In Mexico, there are two distinct payroll concepts: * Integrated Daily Wage (SDI): used for severance pay (liquidations). * Base Contribution Salary (SBC): used for Social Security (IMSS).…
In Mexico, there are two distinct payroll concepts: * Integrated Daily Wage (SDI): used for severance pay (liquidations). * Base Contribution Salary (SBC): used for Social Security (IMSS). Previously, these concepts were used interchangeably in the code. While the calculations for IMSS were mathematically correct, they incorrectly referenced the Integrated Daily Wage. This naming inconsistency could cause users to lose confidence in the system's accuracy. All IMSS rule calculations now correctly reference the SBC concepts. Additionally, to ensure strict compliance with Article 34 of the Mexican Social Security Law (LSS): > The daily wage will be determined by dividing the total amount of variable earnings obtained in the previous bimester by the **number of accrued wage days**, and adding its result to the fixed elements of the daily salary. The calculation for the variable portion of the SBC is updated to reflect the actual accrued days of the previous bimester, excluding unpaid absences. target: master task-6374791
This fix ensures employee departures are handled after payslips are created, so payroll records stay in the right order. It also recomputes payslip history when new payslips are added, improving accuracy for Belgian and Omani payroll processes.
Original PR description
Departure should be generated after payslips Forward-Port-Of: odoo/enterprise#127171
Code cleanup and technical improvements
This cleanup removes redundant internal update handling in manufacturing work orders, Swiss payroll, and e-signature dialogs. It helps keep these screens aligned with the newer OWL framework approach while preserving existing behavior and reducing the risk of stale data in future updates.
Original PR description
Part of the OWL3 migration cleanup. Now that props are reactive, `this.props` always exposes the current values, so an `onWillUpdateProps` callback whose only job is to copy props into instance…
Part of the OWL3 migration cleanup. Now that props are reactive, `this.props` always exposes the current values, so an `onWillUpdateProps` callback whose only job is to copy props into instance fields or component state is redundant — a getter reading `this.props` directly is shorter and always up to date.
Companion PR (odoo): odoo/odoo#282185
### Why this is safe
Reactivity here does not depend on a component declaring `props = useProps(...)`. All four components use the legacy `static props = {...}` declaration, but they extend the `Component` patched by `web/static/src/owl2/owl3_compatibility_layer.js`, whose constructor does `this.props = owl.props(null)` — that builds a signal-backed props object and registers a `propsUpdated` callback keeping the signals in sync. So `this.props` is reactive in all of them.
### Per-module
**mrp_workorder** — `resModel`, `model` and `record` become getters over `this.props.record`.
**l10n_ch_hr_payroll** — `parsedData` (and the salary widget's `institution_domain`) were only ever written from props, with no other writer anywhere, so both `state` proxies disappear in favour of getters.
**sign** — `this.props = nextProps` was not merely redundant but actively harmful: it replaced the reactive, signal-backed props object with a plain snapshot, so every *later* props update silently stopped reaching the component. The `isShown` reset stays, because the template writes `state.isShown = false` on dismiss.
### Behaviour preserved deliberately
Two pre-existing oddities were left alone to keep this PR mechanical; both deserve their own fix:
- `mrp_display_record.js`: `this.quantityToProduce` and `this.displayUOM` are still computed once in `setup()`, so they do not track later record changes. Not covered by the removed hook either, so this is unchanged, not newly broken.
- `salary_result.xml` references `this.institution_domain` (lines 124/128, feeding `t-if="institution_domain == ...'` branches), but no such getter exists — it was only ever `this.state.institution_domain`. I kept the value local to `get parsedData()` rather than exposing a getter, since adding one would silently activate template branches that have never rendered.
### Verification
- eslint: no new errors on any of the four files (the 5 reported errors are pre-existing and identical on `master`, just shifted line numbers).
- No unit test coverage exists for these four components (mrp_workorder only has tours, which need a server), so this needs CI / a manual pass on the shopfloor view and the Swissdec widgets.
- Note: the enterprise pre-commit hook could not run in my environment (`eslint.config.mjs` imports `@eslint/compat`, which is not installed), so the commit was made with `--no-verify` after linting the files manually with `.eslintrc.json`.This update replaces an older internal naming pattern with the current standard across several Odoo Enterprise modules. It improves code consistency and helps prepare the platform for future framework updates, with no expected change for end users.
Original PR description
Replace deprecated props imports with the correctly named useProps hook to align with owl3 hook naming conventions. In owl3, hook functions should follow the use* naming pattern. However, props, plugin, and config were introduced without this convention, making it unclear that they are hooks. This creates confusion and inconsistent usage throughout the codebase, with some code using the old props while other code uses the correctly named useProps. While props is technically deprecated in owl and will eventually be removed, it was retained in Odoo due to widespread usage. This refactoring consolidates all usages to the correctly named useProps hook, ensuring consistency across the codebase and preparing for the eventual removal of the deprecated props function from owl.
16 changes
Enhancements to existing features
When a Bulgarian VAT return is validated, the system now automatically creates and attaches the required monthly SAF-T General Ledger, purchase, and sales report files alongside the PDF. This reduces manual work for large companies and helps them meet Bulgaria's monthly tax reporting requirements more reliably.
Original PR description
Bulgaria made it mandatory for large companies to present a monthly file
to report their VAT to the administration. To streamline that process,
when the VAT return is validated and PDF is added to the attachments,
the monthly General Ledger SAF-T file, the POKUPKI Purchase Report and
PRODAGBI Sale Report are produced and added as well.
Simplify the report file download error wizard's visuals and descriptions to improve readability.
task-6007963Resolved issues and error corrections
Studio approval rules can now be checked even when a sales user lacks access to accounting-related fields used in the rule. This prevents valid sales order confirmations from being blocked by an access error when approvals depend on related customer follow-up information.
Original PR description
continuation of [PR](https://github.com/odoo/enterprise/pull/121856) Issue: Inside _get_approval_spec filtered_domain is called a few times and due to a related field that calls an access rights group that the user who used the action isnt apart of is blocked by the filtered_domain. To Replicate: 1) Install studio, sale, Accounting and make sure "account_followup" is installed 2) create a related field on the sales.order form related to "customer -> follow up status" 3) Save 4) Create a "Studio Approval Rule" (studio.approval.rule) with a domain using the new related studio field -> method : "action_confirm" -> approver:admin 5)create a test user with no accounting access rights 6) in an incognito browser try and create a sales order, and then confirm it. it will throw the access rights error Solution: Go one up the stack where _get_approval_spec is called and add a syudo for those calls opw-6316069
Users with read-only accounting access can now see the General section in the Accounting tab on partner records. This restores access to expected bank account details for users who already have the proper permissions.
Original PR description
Problem: The General group of the Accounting tab of the partner form view is not visible to some users, even if they have the access rights to see it. Steps to reproduce: 1. Create a user or edit an existing one, giving them Accounting Read-Only access rights. 2. Log in with that user. 3. Go to Contacts and select a partner. 4. Open the Accounting tab 5. Notice how the General group (with the bank account details) is not visible. Cause: In the account_accountant module, the partner form view is inherited in one of the views to add additional groups to the General group of the Accounting tab. However, it doesn't add the new group, but instead replaces the existing groups with the new one. opw-6413683 Forward-Port-Of: odoo/enterprise#126679
This fix updates Belgian POS blackbox test setup so required dialog information is present. It prevents automated test crashes, helping keep validation runs reliable without changing business workflows.
Original PR description
This is a backport of https://github.com/odoo/enterprise/commit/f47930c28127662db4ce2a1e68dc2ed0b3486b87 ### Issue: During RunBot single module tests, some tests caused an error: `Maximum call stack…
This is a backport of https://github.com/odoo/enterprise/commit/f47930c28127662db4ce2a1e68dc2ed0b3486b87
### Issue:
During RunBot single module tests, some tests caused an error: `Maximum call stack size exceeded` after repeated: `[Owl] Unhandled error. Destroying the root component`
Affected tests:
- `sign_money_in_out.called at right time`
- `sign_drawer_open.called at right time`
- `sign_work_in.called when opening register, setting & resetting cashier`
- `sign_work_in_employee.called from login screen (closed session)`
### Cause:
The tests passed `dialogData: {}` to the component env But `dialogData` must at least define `scrollToOrigin`, which is called automatically in `onWillDestroy`:
https://github.com/odoo/odoo/blob/0042e83fb60353a49d4759a79a3ceb0eee6f74b6/addons/web/static/src/core/dialog/dialog.js#L122-L126
Calling `scrollToOrigin()` on an empty object raises a `TypeError`, which Owl catches and re-throws repeatedly until the call stack is exceeded
The full `dialogData` shape is defined in `makeDialogMockEnv`: https://github.com/odoo/odoo/blob/62c540d96fc49d9e74d8c660019754651cb0e085/addons/web/static/tests/_framework/env_test_helpers.js#L151-L161
### Steps to reproduce:
- Install `l10n_be_pos_blackbox` (fresh `-i`, or `-u` with `web` on an existing db)
- Run the tests in MobileWebSuite
Before the fix, the errors are triggered
runbot-941232A payroll-related automated test was updated to use a normal working day instead of a weekend date. This prevents false test failures and helps keep Belgian payroll validation checks stable without changing user-facing payroll behavior.
Original PR description
The test `test_float_holiday_attest` fails with a ValidationError: "The following employees are not supposed to work during that period". The previous patch (cf. PR odoo/enterprise#107490) froze time to "2026-02-01 08:00:00", which was a Sunday. When validating the leave created for `today`, check of the employee's calendar fails because zero working hours are scheduled on weekends. This commit updates `@freeze_time` to "2026-02-02 08:00:00" (Monday) so the leave validation runs against a valid working day. runbot-240132 runbot-241193
Australian payroll submissions to the ATO now check that required payslips or employees are present before sending. Instead of a system traceback, users receive a clear validation message, helping them correct incomplete Single Touch Payroll records.
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#127584 Forward-Port-Of: odoo/enterprise#124096
Global invoices for Mexican POS orders now ignore cancelled refunds, preventing invoice creation errors when a customer return was started but not completed. This helps ensure valid paid refunds are processed correctly without incorrectly reducing the original order twice.
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#127560 Forward-Port-Of: odoo/enterprise#120996
Fixed an issue that caused Deferred Revenue Report exports to fail when annotations were present. Users can now export annotated accounting reports to Excel 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 Forward-Port-Of: odoo/enterprise#122768
This fix removes an ambiguity in how Web Studio approval rule conditions are interpreted. Approval rules with empty conditions now correctly apply to all relevant records, preventing inconsistent approval behavior.
Original PR description
Before this commit, there was an ambiguity with the usage of filtered_domain ie ``` self.assertTrue(record.filtered_domain(False)) self.assertFalse(record.filtered_domain(Domain(False))) ``` This is because in that case the API of filtered_domain was not respected After this commit, there is no ambiguity as we cast to a Domain the value we obtain from the rule: - False or None: all records should be impacted by the rule => Domain(True) - otherwise, let the domain do its job opw-6431607
The Sign Documents wizard now keeps the Employee role selectable when users choose multiple signature templates that use separately created roles with the same name. This prevents signature requests from being blocked when combining templates such as contracts and policies.
Original PR description
Problem: When selecting several sign templates with different signatory counts in the "Sign documents" wizard (e.g. a Contract template together with a Computer Policy template), the Employee Role…
Problem: When selecting several sign templates with different signatory counts in the "Sign documents" wizard (e.g. a Contract template together with a Computer Policy template), the Employee Role field would empty out or disappear entirely, with "No records" shown in the dropdown. This blocked users from sending the signature request at all. Purpose: `_compute_responsible_ids` matched roles across the selected templates by recordset identity (`&=`), i.e. by database id. Since the Sign Template Builder allows free-text role creation, two templates can end up with roles that are visually/semantically identical (same name, e.g. "Employee") but were created as separate `sign.item.role` records with different ids. The id-based intersection then evaluated to an empty recordset, which made the Employee Role field's domain empty and the field itself collapse in the UI. This fix matches roles by name instead of by id when computing the common roles across selected templates, and resolves the correct per-template role id by name in `validate_signature` instead of reusing a single id across every template. Steps to Reproduce On Runbot: 1. Go to Sign > Templates and create two templates, each with one role named "Employee", added independently (so they end up as two distinct sign.item.role records with the same name). 2. Go to an employee's Contract, click "Sign Documents". 3. Select both templates in "Documents to sign". 4. Observe the Employee Role field empties out / shows no records, and the request cannot be sent. opw-6445327
Swiss payroll now counts flexible employee absences using the dates selected in the time off request, avoiding an extra day caused by timezone conversion. This prevents one-day accident leave from being prorated as two days, helping keep regular wage and accident salary amounts accurate.
Original PR description
Issue: Swiss payslips count one extra absence day for employees without a working schedule. A one day accident leave can therefore be prorated as two days, reducing the regular wage and overstating…
Issue: Swiss payslips count one extra absence day for employees without a working schedule. A one day accident leave can therefore be prorated as two days, reducing the regular wage and overstating the accident salary. Steps to reproduce: * Install Swiss Payroll. * Configure a monthly employee without a working schedule. * Assign one day of accident time off. * Generate the payslip for that month. Cause: The Swiss wage computation derives absence boundaries from the date portion of the leave's UTC datetimes: https://github.com/odoo/enterprise/blob/16c29e1bab34b5bcb2b001477d928ec5eb294a97/l10n_ch_hr_payroll/models/hr_payslip.py#L313-L330 A fully flexible employee's full day leave starts at local midnight. In timezones ahead of UTC, that start is stored on the previous UTC date, so the inclusive calendar day computation adds an extra day. Solution: We need to use the requested time off dates for both payslip range filtering and absence proration. These fields preserve the calendar days selected by the user independently of timezone conversion, while leaving the UTC datetimes and half-day handling unchanged. opw-6435086
Payroll settings now only show Mexico-specific CFDI options when the selected company is based in Mexico. This prevents irrelevant configuration fields from appearing for companies in other countries and reduces setup confusion.
Original PR description
Steps to reproduce: 1. Switch to a non-Mexican company. 2. Go to Payroll > Configuration > Settings. 3. The CFDI settings block is visible. Reason: The CFDI block was missing a country check. Solution: Restrict the CFDI block visibility to Mexican companies. Task-6448440
Fixes a mobile Documents issue where the Info & Tags panel could appear enabled but remain hidden or inaccessible after reloads, view switches, previews, or selection changes. This keeps document details and chatter actions available in the correct state, reducing confusion for mobile users.
Original PR description
**Steps to reproduce:** - Go to Documents app in mobile - Go to the kanban view - Add some files and select one - Click on `Info & Tags` button in the control panel - Reload the page - Chatter is not…
**Steps to reproduce:** - Go to Documents app in mobile - Go to the kanban view - Add some files and select one - Click on `Info & Tags` button in the control panel - Reload the page - Chatter is not displayed but the button is still enabled - Switching to the list view properly shows it **Issue:** Original fix (see [1]) was not enough for every case. Additional issues: - Chatter hidden on init even when its panel has `visible = true` - State desynchronized with the view when switching menu type (kanban/list) or by previewing a document and coming back - When using the button with an open preview, chatter shows up in the background but is not accessible (and going back discards it) - Removing selection with an open chatter disable the related action **Fix:** - Disable the chatter on mobile init by default to avoid having to manually move it back - Reset chatter on selection removal to avoid getting stuck in the menu - Reset chatter on view switch to avoid being in the wrong state afterwards (and revert the previous css changes) Not a great fix (quite mobile-specific) and there might still be some edge cases. [1] original fix: https://github.com/odoo/enterprise/commit/cf3c2fce8a6b7b2d7547d44a0e4423f887986d52 opw-6061993
Return labels generated through Sendcloud no longer print the customer's house number twice. This makes return shipping labels clearer and helps avoid confusion or delivery issues for customers and carriers.
Original PR description
Issue ----- On return labels, the house number of the origin address (so the customer) is printed twice. Steps to reproduce ----- - Setup sendcloud - Select a return service - Enable "Generate Return Label" - Create a delivery using sendcloud - Validate the delviery > The return label has the house number printed twice Cause ----- For the origin address shown on labels, Sendcloud prints both the address line and the house number. There doesn't seem to be any parsing made on the address line to extract the house number. For the WH -> Customer label, the "from" address is taken directly from the Sendcloud account's configuration. For the Customer -> WH return, we provide it in the `from_` fields of the request. Note that, when including the house number on the address line in Sendcloud, the issue is also present. ----- Ticket: opw-6405054
Large accounting reports now render fewer hidden lines, reducing page weight and improving responsiveness when users fold sections or search. This helps teams work more smoothly with reports containing thousands of lines until the newer virtual grid technology is available.
Original PR description
When a report has 1 000+ lines, the DOM gets quite heavy which make DOM operation very slow. To help reduce this, we now will minimize the number of components rendered by removing components that previous were just hidden using "d-none" on the line. This will require more creation and suppression of components but it should make the DOM size smaller so it should help on larger reports where a lot of lines are hidden (by folding back a line, or by using the search bar). opw-6427411 opw-6442756 PR Note: this is only required until saas-19.5/20.0 since the virtual grids are added then which will resolve this issue since the virtual grids only render what's in the view of the user with long paddings on top and bottom so only ~70-80 lines are actually rendered.
This fix corrects an incorrect enumeration used in Swiss withholding tax mutation reporting. It helps ensure payroll declarations use the expected values, reducing the risk of reporting errors for Swiss payroll users.
Original PR description
task-6116327 Forward-Port-Of: odoo/enterprise#127745
8 changes
Resolved issues and error corrections
The general ledger CSV export now keeps account and transaction lines in the same order, even when multiple companies use the same account codes. This prevents export failures and helps users reliably download reports.
Original PR description
Description of the issue this commit addresses: Account and move lines can be returned in different orders when account codes are shared across companies. The CSV generator can then exhaust its account iterator and raise StopIteration. --- Desired behavior after this commit is merged: This commit orders move lines using the account sequence returned by the report, keeping both CSV iterators aligned. --- runbot-[242131](https://runbot.odoo.com/odoo/error/242131)
Odoo now recognizes valid Brazilian electronic invoice XML files even when the main invoice tag has no attributes. This prevents legitimate vendor bills from being skipped during import, reducing manual rework for Brazilian accounting users.
Original PR description
### Issue before this commit: Certain valid Brazilian NF-e (electronic invoice) XML files fail to import because the system silently ignores them during the initial EDI recognition phase. ### Steps to reproduce the issue: 1. Download Accounting and l10n_br_edi 2. Go to Vendor > Bills 3. Try to import both xmls in the ticket 4. One of the two will not be imported correctly ### Cause of the issue: https://github.com/odoo/enterprise/blob/3ed1721b702555e96c9774969927f6517e855704/l10n_br_edi/models/account_move.py#L819-L827 This function relies on a strict byte string search for b"<NFe " while it's also correct if the tag is only `<NFe>`. ### Reason to introduce the fix: To make the initial NF-e file recognition more robust and compliant with standard XML namespace rules, ensuring Odoo successfully processes all valid Brazilian invoices regardless of attribute formatting. opw-6402843
Luxembourg payroll now calculates historical payslips using the wage index that applied at the payslip period, rather than the current index. This helps ensure past salary calculations remain accurate when wage index rates change over time.
Original PR description
Historical payslips incorrectly used today's wage index instead of the index active during the payslip period. Now, salary rules evaluate the indexed wage using `payslip.date_to` via the new `_get_l10n_lu_indexed_wage(date)` contract method. Task: 6395557
This fixes an incorrect classification used when reporting Swiss withholding tax employee changes. The correction helps ensure payroll mutation data is transmitted accurately to Swissdec, reducing the risk of rejected or misleading declarations.
Original PR description
task-6116327 Forward-Port-Of: odoo/enterprise#127745
Mexican invoices paid within the required short payment window are now correctly treated as PUE and blocked from being sent to CFDI/SAT payment reporting. This prevents incorrect XML submissions, especially when grouped payments involve multiple invoices.
Original PR description
Issue: Sending PUE invoices to CFDI/SAT is no more suitable Step to reproduce: - In a Mexican company - Create an invoice (Invoice A) - Add a line - Set Payment Terms to "Immediate payment" - Confirm…
Issue: Sending PUE invoices to CFDI/SAT is no more suitable Step to reproduce: - In a Mexican company - Create an invoice (Invoice A) - Add a line - Set Payment Terms to "Immediate payment" - Confirm - Duplicate (Invoice B) - Confirm - Duplicate again (Invoice C) - Set Payment Terms to "30 days" - Confirm - Go to Invoice A - Pay it. It should appear as "Paid" - Send it to CFDI - Go to Accounting > Customer > Invoices - Select Invoice B and C - Pay and select the "Group Payments". They should appear as paid. - In every invoice, click the "Update Payment" button Current behavior: - In Invoice A -> Sheet CFDI: A button "Force CFDI" allow sending the invoice to CFDI - In Invoice B/C -> sheet CFDI: Click on the "Download" part of the Payment line, the XML that was sent to CFDI include both invoice B and C Expected behavior: - It shouldn't be possible to send invoice A to CFDI. - Invoice B shouldn't be sent to CFDI Cause: Invoice paid in less than 30 days as referred as PUE and shouldn't be sent to CFDI. opw-5381600
The Edit option on website appointment records now opens the correct appointment form from the kanban view. This removes a dead-end in the website appointment management flow and helps users update appointment pages without switching views manually.
Original PR description
Steps to reproduce: 1. Install website_appointment 2. Website > site > appointment > kanban view 3. On a record, open the dropdown menu and click Edit. Issue: The Edit button does nothing. Cause: The Website appointment pages action only defines list,kanban views. When the kanban Edit action is triggered, the web client tries to switch to a form view, but no form view is available in the action, so nothing happens. Solution: Add the `appointment_type_view_form` to the Website appointment pages action and include form in its view_mode, so kanban Edit can open the selected appointment type correctly. opw-6197438
This fixes an issue where installing Swiss payroll features could assign a Swiss contract type to employees outside Switzerland. The correction prevents incorrect default contract information and avoids related automated test failures.
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
Forward-Port-Of: odoo/enterprise#126507Project Forecast no longer shows the Time Management section in project settings unless the Timesheets app is installed. This prevents users from seeing irrelevant settings and keeps project configuration clearer.
Original PR description
**Steps to reproduce:** - Install the project_forecast module. - Go to Projects -> Open the settings of any project (create one if none exist) -> Settings. - You will see the Time Management section. **Issue:** The project_forecast module was forcefully setting the invisible attribute of group_time_managment to 0. This caused the group to remain visible at all times, even when the Timesheets app was not installed. **Fix:** Remove the forced attribute setting from the project_view. The visibility is already properly managed by the hr_timesheet module, and project_forecast does not depend on timesheet_grid or hr_timesheet. **Merge Till - SaaS-19.1 only, then from SaaS-19.2 : https://github.com/odoo/enterprise/pull/121454** task-6195716 Forward-Port-Of: odoo/enterprise#121565
7 changes
New functionality added to Odoo
A new FedEx-certified delivery module has been added to align Odoo shipping workflows with FedEx certification requirements. This helps businesses using FedEx meet required integration guidelines and continue processing shipments through the updated FedEx API.
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
Enhancements to existing features
The Dutch payroll module now includes the 2026 income tax rates for residents. This helps payroll calculations stay aligned with upcoming tax requirements and supports accurate employee payslips.
Original PR description
Added 2026 values for the residents' income tax rates rule parameter. task-6462877
General Ledger Excel exports now group accounts into smarter batches instead of processing each account separately. This reduces export time for companies with large accounting datasets while keeping memory usage under control.
Original PR description
### Description of the issue/feature this PR addresses: This PR optimizes the XLSX export process for large accounting reports by implementing a "smarter" batching strategy. Three months ago, a…
### Description of the issue/feature this PR addresses: This PR optimizes the XLSX export process for large accounting reports by implementing a "smarter" batching strategy. Three months ago, a batching mechanism was introduced to prevent memory errors during large exports. However, that implementation batched every single account individually. While this solved the memory consumption issue, it introduced a significant performance regression: processing thousands of tiny batches one-by-one is extremely slow due to the overhead of repeated report engine calls. This change introduces a weighted batching system that groups multiple accounts together into a single batch until a maximum line threshold is reached. This strikes an ideal balance between low memory usage and high execution speed. ### Current behavior before PR: The system uses _get_accounts_with_move_lines to retrieve a list of accounts. The export logic iterates through every account individually, creating a separate batch for each one. For reports with many accounts (even those with few moves), the overhead of calling the report engine for every single account causes the export to take an excessive amount of time. Memory usage is low, but time performance is poor. ### Desired behavior after PR is merged: The new _get_account_ids_and_weights_with_move_lines method fetches both the account IDs and the count of moves (weight) associated with them in a single SQL query. The _build_account_batches method packs accounts sequentially into batches of up to 500,000 lines. Small accounts are grouped together. Large "mega-accounts" that exceed the limit are isolated into their own batches to prevent memory spikes. _get_accounts_with_move_lines is deprecated. It is effectively superseded by the more informative weighted query, providing the data necessary for the smarter partition logic. ### Benchmarks | # Move Lines | Before | After | | --- |---|---| | ~5.6million | Times Out | 32sec | | ~3.5million| Times Out | 11sec | ### References #103329 opw-6077972 opw-5723374 opw-5950806 opw-5915227 opw-6066290 opw-5914983 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
Project Forecast no longer shows the Time Management section unless the Timesheets app is installed. This avoids confusing users with settings that are not relevant or available in their setup.
Original PR description
**Steps to reproduce:** - Install the project_forecast module. - Go to Projects -> Open the settings of any project (create one if none exist) -> Settings. - You will see the Time Management section. **Issue:** The project_forecast module was forcefully setting the invisible attribute of group_time_managment to 0. This caused the group to remain visible at all times, even when the Timesheets app was not installed. **Fix:** Remove the forced attribute setting from the project_view. The visibility is already properly managed by the hr_timesheet module, and project_forecast does not depend on timesheet_grid or hr_timesheet. **Merge Till - SaaS-19.1 only, then from SaaS-19.2 : https://github.com/odoo/enterprise/pull/121454** task-6195716
Shipments that require a commercial invoice now explicitly request it from DHL, instead of only sending invoice details in the shipment data. This helps ensure the needed customs invoice is generated for affected DHL deliveries, reducing manual follow-up and shipping delays.
Original PR description
When `_should_generate_commercial_invoice` is True, we add the invoice data to the payload, but we never request this commercial invoice. opw-6357101
This fix corrects an incorrect category value used in Swiss withholding tax mutation reporting. It helps ensure payroll transmissions use the expected official classification, reducing the risk of rejected or inaccurate declarations.
Original PR description
task-6116327
Manufacturing orders now close as expected after users confirm a consumption warning in the shop floor flow. This prevents completed work from remaining visible and reduces confusion for production teams.
Original PR description
When confirming a consumption warning wizard, the MO will not close Steps to reproduce: ------------------- * Create a Product A, Product B * Create a BOM for Product A: - One Component B used during an Operation * Create, confirm and plan a MO for Product A * Start the Operation and go to shopfloor from the smartlink * Set the Quantity of Component B used to 2. * Mark as Done the Operation * Close operation and confirm the consumption warning wizard. -> The Mo is still visible. Observation: ------------- Why the fix: ------------ opw-6449118