Friday, August 21, 2026
34 changes · 19.0
Enhancements to existing features
Job listings now limit available working schedules based on the company linked to the job. This helps recruiters keep job postings consistent and prevents selecting schedules that do not apply to the relevant company.
Original PR description
In order to maintain proper job listings and make sure all working schedules are valid, working schedule domain is now depeding on the job listing company. Task: 6408914 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Guadeloupe, Martinique, and Reunion are now treated like mainland France when automatically selecting the electronic invoicing address. This helps businesses in those regions use the correct PDP/Peppol setup without manual correction.
Original PR description
In France, some drom-com (Guadeloupe, Martinique and Réunion) needs to use pdp just like France. So we should add those 3 for the computation of `peppol_eas`, so it will autocomplete to **France FRCTC Electronic Address**. task-6344558 Forward-Port-Of: odoo/odoo#282995 Forward-Port-Of: odoo/odoo#278272
Time off administrators can now see and adjust whether each time off type creates a Calendar entry. This makes the existing setting easier to manage and helps teams control when leave requests appear in calendars.
Original PR description
The `create_calendar_meeting` field on `hr.leave.type` allows users to choose if leave requests created with a given time off type generate a corresponding entry in the Calendar app. However, this field was not displayed on the form view. This commit adds `create_calendar_meeting` to the `hr.leave.type` form view inside the configuration section, along with dedicated help text explaining its behavior. Task: 6445794 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283450
General Ledger reports can now include the invoice date when a report column is configured for it. This gives finance teams more context directly in ledger exports and views, reducing the need to cross-check invoices separately.
Original PR description
If a column is added with `expression_label` equal to `invoice_date`, include that in results of `_report_custom_engine_general_ledger`. task-5917897
Job listings now show only working schedules that match the listing's company. This helps recruitment teams keep job postings accurate and avoid selecting schedules that are not valid for that company.
Original PR description
In order to maintain proper job listings and make sure all working schedules are valid, working schedule domain is now depeding on the job listing company. Task: 6408914
Resolved issues and error corrections
This fix ensures the online shop only responds to the intended product option inputs when customers choose variants. It prevents unrelated fields from being picked up by mistake, reducing the chance of confusing or incorrect behavior during product selection.
Original PR description
The selector was matching unrelated inputs because it wasn't specific enough.
Documentation and clarification updates
ERPVibe Limited has signed Odoo's Corporate Contributor License Agreement. This records the legal permission needed for the company to contribute code or documentation to Odoo under the project’s contribution terms.
Original PR description
ERPVibe Limited signs the Odoo Corporate Contributor License Agreement v1.0.
Fixes an issue that could block users from setting a bank statement line back to draft. The change ensures the accounting action returns the expected response format, preventing an unexpected error during this workflow.
Original PR description
Problem: An error occurs when trying to set a bank statement line to draft. Cause: The method button_draft() in account_move.py returns True, when it should return an action dict or None. Returning True causes a type error because clean_action gets called on a boolean value, when an action dict is expected. https://github.com/odoo/odoo/blob/61298b0cacda099c902350d64ec79baeecda42db/addons/web/controllers/action.py#L59 https://github.com/odoo/odoo/blob/61298b0cacda099c902350d64ec79baeecda42db/addons/web/controllers/utils.py#L24 This throws an error because setdefault is called on a boolean value, when it should be called on a dict. opw-6443116
The website blog test now starts the page builder in the right mode before loading blog snippet options. This prevents intermittent missing snippet options during automated checks, improving reliability without changing what users see.
Original PR description
The blog post dynamic snippet options tour needs debug mode because the dynamic snippet belongs to the Debug snippet group. The tour used to put `debug=1`in the preview iframe path, while the initial website preview client action was opened without debug. This meant `request.session.debug` was only updated once the iframe request was handled. If the snippet template was rendered before that request, QWeb used the empty session debug value and omitted the Debug snippet group. After this commit, we open the preview action directly in edit and debug mode from the Python test instead, so the first server request sets `request.session.debug` before the website builder loads the snippets.
This fix makes website page caching behave consistently when cached content expires. It helps prevent rare website errors caused by storing an incomplete refreshed response in the cache.
Original PR description
**Problem:** Normally, the cached response for an HTTP request will be 'flattened', meaning the QWEB template is force-rendered and stored as `response.response[0]`. However, when the cached response is too old, a new cache value is set which is not flattened. This is inconsistent with the value normally returned by `_get_response_cached()` which will cause a traceback when accessing `response.response[0]`. This issue is rarely reproducible because `flatten()` is usually called on the response later (outside `_get_response()`), and because the returned response points to the same object as in the cache, the cache gets flattened as well. **Solution:** When the cached response is too old, flatten the new response before caching it. opw-6382359
This fix improves how tables copied from Google Docs are pasted into Odoo's editor. Extra header rows are converted into normal table rows so the table displays and behaves consistently with the editor's supported format.
Original PR description
Steps to Reproduce - Copy a table with multiple header rows from Google Docs. - Paste the table into the editor. Description of the issue: - The pasted table contains multiple header rows, but the editor supports only the first row as the table header row. Cause: - During paste, `cleanForPaste` does not handle tables with multiple header rows - As a result, header cells (`<th>`) in rows other than the first row remain as header cells instead of being converted to normal table cells (`<td>`). Solution: - Update `cleanForPaste` to handle tables with multiple header rows. - If a table contains `<th>` elements in any row other than the first row, replace those `<th>` elements with `<td>` elements. - This ensures that only the first row is treated as the table header row. task-6455248
This fix prevents Accounting payment terms from crashing when a user enters zero or negative days in an end-of-month due term. Instead, the system can continue to show the proper validation message, making setup errors easier to correct.
Original PR description
Steps to reproduce: - Install `Accounting` module - Payment Terms > Create NEW - Add a new Due Term line with "Days end of month on the" and a negative amount of days(eg: -1) Traceback: `ValueError: day is out of range for month` When `days_next_month` is set to a negative value, it is passed directly to `relativedelta` as the 'day' value. Since a negative value is not a valid day of the month, the due-date computation raises a `ValueError`. Use the end of the month for the calculation when `days_next_month` is non-positive. This prevents the traceback while computing the payment term and allows the proper validation error to be raised when the record is saved. opw-6453640 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Peppol invoice XML now uses the reference from the invoice contact when it is available, instead of incorrectly taking the parent company reference. This helps ensure e-invoices identify the correct buyer contact and reduces validation or processing issues for customers with multiple contacts.
Original PR description
**Steps to reproduce:**
* Set up a French company and configure Peppol E-invoicing.
* Install `account_edi_ubl_cii` module.
* Create a company partner (customer) and set a **Reference** value on the company contact under
**Customer** -> **Settings** -> **Sales and Purchase**.
* Create a child contact under that company and set a different Reference value.
* Create an invoice using the child contact as the invoice partner and confirm the invoice.
* Send it via Peppol.
**Observed Behaviour:**
* The BuyerReference in the generated XML contains the reference of the parent
(commercial partner) Instead of the child contact used on the invoice.
**Cause:**
* The buyer reference was taken from the commercial partner instead of the
invoice partner.
**Fix:**
* Update the condition to use the invoice partner's reference when available;
Otherwise, fall back on the commercial partner's reference.
opw - 6330649
Forward-Port-Of: odoo/odoo#273700This fixes an issue that could prevent Odoo from finding the correct previous sales order line for a customer when timesheet-related task data included certain list-based filters. The change helps keep sales and timesheet workflows reliable without changing how users interact with the system.
Original PR description
- Avoid converting list values in `_get_last_sol_of_customer_domain` to an invalid domain structure when computing the last sale order line of a customer. - Fix by using `str(domain)` as the cache key instead of the domain itself, while still passing the original `domain` to `search()`. This keeps the per-domain caching behavior intact and works for any domain, regardless of whether it contains list values. task-6425335 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When a journal cannot be archived because draft entries still exist, Odoo now points users to the correct Journal Entries list where those drafts can be found and handled. The journal form button is also renamed to avoid confusion between journal entries and journal items.
Original PR description
> Replaces https://github.com/odoo/odoo/pull/282286, which GitHub closed automatically after a bad force-push on my side: the branch was pushed from a shallow clone and its head lost its parent…
> Replaces https://github.com/odoo/odoo/pull/282286, which GitHub closed automatically after a bad force-push on my side: the branch was pushed from a shallow clone and its head lost its parent commit, leaving no common ancestor with 18.0. A PR in that state cannot be reopened, so this one continues from a clean branch with the exact same change. The review discussion is in that PR, and the rename asked for there is included here. ### Steps to reproduce 1. Go to `Accounting > Customers > Invoices` and create an invoice on a given journal, leaving it in draft. For the clearest case, leave it with no invoice line. 2. Go to `Accounting > Configuration > Journals`, open that journal and archive it. 3. `_check_auto_post_draft_entries` raises: *"You can not archive a journal containing draft journal entries. To proceed: 1/ click on the top-right button 'Journal Entries' from this journal form 2/ then filter on 'Draft' entries 3/ select them all and post or delete them through the action menu"*. 4. Follow those steps: click the `Journal Entries` smart button on the journal form. ### Current behaviour The list comes up empty, so the user concludes the error message is wrong, while the draft entries do exist. The instructions cannot be followed: - The smart button opens `action_account_moves_all_a`, which is named **"Journal Items"** and targets **`account.move.line`**, not `account.move`. The label of the button and the name of the action it opens do not match. - That action defaults to `search_default_posted: 1`, so no draft record is listed. - Draft entries with **no line at all** — commonly created through the incoming mail alias of a journal — have no `account.move.line`, so they stay invisible in that view even after switching the filter. - The action menu of a move line list offers no way to post or delete the entries, and the action sets `create: 0`. - The filter is labelled **"Unposted"**, not "Draft". The offending entries are only reachable through `Accounting > Accounting > Journal Entries`, filtering by journal and by "Unposted". ### Expected behaviour The error should point to a view where the records blocking the archiving are actually listed and actionable. ### This PR Two changes, the validation itself is unchanged: - The error message now points to `Accounting > Accounting > Journal Entries` and uses the real filter name, "Unposted". - The smart button of the journal form is renamed to **"Journal Items"**, so its label matches the action it opens and no longer suggests it lists journal entries. This was asked for in the review of the previous PR. Targeted at 18.0 because that is where the misleading message is being hit in practice; it is identical on 19.0 and master. If a translatable string change does not qualify for the stable series, tell me and I will retarget to master. Forward-Port-Of: odoo/odoo#282956
This fixes signup flows so the required signup type is always set before creating a signup token. It helps prevent account invitation or signup links from failing due to missing setup data.
Original PR description
A `signup_type` is required to generate a token. Task-6452339 Forward-Port-Of: odoo/odoo#280891
Sales email templates now use separate full sentences for quotations and orders, instead of inserting those words into one shared phrase. This lets translators adapt grammar correctly in languages where the surrounding words change, improving the quality of customer-facing emails.
Original PR description
The quotation and pro forma email templates inserted either "quotation" or "order" into shared translatable text. In French, for example, "devis" is masculine while "commande" is feminine, so the surrounding articles and adjectives cannot agree with both terms. Define a complete sentence for each document state so translators can translate the surrounding grammar independently. opw-6445304
The HTML editor now keeps text background colors when users turn colored paragraphs into lists or convert list items back to normal text. This prevents formatting from unexpectedly disappearing while editing content, making list formatting more reliable.
Original PR description
Problem: Background color was lost both when converting text with a background color into a list item and when converting a list item with a background color back into a paragraph. Cause: - `insertListAfter` only copied `color` from the font wrapper to `li.style.color`, ignoring `background-color`. - Unwrapping a list item (`ListPlugin`) extracted `color`, `font-size`, and `text-align`, but ignored `backgroundColor`. Solution: - Preserve `background-color` from font wrapper onto `li.style.backgroundColor` when creating a list. - Restore `li.style.backgroundColor` onto a `<font>` wrapper when unwrapping a list item. Steps to reproduce: - Apply background color to a paragraph and toggle list -> background color is lost. - Apply background color to a list item and toggle list off -> background color is lost. opw-6481665 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The Sales app now shows clearer and grammatically correct help text for the Expiration field on sales orders. This improves user understanding when setting or reviewing quotation expiration dates, without changing any business process or functionality.
Original PR description
Steps to produce: --- - Install the Sales module. - Create a new Sales Order. - Hover over the `Expiration` field. Issue: --- - The help text of the Expiration field contains a grammatical error and the overall sentence is slightly awkward. Improve the help text to make it grammatically correct and more natural. opw-6481226 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283187
This fix ensures Odoo closes read-only replica database connections using the correct replica settings. It prevents unused connections from staying open when replica database details differ from the main database, helping keep database resources under control.
Original PR description
close_db matched readonly connections against the primary DSN. When db_replica_* differs, those connections were left open. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282671
Regular sales users can now see the three-dot menu on product cards in the Product Catalog, matching the access they already have elsewhere. This removes an unnecessary administrator-only restriction and helps sales teams manage product-related actions without needing elevated permissions.
Original PR description
**Steps to Reproduce:** 1. Give the logged in user "Sales / User: Own Documents Only" access rights 2. Open the Product Catalog (from a Sales Order line) 3. The three-dot menu on a product card is not visible when you hover over it 4. Change user rights with "Sales Administrator" access rights, the three-dot menu appears as expected **Issue:** The three-dot menu on the Product Catalog kanban card is restricted to the Sales Administrator group, even though the actions it exposes (edit product, availability, etc) are already accessible to regular Sales users through other menus/views. **Why this happens:** The view `product.view.kanban.catalog.inherit.sale` sets the `groups` attribute to `sales_team.group_sale_manager`, restricting the menu behind Administrator rights instead of the base Sales access group opw-6416629 Forward-Port-Of: odoo/odoo#279400
Fixed an issue where clicking the cashier status icon could trigger an error in Point of Sale setups using Belgium Blackbox without employee login. This prevents an unexpected interruption during cashier session use and keeps the interface stable for affected configurations.
Original PR description
Steps: ----------- - Install pos_blackbox_be. - Configure a PoS with Blackbox Belgium enabled and `Log in with Employees` disabled. - Open a PoS session and click exactly on the session status circle on the cashier icon. Issue: ----------- - A traceback is raised with the following error: `this.cashierSelector is not a function`. Cause: ----------- - Installing pos_blackbox_be makes the cashier icon appear clickable by adding the `pe-auto` class to the cashier icon's session status circle, even when `Log in with Employees` is disabled. In this configuration, the cashier selector is unavailable, causing the click handler to fail. Fix: ----------- - Add a dedicated onClick handler to the CashierName button. - Return early when `module_pos_hr` is not enabled before calling `selectCashier`, ensuring that `selectCashier` is called only when the `module_pos_hr` configuration is enabled. Task-6369404 Forward-Port-Of: odoo/odoo#282656
Point of Sale now automatically selects a product option when there is only one available choice and no multiple selection is needed. This removes an unnecessary step for cashiers and helps products with simple variants be added to orders smoothly.
Original PR description
Before this commit: ----------- - When a product attribute had only one available value, it was not automatically selected for display types other than multi. After this commit: ------------ - Automatically select the attribute value when an attribute has a single available value and its display type is not multi, allowing the product to be added without any additional user interaction. Task-6327371 Forward-Port-Of: odoo/odoo#282036 Forward-Port-Of: odoo/odoo#272437
Appointment-related placeholders now choose a readable field name by default instead of an internal ID when possible. This makes generated content clearer for users while still allowing the ID to be selected when needed.
Original PR description
Before this commit: when clicking a field having sub fields (canFollowRelationFor is true), we just return this field's id, which is not very useful in most cases. After this commit: We created subclass of DynamicPlaceholderPopover, EditorDynamicPlaceholderPopover, which uses EditorModelFieldSelectorPopover. We use the display name of the followable field by default and if the user really want the id, they may choose the id subfield. We also show the followable field's name as the default placeholder instead of "Display name". task-6265223
A test that checks the online purchase flow for rental planning products has been temporarily turned off. This avoids false failures while the rental planning flow is still changing, with the intent to re-enable coverage once the process is finalized.
Original PR description
Given the rapid changes in spec for `{website_}sale_renting_planning` it doesn't make sense to fix the tour only for the flow to break right away after. Therefore, the tour is temporarily disabled until the flow of the module(s) is finalized.
task-6389324This fix updates Indian Payroll settings so EPF Employee IDs are validated against the correct official format. It prevents users from entering an outdated longer ID format and clarifies the expected value in the setup guidance.
Original PR description
Steps to reproduce: - Install Indian localization, and use an Indian company - Go to Settings under Payroll > Indian Localization - Tick the "Employee Provident Fund (EPF)" - Insert a EPF Employee ID Issue: The "valid" format is not correct: XX/XXX/1234567/000/1234567 with the first series of 7 numbers having a flexible range from 1 to 7. The first series of 7 numbers must always equal to 7 (it represents the establishment ID), and the last series of number should be dropped as it represents the employee's unique PF account number. Solution: - Modify the constraint for the variable: - Remove last 7 trailing digits from the constraint. - Make the length of the first series of 7 digits strictly equal to 7. - Update placeholder value and help info. Task: 6482315
SEPA direct debit payment files now include the required scheme name information for the initiating party. This helps ensure payments are accepted by banks that require this field, such as Nordea in Sweden.
Original PR description
We are missing a SchmeNm node in the InitgPty node. This is mandatory for Nordea in Sweden at least. Such as: ```xml <SchmeNm> <Cd>CUST</Cd> </SchmeNm> ``` task-6385960 Forward-Port-Of: odoo/enterprise#124693
Users can now update rental start or end dates on sales orders even if they do not have direct access to planning entries. The related planning slots are still updated automatically, reducing errors and keeping rental schedules aligned.
Original PR description
This commit prevents a potential access error, if a user changes the rental start date and/or end date of a sale order without the access rights to the 'planning.slot' model. In this case, we want the write to be executed and changes repercuted to the associated slots.
Project sales views now correctly include rental orders when users open the Sales button from a project. This keeps the list of orders consistent with the displayed sales count and avoids confusion for teams managing both standard sales and rentals.
Original PR description
Steps to Reproduce --- 1. Install sale_renting_project. 2. Create a Project linked to 1 standard Sales Order and 1 Rental Order. 3. Observe the "Sales" stat button counts 2 Sales. 4. Click the stat button. Only the standard Sales Order is displayed. Issue --- In saas-18.4, the project Sales stat button calls action_view_sos without the from_embedded_action context key. As a result, _get_sale_orders_domain applies the non-rental filter by default, causing rental orders to be excluded from the action even though they are included in the displayed counter. Expected Behavior --- The Sales stat button should display all orders linked to the project, including both standard and rental orders, matching its total counter. Fix --- Return the base project domain unmodified when from_embedded_action is not set in the context. task-6140201 Forward-Port-Of: odoo/enterprise#121449
Swiss payroll payment files now include the beneficiary name when using Revolut-related bank payment formats. This helps banks process salary payments more reliably and reduces the risk of rejected or delayed transfers.
Original PR description
Forward-Port-Of: odoo/enterprise#126632
Opening spreadsheet version history now uses the correct type of database request from the start. This avoids an unnecessary retry when contributor information is updated, making the history view more reliable and efficient for users.
Original PR description
The get_spreadsheet_history method is marked as readonly, causing RPC requests to use a read-only transaction. However, retrieving the metadata of a document spreadsheet updates its spreadsheet contributors. Opening the version history consequently attempts an UPDATE in a read-only transaction and forces the request to be retried with a read-write cursor. Remove the readonly decorator so the request uses a read-write cursor directly. Task-6176364 Forward-Port-Of: odoo/enterprise#126626
Restores the missing preview image for the AI livechat website snippet. This ensures the livechat option displays correctly in the website builder before it is installed, avoiding confusion for users setting up their site.
Original PR description
Problem: 1) The preview image of the livechat snippet was removed in this [commit][1] and wasn't replaced with another image. As a result, the uninstalled livechat snippet doesn't display properly in the website builder. Solutions: 1) An image has been added `ai_livechat.png` which is shown on preview Note: This fix will change in master to be up to date with current website snippet previews. The location will be moved to `snippet_previews` and the file type will be changed to `.webp` [1]: https://github.com/odoo/enterprise/commit/df05441e469157890253b5550b5f8735723b28fb Task-5248712
Split PDF pages now appear in a predictable order in Documents instead of being randomly arranged when created at the same time. This makes reviewing and managing uploaded multi-page PDFs clearer and reduces confusion for users.
Original PR description
steps: - upload a multi-page pdf - split all the pages -> they now show in a random order The issue is that the current documents are sorted by create_date desc, but the split creates all the different documents at the same time so they are sorted in the order they happen to be on the disk. We now add a sort by id to act as a tie-breaker. opw-6176840 Forward-Port-Of: odoo/enterprise#127433 Forward-Port-Of: odoo/enterprise#117255
This fix updates a Peru electronic invoicing test so it works consistently across environments using different versions of a number-to-words library. It prevents false test failures caused by an accent difference, improving reliability without changing customer-facing behavior.
Original PR description
### Issue: `test_invoice_down_payment_with_withholding_tax` fails on RunBot when using `num2words==0.5.10` (Python < 3.12) The expected XML contains `DIECISÉIS` but older versions of `num2words` generate `DIECISEIS` without the accent ### Cause: The accent on `DIECISÉIS` was added in `num2words` PR #443, between versions `0.5.10` and `0.5.13` RunBot uses different versions depending on the Python version: `num2words==0.5.10` for Python < 3.12 (Jammy / Bookworm) `num2words==0.5.13` for Python >= 3.12 ### Steps to reproduce: - Run the test with `num2words==0.5.10` Before the fix, the test fails on the `cbc:Note` comparison runbot-945461 Forward-Port-Of: odoo/enterprise#127356