Daily updates from Odoo
Wednesday, June 25, 2025
27 changes · master
Enhancements to existing features
This update standardizes how HR-related features define and apply filtering rules behind the scenes. It helps keep payroll, attendance, appraisal, contract salary, and planning workflows consistent and easier to maintain without changing day-to-day user behavior.
Original PR description
odoo/odoo#206645
Appointment and Helpdesk website pages now use a clearer heading structure. This helps search engines and accessibility tools better understand the content, supporting improved discoverability and user experience.
Original PR description
*: website_helpdesk Refactored enterprise modules templates to use a consistent and semantically correct heading structure (h1, h2 etc.). This improves SEO.
This change streamlines an internal accounting report test by preparing accounting entries once during setup instead of repeatedly switching them back and forth for each report. It reduces unnecessary test work and should make the test suite faster without changing business functionality.
Original PR description
In `test_balance_sheet_balanced`, during the balance test the case first sets a bunch of lines to `posted`, then sets them (back?) to `draft`. However this is done per report, even though in the default mode the amls involved don't change between reports. Not only that, but since f2100c2654a068fe197025aecc605fdada3a919a each CoA's test case is within a savepoint, so the AMLs get reverted implicitly. Hence rejigger the thing to activate the relevant AMLs while setting up localization if not in `IDENTIFY_INCORRECT_ACCOUNTS` mode, that way we don't even pay for the activation, let alone do so repeatedly for each report we test.
Email and SMS templates now rely on the main customer's language automatically instead of showing technical language expressions. This makes template setup clearer for users while preserving the same customer-language behavior across affected business flows.
Original PR description
This PR streamlines mail templates by removing redundant `lang` assignments when the language matches the main partner's. Specifically, it eliminates calls such as `object._mail_get_customer().lang` and `object.partner_id.lang` when they are unnecessary. By unsetting these values, the form view will now display the new placeholder "Main partner's language" in the `lang` field for those records. This change provides a clearer and more user-friendly alternative to technical inline expressions. See: odoo/odoo#189743 task-4365019
Resolved issues and error corrections
This fix updates several business modules to use the current file conversion setting after an older option was deprecated. It helps keep appraisal, marketing automation, CRM marketing, and product classification features compatible with platform changes and reduces the risk of future errors.
The spreadsheet edition test coverage was adjusted to reflect the corrected handling of empty labels in global filters. This helps ensure future updates preserve the expected spreadsheet behavior and reduces the risk of regressions.
Original PR description
Task: 4876003
Features or functions removed from Odoo
`hr_contract` was merged into `hr` in https://github.com/odoo/enterprise/pull/83136
Original PR description
`hr_contract` was merged into `hr` in https://github.com/odoo/enterprise/pull/83136
Code cleanup and technical improvements
This update reorganizes shared HTML formatting helpers so several apps use the common web foundation instead of maintaining separate copies. The change is internal, reducing duplication and helping keep AI chat, VoIP, barcode, and live chat behavior consistent without changing day-to-day workflows.
Original PR description
Enterprise counter-part. https://github.com/odoo/odoo/pull/215145
The salary package setup experience was converted to Odoo’s newer interaction framework across core, payroll, and Belgian localization modules. This is mainly an internal modernization that should preserve existing behavior while making the feature easier to maintain and extend.
Original PR description
Changed hr_contract_salary of - hr_contract_salary - hr_contract_salary_payroll - l10n_be_hr_contract_salary modules, following refactoring Refacto in the continuity of the PublicWidget to Interaction conversion task-4367641
Miscellaneous changes
Before this commit, the payrunId prop definition said it is a required prop and an integer. However, that property is not really required. This commit changes the property definition to make that property optional. runbot-error-226806 Forward-Port-Of: odoo/enterprise#88328
Original PR description
Before this commit, the payrunId prop definition said it is a required prop and an integer. However, that property is not really required. This commit changes the property definition to make that property optional. runbot-error-226806 Forward-Port-Of: odoo/enterprise#88328
Forward-Port-Of: odoo/enterprise#88471
Original PR description
Forward-Port-Of: odoo/enterprise#88471
Since 5f001cbf0ea5e382f00602e3307ffd1fc2eb5bf1, it was possible to save a global filter with an empty label, which is not intended. This commit restore the previous behavior by preventing the saving of a global filter with an empty label. Task: 4876003 Forward-Port-Of: odoo/enterprise#88403 Forward-Port-Of: odoo/enterprise#87847
Original PR description
Since 5f001cbf0ea5e382f00602e3307ffd1fc2eb5bf1, it was possible to save a global filter with an empty label, which is not intended. This commit restore the previous behavior by preventing the saving of a global filter with an empty label. Task: 4876003 Forward-Port-Of: odoo/enterprise#88403 Forward-Port-Of: odoo/enterprise#87847
The current code of `_recompute_shifts_in_leave_periods` explicitely calls the compute method `_compute_allocated_hours` of planning.slot to recompute the allocated hours according to modifications done to the public holidays. Calling the method directly like that is far from ideal as we are missing proper batching, fields protection, etc.. that the ORM usually does for computed fields. This commit replaces the explicit call by an `add_to_compute`. This essentially marks the field as "to be r
Original PR description
The current code of `_recompute_shifts_in_leave_periods` explicitely calls the compute method `_compute_allocated_hours` of planning.slot to recompute the allocated hours according to modifications…
The current code of `_recompute_shifts_in_leave_periods` explicitely calls the compute method `_compute_allocated_hours` of planning.slot to recompute the allocated hours according to modifications done to the public holidays. Calling the method directly like that is far from ideal as we are missing proper batching, fields protection, etc.. that the ORM usually does for computed fields. This commit replaces the explicit call by an `add_to_compute`. This essentially marks the field as "to be recomputed". This recomputation then happens at the next flush_model/recompute_model call and can applies the proper ORM optimizations of batching by `PREFETCH_MAX` size, protecting fields to avoid triggering loops of recomputations. This speeds up the import of new Public Holidays in an already populated database. #### speedup In a customer database with 50K planning.slots, 1300 of which needs to recompute their allocated_hours, the import timing Before PR vs After PR is the following: - 40 min -> 4 min opw-4782452 Forward-Port-Of: odoo/enterprise#88351
Currently when using Fiskaly, the receipt gets printed with the technical names of the tss values. Steps to reproduce: ------------------- * Set up the db to use fiskaly * Open restaurant * Place and pay an order > Observation: On the receipt screen the name of the tss values are shown as: transaction_number, signature_algorithm, client_serial_number, .... Why the fix: ------------ Beore this commit https://github.com/odoo/enterprise/commit/d1a94147060083da54f9423f8c379676fbb7db66#
Original PR description
Currently when using Fiskaly, the receipt gets printed with the technical names of the tss values. Steps to reproduce: ------------------- * Set up the db to use fiskaly * Open restaurant * Place and…
Currently when using Fiskaly, the receipt gets printed with the technical names of the tss values. Steps to reproduce: ------------------- * Set up the db to use fiskaly * Open restaurant * Place and pay an order > Observation: On the receipt screen the name of the tss values are shown as: transaction_number, signature_algorithm, client_serial_number, .... Why the fix: ------------ Beore this commit https://github.com/odoo/enterprise/commit/d1a94147060083da54f9423f8c379676fbb7db66#diff-960ffa6839618d084dd5de6e29458ef68766a31250fc7d296512ec5358f04056 we were using a dictionnary `name, value` when using tss information, cf `_initTssInformation()` in `l10n_de_pos_cert/static/src/overrides/models/models.js`. We re-introduce this behavior and revert the following commit https://github.com/odoo-dev/enterprise/commit/9f75e3fe092bd838fffb11a35a8d854afff71869 to use the official names instead of the technical ones. opw-4822342 Forward-Port-Of: odoo/enterprise#88179 Forward-Port-Of: odoo/enterprise#87717
UI-wise, there are two types of VoIP errors: blocking and non-blocking. Blocking errors are unrecoverable, they're displayed at the top of the UI and prevent further use of the softphone. Non-blocking errors, on the other hand, can be dismissed by a simple click on the error screen. Problem: the handler that hides the error screen in case of non-blocking errors wasn't attached to anything, and even if it was, its implementation was wrong! This commit makes it work as intended. Part of [tas
Original PR description
UI-wise, there are two types of VoIP errors: blocking and non-blocking. Blocking errors are unrecoverable, they're displayed at the top of the UI and prevent further use of the softphone. Non-blocking errors, on the other hand, can be dismissed by a simple click on the error screen. Problem: the handler that hides the error screen in case of non-blocking errors wasn't attached to anything, and even if it was, its implementation was wrong! This commit makes it work as intended. Part of [task-4891947](https://www.odoo.com/odoo/project/5778/tasks/4891947). Forward-Port-Of: odoo/enterprise#88358
**Issue:** - In sale order, first select the quotation template with a recurring plan, then, change the quotation template to without a recurring plan. After changing the quotation template, the 'Recurring Plan' (`plan_id`) field still shows the value from the previously selected template. This happens because the `plan_id` is not reset when the new template has no recurring plan. - In version 17, this case was handled in the else part and set [default value](https://github.com/odoo/enterp
Original PR description
**Issue:** - In sale order, first select the quotation template with a recurring plan, then, change the quotation template to without a recurring plan. After changing the quotation template, the…
**Issue:** - In sale order, first select the quotation template with a recurring plan, then, change the quotation template to without a recurring plan. After changing the quotation template, the 'Recurring Plan' (`plan_id`) field still shows the value from the previously selected template. This happens because the `plan_id` is not reset when the new template has no recurring plan. - In version 17, this case was handled in the else part and set [default value](https://github.com/odoo/enterprise/blob/17.0/sale_subscription/models/sale_order.py#L490) (company_id.subscription_default_plan_id), but in version 18.0, the field was [removed](https://github.com/odoo/enterprise/pull/55355/files). **Steps to reproduce:** - Install the Sales and Subscriptions modules. - Create two quotation templates — one with a recurring plan and one without. - Create a Sale Order and first select the quotation template 'with a recurring plan'. - Then, change the quotation template to 'without a recurring plan'. **Solution:** - Reset `plan_id` to `None` before computing the new value to ensure accurate computation. If the selected quotation template has a recurring plan, it will be assigned; otherwise, the plan_id field will remain empty. **Runbot v18.0 (without fix)**   OPW: [4845478](https://www.odoo.com/odoo/70/tasks/4845478) Forward-Port-Of: odoo/enterprise#87821
We adapt a studio test to the changes brought by https://github.com/odoo/odoo/pull/215437. Forward-Port-Of: odoo/enterprise#88281
Original PR description
We adapt a studio test to the changes brought by https://github.com/odoo/odoo/pull/215437. Forward-Port-Of: odoo/enterprise#88281
### Steps to reproduce: - Create 2 storable products: Product A, Product B - Create a control point pass/fail control by quantity on receipt and set both products on it. - Create and confirm a receipt with 2 moves: - 2 x Product A - 2 x Product B - Click on the "Quality Check" button and mark one unit of Product A as failed. > This should open the QC for product B. - Close the QC for prodcut B wihtout setting it as failed or passed. - Click on the "Quality Check" button ####
Original PR description
### Steps to reproduce: - Create 2 storable products: Product A, Product B - Create a control point pass/fail control by quantity on receipt and set both products on it. - Create and confirm a…
### Steps to reproduce:
- Create 2 storable products: Product A, Product B
- Create a control point pass/fail control by quantity on receipt and set both products on it.
- Create and confirm a receipt with 2 moves:
- 2 x Product A
- 2 x Product B
- Click on the "Quality Check" button and mark one unit of Product A as failed.
> This should open the QC for product B.
- Close the QC for prodcut B wihtout setting it as failed or passed.
- Click on the "Quality Check" button
#### > Nothing happends
### Expected behavior:
The QC for product B should open.
### Cause of the issue:
When the quality check is marked as failed, the related move is picked: https://github.com/odoo/enterprise/blob/679c81924e05e7544eecfdb960c9ed9611e9cdd5/quality_control/models/quality.py#L438-L451 However, the move for your second porduct is not and hence, its product is not considered to be checkable by the `check_quality` action: https://github.com/odoo/enterprise/blob/679c81924e05e7544eecfdb960c9ed9611e9cdd5/quality_control/models/stock_picking.py#L61-L69
Since these lines were added in c83728f3a7f1504b272f4ef97e4187868338adb3 to not bypass the QC of the unpicked move at validation we should probably only add that filtering condition in that case and continue to consider the unchecked moves as checkable prior to validation.
opw-4765075
Forward-Port-Of: odoo/enterprise#84743### Issue: The tour test_add_component_from_shop_foor_in_multi_step_manufacturing makes an assert on the value of an input before waiting for this input to be updated. runbot-build-error-226734 Forward-Port-Of: odoo/enterprise#88241
Original PR description
### Issue: The tour test_add_component_from_shop_foor_in_multi_step_manufacturing makes an assert on the value of an input before waiting for this input to be updated. runbot-build-error-226734 Forward-Port-Of: odoo/enterprise#88241
Case 1: How to reproduce ================ - Select a record in any folder in Kanban view - Display its chatter - Add an activity from the kanban tile --> the chatter is not updated and needs a refresh Expected behavior ================= Chatter should update instantly Case 2: How to reproduce ================ - Select a record in any folder in Kanban view - Display its chatter - Mark done or cancel one or more activities from Chatter - Click on the activity button of the r
Original PR description
Case 1: How to reproduce ================ - Select a record in any folder in Kanban view - Display its chatter - Add an activity from the kanban tile --> the chatter is not updated and needs a refresh Expected behavior ================= Chatter should update instantly Case 2: How to reproduce ================ - Select a record in any folder in Kanban view - Display its chatter - Mark done or cancel one or more activities from Chatter - Click on the activity button of the related kanban record --> stack trace Expected behavior ================= Corresponding KanbanRecord should update. Note: v. 17.4 raises a missing record exception for the same case task-4690165 Forward-Port-Of: odoo/enterprise#87422 Forward-Port-Of: odoo/enterprise#84128
To reproduce the issue, on a Belgian company: 1) Create and post an entry impacting line "Other Appropriations of the Year", typically by using an account prefixed 69 in it. 2) Enable totals below sections in the settings 3) Open the Belgian BS at a date including the move created in 1). 4) Enable 'unfold all' in the report ===> "Other Appropriations of the Year" displays no amount This happens because this line is considered as having sublines by the engine (has_sublines is Tr
Original PR description
To reproduce the issue, on a Belgian company: 1) Create and post an entry impacting line "Other Appropriations of the Year", typically by using an account prefixed 69 in it. 2) Enable totals below…
To reproduce the issue, on a Belgian company: 1) Create and post an entry impacting line "Other Appropriations of the Year", typically by using an account prefixed 69 in it. 2) Enable totals below sections in the settings 3) Open the Belgian BS at a date including the move created in 1). 4) Enable 'unfold all' in the report ===> "Other Appropriations of the Year" displays no amount This happens because this line is considered as having sublines by the engine (has_sublines is True), since it considered a non-zero number of move lines in its computation. The condition that was there before makes it so that in that case, when using unfold_all, the line would have the 'unfolded' key set to True, even though, here, the line has no means of generating any subline (no child lines, nor groupby value). Therefore, the "totals below sections" feature hid the amount of the line, since it was supposed to be displayed in the total line. The total line, however was never added, since no expand function was ever called. Note that we could avoid doing 'groupby or has_children' in the condition here, to only use 'has_children'. We do that because that's the former behavior, and some engines (custom or standard) don't return any value for has_sublines in some cases, relying on the presence of the groupby field to properly trigger the unfold. This has changed a little in 18.1, with the introduction of a custom engine for the Trial Balance. We'll see what can be done when forward-porting, and if it's not possible, will probably do something in master later on. has_sublines should probably be mandatory everywhere. opw-4640606 Forward-Port-Of: odoo/enterprise#88359
This mostly benefits `test_balance_sheet_balanced` as it mass activates reports on every `_set_up_localization` (so before rendering each report, something it does ~200 times). Forward-Port-Of: odoo/enterprise#88115
Original PR description
This mostly benefits `test_balance_sheet_balanced` as it mass activates reports on every `_set_up_localization` (so before rendering each report, something it does ~200 times). Forward-Port-Of: odoo/enterprise#88115
The default_get method of the 'l10n_uk.hmrc.send.wizard' model assumed the presence of 'client_data' in the context, leading to a KeyError during test_display_name_new_record. This fix checks for the presence of 'client_data' before attempting to call import_vat_obligations. If 'client_data' is not present, it avoids calling import_vat_obligations and raises a UserError, thus preventing the KeyError. build_error-115767 Forward-Port-Of: odoo/enterprise#88297 Forward-Port-Of: odoo/enter
Original PR description
The default_get method of the 'l10n_uk.hmrc.send.wizard' model assumed the presence of 'client_data' in the context, leading to a KeyError during test_display_name_new_record. This fix checks for the presence of 'client_data' before attempting to call import_vat_obligations. If 'client_data' is not present, it avoids calling import_vat_obligations and raises a UserError, thus preventing the KeyError. build_error-115767 Forward-Port-Of: odoo/enterprise#88297 Forward-Port-Of: odoo/enterprise#84327
Before, with some errors in the regex search in the different statement line attributes, the search would just return 0, when the regex was just badly written, without giving any hint to the user. Now the method will raise an user error telling the user that the regex is badly written instead of returning 0.0 or a traceback (AttributeError was not handled). Examples of previously failing regexes: - "([^\d]*)" -> AttributeError - [\d,]* -> IndexError (was already handled by https://github.co
Original PR description
Before, with some errors in the regex search in the different statement line attributes, the search would just return 0, when the regex was just badly written, without giving any hint to the user. Now the method will raise an user error telling the user that the regex is badly written instead of returning 0.0 or a traceback (AttributeError was not handled). Examples of previously failing regexes: - "([^\d]*)" -> AttributeError - [\d,]* -> IndexError (was already handled by https://github.com/odoo/enterprise/pull/84284) - ValueError shouldn't arise anymore with that same PR, but better safe than sorry Forward-Port-Of: odoo/enterprise#85881
Before, a fix was done to round column for materials and payments columns but the method was HALF-UP. This should always be DOWN as specified here https://assets.publishing.service.gov.uk/media/5d53df0040f0b6098ead46c2/cis-qsbvr-v2.2.pdf page 28 task-4881298 Forward-Port-Of: odoo/enterprise#88018
Original PR description
Before, a fix was done to round column for materials and payments columns but the method was HALF-UP. This should always be DOWN as specified here https://assets.publishing.service.gov.uk/media/5d53df0040f0b6098ead46c2/cis-qsbvr-v2.2.pdf page 28 task-4881298 Forward-Port-Of: odoo/enterprise#88018
Community: https://github.com/odoo/odoo/pull/208609 Design Themes: https://github.com/odoo/design-themes/pull/1059 Forward-Port-Of: odoo/enterprise#84782
Original PR description
Community: https://github.com/odoo/odoo/pull/208609 Design Themes: https://github.com/odoo/design-themes/pull/1059 Forward-Port-Of: odoo/enterprise#84782
Currently, an error occurs when finding duplicate transactions in the bank. Steps to Reproduce: - Install the `accountant` module. - In `Accounting Dashboard`, click on `Bank`. - In Actions, click `Find Duplicate Transactions`. - Clear the `Starting Date` field and click save. `TypeError: unsupported operand type(s) for -: 'bool' and 'relativedelta'` This error occurs when the system attempts to find duplicate transactions without a Starting Date. When finding duplicate transa
Original PR description
Currently, an error occurs when finding duplicate transactions in the bank. Steps to Reproduce: - Install the `accountant` module. - In `Accounting Dashboard`, click on `Bank`. - In Actions, click…
Currently, an error occurs when finding duplicate transactions in the bank. Steps to Reproduce: - Install the `accountant` module. - In `Accounting Dashboard`, click on `Bank`. - In Actions, click `Find Duplicate Transactions`. - Clear the `Starting Date` field and click save. `TypeError: unsupported operand type(s) for -: 'bool' and 'relativedelta'` This error occurs when the system attempts to find duplicate transactions without a Starting Date. When finding duplicate transactions, it tries to calculate the `prior_date` using `date_from - relativedelta(months=3)` [1]. However, since `date_from` is `False`, this raises an error. [1] https://github.com/odoo/enterprise/blob/acdba5ecf89ee8920f82e07e16fac2a0f9659b12/account_online_synchronization/models/account_journal.py#L314 This commit ensures that if the Starting Date is empty when finding duplicate transactions, it uses today’s date as the Starting Date. sentry-6653835511 Forward-Port-Of: odoo/enterprise#87000