Friday, September 4, 2026
282 changes · master
Security fixes and vulnerability patches
Restaurants can now choose a Dynamic QR mode for table self-ordering, where staff generate a unique QR code for each meal instead of leaving a reusable table QR available. This helps prevent former guests or anyone with an old link from viewing, changing, or paying for an active table order, while existing table QR setups continue to work as before.
Original PR description
..., point_of_sale, pos_restaurant, pos_loyalty, pos_sale, l10n_id_pos, l10n_in_pos, pos_safaricom, pos_bancontact_pay, pos_online_payment, pos_online_payment_self_order, obox_pos_self_order --- When…
..., point_of_sale, pos_restaurant, pos_loyalty, pos_sale, l10n_id_pos, l10n_in_pos, pos_safaricom, pos_bancontact_pay, pos_online_payment, pos_online_payment_self_order, obox_pos_self_order --- When a self-order config is set to service mode "Table" with "Pay after" set to "Meal", the QR code printed on the table stays valid for as long as the meal lasts. Anyone who knows that URL - not just the customers currently seated there - can open it and view or edit the order tied to that table, even after those customers have left. There is no way to tell, from the URL alone, whether the person opening it is still at the table. To fix this, this introduces a new self-ordering service mode, "Dynamic QR", as an alternative to "Table" for restaurants that want this guarantee. Selecting it automatically sets "Pay after" to "Meal", since the whole point of this mode is a tab that stays open for the length of the meal. With "Dynamic QR" active, the self-order app is inactive for that table by default - there's nothing to scan on the table itself. Instead, once staff open an order for the table at the register, they can generate a QR code for that specific order from the POS screen. Scanning it is the only way to load that order in the self-order app. The QR can be shown on the customer-facing display or printed on a paper receipt, so it can be handed to the table. Anyone without that QR simply sees a message asking them to get one from staff - browsing the menu, seeing the order, or paying isn't possible without it. Existing "Table" configs are unaffected by this - they keep working the same way as before, QR-code-on-the-table included. This is an additional, opt-in mode for restaurants that specifically want this tighter guarantee. Along the way, this also simplifies how a payment integration pushes a QR code to the customer-facing display - previously each integration had to fetch that method from the POS and manually check whether it existed before calling it; the base point_of_sale API now standard. --- Task: https://www.odoo.com/odoo/project/1737/tasks/6381129
Restaurants can now choose a Dynamic QR mode for pay-after-meal table orders, where staff generate a QR code for each specific meal instead of leaving a permanent table QR available. This helps ensure only current diners with the issued QR can view, edit, or pay for their order, while existing table QR setups continue to work unchanged.
Signing certificates now clearly show when a document was signed through a shared public link without email verification, helping businesses understand the level of assurance behind a signature. The update also improves privacy and security by discarding sent signature request emails and strengthening protection for signing links against timing-based attacks.
Original PR description
### [IMP] Sign: Tell on the Certificate When a Document Was Signed via Shared Link A document shared through a public link can be signed by anyone who has access to that link, without email…
### [IMP] Sign: Tell on the Certificate When a Document Was Signed via Shared Link A document shared through a public link can be signed by anyone who has access to that link, without email verification. Previously, the certificate of completion did not clearly indicate this and could even display an email verification column that was not applicable to shared-link signers. The certificate now explicitly states when: - The document was signed via a shared link. - The signature was not verified by email. - Anyone with access to the link could sign the document. ### [IMP] Sign: Delete Signature Request Emails Once Sent Signature request emails contain private signing links for recipients. Keeping copies of these emails could expose those links through the mail application. Signature request emails are now automatically discarded after they have been sent successfully. ### [FIX] Sign: Compare Sign Access Tokens in Constant Time Public signing routes are protected solely by the access tokens embedded in their URLs. Previously, token validation used a standard equality comparison, which could leak information through response timing differences. An attacker could potentially exploit this behavior to recover a valid token and gain unauthorized access to another user's document. Access tokens are now compared using a constant-time comparison method to mitigate timing attacks. **Task:** `task-6196852`
This update reduces exposure of sensitive technical error details in web responses while keeping full information available in server logs for troubleshooting. It also makes internal server signaling utilities reusable for new infrastructure services, supporting future platform work.
Original PR description
* [IMP] core: suppress_debug_traceback() * [MOV] core: make pipe_ping and co public Forward-Port-Of: odoo/odoo#285728
New functionality added to Odoo
This update makes VoIP administration more flexible by allowing key provider settings to be edited when infrastructure changes. It also adds QR-code based Linphone setup for users, making mobile softphone onboarding faster while keeping access controlled through short-lived signed links.
Enhancements to existing features
Withholding tax residual amounts can now be used more reliably in search filters and automated rules. This makes it easier for teams to find and act on accounting entries based on remaining withholding balances.
Original PR description
This PR adds a `_compute_sql` on `withholding_residual_amount_currency` so that it can be used in domains. task-6182154 Enterprise PR - https://github.com/odoo/enterprise/pull/130274
Resolved issues and error corrections
Portal navigation breadcrumbs were standardized across several customer-facing pages, including the quotes page. This makes the portal experience more consistent and easier for customers to navigate.
Original PR description
Breadcrumbs were added to most portal pages [here][1]. This commit adds breadcrumbs to `/my/quotes` and fixes UI issues to ensure all portal pages with breadcrumbs look the same. [1]: https://github.com/odoo/odoo/commit/123d5876900a73f674a2286e891b2e442f63d93c task-6365169
Features or functions removed from Odoo
This change removes several Odoo modules and related files that had previously been deleted but reappeared unexpectedly. It helps keep the product codebase clean and avoids maintaining unsupported or obsolete functionality.
Original PR description
They got resurrected through foul play and unnatural means, lay them to rest.
Code cleanup and technical improvements
The change centralizes what happens when someone leaves a Discuss or Live Chat channel, making the process more consistent and easier to maintain. It also improves efficiency when handling bounced messages and keeps existing user-facing leave notifications working as expected.
Original PR description
*=im_livechat. - Remove discuss.channel._action_unfollow and call self_member_id.unlink() from action_unfollow, flagging the voluntary leave with a context sentinel so that only that flow posts the leave message - Post the leave message, notify the bus and unsubscribe the partner from an @api.ondelete hook on discuss.channel.member, so that none of it runs when mail is uninstalled - Keep the sub-channel member cleanup in unlink(), skipping the search entirely on an empty recordset - Move the livechat end-date handling to an @api.ondelete hook on discuss.channel.member - Unsubscribe bouncing partners with a single search in _message_receive_bounce instead of one unfollow call per partner - Updated the discuss channel tests to go through action_unfollow task-4715497 https://github.com/odoo/enterprise/pull/121613
Documentation and clarification updates
BWEALTHICS LLC and Alejandro Fernandez have signed Odoo's contributor license agreements. This documents the legal permission needed for their covered contribution to be accepted into the project.
Original PR description
Signs the Odoo Individual and Corporate Contributor License Agreements v1.0, following the procedure in `doc/cla/sign-cla.md`. * `doc/cla/individual/bwealthics.md` for Alejandro Fernandez * `doc/cla/corporate/bwealthics.md` for BWEALTHICS LLC, whose list of contributors currently holds a single entry The email in both files is the git committer email on the contribution this covers, #285503.
Original PR description
..., point_of_sale, pos_restaurant, pos_loyalty, pos_sale, l10n_id_pos, l10n_in_pos, pos_safaricom, pos_bancontact_pay, pos_online_payment, pos_online_payment_self_order, obox_pos_self_order --- When…
..., point_of_sale, pos_restaurant, pos_loyalty, pos_sale, l10n_id_pos, l10n_in_pos, pos_safaricom, pos_bancontact_pay, pos_online_payment, pos_online_payment_self_order, obox_pos_self_order --- When a self-order config is set to service mode "Table" with "Pay after" set to "Meal", the QR code printed on the table stays valid for as long as the meal lasts. Anyone who knows that URL - not just the customers currently seated there - can open it and view or edit the order tied to that table, even after those customers have left. There is no way to tell, from the URL alone, whether the person opening it is still at the table. To fix this, this introduces a new self-ordering service mode, "Dynamic QR", as an alternative to "Table" for restaurants that want this guarantee. Selecting it automatically sets "Pay after" to "Meal", since the whole point of this mode is a tab that stays open for the length of the meal. With "Dynamic QR" active, the self-order app is inactive for that table by default - there's nothing to scan on the table itself. Instead, once staff open an order for the table at the register, they can generate a QR code for that specific order from the POS screen. Scanning it is the only way to load that order in the self-order app. The QR can be shown on the customer-facing display or printed on a paper receipt, so it can be handed to the table. Anyone without that QR simply sees a message asking them to get one from staff - browsing the menu, seeing the order, or paying isn't possible without it. Existing "Table" configs are unaffected by this - they keep working the same way as before, QR-code-on-the-table included. This is an additional, opt-in mode for restaurants that specifically want this tighter guarantee. Along the way, this also simplifies how a payment integration pushes a QR code to the customer-facing display - previously each integration had to fetch that method from the POS and manually check whether it existed before calling it; the base point_of_sale API now standard. --- Task: https://www.odoo.com/odoo/project/1737/tasks/6381129
Website editors can now showcase blog posts and upcoming events in dynamic carousel layouts, making content-heavy pages easier to browse without taking up too much space. The update also reuses shared filtering logic so future changes are easier to maintain across similar snippets.
Original PR description
### [IMP] website, website_blog, *: add dynamic blog posts carousel snippet *: website_sale This PR adds a new "Blog Posts Carousel" snippet that displays blog posts in a paginated carousel layout,…
### [IMP] website, website_blog, *: add dynamic blog posts carousel snippet *: website_sale This PR adds a new "Blog Posts Carousel" snippet that displays blog posts in a paginated carousel layout, showing multiple posts per slide. This fills a gap where the existing grid/list snippets were the only options, making it difficult to showcase many posts compactly without overwhelming the page. How to use: 1. Enter Edit mode 2. Click on Blogs 3. Select the one with "Dynamic Carousel" label The search domain logic (filtering by blog ID) is extracted into a BlogPostsMixin so it is shared between the existing BlogPosts and the new BlogPostsCarousel interaction, keeping future domain changes in one place. The .carousel-item vertical padding rule is moved from s_dynamic_snippet_products to s_dynamic_snippet_carousel so it applies to all carousel-based snippets, not just products. task-5090459 ### [IMP] website_event: add dynamic events carousel snippet This PR adds a new "Events Carousel" snippet that displays upcoming events in a paginated carousel layout. The existing snippets only supported grid and list layouts, leaving no compact option for content-dense pages where horizontal space is limited. How to use: 1. Enter Edit mode 2. Click on Events 3. Select the one with "Dynamic Carousel" label The tag filtering domain logic is extracted into an EventsMixin shared between the existing Events and the new EventsCarousel interaction, ensuring any future domain changes only need to happen in one place. Enterprise PR - https://github.com/odoo/enterprise/pull/101478 task-[5090459](https://www.odoo.com/odoo/project/974/tasks/5090459)
Philippine companies can now use a default invoice layout that follows BIR Computerized Accounting System requirements. The report includes required tax wording, category breakdowns, and special discount fields for both VAT-registered and non-VAT-registered businesses.
Original PR description
Sales invoices issued by Philippine companies using a Computerized Accounting System (CAS) must follow a BIR-prescribed format that differs from the standard invoice layout: TIN/VAT-status wording, a tax-category breakdown (VATable/Zero-Rated/VAT-Exempt, or Exempt/Percentage-Tax for non-VAT-registered companies), and mandatory SC/PWD/NAAC/MOV fields. Add a BIR-compliant invoice report used by default for Philippines companies, covering both the VAT-registered and non-VAT-registered variants. Enterprise PR: https://github.com/odoo/enterprise/pull/127885 Upgrade PR: https://github.com/odoo/upgrade/pull/11029 task-6032311
Adds support for connecting a weighing scale directly through the browser for quality control checks. This helps operators capture weights automatically for kilogram-based checks, reducing manual entry and improving accuracy on the shop floor.
Original PR description
Community PR: <https://github.com/odoo/odoo/pull/284985> This commit adds a new bridge module to allow measuring the weight at quality control points using a scale connected directly via Web Serial. Once a scale is connected, it will be used automatically whenever a quality check with unit 'kg' is performed. task-6485996
Website editors can now add an Appointments Carousel that presents appointment types in a compact, paginated layout. This makes it easier to promote many bookable services on a page without overwhelming visitors, while preserving the existing filtering options.
Original PR description
This PR adds a new "Appointments Carousel" snippet that displays appointment types in a paginated carousel layout. The existing snippets only supported card, picture, and list layouts, with no compact option for showcasing many appointment types without overwhelming the page. How to use: 1. Enter Edit mode 2. Click on Appointments 3. Select the one with "Dynamic Carousel" label The filter domain logic (by type, users, resources, and names) is extracted into an AppointmentsMixin shared between the existing AppointmentsListSnippet and the new AppointmentsCarousel, keeping future domain changes in one place. Community PR - https://github.com/odoo/odoo/pull/238099 task-[5090459](https://www.odoo.com/odoo/project/974/tasks/5090459)
Adds Philippines-specific Point of Sale controls to help businesses meet Bureau of Internal Revenue requirements. The update records and authorizes line voids, supports offline audit tracking, tracks sales and void counters, stores POS machine details, and enables audit CSV exports.
Original PR description
This commit introduces the `l10n_ph_pos` module to support Point of Sale regulatory requirements mandated by the Bureau of Internal Revenue (BIR) in the Philippines. Key features included in this…
This commit introduces the `l10n_ph_pos` module to support Point of Sale regulatory requirements mandated by the Bureau of Internal Revenue (BIR) in the Philippines. Key features included in this localization: * **Audit Logging for Line Voids & Quantity Reductions:** Triggers a mandatory popup requiring authorization (via PIN from Basic/Advanced employees) and an optional reason when a cashier removes an order line or decreases its quantity. * **Offline Support for Audits:** Queues audit actions locally when offline and replays them via `l10n_ph_pending_audit_actions` during backend order synchronization. * **Bypass Audit Control:** Adds a `l10n_ph_pos_bypass_line_void` flag on `hr.employee` to allow specific cashiers to skip the authorization popup and logging altogether. * **Accumulated Total Sales:** Tracks and securely increments the "Accumulated Grand Total Sales" on the `pos.config` whenever an order is paid. * **Void Counter:** Maintains a running, immutable counter of void transactions per POS configuration. * **POS Machine Identification:** Adds fields for "Machine Identification Number" and "Machine Serial Number" to the POS configuration and settings. * **Register Management Override:** Introduces a new config setting (`l10n_ph_basic_can_close_register`) that grants basic-rights employees the ability to close the POS register. * **CSV Export:** Includes a backend controller to securely export Line Void Transactions for external auditing purposes. Task-5975565 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
French accounting localization now treats Monaco as part of the EU VAT group while preserving a separate EU group that excludes Monaco. New localization packages were also added for French overseas territories, helping businesses apply the right local accounting and tax setup in those regions.
Original PR description
[[IMP] l10n_fr,l10n_fr_account: European union vat](https://github.com/odoo/odoo/commit/9870a204bb64bdf8a11e433eef3a9e9f8f3fad86)
This commit will add Monaco to the European union vat country group and
create a new country group that is the same than the european union but
without monaco
task-6321652
[[ADD] l10n_{gf,gp,mq,re,yt}: new localization](https://github.com/odoo/odoo/commit/58518e1d7df773a70c595bd3842a33ac6be611bb)
Like Monaco, we need to add new localization package for
the drom countries
task-6321652
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#284404Sales cash rounding is easier to manage, with editable and archivable rounding methods, clearer handling when rounding has no effect, and better default profit and loss account setup. These changes reduce configuration mistakes and make invoice rounding behavior more transparent for users.
Original PR description
This commit is a followup of the work done in this PR https://github.com/odoo/odoo/pull/283020 It adds the following improvements: 1) Show the icon to remove the cash rounding in case of biggest_tax strategy before saving the record 2) set profit/loss default accounts on the company 3) Fix unit test (partner category count says 3 while actually 2 are included) 4) when the tax group groups 0% taxes, should never be != 0, and notify the user that no rounding took effect 5) Make rounding methods archivable 6) Make the rounding methods list view editable top, and support multi edit 7) Compute new rounding method records names 8) Restrict rounding profit/loss accounts to internal groups of income/expense task-6501537
Users can now open the full composer while editing existing Chatter messages or notes, with the current content carried over. This makes it easier to use richer editing options such as formatting, attachments, and mentions while ensuring the original message is updated rather than duplicated.
Original PR description
**Description of the issue/feature this PR addresses:** ---------------------------------------------- When editing messages or log notes from the Chatter, users are limited to the inline composer…
**Description of the issue/feature this PR addresses:** ---------------------------------------------- When editing messages or log notes from the Chatter, users are limited to the inline composer and cannot switch to the full composer. This restricts their ability to perform advanced editing (rich formatting, attachments, mentions handling, etc.) once edit mode is initiated. **Current behavior before PR:** ---------------------------------------------- - No option is available to open the full composer while editing - Users must either continue with limited inline editing or discard changes - Full composer can only be used when creating new messages, not editing existing ones **Desired behavior after PR is merged:** ---------------------------------------------- - "Open Full Composer" action is available while editing messages/notes - Full composer opens with existing message content pre-filled - Attachments, mentions, and formatting are preserved during transition - Saving from full composer updates the original message instead of creating a new one - Existing behavior for new messages remains unchanged Related Enterprise PR: https://github.com/odoo/enterprise/pull/126622 Task-6015654 ---------------------------------------------- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update makes two additional phone status icons available in Odoo's web interface: forwarded calls and paused phone state. It helps ensure these call-related statuses can be displayed consistently wherever the interface needs them.
Original PR description
Task-6524528
Indian reporting now includes audit checks for Form 26, helping businesses review required tax return information more consistently. This improves compliance support by flagging relevant items during the reporting process.
Original PR description
This PR adds audit checks for Form 26 in India. task-6182154 Community PR - https://github.com/odoo/odoo/pull/286430
The VoIP call transfer screen now uses clearer action buttons for direct and attended transfers, while the cancel option has been moved to a back button in the header. This makes the transfer flow easier to understand and helps users choose the right transfer action more quickly.
Original PR description
[Task-6524528](https://www.odoo.com/odoo/project/5778/tasks/6524528)
Users can now open the full message composer when editing chatter messages, giving them a more complete editing experience. The underlying context naming was also aligned with existing mail conventions, improving consistency for future maintenance.
Original PR description
The clicked_on_full_composer context key is renamed tomail_full_composer. The new name follows the naming of the other mail context keys. Related Community PR: https://github.com/odoo/odoo/pull/256870 task-6015654
The timesheet assistant now gives more importance to recent activity matches, so suggestions adapt faster when people move to new projects or tasks. It also cleans up outdated local history and reduces unnecessary lookups, making suggestions more relevant and efficient.
Original PR description
Previously, the timesheet assistant's local configuration matched activities to projects/tasks using a strict historical tally. A match made 6 months ago carried the exact same mathematical weight as a match made today. This caused old habits to stubbornly override new assignments. This commit introduces an exponential time-decay algorithm to the frequency computation: - Matches are now weighted based on their `datetime` stamp. - The weight drops by 50% every 5 days (half-life algorithm). - Recent timesheet entries quickly accumulate enough fractional votes to surpass the decayed votes of older, outdated projects. in this commit i updated the matching of local rules to be case sensitive for better matching (eg. "Meeting with client" is the same as "meeting with client") Task: 6267713 Forward-Port-Of: odoo/enterprise#129997 Forward-Port-Of: odoo/enterprise#124669
The AI update process now blocks empty selection criteria in all cases, including flows that ask for confirmation. This reduces the risk of an AI mistake changing every record unintentionally, while still allowing deliberate all-record updates when an explicit matching condition is provided.
Original PR description
The llm can hallucinate and call the update tool with an empty domain which will result in performing the updates on all the records of a certain model. To prevent hallucinations and at the same time allow the llm to update all the records if it actually needs to, an error is thrown if the domain is empty stating that updating with an empty domain is prohibited and a domain that matches all records should be used instead. This will make the llm conscious about passing a domain that actually matches all records and not just use an empty domain. Note: the update tool was already throwing an error if the domain is empty but only if tool_request_confirmation is False. If the confirmation is True, which is the case in mcp, the domain would be accepted and the updates would go through. Forward-Port-Of: odoo/enterprise#130349
Manufacturing now supports packing finished products as part of the production workflow, aligning manufacturing with existing stock packing processes. This helps teams prepare goods for shipping or storage more efficiently, though some automated print actions from detailed stock move lines are not yet triggered and are planned for a later update.
Original PR description
In this commit, we introduce the basic functionality of put in pack in MRP, as it makes sense to pack the manufactured product when needed. Later improvements to be done in order to tweak the behaviour and a `Put in Pack` action might be added on the operation directly. For now, the `Put in Pack` action in stock move lines don't trigger the hooks correctly and it should be fixed in another PR for 19.0 (since this PR targets V20), This means that on putting on pack from the stock move line operations list, f you have the print on "Put on Pack" or similar on, it won't be triggered. Task: 6247512 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Public holidays now appear in Discuss the same way as regular time off, using each employee's company calendar when they have no approved leave. This helps colleagues better understand availability by showing banners, status, and names with an expected return date when relevant.
Original PR description
**Public holidays** are now treated like regular out-of-office status in Discuss. and the holiday is computed on hr.employee from the employee’s company calendar (only when they have no validated leave). The Discuss banner, IM status, and formatted display name show “back on XXX” when appropriate, task-2377854 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Invoices sent through Egypt ETA e-invoicing will now be checked for overly long sales or purchase references before submission. This gives users a clearer error message when references exceed the 100-character limit, helping them correct the issue faster and avoid confusing API responses.
Original PR description
… and purchase order reference Currently, when users submit invoices with ref exceeding 100 characters including spaces, the ETA API returns a JSON validation error offering no clear guidance on how to fix the error. Therefore, we are adding a check in _check_move_configuration to add an error if length of ref or invoice_origin is greater than 100 task-6420490 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
Website builder record selection buttons can now show custom wording instead of only the default prompt. They also handle simpler selection data by looking up missing record names automatically, making builder components easier to reuse and maintain.
Original PR description
- accept non-default message on button of builder many2many - support only `id` from action with builder many2many This was part of https://github.com/odoo/odoo/pull/258135, but it can be merged independently
Online shop filtering now refreshes key page controls consistently, including breadcrumbs, sorting, search, category links, and floating filter controls. This gives shoppers clearer navigation and prevents old filter options or reset links from lingering after they refine product results.
Original PR description
Applying shop filters without a full page reload left several server-rendered regions stuck at their page-load state. The products header (breadcrumb, sort, filmstrip, search) and the floating bar are now refreshed on each update, so their keep() links are rebuilt against the current filters rather than the ones present at page load. Searching now targets a clean /shop, and the category links, "All Products" and "Clear Filters" share one reset dict, so searching or selecting a category clears the active filters consistently. The on-sale and in-stock ribbon pills now go through the same async flow as the other filters instead of forcing a full page reload. Also fix the collapsible category tree, whose toggle collapsed its own header: after the title became a div, the inheriting xpath matched the title instead of the category list. task-6297769 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Purchase orders will no longer automatically create vendor price lists when confirmed. If no manual vendor price list exists, Odoo now uses the most recent confirmed purchase order line as the reference price, helping businesses with frequently changing supplier prices avoid outdated pricing records.
Original PR description
Before, confirming a purchase order automatically created a vendor pricelist (product.supplierinfo) for every product/vendor without one, silently locking the first purchase price in as pricelist. In…
Before, confirming a purchase order automatically created a vendor pricelist (product.supplierinfo) for every product/vendor without one, silently locking the first purchase price in as pricelist. In industries with constantly fluctuating prices (e.g. oil), purchasers do not negotiate pricelists, they simply apply the last price communicated by the vendor. For them, the pricelist automatically created on order confirmation was outdated by the next price change, and maintaining pricelists could be tedious. Now vendor pricelists are only created manually. When no pricelist is defined for a product/vendor, the most recently confirmed purchase order line acts as the vendor pricelist. Additionally, the purchase history / price comparison view gains an optional 'Discount %' column, and is grouped by vendor by default. _select_seller now returns the seller information as a dictionary instead of a product.supplierinfo record, since a seller can come from the last confirmed purchase order line, which has no record. task-5456444
Warehouse batch transfers and wave picking are now presented as a unified workflow, making it easier for teams to group either full transfers or individual move lines in one place. Automatic batching by carrier was also corrected so deliveries for different carriers are no longer incorrectly mixed.
Original PR description
Odoo's definition of wave picking does not match the industry standard. This commit blends the two concepts at the UI level. Inside a batch transfer, you can add a whole transfer or individual move lines, as previously with a wave transfer. Task-6294586
Manufacturing barcode workflows now include Put in Pack actions, letting users package finished goods or by-products directly during barcode operations. Manufacturing operation settings also expose the related packaging options, making package handling and package PDF printing easier to configure and use.
Original PR description
After https://github.com/odoo/odoo/pull/267679 and the introduction of `Put in Pack` in MRP. We can now show put in pack options in the configuration of MRP. Task: 6247512
The appointment website editor now shows the intended message when a selection list is empty. This makes the configuration experience clearer for users setting up appointment options.
Original PR description
The corresponding commit in community add the `message` props to `BuilderMany2Many`. This commit uses it (instead of the non-existant `defaultMessage`) task-5245362
Employee group insurance fields now appear only when group insurance is selected, making employee records cleaner and easier to manage. Group insurance employee contributions are also included in Belgian tax reports and used to reduce withholding taxes where applicable.
Original PR description
Now, the group insurance fields are only displayed on the employee's form when the Group Insurance field is checked. Also changed the _onchange methods for hospital and ambulatory insurances to _compute methods. Added group insurance employee contribution to 281.10 and 281.20 reports. Added reduction for the withholding taxes based on 30% of the personnal employee contribution to the group insurance. task-6263912
The fleet stock planning view now shows recently used docks and responsible people even when they have no batches scheduled in the current period. This makes drag-and-drop planning easier by keeping common planning groups visible and ready to use.
Original PR description
To improve the drag and drop planning inside the gantt view, 'recent' docks and responsibles groups are displayed, even if they don't have any batch for the current period. Task-6294586
Customer reminder information is now handled more accurately per company, reducing confusion in multi-company setups. The update also standardizes report file naming and streamlines how follow-up responsibilities are selected, making reminder workflows more reliable.
Original PR description
- Make last_reminder computed per company. - Add get_default_partner_report_filename as a separate function for renaming the Open Items report instead of doing it manually. - Pass the follow-up line to _get_followup_responsible instead of recomputing it from the partner field in _execute_followup_partner. task-6401457
Quality checks are now created more efficiently when stock move lines are created or updated. This reduces database work for large warehouse operations with category-based quality rules, improving performance without changing user workflows.
Original PR description
Description ----------- Creating or updating stock move lines calls `_create_check()` to find the quality control points applicable to each detailed operation. Category-scoped points previously…
Description
-----------
Creating or updating stock move lines calls `_create_check()` to find the quality control points applicable to each detailed operation.
Category-scoped points previously searched for products once per quality point and category. The method then performed another `quality. point` search for every move line, although those point ids came from the recordset fetched at the beginning of the method.
This commit resolves all category-scoped products in one search and reuse the already-fetched quality points.
Benchmark
---------
```xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--
Reproduces the two query-scaling paths in stock.move.line._create_check:
category-scoped control points and a large batched move-line creation.
The final job is the benchmark target. With the former implementation,
its query count grew with both the control-point/category pairs and the
1,000 move lines. Use the scale option to increase only the move-line count.
-->
<record id="benchmark_move_line_quality_checks" model="populate.blueprint">
<field name="name">Benchmark: Move Line Quality Checks</field>
<field name="definition_xml" type="xml">
<create model="product.category" count="20" id="quality_parent_categories" scale="False">
<value name="counter" generator="misc.counter" start="1"/>
<field name="name" eval="f'Quality Benchmark Category {counter:02}'"/>
</create>
<create model="product.category" count="100" id="quality_child_categories" scale="False">
<value name="counter" generator="misc.counter" start="1"/>
<field name="name" eval="f'Quality Benchmark Subcategory {counter:03}'"/>
<field name="parent_id" ref="quality_parent_categories"/>
</create>
<create model="product.product" count="100" id="quality_products" scale="False" context="{'tracking_disable': True}">
<value name="counter" generator="misc.counter" start="1"/>
<field name="name" eval="f'Quality Benchmark Product {counter:03}'"/>
<field name="type" eval="'consu'"/>
<field name="is_storable" eval="True"/>
<field name="tracking" eval="'none'"/>
<field name="categ_id" ref="quality_child_categories"/>
</create>
<create model="quality.point" count="20" id="category_quality_points" scale="False">
<value name="counter" generator="misc.counter" start="1"/>
<field name="title" eval="f'Benchmark Category Control Point {counter:02}'"/>
<field name="apply_to" eval="'categories'"/>
<field name="product_category_ids" ref="quality_parent_categories" count="5"/>
<field name="picking_type_ids" eval="[Command.set([env.ref('stock.picking_type_in').id])]"/>
<field name="measure_on" eval="'move_line'"/>
<field name="measure_frequency_type" eval="'all'"/>
<field name="test_type_id" eval="env.ref('quality_control.test_type_passfail').id"/>
</create>
<create model="stock.picking" count="1" id="quality_picking" scale="False">
<field name="picking_type_id" eval="env.ref('stock.picking_type_in').id"/>
<field name="location_id" eval="env.ref('stock.stock_location_suppliers').id"/>
<field name="location_dest_id" eval="env.ref('stock.stock_location_stock').id"/>
<field name="origin" eval="'Quality control performance benchmark'"/>
</create>
<create model="stock.move" count="1000" id="quality_moves" scale="False" context="{'tracking_disable': True}">
<field name="picking_id" ref="quality_picking"/>
<field name="product_id" ref="quality_products"/>
<field name="product_uom_qty" eval="1.0"/>
<field name="uom_id" eval="env['product.product'].browse(product_id).uom_id.id"/>
<field name="location_id" eval="env.ref('stock.stock_location_suppliers').id"/>
<field name="location_dest_id" eval="env.ref('stock.stock_location_stock').id"/>
</create>
<create model="stock.move.line" count="1000" id="quality_move_lines" parallel="False">
<field name="move_id" ref="quality_moves"/>
<field name="product_id" eval="env['stock.move'].browse(move_id).product_id.id"/>
<field name="uom_id" eval="env['stock.move'].browse(move_id).uom_id.id"/>
<field name="quantity" eval="1.0"/>
<field name="location_id" eval="env.ref('stock.stock_location_suppliers').id"/>
<field name="location_dest_id" eval="env.ref('stock.stock_location_stock').id"/>
</create>
</field>
</record>
</odoo>
```
The populate benchmark creates 20 quality points linked to 5 categories each, resulting in 100 point/category relationships. It then creates 1,000 move lines in one batch, generating +-4.5k quality checks.
Products belong to child categories while quality points target their parents, this represents large stock operations with category-wide quality rules.
| | Before | After | Improvement |
|-------------|--------|-------|-------------|
| Time | 11.8s | 10.3s | 12.7% |
| Query count | 12487 | 10120 | 19.0% |
Reference
---------
task-6488454Website social media links now apply the correct brand colors for more supported platforms. This makes social media blocks look more consistent and polished when businesses add their profile URLs.
Original PR description
Colors for social media are defined with `$o-social-colors` in `addons/website/static/src/scss/primary_variables.scss`. css rules are defined to use these colors for links in "Social Media" snippet, but not all social media have a class defined. Also, some of these social media have a domain that do not match their name. With this change, setting a url of a social media (one added in `s_social_media/000.scss`) will show the icon with the correct color
Point of Sale reports now show clearer session timing, including opening dates for active sessions and full start-to-end periods for closed sessions. The Sales Details report layout and multi-configuration names are also improved, making reports easier for managers to read and compare.
Original PR description
In this commit: - Display the opening date in the Session report when the session state is opened (X report). - Show the session period (start and end datetime) for closed sessions and sales details report. - Move the "Sales Details" title to the header for the Sales Details report for better layout consistency. - Improve config name display in multi-config reports by joining them in a single line. - Extend `pos.session` display_name to optionally include the session start datetime using the `display_start_at` context. Task: 5980266
Adds support for work injury sick leave calculations required under Hong Kong Cap. 282. This helps payroll and HR processes apply the correct leave amount after accounting for any post-accident earnings.
Original PR description
Implement support for work injury sick leaves as per the Cap. 282 from Hong Kong. These calculations require some special logic to handle the worked day line calculation; as the rate should be applied AFTER reducing the leave amount by any post accident earnings given to the employee. task-6517522 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Product images can now be assigned to shared attributes like color or size, so businesses no longer need to duplicate the same image across every variant. This makes product setup faster and ensures customers see the most relevant images on product pages while shop listings stay consistent.
Original PR description
## Before this commit: - Variant images had to be uploaded and managed separately for each product variant. - Even when multiple variants shared the same characteristics (e.g., the same image for all…
## Before this commit:
- Variant images had to be uploaded and managed separately for each product
variant.
- Even when multiple variants shared the same characteristics (e.g., the same
image for all sizes of a blue T-shirt), the image had to be duplicated across
variants.
## After this commit:
### 1. Image assignment using attribute values
- All images related to a product template, including variant specific images,
are now visible in the Extra Media section on both the template and its
variant forms.
- In the variant form, images that do not apply to the current variant (i.e.,
belonging to other variants) are visually muted.
- Each image can be linked to specific attribute values using a dropdown in the
kanban view.
- An image is applied to a variant only if the variant matches all attribute
values assigned to the image.
- If none of the values of attribute is selected on the image, then that
attribute will not affect the matching logic.
- In the product form view, images with attribute values are displayed first,
followed by images without attribute values.
This removes unnecessary duplication and simplifies variant image management.
### 2. Shop page behavior
- The primary image is always the template's main image.
- The secondary image is the second template image.
### 3. Product page behavior
- For the selected variant:
- Variant specific images are displayed first, with the first image serving as
the variant's main image.
- Template images without attribute values are displayed afterward.
### 4. Variant main image logic
- The first variant specific extra image is used as the variant's main image.
- If the user manually updates the variant's main image, the first variant
specific extra image is updated to match it. If no variant specific extra
image exists, a new one is created using the main image.
- If no variant specific extra images exist, the variant falls back to the
template's main image.
### 5. Template main image logic
- The first extra image is used as the template's main image.
- If the user manually updates the template's main image, the first extra image
is updated to match it. If no extra image exists, a new one is created using
the main image.
task-5405584The Discuss app interface has been updated to better match Odoo's Frost design, with clearer navigation, rounded search bars, stronger visual separation, and more readable message and settings areas. These changes improve day-to-day usability for teams using chat, channels, calls, and notifications without changing core workflows.
Original PR description
This commit adapts the overall UI of Discuss app to match with frost design. 1. Overall layout of Discuss app follows the floating box style of other Odoo screens 2. Messaging Menu style has been…
This commit adapts the overall UI of Discuss app to match with frost design. 1. Overall layout of Discuss app follows the floating box style of other Odoo screens 2. Messaging Menu style has been tweaked for improved readability: less muted items, better spacing, better visual of active item 3. Search bars are pilled-shaped to match search view. 4. Discuss app thread actions have style matching view switcher for panel actions. 5. Channel Member role iconography and action label has been changed to be more natural: crown icon, filled (owner) and unfilled (admin), "Set Member" for cleared downgrading of member role, consistent order of actions based on role hierarchy) 6. More visible border around core UI elements, like composer or message bubble. 7. Add People button has now an icon next to label. 8. Chat bubble message preview now is colored to match the message bubble color. 9. Notification Settings and Voice & Video Settings have their visual slightly simplified, with more spacing and less borders. 10. Call View actions and dropdowns no longer have weird gradient effect in simulated dark theme. 11. Call View Card's context menu stays open even when mouse leaving the card without any click away. Also improved color in this context menu. 12. Orange message bubble (mention to self) color has been tweaked to catch more the eye of the user. 13. Mentions style has been tweaked to pop a bit more. 14. Chat window outline is more separated from the background content through stronger border instead of shadow effect. 15. Add icons to Save as Template and Manage Templates in full composer. 16. Is typing text now shows member names in bold. 17. Autoresize, AutoresizeInput and DiscussContent's header have been fixed to properly follow the shrink-to-fit content aspect of header. <img width="2137" height="563" alt="Screenshot 2026-09-04 at 12 35 50" src="https://github.com/user-attachments/assets/81d317f2-bb56-4bdf-81d8-5aaa07e4eb4b" />
This update brings Odoo's spreadsheet component up to the latest version, improving day-to-day usability and visual consistency. Users should see smoother undo/redo behavior, more reliable area charts, better font handling on Linux, and colors that better match the rest of Odoo.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/bb7357a197 [REL] 19.5.0-alpha.16 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/bb7357a197 [REL] 19.5.0-alpha.16 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/75ceb30aaa [FIX] Fonts: fix linux font on css variable [Task: 6452045](https://www.odoo.com/odoo/2328/tasks/6452045) https://github.com/odoo/o-spreadsheet/commit/e8d059f38e [FIX] svg: remove unused commented SVGs [Task: 6317134](https://www.odoo.com/odoo/2328/tasks/6317134) https://github.com/odoo/o-spreadsheet/commit/60c210afc2 [IMP] viewports_store: do not jump viewport on UNDO/REDO [Task: 6481352](https://www.odoo.com/odoo/2328/tasks/6481352) https://github.com/odoo/o-spreadsheet/commit/537711e139 [FIX] chart: connect area charts through invalid values [Task: 6458796](https://www.odoo.com/odoo/2328/tasks/6458796) https://github.com/odoo/o-spreadsheet/commit/ea25ccfa4b [FIX] css: update global gray colors to match Odoo [Task: 6515003](https://www.odoo.com/odoo/2328/tasks/6515003) Co-authored-by: Florian Damhaut (flda) <flda@odoo.com> Co-authored-by: Anthony Hendrickx (anhe) <anhe@odoo.com> Co-authored-by: Alexis Lacroix (laa) <laa@odoo.com> Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com> Co-authored-by: Adrien Minne (adrm) <adrm@odoo.com> Co-authored-by: Ronak Mukeshbhai Bharadiya (rmbh) <rmbh@odoo.com> Co-authored-by: Dhrutik Patel (dhrp) <dhrp@odoo.com> Co-authored-by: Rémi Rahir (rar) <rar@odoo.com> Co-authored-by: Pierre Rousseau (pro) <pro@odoo.com> Co-authored-by: Vincent Schippefilt (vsc) <vsc@odoo.com> Co-authored-by: Marceline Thomas (matho) <matho@odoo.com>
Point of Sale sales details now show both VAT-included and VAT-excluded prices. This makes it easier to distinguish gross sales from net sales amounts for clearer reporting and reconciliation.
Original PR description
We now display both prices VAT included and excluded in order to better distinguish the net sale amount. task-6517995
Users can now download German TSS fiscal exports directly from Odoo instead of using the external Fiskaly dashboard. The DSFinV-K export option has also been moved into the Fiscalization reporting area, making compliance exports easier to find and manage.
Original PR description
In this commit: - Introduce TSS export directly from Odoo, allowing users to download the TSS export without accessing the Fiskaly dashboard. - Move the DSFinV-K export from the Orders menu to the Fiscalization section of the Reporting menu for better organization. Task-6421997
Hong Kong payroll now supports work injury sick leave calculations required under Cap. 282. This helps employers calculate affected leave pay more accurately by accounting for post-accident earnings before applying the sick leave rate.
Original PR description
Implement support for work injury sick leaves as per the Cap. 282. These calculations require some special logic to handle the worked day line calculation; as the rate should be applied AFTER reducing the leave amount by any post accident earnings given to the employee. task-6517522
VoIP time condition periods now use clearer, localized time inputs and include an explicit All Day option. This makes period setup easier and prevents users from getting stuck when correcting invalid start or end times.
Original PR description
Time Condition periods used character fields with manual hour validation. The end time was also hidden until a start time was set, which could leave users unable to correct an invalid period when the start time was cleared. Use the standard float time widget for entering period boundaries and add an explicit All Day option. Keep both inputs on the same line as the option to avoid resizing the period dialog. Format period hours in the list with the same localized representation as the form inputs while preserving the HH:MM values expected by Wazo.
Belgian payroll now reports specific partially paid sick leave and work accident salary codes in the correct tax forms. This helps ensure these payments are taxed and counted correctly in annual and withholding tax declarations.
Original PR description
Some salaries for sick days and work accidents are partially paid (e.g., for short-term contract employees). These salaries should not be declared in forms 281.10 and 274.10, but in 281.18 and 274.18, as they are taxed differently (bonus withholding tax base). Following the previous implementation for LEAVE218, LEAVE219, and LEAVE229, this commit adds the missing work accident codes: - LEAVE271 - LEAVE272 Their categories have been updated to use `REPLACEMENT_REVENUE_BASE` instead of the standard remuneration and withholding bases. These codes are also added to the 281.18 sheet generation to properly compute the number of days. Task: 6482702
The Shopee Shops menu now guides users through the correct setup flow instead of leading to a dead end when creating a shop. Users can choose or create the needed Shopee account before authorizing a new shop, making setup clearer and easier.
Original PR description
The Shopee menu now exposes the shops instead of the accounts, as the shops are what the users work with. However, shops cannot be created manually: they only exist once they have been authorized on Shopee, which requires an account. Clicking "New" on an empty form was therefore a dead end. The "New" button of the Shops list now opens the account creation dialog when no account exists yet, and a wizard otherwise. From that wizard, the user selects the account on which to authorize the new shop, opens that account, browses all the accounts, or registers a new one. Accounts are also identified by their partner ID and API endpoint rather than by their name, so that the account to authorize the shop on can be told apart from the others. task-6487410
Half-day time off entries now appear as wide as full-day entries in the payroll Time Off calendar, making monthly reviews easier to scan. The selection count was also adjusted so selected days are reported correctly in both payroll and regular Time Off views.
Original PR description
In the Time Off step of a payrun, a half day time off was displayed half as wide as a full day one, making the gantt hard to read when scanning a month of time off. Pill width comes from the grid:…
In the Time Off step of a payrun, a half day time off was displayed half as wide as a full day one, making the gantt hard to read when scanning a month of time off. Pill width comes from the grid: the leave gantt declares precision="day:half", so a day spans two grid columns and a morning or afternoon time off covers only one of them. Override the precision to "day:full" on hr_leave_gantt_view_payroll, the primary view used by the payrun Time Off step and by the payroll time off action. A day is now a single column there, so half day and full day time off are displayed with the same width. The Time Off app gantt keeps its half day precision. The multi selection counted the selected grid cells and divided them by 2 to get a number of days. That only holds when a day is two cells, so with the new precision selecting a single day displayed "0.5 selected". Divide by the scale cellPart instead, which is the number of cells in a day: 2 with day:half, giving the same result as before, and 1 with day:full.
Repair orders now move through a shorter, clearer process by removing the unnecessary “Under Repair” step and the related “Start Repair” action. The final repaired status is now labeled “Done,” making the workflow easier for users to understand across repair, manufacturing repair, and point of sale repair scenarios.
Original PR description
This commit improves the repair workflow by: - Removing the `Under Repair` state and its related logic, as it provided no functional value beyond an intermediate state. - Removing the `Start Repair` action, which is no longer needed without the Under Repair state. - Renaming the `Repaired` state to `Done` and updating the tests to reflect the new repair workflow. Enterprise PR:- odoo/enterprise#123736 Upgrade PR:- odoo/upgrade#10739 TaskId-6361476
Manufacturing orders now show planning and status options only when they are relevant, especially when work orders are not used. This reduces confusion for users by hiding unnecessary buttons and filters, showing helpful messages, and keeping order statuses aligned with actual production progress.
Original PR description
*: project_mrp_account This improvement enhances the UX by: - Hiding the `Plan` button on the MO form when there are no work orders. - Ensure the MO state moves to `In Progress` only when the user clicks `Start`, when any work order is in `In Progress or Done` state, or when any component is `picked`. For MOs without work orders, the `To Close` state will never be used. - Display all relevant MO states by default, except the `Cancel` state. For MOs without work orders, the `To Close` state is also not displayed. - Showing a `toaster` when the user tries to plan an MO without work orders or an MO that is already planned. - Hide unnecessary actions, buttons, and filters when the `Work Orders` option is disabled in the settings. - Update the `To Plan` filter to include only MOs with work orders. - Update test cases to maintain consistency with the changes. Enterprise PR:- odoo/enterprise#129971 TaskId-6453469
Odoo now checks self-billed Malaysian e-invoice bill references before sending them to MyInvois. If the reference is over the 50-character limit, users see the issue directly on the Bill Reference field so they can shorten it before submission.
Original PR description
For self billed documents, the bill reference is used as the InternalID (cbc:ID) of the document sent to MyInvois. That field is limited to 50 characters, so a longer reference makes the submission fail with an error coming from MyInvois. Validate the length before sending, so that the issue is reported directly on the "Bill Reference" that needs to be shortened. task-6522168 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The Point of Sale product information popup now shows each product's tags below the product header. This helps staff quickly recognize product categories or labels, with tag colors matching the back-office setup.
Original PR description
In this commit: ================== Product tags were not displayed in the POS product information popup. Display the product tags below the product header and use their configured backend color for the badge background. Task-6484273
Quality control point forms are now clearer and easier to complete, with better title handling, inline options, and helpful placeholders. Work order planning popovers now show key assignment details, helping users understand responsibilities faster.
Original PR description
*= mrp_workorder, helpdesk_repair The improvement includes: - Use a large title input, remove the `New` heading, and display the title next to the reference after creation. - Display the `Apply to` options inline and rename `Quantity` to `Lot` in the `Control per` field. - Improve the QCP `quick create` by using the entered text as the `title` instead of the `reference`. - Add placeholders to the title and failure location fields. - Display the work center and assignee of the work order in the planning popover - Update the tests to reflect the removal of the `Under Repair` state. Community PR:- odoo/odoo#275310 Upgrade PR:- odoo/upgrade#10739 TaskId-6361476
This update tidies the internal organization of Belgian payroll calculation entries so related items are kept together. It has no expected impact on day-to-day payroll use, but helps reduce maintenance errors in future updates.
Original PR description
Two entries in the common localdict were not together. This was probably due to a mistake during a fw-port or rebase.
Belgian payroll now makes lump sum and representation allowances easier to manage by replacing fixed checkbox options with editable allowance fields and clearer categories. This gives payroll teams more flexibility to activate specific allowances, set employee-specific amounts, and calculate prorated allowances more accurately.
Original PR description
For details, see the docs in the related task. As a general ides, this PR aims at simplifying the management of Lump Sum Allowances. We first refactor the Representation Fees section in the Payroll…
For details, see the docs in the related task. As a general ides, this PR aims at simplifying the management of Lump Sum Allowances. We first refactor the Representation Fees section in the Payroll tab of the employee form view by switching from using checkboxes with their related fixed amounts, to using editable fields that have their defaults fixed to those amounts. We then introduce new categories to include a miriad of other possible allowances. Finally, we integrate this with the new view_id system so that each lump sum can be activated/deactivated at will. All Benefits under the Lump Sum Allowances section except for Daily Misc. Other Criteria and Monthly Misc. Other Criteria are considered normal Representation Fees (i.e. with serious standard). Each of them has their own Salary Rule with category SERIOUS_REPRESENTATION, all these values are later grouped (summed) in the Representation Fees salary rule. In the same way, Daily Misc. Other Criteria and Monthly Misc. Other Criteria have their Salary rules with category NON_SERIOUS_REPRESENTATION and are summed to become Representation Fees (Without Serious Standard). Representation fees with serious standard are fixed amounts, while those without serious standard are prorated based on the amount of days in the payslip period that are eligible for representation fees. Some Benefits (namely Homeworking, Phone, Internet, all the Car Management ones and the Daily and Monthly Misc. ones) are only based on the amount set on the employee's profile. The other benefits are based on both the value on the employee profile and a Salary Input on the payslip, that specifies either the distance traveled or the days of outside work depending on the type of benefit. We also have to modify some tests that were failing because they were expecting different rules to appear in the payslip and a threshold to the With Serious Standard amount. Task: 5443155
Payslip forms now show worked day totals that exclude unpaid time, while keeping existing payroll calculations intact. This gives payroll users a clearer view of paid work without disrupting FTE or amount calculations that depend on total worked time.
Original PR description
Rework the previous reverted commit to keep old fields used in FTE and amount of worked_days_line, and add 2 new computed field that only count paid time. Task-6205747
The Sign field list now shows who created each field and provides useful search and grouping options. This helps users quickly find signature fields by name or linked record, and organize them by creator, related record, or allowed user groups.
Original PR description
In the fields list view, there was no way to tell who added a field, and the search bar offered nothing to search or group on. The list now has a "Created by" column, fields can be searched by name or by the record they are linked to, and grouped by creator, linked record, or the groups allowed to use them. task-6480123
The Unplan Orders action is now hidden when the Work Orders setting is disabled. This keeps the manufacturing interface cleaner and prevents users from seeing an option that is not relevant to their current setup.
Original PR description
This improvement hides the Unplan Orders action when the Work Orders option is disabled in the settings. Community PR:- odoo/odoo#282221 TaskID-6453469
AI-generated website pages now get stronger visual direction, more consistent branding, better image handling, and extra polish before users see the final result. The process is split into a separate finishing step to avoid timeouts, making page generation more reliable while improving the quality of the finished pages.
Original PR description
Improves AI-generated page quality, and splits a full-page build in two so it fits the worker time limit. - **Art direction** - new `apply_brand_kit` tool (palette, font pairing, corners/shadows);…
Improves AI-generated page quality, and splits a full-page build in two so it fits the worker time limit. - **Art direction** - new `apply_brand_kit` tool (palette, font pairing, corners/shadows); the prompt now picks an aesthetic direction and layout before writing HTML. - **Refinement passes** - after a page is composed, two one shot passes add section shapes and CSS polish. The LLM returns decisions only, markup is built in Python so rules it ignores can be enforced. - **Snippets** - explicit allowlist with intent hints, shuffled so picks rotate. - **Images** - written as `<img data-ai-image-prompt>` and generated during finalization. - **Deferred finalization** - images and both refinement passes moved to `/ai_website/finalize_page`. Page and reply are held server-side and released together, so only the finished result is shown. **Why split:** `- limit-time-real` (120s) killed the worker, at least on runbot, so image generation, refinement passes are not part of the main loop anymore and are a separate request. worth looking at if another solution would be available
Payroll correction handling has been improved for standard payroll and Belgian payroll processes. This should help payroll teams process correction proofs of concept more reliably and reduce manual follow-up in affected payslip workflows.
The replenishment page now updates more smoothly when users close related pop-up wizards, instead of reloading the whole page each time. This reduces interruptions and helps warehouse teams continue working faster.
Original PR description
Do not refresh the entire orderpoint page every time a wizard is closed. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Belgian payroll declarations now calculate withholding-tax exemptions for eligible overtime hours and apply annual employee caps across the year. This improves compliance and reporting accuracy for companies using Belgian payroll, with updated XLS/PDF reporting and configuration for sector-specific limits.
Original PR description
Compute the withholding-tax exemption for overtime hours (natures 44–59) within the Belgian 274.XX declaration. Overtime worked-day lines are collected from validated payslips, bucketed by rate and sector (CP124/CP302/immovable work), and allocated to the appropriate nature codes while respecting each employee's annual hour cap. Hours already declared in earlier months of the same year are carried forward so the cap is enforced cumulatively. The exemption rate is stored as an updatable rule parameter. A white-cash-register flag on the company controls the higher cap for CP302 employees. New work-entry types, an XLS extra-hours sheet, a PDF section, and extended tests are included. Task Id: 5430988
The barcode app now opens serial and lot number generation in a dedicated screen instead of a pop-up dialog. This makes the workflow easier to use on mobile devices and keeps it more consistent with the rest of the barcode experience.
Original PR description
In the barcode app currently there's a dialog to generate serial/lot numbers. In this PR the dialog gets replaced by a view since it's easier for users on mobile devices. Task-5469775
PayPal in Odoo now supports a wider range of payment methods, including Pay Later, Venmo, card payments, and several local European payment options. The update also adds a smoother seller onboarding flow and standardizes the PayPal checkout experience, helping merchants activate and offer more payment choices globally.
Original PR description
We currently only support PayPal Wallet, but PayPal can also be integrated as a regular payment provider, offering many payment methods and worldwide coverage. In this commit, we add the following payment methods: - Via PayPal's JS SDK: Pay Later, Venmo, and Advanced Credit and Debit Cards. - Via Orders API: Bancontact, BLIK, EPS, iDEAL, Multibanco, MyBank, Przelewy24, and Trustly. We also migrate PayPal Wallet integration from JS SDK to Orders API to uniformize the look of payment methods through different payment providers. task-6090080
PayPal payments now support more payment options, easier merchant onboarding, and the ability for customers to save eligible PayPal Wallet or card details for future use. This helps reduce repeat checkout friction and enables merchants to handle recurring or follow-up payments when PayPal vaulting is enabled.
Original PR description
In recent commits, we integrated various payment methods provided by PayPal, including Advanced Credit and Debit Cards. We also migrated the PayPal Wallet integration from the JS SDK to the Orders API to standardize the appearance of payment methods across different providers. Before this commit, customers had to re-enter their payment details for every PayPal transaction, and merchants could not charge them offline (e.g., for subscriptions or invoice follow-ups). This commit introduces the ability to tokenize PayPal Wallet and PayPal-provided cards. Tokenization is available if the merchant's account has the advanced vaulting capability enabled. We also handle the case where PayPal creates the vault asynchronously, generating the token via a webhook rather than the immediate checkout response. task-6095033
The Project app search screens have been reorganized and cleaned up to make finding tasks and project information easier. This improves day-to-day navigation across Project-related areas such as timesheets, sales projects, sharing, and skills reporting without changing core business workflows.
Original PR description
In this commit, we refactor and clean the search view of Project. task-6516390
Call activities in the chatter now show the phone number from the related record, making it easier for users to place calls directly. Standard users get a normal phone link, while VoIP users continue to launch calls through the softphone, with shared handling across phone-related features.
Original PR description
[IMP] mail: display call activity phone numbers in the chatter
This was an enterprise VoIP feature: showing the phone number found on
the related record for call activities, in their chatter, and allowing
to call it by clicking on it.
This is now a standard feature. In standard, it is a `tel:` link. In
VoIP, it will still start a call through the softphone, as before.
[IMP] web, mail: merge activity/phone field code into 1 patchable point
The parent commit basically adds a VoIP feature to all call activities:
showing the phone number and being able to call it by clicking... this
is something the phone field widget also does. This commit factorizes
the code and makes it so VoIP can patch both points as an unique patch.
This also allows web_enterprise to patch both at the same time to add
the "Phone Install Dialog", suggesting VoIP installation to admins when
available.
task-6416875This update removes redundant tooltip text from buttons that already have visible labels. It slightly streamlines the interface setup across several Odoo apps without changing what users can do.
Original PR description
*=base_geolocalize,crm,event,l10n_in,mail_group,mrp,project,sale_crm,stock Remove unnecessary "title" attributes from buttons across views where a visible "string" label is present. The button in which string signifies the original purpose does not need title tooltip which adds unnecessary arch overhead without delivering additional value to the user interface. task-6527163 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update improves how Odoo retrieves bus notifications, especially when many notification channels are checked at once. It should reduce delays and server load for real-time updates while keeping behavior unchanged for users.
Original PR description
The `fetch_bus_notifications` method receives a dict mapping channels to be fetched to their `last_fetched_id`, producing several `channel_X = %s and id > %s` OR branches. Since [1], notifications…
The `fetch_bus_notifications` method receives a dict mapping channels to be fetched to their `last_fetched_id`, producing several `channel_X = %s and id > %s` OR branches. Since [1], notifications are fetched by DB, increasing the number of OR branches. Multiple ORs lead to O(n_row * n_groups) complexity as PostgreSQL has to walk through each OR branch for each row. A better approach is to JOIN the groups, which results in an O(n_row + n_groups) complexity: PostgreSQL first builds the hash table then can do a quick lookup for each row. This is an order-of-magnitude win for large batches, with a negligible difference for small ones. [1]: https://github.com/odoo/odoo/pull/278597 ------ Benchmark code, explain analyze for each case + plots: [benchmark.zip](https://github.com/user-attachments/files/31776770/benchmark.zip) Comparing old approach vs new approach with a growing amount of groups passed to `fetch_bus_notifications` on a 30k rows bus table. Median time over 50 run per batch. <img width="400" alt="bench_no_index" src="https://github.com/user-attachments/assets/e8c8dbee-ed1a-4941-867c-9ac0f251693a" />
This update adds a dedicated checker to catch risky database query patterns that could lead to SQL injection vulnerabilities. It helps Odoo maintain stronger internal code quality controls while preparing to remove a broader legacy linting dependency.
Original PR description
New linter for sql-injection. The goal is to replace the pylint implementation by a specialized and stricter implementation so that pylint can be removed entirely in https://github.com/odoo/odoo/pull/257457. Findings of this linter are covered in https://github.com/odoo/odoo/pull/282652. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Timesheet and invoice analytic records now automatically fill in missing sales and product details from related information. This makes reporting and grouping by product or sales order item more accurate for sales and service teams.
Original PR description
Analytic lines are missing two direct links that could be inferred from existing information: a timesheet has a sales order item and no product, and the analytic entries of an invoice have a product and no sales order item. With this PR, each side is filled in from what is already known Task-6486240
Customer lists now show reminder levels and include filters for overdue customers and reminder status. This helps teams quickly identify which customers need follow-up and prioritize collection activity.
Original PR description
- add reminder level column in partner list views - add overdue filter in partner search view - add reminder level in custom filters see odoo/enterprise#128176 task-6462889
The tooltip for the plus button in the Work Orders planning Kanban view now says "Plan Work Order" instead of "Quick add." This makes the button's purpose clearer for manufacturing users and helps reduce confusion when planning work orders.
Original PR description
- Changed the 'Quick add' tooltip to 'Plan Work Order' for the '+' icon in the Work Orders planning Kanban view, making it clearer to users that the action is used to plan a work order. Task ID - 6515112 Enterprise PR: https://github.com/odoo/enterprise/pull/129793
The CRM team switcher is easier to use, with simpler team names and a new default option to view all sales teams. It now appears whenever multiple sales teams use opportunities, making it more consistent and less dependent on configuration settings.
Original PR description
Purpose ======= Improve the usability of the crm team switcher. Specification ============= 1) Removing the "Pipeline" prefix from the switcher title. Users will get that it's the specified team…
Purpose ======= Improve the usability of the crm team switcher. Specification ============= 1) Removing the "Pipeline" prefix from the switcher title. Users will get that it's the specified team pipeline. 2) The "multi-memberships" settings shouldn't impact the switcher visibility anymore. The team switcher is now visible as soon as there's at least 2 teams using opportunities in the DB. NB: The teams actually displayed in the switcher could be a subset of those depending on the current user rights. 3) Adding an "All Sales Teams" option at the top of the team switcher acting as default. The switcher will fallback to it when no team has previously been selected or when the previously selected team cannot be found. Selecting it will remove the team id filter from the domain and remove the "default_team_id" context key from the context. With this scenario, the default team on record creation will be set by the crm.lead "team_id" field compute which will call "_get_default_team_id" from the sales_team module. Task-6485445
The Saudi Arabia accounting template has been reorganized to use a clearer six-digit account numbering structure. This makes the chart of accounts easier to navigate, removes duplicate or obsolete entries, and leaves room for future account additions without disrupting the order.
Original PR description
Restructure the Saudi Arabia chart of accounts to follow the standardized 6-digit numbering convention adopted across recent localizations (account group / subgroup / identifier), reorganizing account ordering for a more logical flow within each category and leaving spacing between codes so new accounts can be inserted later without disrupting the sequence. - Removed 9 obsolete/duplicate accounts (incl. duplicate Withholding Tax Payable) - Added 30 new leaf accounts and 19 new parent/header accounts - Re-mapped codes for all retained accounts while preserving their external ids Related PR: https://github.com/odoo/upgrade/pull/11120 https://github.com/odoo/enterprise/pull/128987 task-6390722
Phone numbers on activities are now available more broadly, so users can click to call even when VoIP is not installed. When VoIP is installed, the calling experience stays consistent across activity links and phone fields, with fixes for mobile and desktop phone link behavior.
Original PR description
See community PR for summary of the feature: https://github.com/odoo/odoo/pull/281277
task-6416875Website editors now see clearer tooltips explaining font weight choices and how multiple form requirement settings work together. The website builder color picker also displays its hex input with the correct light styling in edit mode, improving readability while editing.
Original PR description
**[IMP] website: clarify builder option tooltips** Clarify (with tooltips) font weight settings and how multiple form requirement values are combined. ---------------- **[FIX] html_builder, html_editor: fix color picker hex input** Before this commit, the `hex` color input was dark in Website edit mode. After this commit, it uses the light color defined by the builder. task-6259086 Forward-Port-Of: odoo/odoo#282923
Several buttons across accounting, databases, payroll, marketing, planning, rental CRM, and barcode screens were simplified by removing redundant hover text where the button already has a visible label. This keeps the interface lighter without changing what users can do.
Original PR description
*=databases,l10n_be_hr_payroll,marketing_automation,planning,sale_renting_crm,stock_barcode Remove unnecessary "title" attributes from buttons across views where a visible "string" label is present. The button in which string signifies the original purpose does not need title tooltip which adds unnecessary arch overhead without delivering additional value to the user interface. task-6527163
Customer lists now show reminder levels and include filters for overdue accounts and reminder status. This helps teams quickly prioritize follow-up work and identify customers needing attention without extra manual checks.
Original PR description
- add reminder level column in partner list views - add overdue filter in partner search view - add reminder level in custom filters see odoo/odoo#282886 task-6462889
Hong Kong payroll salary rules now distinguish non-taxable reimbursements and deductions from taxable ones. This makes payroll entries easier to understand and ensures non-taxable deductions are correctly subtracted from net pay.
Original PR description
The CAP57 structure has two reimbursement and two deduction rules, one pair taxable and one not, all named "Reimbursement" and "Deduction". Rename the non-taxable pair accordingly for clarity. Also compute the non-taxable deduction in Python so it is negated, as the DED category is added to NET. task-6263356
Saudi payroll accounting defaults now align with the redesigned local chart of accounts and its standardized numbering. Medical insurance and Iqama/work permit payroll credits are assigned to more specific prepaid accounts, improving financial classification and reporting accuracy.
Original PR description
- In the related PR, we redesign the Saudi Arabia chart of accounts to follow the standardized 6-digit numbering convention. - Following that re-sequencing, this PR splits the Medical Insurance and Iqama/Work Permit rules' credit account from the old Prepaid Employee Expenses account to the new Prepaid Medical Insurance and Prepaid Sponsorship Fees accounts. Related PR: https://github.com/odoo/odoo/pull/284216 https://github.com/odoo/upgrade/pull/11120 task-6390722
The work order planning view now uses default filters that match the Kanban view. This gives manufacturing teams a more consistent experience when switching between planning and Kanban views.
Original PR description
- Updated the work order planning filter to align with the default filters in the Kanban view. Task ID - 6515112 Community PR: https://github.com/odoo/odoo/pull/285566
The Philippines VAT registration setting has been moved from Enterprise reporting into the core Philippines localization so it can be reused by new official invoice reporting. Existing BIR 2306 and 2307 PDF exports continue to use the same setting without requiring business users to change their workflow.
Original PR description
`l10n_ph_is_vat_registered` lived in `l10n_ph_reports`, but the new BIR CAS invoice report added to core `l10n_ph` also needs it, and core cannot depend on an enterprise module. Move the field and its view exposure to core `l10n_ph`, which `l10n_ph_reports` already depends on, so the BIR 2306/2307 PDF exports keep working unchanged against the same field/column. Community PR: https://github.com/odoo/odoo/pull/282405 Upgrade PR: https://github.com/odoo/upgrade/pull/11029 task-6032311
This update fixes reliability issues in guided onboarding tours, especially when tours switch modes, open the editor, or move across pages. Users should experience fewer interrupted or incorrectly validated tour steps in areas such as website forum onboarding.
Original PR description
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
The stock replenishment wizard now has clearer help text, visible tooltips, a slightly larger input field, and smoother refresh behavior. These small usability fixes make replenishment tasks easier and less disruptive for users.
Original PR description
bunch of small fixes that can be merged fast - show tooltips - reword tooltip - remove unused libraries - use soft reload - make the input field slightly larger task 6304907 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an issue where Odoo live chat embeds could block browser keyboard shortcuts such as Alt+D on external websites. The shortcut overlay now only intercepts the Alt key when there are actual Odoo shortcut hints to show, preserving normal browser behavior otherwise.
Original PR description
Description of the issue/feature this PR addresses: When `im_livechat` (or any page) boots the OWL web stack with no `[data-hotkey]` / `withOverlay` targets, pressing Alt still called…
Description of the issue/feature this PR addresses: When `im_livechat` (or any page) boots the OWL web stack with no `[data-hotkey]` / `withOverlay` targets, pressing Alt still called `preventDefault()` in `hotkey_service`. That blocked browser shortcuts such as Alt+D (focus address bar) on websites that embed the livechat scripts. See https://github.com/odoo/odoo/issues/267928 Current behavior before PR: - Pressing the overlay modifier (Alt, or Ctrl on macOS mapped to `"alt"`) always set `overlaysVisible = true` and called `preventDefault()`, even when there were no hotkeys to overlay. - A follow-up key (e.g. D while Alt is held) then also hit `preventDefault()` because overlays were considered visible. - Loading `/im_livechat/loader/...` + `assets_embed.js` on an external site therefore broke browser Alt shortcuts. Desired behavior after PR is merged: - `addHotkeyOverlays` returns whether overlays were actually displayed. - `preventDefault` on the overlay modifier runs only when there is at least one overlay target. - Pages with no hotkeys (typical livechat embed) leave browser shortcuts alone. - When hotkeys exist, Alt still shows overlays and cancels the default, same as before. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284145
This fixes a Point of Sale issue where the cash drawer could fail silently after refreshing the session because the default printer was not always remembered. The system now consistently saves the printer choice and prompts staff to select one when needed, helping checkout operations run smoothly.
Original PR description
Steps to reproduce: - Set only one printer with cashdrawer - Open PoS - Try to open the casdrawer => Silently won't open Issue: defaultPrinter was only saved in localstorage when various printer was set on the config. Fix: Now the printer is always saved in the localstorage so that when the pos is refresh, defaultPrinter is always set. Also when trying to open the cashdrawer if various printer are set in the config, make sure that the select default printer popup is shown. Task-6519466 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#285689
Product pages now keep multi-checkbox options unselected unless the shopper chooses them. This prevents confusing automatic selections and unwanted URL changes after refreshing a product page.
Original PR description
**Steps to reproduce:** 1. Create a product. 2. Add two attributes: multi-checkbox and any single-select type (e.g. Radio). 3. Publish the product and open its page on eCommerce. 4. Verify that no…
**Steps to reproduce:**
1. Create a product.
2. Add two attributes: multi-checkbox and any single-select type (e.g. Radio).
3. Publish the product and open its page on eCommerce.
4. Verify that no multi-checkbox option is selected by default.
5. Refresh the page twice.
**Issue:**
On the second page refresh, the first option of the multi-checkbox attribute is automatically selected, and the URL is updated with its parameter.
**Cause:**
- `_prepare_product_values` construct attribute combinations by mapping requested `attribute_values` query parameters line by line.
- When URL query parameters were present (e.g., set after the first refresh), the fallback logic `or ptal.product_template_value_ids.filtered('ptav_active')[:1]` treated unselected `multi_checkbox` attribute lines as missing required selections rather than empty selections, forcing them to default to their first active option.
**Fix:**
If no selection is provided for `multi_checkbox` line, return an empty recordset instead of falling back to the first active option.
opw-6494697
Forward-Port-Of: odoo/odoo#286492
Forward-Port-Of: odoo/odoo#284798Custom website snippet previews now display oversized responsive text more accurately in the snippet selection dialog. This helps editors recognize saved snippets without the preview being distorted, while leaving the actual page content unchanged.
Original PR description
Steps to reproduce: - Go to the website editor. - Add a snippet with editable text to the page. - Select the text and set its font size to 144. - Save the edited block as a custom snippet. - Open the…
Steps to reproduce: - Go to the website editor. - Add a snippet with editable text to the page. - Select the text and set its font size to 144. - Save the edited block as a custom snippet. - Open the snippets dialog. - Go to the Custom category. => The custom snippet preview shows the text too large. Before this commit, responsive font sizes using `clamp()` with a `vw` term were rendered too large in the block dialog. The `vw` value was based on the full preview iframe width, while snippets were displayed inside columns. After this commit, the block dialog adjusts `vw` values on cloned `.o_rfs` preview content only, so the preview matches its column width without changing the snippet dropped on the page. task-6303725 | BEFORE (font size -> 144) | AFTER (font size -> 144) | | ------------- | ------------- | | <img width="416" height="409" alt="image" src="https://github.com/user-attachments/assets/e0eb0a4e-eb7b-4ee6-b080-536ea2a75c68" /> | <img width="421" height="272" alt="image" src="https://github.com/user-attachments/assets/6468a234-0966-45c9-9435-e97d9752b794" /> | Forward-Port-Of: odoo/odoo#286228 Forward-Port-Of: odoo/odoo#273257
The website shop editor no longer crashes when users choose the Grid catalog preset in the products design panel. This makes product page customization more reliable by preventing duplicate preset controls from conflicting internally.
Original PR description
Steps to reproduce: 1. Open the website editor on /shop. 2. Select the products grid and expand Products Page in the sidebar. 3. Click the Design button to open the Products Design sliding panel. 4. Click the 4th preset (Grid catalog) in the Preset picker. Before this pr: - The page crashed with a render loop error. After this pr: - presets can be picked normally, no crash. The preset list was being drawn twice at once, and both copies were registering under the same internal ID. Now each copy gets its ownnsuffixed ID, so they don't clash anymore. Also removed a redundant duplicate t-if on BuilderSelectItem already covered by its parent t-if. Also removed a dead label.translate="Presets" attribute that ProductsDesignPanelPresets never reads. opw-6478531 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284636
Fixes a spelling mistake in the website editor’s Instagram video embed option. Users will now see “Instagram” spelled correctly when adding an Instagram reel, making the editor look more polished and professional.
Original PR description
Steps to reproduce: - Edit existing page. - Paste any Instagram reel. - In powerbox Instagram entry is listed as "Embed Intagram Video". Introduced by https://github.com/odoo/odoo/commit/2bae2abd4db704451234b115eb4942dcae7d8afa This commit fixes typo. Forward-Port-Of: odoo/odoo#286529
The demo payment provider now handles refunds correctly after a manually captured payment. This prevents users from getting stuck with a negative authorized amount and keeps refund testing flows reliable.
Original PR description
Issue: --- When using manual capture, you can refund the transaction but it will be only authorized, and you'll then be blocked with a negative authorized amount and the impossibility to refund it. This seems to be specific to demo payment provider. Steps: 1- Enable manual capture on demo provider. 2- Buy a product from shop and checkout and pay. 3- Capture the payment in backend. Then click on post process. 4- Try refund. opw-6413515 Forward-Port-Of: odoo/odoo#286625 Forward-Port-Of: odoo/odoo#282315
This fixes an issue where some already-applied website editor options could be ignored when their priority value was negative. It helps ensure the editor correctly recognizes the selected option, improving reliability for users editing page components.
Original PR description
The function `useSelectableComponent` looked for the selected option by searching for the option with the highest priority among the options that are applied. The search for highest priority implicitely excluded options with negative priority. This case happens with `composite` action when the inner actions have no definition of `getPriority`. This commit initialize the "highest priority found so far" as `-Infinity` instead of 0. task-5245362 Forward-Port-Of: odoo/odoo#286652 Forward-Port-Of: odoo/odoo#286503
Users can now download spreadsheets with inserted images as Excel files without hitting an access error. The export process now uses the image access permissions already used in the web interface, so shared spreadsheet images remain available during export.
Original PR description
Since https://github.com/odoo/enterprise/pull/97488, the images are shared across spreadsheets and the attachments are no longer related to a specific record. Due to the management of the…
Since https://github.com/odoo/enterprise/pull/97488, the images are shared across spreadsheets and the attachments are no longer related to a specific record. Due to the management of the IrAttachment access rights, it means that those attachments are not accessible by anyone by default and we rely on the access_token to display them in the webclient. However, the method that builds the final xlsx file fetches the images from the server and did not use the access token, meaning that it could never access the attachment. Such situation raised a UserError that was caught by the webclient. How to reproduce: - As admin, create a spreadsheet and insert an image inside of it - try to download the spreadsheet as an xlsx file counterpart of https://github.com/odoo/enterprise/pull/126384 Task-6432724 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#285981 Forward-Port-Of: odoo/odoo#279788
This update fixes outdated internal documentation about how temporary records are accessed. It clarifies that these records follow normal access rights and record rules, reducing confusion for teams maintaining or auditing permissions.
Original PR description
Since 6d8688bb124d, TransientModel records use the regular access rights mechanisms instead of being implicitly restricted to their creator. The docstring was not updated with that change and has therefore incorrectly documented creator-only access since 14.0. Forward-Port-Of: odoo/odoo#286374 Forward-Port-Of: odoo/odoo#286251
Italian electronic invoices now list only the relevant linked down payment document instead of including unrelated past invoices or the current credit note. This helps avoid incorrect FatturaPA XML content and reduces confusion or compliance issues when issuing credit notes and final invoices.
Original PR description
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without…
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without reconciling it with anything else. - Generate the FatturaPA XML for credit note A. - Observe that DatiFattureCollegate lists both down payment invoice A and credit note A itself, instead of only down payment invoice A. On an order with several down payment invoices/credit notes over time, every one of them is listed instead of just the document the current credit note actually reverses. Cause of the issue: _l10n_it_edi_export_data built downpayment_moves from self.invoice_line_ids._get_downpayment_lines().move_id with no filtering. _get_downpayment_lines() (sale override) returns every invoice line ever created against the same down payment sale order line, across the whole life of the order, not just the invoice the current document actually relates to. The template renders DatiFattureCollegate for every one of those moves unconditionally, on top of the already-correct reversed_entry_id/reconciled_moves fallback, including the current document itself. Solution: Restrict downpayment_moves to lines with a negative price_subtotal, mirroring the existing down payment deduction-line detection a few lines above, and explicitly exclude the current document. This limits DatiFattureCollegate's down payment entries to the case they are meant for: a final invoice actually deducting a previously invoiced down payment. opw-6429716 Forward-Port-Of: odoo/odoo#285555 Forward-Port-Of: odoo/odoo#279938
The onboarding walkthroughs for Rental and Studio were adjusted so automated guided tours run correctly. This helps keep setup guidance reliable for users and prevents validation issues in tour steps.
Original PR description
rental_tour: use stepUtils.saveForm() instead of a manual save click, and add missing isActive:["manual"] twins for autocomplete selection steps. web_studio_new_app_tour: drop two timeout keys rejected by the onboarding step schema.
Belgian payroll attestations now handle employee contracts that do not have an end date. This prevents errors or incorrect occupation information for ongoing contracts, improving payroll document reliability.
Original PR description
A check was missing if the contract end date was false Forward-Port-Of: odoo/enterprise#130410 Forward-Port-Of: odoo/enterprise#130346
The UK CIS report now correctly includes payment information for receipts that use CIS taxes. This ensures businesses get a more complete and accurate view of CIS-related transactions, not just vendor bills.
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#129395 Forward-Port-Of: odoo/enterprise#124043
This fixes an issue in Project Forecast where automatic planning could behave incorrectly when several roles were involved. Businesses using role-based forecasting should see more reliable planning results and fewer manual corrections.
Original PR description
task-6484707 Forward-Port-Of: odoo/enterprise#130166 Forward-Port-Of: odoo/enterprise#128541
DHL shipping in Odoo no longer automatically requests a package pickup. This removes the need to set pickup windows, reduces DHL configuration errors, and makes DHL behave more consistently with other shipping carriers.
Original PR description
Before this commit, the DHL REST module had the pick-up request set, which led to an unnatural use flow, needing to set up an scheduled date for pick-up, and several errors from DHL when these were not properly configured. This feature was unique to this module among the shipping carriers as we don't normally request pick-up for packages and leave it to user to decide how to do it. This commit removes the request for pick up and the logic that was needed to make it work. This will make the behavior consistent with other carriers in Odoo, and avoids the need to set scheduled pick-up windows and having to deal with unnecessary errors. opw-6148927 Forward-Port-Of: odoo/enterprise#123773
The event booth registration page now ignores outdated booth lists when visitors switch categories quickly. This prevents the page from showing booths from the wrong category and helps exhibitors complete booth selection without needing to reload.
Original PR description
Before this commit, the "Get A Booth" page of an event could keep listing the booths of the category checked on load after the visitor picks another one. Only a page reload brought the right ones…
Before this commit, the "Get A Booth" page of an event could keep listing the booths of the category checked on load after the visitor picks another one. Only a page reload brought the right ones back. The tour webooth_exhibitor_register timed out on that list: FAILED: [5/13] Tour webooth_exhibitor_register -> Step Choose Booth (trigger: .o_wbooth_booths div:contains(OpenWood Demonstrator 2) input:not(:visible)). TIMEOUT step failed to complete within 10000 ms. This happens because the page fetches the booths of the category checked on load, and clicking another category fetches its booths while that first answer is still on its way. The answer coming back last fills the list, and the widget caches it under the category active on arrival, so the booths of the first category land in the cache of the clicked one. This commit fixes the issue by caching an answer under the category it was asked for, and by filling the list only while that category is still the chosen one. https://runbot.odoo.com/odoo/error/110527 https://runbot.odoo.com/odoo/error/161834 Forward-Port-Of: odoo/odoo#286552 Forward-Port-Of: odoo/odoo#286266
French tax closing entries now correctly include VAT credits carried over from the previous period. This helps ensure VAT returns and journal entries comply with French accounting requirements and avoid missing credit balances.
Original PR description
### Issue before this commit: When generating a tax closing entry for France, the VAT credit carryover from the previous period is missing from the journal entry lines. ### Steps to reproduce the…
### Issue before this commit: When generating a tax closing entry for France, the VAT credit carryover from the previous period is missing from the journal entry lines. ### Steps to reproduce the issue: 1. Download Accounting and l10n_fr 2. Go to Vendor > Bills 3. Create a vendor bill with date in June and price > 0 (ex. 1000$) and the 20% G tax that produce a 200$ VAT tax 4. Go to Customers > Invoices 5. Create an invoice with price > 0 (ex. 9000$), the date in July and the 20% G tax that will produce a 1800$ VAT tax 6. Go to Tax Return and validate all opened months up to July and see that for June the balance is -200$ 9. Then go to View Entries of July using the 3 dots next to the "submit" button and see that there is no mentioning of the 200$ carry over of credit from the month before ### Cause of the issue: The issue stems from a structural change in the core code where the logic to evaluate and balance the tax receivable account was removed from the _add_tax_group_closing_items method. Consequently, the VAT closing entry now only processes the current period's taxes and there is no reporting of any carried-forward VAT credits. ### Reason to introduce the fix: French accounting rules strictly require the carried-forward VAT credit to be explicitly integrated into the current period's tax closing entry. opw-6438648 Forward-Port-Of: odoo/enterprise#130377 Forward-Port-Of: odoo/enterprise#129181
This update adds test coverage to ensure spreadsheets exported to Excel keep embedded images correctly. It helps reduce the risk of broken exports for users sharing or downloading spreadsheet documents.
Original PR description
Counterpart of https://github.com/odoo/odoo/pull/279788 Task-6432724 Forward-Port-Of: odoo/enterprise#130172 Forward-Port-Of: odoo/enterprise#126384
This fix removes sample planning data that could fail to load when an optional project planning feature is not installed. It helps ensure the Helpdesk, Field Service, Sales, and Timesheets integration installs reliably without requiring an unrelated module.
Original PR description
…ct on helpdesk intervention Before this commit, `project_id` field in `planning.slot` only exists if `project_forecast` module is installed. However, when `helpdesk_planning_field_service_sale_timesheet` is installed, we cannot guarranty `project_forecast` module is also installed since it is not in the dependencies of `helpdesk_planning_field_service_sale_timesheet` module. This commit just removes the demo data inside `helpdesk_planning_field_service_sale_timesheet` module. Forward-Port-Of: odoo/enterprise#130433
The French VAT reporting flow now checks for duplicate XML declarations before sending them to Aspone. This helps avoid rejected submissions and prevents unnecessary paid contacts with the service provider.
Original PR description
When sending an xml to aspone, they will check if a duplicate declaration exist, and if it's the case, then they will refuse it. Since contacting aspone cost us money we will block the sending before that. task-6420220 Forward-Port-Of: odoo/enterprise#130406 Forward-Port-Of: odoo/enterprise#127953
This fix prevents point-of-sale online payments from appearing twice in an order's payment history after confirmation. It also avoids an error when online self-ordering settings are unavailable, improving reliability for stores using POS online payments.
Original PR description
Also, bug noticed while working on task-6472188
Opening a project task in the customer portal could fail when the Timesheets app was not installed. The fix keeps time formatting available from the Project app itself, so portal task pages load reliably in more setups.
Original PR description
Before this commit, opening the portal page of a task in a database without hr_timesheet answers a 500:
AttributeError: 'account.analytic.line' object has no attribute
'_format_portal_hours'
This happens because project's portal_my_task_allocated_hours_template formats the allocated time with `_format_portal_hours`, a method hr_timesheet adds on `account.analytic.line`.
This commit moves that method to project, next to the template that calls it.
https://runbot.odoo.com/odoo/error/946944This fixes a small display issue where expanded inventory valuation lines still showed a closed-folder icon. Users now get the correct visual cue when sublines are open, reducing confusion while reviewing stock valuation details.
Original PR description
c5a40a608280 ([IMP] *: apply new icon implementation globally) introduced a typo: it replaced a working `fa-folder#{this.state.displaySublines ? '-open' : ''}-o` with the new icon API and dropped the `s` on the way. Only master carries that rewrite, so this is master-only -- saas-19.4 and older still have the FontAwesome form and are correct there.
Additionally before the commit rewrite the icon was never filled so we drop the fill condition as wellBelgian payroll meal voucher reports now correctly include postponed vouchers for employees assigned to a branch company. This prevents missing carryovers when payroll documents are created under a branch while the report is managed by the parent company.
Original PR description
Steps to reproduce: - Create a July payslip for Bernice and mark it as paid - Generate the meal voucher report for july - Create 3 time off for Bernice in July - Correct the payslip of July, in total…
Steps to reproduce: - Create a July payslip for Bernice and mark it as paid - Generate the meal voucher report for july - Create 3 time off for Bernice in July - Correct the payslip of July, in total we have 3 payslips now - Create an August payslip for Bernice - Create the meal voucher report for august Pay attention to: everything has been created under "My Belgian Company" while Bernice is in the branch "My Belgian Office" Current Behaviour: When the august mealvoucher report is not marked as done, the postponed shows 0 for Bernice. Expected Behavior: When the report is not marked as done, august should have 3 mealvoucher postponed for Bernice. The technical reasons behind this bug is that the SQL query for unreported payslips mapped to draft/ready reports filtered the payslips `company_id` on the mealvoucher `company_id`. But payslips for Bernice are under the branch "My Belgian Office" and the mealvoucher is created in "My belgian company". The SQL query should take company branches into account, same as in `_get_corrected_payslips`. task-6428719
The map view now uses the record limit defined by the action when no specific map limit is set. This makes map behavior consistent with other views and helps users see the expected number of records.
Original PR description
The map view only considered the `limit` set in the arch, ignoring the one coming from the action (`ir.actions.act_window.limit`), unlike other views (list, kanban) which fall back to it. task-6531776
Discount reward products are now created without automatically applying the company's default sales tax. This prevents discounts from being taxed incorrectly and keeps loyalty reward calculations aligned with expected untaxed discount behavior.
Original PR description
The reward's discount_line_product_id was created without an explicit taxes_id, so it silently fell back to the company's default sale tax (account_sale_tax_id) instead of staying untaxed like the rest of the program's discount/reward mechanics expect. Explicitly clear taxes_id when creating the discount product. task-6528122
This fix prevents automated accounting-related processes from failing when they run with elevated permissions on behalf of users who do not have accounting access rights. It helps modules that need accounting reports, such as localization reporting, complete setup or return creation reliably.
Original PR description
This was spotted in a dev branch for master, where we set a default account_opening_date on every company, hence trying to directly create the returns for it. Some modules need to call reports for that (like intrastat l10n), and do it in sudo(). However, even in sudo, a user without the accounting rights still doesn't have the proper group, and it raises an exception. We hence adapt the condition. Forward-Port-Of: odoo/enterprise#130448
This fixes a small visual issue where the side area of kanban cards could have slightly mismatched rounded corners. The update makes card styling more polished and consistent by accounting for the card border when applying corner rounding.
Original PR description
Ensure the aside element gets the right `border-radius` value by taking the `border-width` of the kanban card into account when computing the radius value. task-6537730 | Master (top radius is incorrect due to the border width) | This PR (take the border width into account) | |--------|--------| | <img width="122" height="186" alt="image" src="https://github.com/user-attachments/assets/ec39123d-f874-4374-805e-82371d5ed8d4" /> | <img width="125" height="191" alt="image" src="https://github.com/user-attachments/assets/25ba6513-d1b3-4f18-805d-afa83c152bff" /> |
Point of Sale screens now keep category images inside their buttons and use higher-resolution product images. This makes the sales interface cleaner and easier to recognize items quickly during checkout.
Original PR description
Category images overflowed their buttons because width-based ratio classes conflicted with the fixed button heights. Furthermore, product images appeared blurry because the low-resolution `image_128` was stretched to fit modern product cards. This ensures category images respect parent boundaries and fetches higher resolution product images. task-6479160
Time entries recorded outside an employee's normal schedule now behave correctly. Working time is counted as requested, while absences outside the schedule now show a clear message instead of silently recording zero time.
Original PR description
…dule Encoding a time type outside an employee's working schedule silently did nothing: 0 duration, no feedback, for both working time and absence types. Working time entries now count the requested time instead of 0. Absences still can't be taken outside the schedule, but now say so instead of silently doing nothing. Task-6501553
Fixes visual spacing problems introduced by the Frost design in list, kanban, and search panel views. This keeps the Community interface cleaner and more consistent while moving edition-specific styling to the right place.
Original PR description
Since the introduction of the Frost design, some spacing customizations for the List, Kanban, and Search Panel views have been defined in Community instead of Enterprise, causing spacing issues in…
Since the introduction of the Frost design, some spacing customizations for the List, Kanban, and Search Panel views have been defined in Community instead of Enterprise, causing spacing issues in Community. To fix this, this commit moves the relevant customizations to Enterprise and adapts them accordingly. task-6527607 Requires: - https://github.com/odoo/enterprise/pull/130335 | Before | After | |--------|--------| | <img width="1914" height="769" alt="Screenshot 2026-09-03 at 16 41 22" src="https://github.com/user-attachments/assets/9fa1be40-e3ff-4679-a739-dc86de516607" /> | <img width="1916" height="756" alt="Screenshot 2026-09-03 at 16 39 55" src="https://github.com/user-attachments/assets/6c6530f6-b20f-4339-b1ce-2ac4d7f8b837" /> | | <img width="1915" height="723" alt="Screenshot 2026-09-03 at 16 41 20" src="https://github.com/user-attachments/assets/0f7abbea-d9ab-4850-9d7f-7aae0995321b" /> | <img width="1918" height="753" alt="Screenshot 2026-09-03 at 16 39 46" src="https://github.com/user-attachments/assets/03855cf2-28b5-4b26-9fe2-30a9f9eec3d5" /> | | <img width="1918" height="550" alt="Screenshot 2026-09-03 at 16 41 05" src="https://github.com/user-attachments/assets/c4c6c703-55e9-4653-90c1-c6ce93610c0a" /> | <img width="1917" height="598" alt="Screenshot 2026-09-03 at 16 40 59" src="https://github.com/user-attachments/assets/02af42f0-84ed-457a-870c-8afd3efb0bcd" /> | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change restores the correct table layout in the inventory report after a previous update caused extra columns to appear in the report body. It helps ensure inventory information is displayed clearly and consistently for users reviewing stock reports.
Original PR description
This reverts commit 43add3f72f29c35280869010b897c3c5656f5120. It was adding too many columns in table body after columns were removed from the header in 19.0. opw-6307728 Forward-Port-Of: odoo/odoo#286294
This fixes a visual spacing issue in the control panel actions that could appear when custom actions were added. It helps keep the interface aligned and consistent after recent UI updates.
Original PR description
After the new ui improvements the control panel actions had some styling issues when xpath is used to add new actions. no task id
Accounting now correctly flags a draft journal entry as creating a numbering gap when a later entry is posted after it. This helps businesses maintain clearer audit trails and avoids unnoticed gaps in journal entry sequences.
Original PR description
To reproduce: * create and post 2 journal entries in the same journal * reset to draft the entry with the highest number * create and post a third entry in the same journal The draft entry is not flagged as having made a gap, because at the time of resetting it to draft, it was the last entry and therefore didn't really make a gap. 3 options to solve were considered: * flag all moves when reseting to draft even if they were the last of the chain * if we reset the last move of the sequence to draft, also remove its sequence and put it back to `/` * when posting, check if the previous number was draft. If it was the case, flag it. The last options was taken in this fix to avoid changing the previous behavior while fixing the current issue. Forward-Port-Of: odoo/odoo#286204
The VoIP sound upload area now opens the file selector when users click anywhere inside the upload zone, not just on the icon or label. This makes the form behave as users expect and reduces confusion when uploading or recording sounds.
Original PR description
In a sound form, the file selector only opened when clicking directly on the Upload icon or label. Clicking elsewhere inside the drop zone had no effect, although the entire area looked interactive. Use the complete drop zone as the FileUploader toggler and render it as a button. Also show the pointer cursor consistently on the Upload and Record zones.
Creating a salary contract offer for Belgian employees no longer triggers an unintended Dimona update. This prevents incorrect or meaningless data from being sent to the government service during salary simulations.
Original PR description
### Issue When creating a salary contract offer (smart button 'New Offer' in the employee form), a dimona action can be triggered, sending no-sense value to the government api. ### Reproducing steps…
### Issue
When creating a salary contract offer (smart button 'New Offer' in the employee form), a dimona action can be triggered, sending no-sense value to the government api.
### Reproducing steps
I've only been able to observe that by placing a breakpoint in the `hr.version.write` of the `hr_version.py` of `l10n_be_hr_payroll`:
- Create a master (1 sept. 2026) database with demo data and the following modules installed: `l10n_be_hr_contract_salary,test_l10n_be_hr_payroll_account`
- Set the dimona environment of the demo belgian company to 'Sandbox'
- Go to the employee Laurie Poiret
- Set the current contract end date to 1 day before today
- Create a dimona IN declaration for the last contract of Laurie Poiret (the one that has just been modified) (ctrl + k / DIMONA)
- On employee form: click on 'Check Dimona' and apply the response, the state of the dimona should appear ('Done')
- Create a new contract ('New Contract' button on the employee payroll tab) and set it to today
- Change the contract start date to tomorrow so that the dimona state become 'In progress'
- Click on the smart button 'New Offer'
- See that the `hr.version.action_update_dimona` is executed (but it shouldn't)
task-6521357This fix restores the intended visual spacing in key Enterprise views after design-related styles were placed in the wrong edition. Users should see more consistent layout spacing in list, kanban, and search panel areas, while Community no longer inherits Enterprise-specific spacing behavior.
Original PR description
Since the introduction of the Frost design, some spacing customizations for the List, Kanban, and Search Panel views have been defined in Community instead of Enterprise, causing spacing issues in Community. To fix this, this commit moves the relevant customizations to Enterprise and adapts them accordingly. task-6527607 Requires: - https://github.com/odoo/odoo/pull/286518 | Before | After | |--------|--------| | <img width="400" height="302" alt="Screenshot 2026-09-03 at 16 44 42" src="https://github.com/user-attachments/assets/4872fb70-cc75-4d8b-80d2-6d5ff44fe1b0" /> | <img width="399" height="301" alt="Screenshot 2026-09-03 at 16 44 45" src="https://github.com/user-attachments/assets/92ff245a-7416-4652-98b1-1a90951cc8c3" /> |
This fix prevents Belgian payroll payslips from creating duplicate input lines when a payslip is recalculated. It keeps payroll records cleaner and helps avoid incorrect or confusing payroll calculations after edits.
Original PR description
Steps to reproduce: - Create a December BE payslip so SIMPLE_DECEMBER/DOUBLE_DECEMBER_BASIC get seeded (or any struct feeding a BE-specific input code). - Trigger a recompute (edit date_from and save again). - Input line for that code is duplicated instead of replaced. _compute_input_line_ids's BE override only appended input lines, never unlinking the one it created last pass. Unlink existing line for a code before recreating it Task 6516068
Hourly and half-day time off requests on weekends or public holidays will no longer disappear without explanation. The system now sends these requests to the server so valid working-time entries are created and invalid absence requests return a clear message.
Original PR description
Issue: Creating an hourly or half-day (AM/PM) time off entry on a day flagged as a weekend/public holiday for the employee did nothing: no entry, no error. Cause: multiCreateRecords() pre-filtered out any such day client side via get_unusual_days(), regardless of the work entry type. Fix: Remove the client-side filter and let every selected day go through create(), with multi_leave_request set in the context so the server decides and notifies. working time entries get a real duration, absences get dropped with a clear message (see community PR). Task-6501553
Expense-created vendor receipts in Mexico now correctly include and display their CFDI XML attachment. This helps users access required tax documents directly from the bill and ensures these receipts can be checked with SAT services when needed.
Original PR description
**Current behavior:** Currently, account moves created from expenses (type receipt) don't include the XML when it is a CFDI. Causing users cannot see their attachment even though it is created on DB. https://docs.google.com/videos/d/1eFSAA-wvUzPDwIJDeiS2dkne94lGM7QBxRfjN3HxaLw/play **Versions:** 19+ **Fix:** Implementing a new helper to identify those moves that can actually hold a CFDI document (for now, all `is_invoice()` documents + vendor bill receipt, `in_receipt`), so now, we include 'in_receipts' in _compute_l10n_mx_edi_cfdi_state_and_attachment, _compute_l10n_mx_edi_document_ids, _compute_l10n_mx_edi_update_sat_needed and l10n_mx_edi_cfdi_try_sat. As these documents might need to fetch SAT services as well. Task-id: [6397080](https://www.odoo.com/odoo/project/49/tasks/6397080) Forward-Port-Of: odoo/enterprise#130045 Forward-Port-Of: odoo/enterprise#126493
Uploading a refund from bank transactions now creates a vendor credit note in the correct purchase journal instead of a customer credit note. This helps refunds reconcile properly against vendor payables and prevents accounting errors during bank reconciliation.
Original PR description
**Steps to reproduce:** * Install **Accounting** module. * Go to **Accounting → Bank → Transactions** (bank reconciliation widget). * Open a transaction with a **positive** amount (e.g. a vendor…
**Steps to reproduce:** * Install **Accounting** module. * Go to **Accounting → Bank → Transactions** (bank reconciliation widget). * Open a transaction with a **positive** amount (e.g. a vendor sending money back). * Click the three-dot menu on the transaction line and choose **Upload a Refund**. * Upload any document (XML or PDF). **Observed behavior:** * A **Customer Credit Note** (`out_refund`) is created in a **sale** journal instead of a **Vendor Credit Note** (`in_refund`) in a **purchase** journal. * The wrong document type means the reconciliation fails to link the refund against the correct payable account. **Cause:** * In `create_document_from_attachment` (`account_bank_statement.py`), the JS widget sends `type='sale'` in context when the transaction amount is positive (JS: `amount > 0 ? "sale" : "purchase"`). * The original code mapped `type='sale'` → `default_move_type='out_refund'` (customer credit note) and searched for a `sale` journal — both wrong. * Uploading from a bank statement is always a **vendor-side** operation: negative amount = vendor bill (`in_invoice`), positive amount = vendor refund (`in_refund`). The `type` context key from JS reflects transaction direction, not the accounting document type. * Additionally, `in_refund` is a purchase document; Odoo's `_check_journal_move_type` constraint raises a `ValidationError` if a purchase document is created in a non-purchase journal, meaning the old code would crash at the ORM level for the refund path. **Fix:** * Map `type='sale'` → `default_move_type='in_refund'` (vendor credit note) instead of `out_refund`. * Always search for a **purchase** journal regardless of the `type` context value, since both `in_invoice` and `in_refund` are purchase-side documents. opw-6468779 Forward-Port-Of: odoo/enterprise#129385 Forward-Port-Of: odoo/enterprise#127912
This update adjusts how dropdown menus track their target elements as part of the ongoing web platform migration. It prevents pivot table dropdowns from losing required styling or failing to open correctly, improving reliability without changing the user experience.
Original PR description
Remove useLayoutEffect from dropdown.js as part of OWL3 migration.
Odoo now calculates Mexican CFDI payment complements using the same rounded amounts that appear in the XML. This prevents valid USD invoices with MXN payments from being rejected by the tax certification provider with error CRP20268.
Original PR description
**Steps to reproduce:** * Install the **l10n_mx** localization. * Enable **USD** and fetch the latest currency exchange rate from the settings. * Configure **Quadrum** as the **PAC** in the settings.…
**Steps to reproduce:**
* Install the **l10n_mx** localization.
* Enable **USD** and fetch the latest currency exchange rate from the settings.
* Configure **Quadrum** as the **PAC** in the settings.
* Create and sign a USD invoice with **16% IVA** (e.g. 4,500 USD + 720 USD tax = 5,220 USD total).
* Send the invoice to **CFDI**.
* Register a **partial MXN payment** that does not convert to a round USD amount (e.g. 30,000 MXN = 1,762.45 USD).
* Send the payment complement to the PAC by clicking **Update Payments** on the invoice.
**Observed behavior:**
The PAC rejects the CFDI with error **CRP20268**:
> El campo BaseP que corresponde a Traslado, no es igual a la suma de
> los importes de las bases registrados en los documentos relacionados
> donde el impuesto del documento relacionado sea igual al campo
> ImpuestoP de este elemento y la TasaOCuotaDR del documento
> relacionado sea igual al campo TasaOCuotaP de este elemento.
**Cause:**
* The SAT validator enforces a strict arithmetic relationship between three fields that are printed in the payment complement XML:
```
BaseP == round(BaseDR / EquivalenciaDR, 6)
```
* When `percentage_paid` is a non-terminating decimal (which happens for any partial MXN payment against a USD invoice), the internal `raw_base` float carries more precision than the 6-decimal-place `BaseDR` that is actually written to the XML:
```
percentage_paid = 1762.45 / 5220 = 0.33763409961685825...
raw_base = 4500 × 0.33763... = 1519.353448275862...
BaseDR (XML) = float_round(raw_base, 6) = 1519.353448
```
* The old code then used `raw_base` (the unrounded internal value) as the dividend when computing BaseP:
```
BaseP (old) = float_round(1519.353448275862... / 0.0587483333, 6)
= 25862.068980 ← written to <TrasladoP BaseP="...">
```
* The PAC performs the same division using only what it can read from the XML. The already-rounded BaseDR:
```
BaseP (PAC) = round(1519.353448 / 0.0587483333, 6)
= 25862.068975
```
* The 6th-decimal mismatch (25862.068980 ≠ 25862.068975) triggers CRP20268 and the document is rejected.
* The same issue occurs with a full MXN payment on a different date than the invoice when multiple invoice lines cause the rounded aggregate to diverge from the sum of per-line raw values.
**Fix:**
In `_l10n_mx_edi_add_payment_cfdi_values` (`account_move.py`), the block that builds the BaseP aggregation list was changed from iterating over raw per-`base_line` amounts to building a single synthetic entry per invoice using the already-rounded document-level `BaseDR` values (`tax_details['base']`) as the dividend:
- Before : wrong: raw_base ≠ BaseDR printed in the XML
'raw_base': tax_details['raw_base'] / inv_rate
- After : correct: 'base' == BaseDR, the exact value in the XML
'raw_base': tax_details['base'] / inv_rate
This guarantees that Odoo and the PAC divide the identical value, producing the identical 6-decimal result.
The `base_line_cfdi_values_mx_curr_list` path (used only for the `Totales` summary fields rounded to 2 dp) is left unchanged because the CRP20268 rule does not apply to that block.
opw-6468077
Forward-Port-Of: odoo/enterprise#128357The website scroll button now keeps a visible focus indicator when people navigate with a keyboard. This improves accessibility by making it clearer which page control is currently selected.
Original PR description
Scroll button had no outline, which is an issue for people navigating with their keyboards. Now, outline is removed with :focus, but not :focus-visible Task-6009931
Consolidated Malaysian e-invoice reports now group point-of-sale receipts only when they are truly consecutive on the same device. This prevents unrelated receipts or refund-only transactions from being hidden inside misleading ranges, making reports easier to verify and more accurate for compliance.
Original PR description
A consolidated invoice reports a range of PoS receipts per line, so every line claims that the receipts between its two endpoints follow each other. That claim was only loosely enforced: lines were…
A consolidated invoice reports a range of PoS receipts per line, so every line claims that the receipts between its two endpoints follow each other. That claim was only loosely enforced: lines were built by walking every order of the sessions involved and breaking whenever one was not part of the batch. Two receipts that were both in the batch were therefore always merged, whatever sat between them. This breaks down as soon as several devices sell under one config. Receipt numbers come from a counter local to each device, so two orders taken on two devices can carry adjacent numbers without being consecutive receipts, and were reported as a range covering receipts that were never part of it. Lines are now built from an explicit continuity test on both `sequence_number`, gapless within a config, and the receipt reference read from `pos_reference`, which must name the same device and the next receipt number. Neither is sufficient alone: an order can reach the database later than its ticket was opened, so following sequence numbers do not imply consecutive receipts either. A receipt made exclusively of refund lines is no longer merged into the line of the sales it follows. Refunds are usually rung up shortly after the sale they cancel, which made them contiguous with it and hid both inside a netted total - two sales and the two refunds cancelling them were reported as a single line of 0.00. An order mixing refund lines with new sales remains a receipt of its own, reported like any other with the amounts it refunded already deducted from it. The orders linked to a consolidated invoice are also listed in the order in which they are reported on it, rather than in the reverse chronological one used by default for PoS orders, so that the two can be read together. [task-6166533](https://www.odoo.com/odoo/my-tasks/6166533)
Fixes a billing issue where manually increasing a timesheet invoice could prevent later time entries from being invoiced. Businesses can now bill future timesheet periods correctly while keeping refund-related safeguards intact.
Original PR description
## Issue When a use rmanually increases the invoiced quantity on a timesheet invoice, subsequent timesheets logged in future periods can no longer be invoiced. The system assumes that the most recent…
## Issue
When a use rmanually increases the invoiced quantity on a timesheet invoice, subsequent timesheets logged in future periods can no longer be invoiced. The system assumes that the most recent logged hours are already covered by the previously over-invoiced amount, blocking the billing of the most recent timesheet entries.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P
- Product Type: Service
- Invoicing Policy: Based on Timesheets
- Create on Order: (Project &) Task
3. Create an SO:
- Customer: Any
- Product: P (any quantity)
- Confirm
4. Record hours on the task created:
- 06/01/2026 (June 1st): 1 hour
- 07/01/2026 (July 1st): 1 hour
5. Create the invoice for the June timesheet entry (by setting a timesheets period when creating the invoice), then **change the quantity to any value strictly greater than 2** and confirm.
6. Create the invoice for July
7. **An "Invalid Operation" error appears, stating that there's nothing to invoice, even though the timesheet entry from July was never invoiced.**
## Cause
Since https://github.com/odoo/odoo/commit/3b86ac3d180993239b63fd305ee0ba1f17f7eb20, the computation of the quantity to invoice changed to include the difference between the quantity delivered and the quantity already invoiced. In the flow described by the steps to reproduce above, the quantity to invoice is larger than the quantity delivered, making the `qty_to_invoice` equal to `0.0`.
https://github.com/odoo/odoo/blob/626d31fa0191bfe7ca8e1fcf177357eeeb60f2c7/addons/sale_timesheet/models/sale_order.py#L331-L334
The reason for the fix above being the partial refunding of timesheet-related invoices, we can keep that solution when working with refunded invoices, and keep the previous behavior for other cases.
This solution solves the issue in the steps to reproduce above, but was also manually tested on the issues from https://github.com/odoo/odoo/commit/3b86ac3d180993239b63fd305ee0ba1f17f7eb20 and https://github.com/odoo/odoo/commit/64cf4afabd0c5ef040cf87fc6f3125fe0bb81bbb.
opw-6485674
Forward-Port-Of: odoo/odoo#286301
Forward-Port-Of: odoo/odoo#284470This fix ensures Adyen payment information is read from the correct part of the payment notification. It helps prevent payment records from being updated with wrong or missing values, improving transaction reliability for businesses using Adyen.
Original PR description
opw-6512723 Forward-Port-Of: odoo/odoo#286391 Forward-Port-Of: odoo/odoo#284773
Website theme installation now correctly applies the selected theme's layout changes, such as headers and footers. This prevents customers from seeing an incomplete or unchanged website design after using the website configurator.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286407 Forward-Port-Of: odoo/odoo#283174
Selecting a company or contact suggestion now correctly returns the form to its saved state after the record is updated. This prevents users from seeing inactive save or discard buttons after autocomplete has already saved the enriched partner details.
Original PR description
Steps to reproduce: 1) open partner form view 2) type in the name field 3) select a suggestion from the autocomplete dropdown Issue: The record is enriched and saved, but the form still displays the save/discard buttons, and clicking them does nothing. The record dirty indicator is driven by 2 signals 1) `model.root.dirty`, which is cleared by save() call earlier in the onSelect() 2) the state `fieldIsDirty` of the `FormStatusIndicator` The second indicator is set to true when the user types in an input field, and selecting an option never clears it. The `setDirty` prop no longer exists, and therefore was deadcode. This commit emits `FIELD_IS_DIRTY` bus event, which is the only way to update the second indicator. With that, the indicator goes back to saved state once the record is updated. task-6475332 Forward-Port-Of: odoo/odoo#286651 Forward-Port-Of: odoo/odoo#285897
This fixes a crash when generating electronic invoice data in Community Edition without the Enterprise accounting add-on installed. The system now checks whether optional deferred billing date fields are available before using them, helping electronic invoicing work reliably across editions.
Original PR description
The fields `deferred_start_date` and `deferred_end_date` are created by the enterprise addon `account_accountant`, so not having it installed, this crashes with:
```
File "/opt/odoo/auto/addons/account_edi_ubl_cii/models/account_edi_cii.py", line 684, in <listcomp>
billing_start_dates += [move_line.deferred_start_date for move_line in invoice.invoice_line_ids if move_line.deferred_start_date]
AttributeError: 'account.move.line' object has no attribute 'deferred_start_date'
```
This PR protects the access to these fields checking first if they exist.
Bug introduced in the refactoring in #261572.
@Tecnativa TT64359
Forward-Port-Of: odoo/odoo#286245Portal users who follow a project can now reliably open the tasks they are allowed to see, instead of sometimes getting a “not found” error. This improves the customer portal experience by aligning task page access with the task list permissions.
Original PR description
Before this commit, the portal user could have a request not found when he wants to access to a task from a project he follows even if he can access to the task in /my/tasks route. This commit makes sure the read access are checked instead of checking if the user can access to the task thanks to the token since the token if the one of the project. Forward-Port-Of: odoo/odoo#285878
This fix prevents restaurant preparation tickets from failing during installation when the point of sale module has not yet been upgraded. It uses a more stable receipt section that already exists across versions, reducing manual upgrade steps and avoiding issues for customized setups.
Original PR description
The template for the preparation tickets was using an xpath targeting a newly added div element. This raised an error when installing the `pos_restaurant` module while an old version of `point_of_sale` was still in place, since the customer would need to manually upgrade `point_of_sale` first to have that new div element available. We now use receipt-header as the xpath target, which was always present in the template. We also refill `pos_self_order.pos_order_change_receipt` to prevent breaks with custo. --- Report: https://github.com/odoo/odoo/pull/267161#discussion_r3758115362 Forward-Port-Of: odoo/odoo#281768
Live chat visitors will now see the chatbot typing animation while the bot pauses between scripted steps. This makes automated conversations feel more responsive and reduces confusion during short waits.
Original PR description
Before this commit, a chatbot never shows that it is typing: the animated dots between two steps of its script never appear in the livechat. This happens because typingMessage tests this.isTypingUi on the Chatbot record, a getter of discuss.channel.member that Chatbot does not have, so the read is always undefined and no typing message is inserted. This comes from "[IMP] mail: disable isTyping when muted", which renamed the reads of the member field and took the read of the chatbot's own isTyping attribute along. This commit tests isTyping again, so the typing message shows while the script waits between two steps. Forward-Port-Of: odoo/odoo#285930
This fixes a mobile usability issue in the HTML editor where users could not drag and drop table cells inside Todo items. The change prevents the browser's touch handling from interrupting the drag action, making table editing work as expected on phones and tablets.
Original PR description
Steps to Reproduce - Insert a table inside a Todo item. - Long-press the table menu to open the drag-and-drop overlay. - Try to drag and drop table cells. Issue: - Table cells cannot be dragged and dropped on mobile devices. Cause: - On mobile devices, the browser fires `pointercancel`/`pointerleave` during a drag operation, which ends the drag operation prematurely. As a result, subsequent `pointermove` events are not triggered causing the drag-and-drop operation to fail. Solution: - Add `touch-action: none` to the table menu element. This prevents the browser default touch handling from interfering with the drag operation, allowing `pointermove` events to continue and drag-and-drop to work correctly on mobile devices. task-6201176 Forward-Port-Of: odoo/odoo#283866 Forward-Port-Of: odoo/odoo#267680
The Belgian payroll DMFA check no longer fails for flexible employees who do not have a standard work calendar. It now uses their expected weekly hours to validate quarterly work days, helping payroll teams avoid incorrect warnings or blocked processing.
Original PR description
In this other PR (https://github.com/odoo/enterprise/pull/120063) we added a DMFA warning to check that every employee included in a DMFA has worked the correct number of days in the quarter. Since the calendar can change between employees, we were calling a function to tell us for each employee how many days was he supposed to work. However, if an employee is flexible he has no calendar, the function fails. In that case we have the number of hours it's supposed to work per week and we can fallback to that since we know there are exactly 13 weeks in a quarter. Task: 6497142
Odoo now records a VoIP call more accurately when it is answered or rejected in another phone application such as Linphone. This prevents calls from being incorrectly shown as missed and gives users a clearer call history when multiple VoIP tools are open.
Original PR description
Steps to reproduce: - Have an external VoIP software configured (e.g. Linphone) - Have your Odoo configured and opened too - Call your VoIP number, using your smartphone => Both the softphone and…
Steps to reproduce: - Have an external VoIP software configured (e.g. Linphone) - Have your Odoo configured and opened too - Call your VoIP number, using your smartphone => Both the softphone and Linphone ring - Answer or reject using Linphone => The VoIP call record in Odoo immediately switches from "Trying to call" to "Missed". While there was no guarantee for our VoIP integration to work alongside Linphone in 19.0, we decided this should be an easy safe enough fix. Starting 19.2 (with [1]), the fix will be simplified and hopefully prettier thanks to the ameliorations that were made. After this fix, provided Odoo is open while Linphone is used, the call records will now switch to the right terminated / rejected status, still immediately once Linphone answers / rejects. In future versions and especially 20.0+, the system will be different and will allow way more features like this one to work better (e.g. here the call record only even exists if Odoo is opened while using Linphone and we won't have any information about the call duration). [1]: https://github.com/odoo/enterprise/commit/942f32316ab02d8c739fe7fdd5ec2bdde472a68e task-6449259 Forward-Port-Of: odoo/enterprise#130047 Forward-Port-Of: odoo/enterprise#127077
This fixes a visual inconsistency in the VoIP sound form when dark mode is enabled. The form background and its surrounding header now use matching colors, creating a cleaner and less distracting experience for users.
Original PR description
In dark mode, the sound form background and the header of the node containing it used inconsistent colors.
Financial reports no longer show the unallocated earnings or losses line when its balance is zero across all columns. This keeps trial balance reports cleaner and helps users focus on meaningful figures.
Original PR description
… zero The unallocated earnings/losses line was displayed even when its balance was zero in every column group, cluttering the report with uninformative rows. We therefore filter out lines whose balance is zero across all column groups. Forward-Port-Of: odoo/enterprise#129666 Forward-Port-Of: odoo/enterprise#129129
The VoIP call flow editor now displays correctly when dark mode is enabled. This improves readability and creates a more consistent experience for users working with call flows in darker interface settings.
Original PR description
Before this commit, the call flow editor kept its light background and node colors when dark mode was enabled, resulting in poor contrast and inconsistent styling. This commit adds dark mode styles for the canvas, grid, nodes, connections, ports, selection states, and location indicator.
This fix stops users from creating order boxes directly from printer settings. Order boxes must be linked to a real physical device, helping avoid incorrect setup and operational confusion in point-of-sale self-order flows.
Original PR description
We prevent users from creating oboxes from pos.printer model, as oboxes should be paired with an actual device. Forward-Port-Of: odoo/enterprise#130197 Forward-Port-Of: odoo/enterprise#129960
Refund payslips are now recalculated correctly whenever worked days or payslip lines are recomputed, not only after a reset. This helps ensure payroll corrections remain accurate and reduces the risk of incorrect refund amounts.
Original PR description
Instead of only resetting correctly the refund payslip in the reset, ensure that anytime we recompute worked days or lines, the refund is correctly computed. Forward-Port-Of: odoo/enterprise#129332
Added automated checks to ensure time-tracking assistant suggestions are correctly matched to helpdesk tickets and related calendar entries. This reduces the risk of incorrect timesheet links and helps maintain reliable support reporting.
Original PR description
task: 6475133 Forward-Port-Of: odoo/enterprise#130157
Belgian payroll now correctly treats public holidays as unpaid when they fall after an employee's guaranteed sick pay period has ended, even if a new medical certificate starts that same day. This prevents accidental overpayment and improves payroll accuracy for long-term sickness cases.
Original PR description
Steps to reproduce: - Employee on full-time sickness certified month by month (one hr.leave per medical certificate), guaranteed salary period already exhausted. - Compute payroll for the month whose public holiday falls on the first day of a new certificate. - Public holiday work entry stays paid, every other day that month is correctly unpaid. Cause: the 30-day lookback compared exact datetimes instead of calendar dates, so a certificate starting the same day as the holiday but later in clock-time got excluded. Also ignored timezone: date_from is stored in UTC and needs localizing before taking .date(). Fix: compare local calendar dates via hr.leave's own request_date_from/request_date_to instead of raw UTC datetimes. Added a regression test for the split-certificate case. Task 6512860 Forward-Port-Of: odoo/enterprise#129889
Dark mode now uses the full expected color palette and avoids mixing light-mode colors into dark-mode styling. This prevents missing or incorrect colors in screens and labels that rely on automatic color selection.
Original PR description
1) The "$o-colors" css variable was rebuilt in "secondary_variables.dark.scss", which loads after community's "primary_variables.scss" already assigned it via !default. The dark "$o-colors: ()!default;" reset was silently skipped, so dark colors were appended onto the light ones instead of replacing them, doubling "$o-colors" to 24 entries. => Moving this logic to "primary_variables.dark.scss", which correctly loads first. 2) "$o-colors-secondary-original" only listed 18 colors instead of the 44 used in the original "$o-colors-secondary" of light mode, meaning the dark mode's total palette ($o-colors-complete) had far fewer entries than the 56 that the JS helper "getColor()" assumes leading to missing coloring. => Extending the list so that the dark mode "$o-colors-secondary-original" matches the original "$o-colors-secondary" light mode's 44 colors.
This update corrects icon-related issues across the application to improve visual consistency and usability. Users should see clearer, more reliable interface elements, with no expected workflow changes.
This fixes a timing issue in the self-order interface where closing or changing a carousel during a slide could trigger errors in automated flows. The change improves reliability of the self-order experience without altering user-facing features.
Original PR description
Option A (guard in the hook). Disposing a Carousel mid-slide left its queued transition callback running against a nulled `_element`, throwing `TypeError: Illegal invocation` in unrelated self-order tours. Option B. The self-order bundle ships Bootstrap without `web/static/src/libs/bootstrap.js`, so the fix skipping a transition callback whose element is gone never applied here. Costs ~89kB: the patch file needs Tooltip/Dropdown/Modal. runbot-946931 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Opening the generate lot dialog during receiving could show an error because the system tried to use missing information. The update adds safeguards so warehouse users can open the dialog without the warning interrupting their workflow.
Original PR description
When opening the dialog in stock delivery there is an error warning about reading from undefined. This commit adds extra checks to prevent this.
Analytic plan applicability now falls back to the default setting when a screen does not provide a business context, even if a company-specific rule exists for invoices. This prevents unrelated areas like Work Centers or Employee views from incorrectly requiring analytic distribution.
Original PR description
### Issue: When an analytic plan has applicability lines with a company filter, the applicability is incorrectly applied on views that do not define a `business_domain`, such as Work Centers or…
### Issue: When an analytic plan has applicability lines with a company filter, the applicability is incorrectly applied on views that do not define a `business_domain`, such as Work Centers or Employee views For example, if a plan has: - Default Applicability: Unavailable - A line with Domain: Invoice, Company: My Company, Applicability: Mandatory Opening the analytic distribution on a Work Center shows `Mandatory` instead of the default `Unavailable` ### Cause: In commit https://github.com/odoo/odoo/commit/ffcf2ee1a3185ef73db93bfd95625844506692c5 `_get_score` was updated to return `0.5` when the applicability line's company matches the caller's company, even when no `business_domain` is provided In `_get_applicability`, the loop selects the first rule whose score exceeds the current minimum, which starts at `0`: https://github.com/odoo/odoo/blob/710e056e5171af2ab72d7d7793da3518f12faf5e/addons/analytic/models/analytic_plan.py#L255-L264 A score of `0.5` is enough to win over the default applicability, so a company-only match on a domain-specific rule incorrectly overrides the default when no `business_domain` is passed ### Steps to reproduce: - Install `mrp` and `accountant` with demo data - Enable Analytic Accounting in Settings - Open the Internal analytic plan and edit its applicability line: -- Remove the account prefix -- Default Applicability: Unavailable -- Domain: Invoice, Company: My Company (SF), Applicability: Mandatory - Go to Manufacturing > Configuration > Work Centers - Open any work center and click on Analytic Distribution Before the fix, Internal is shown as Mandatory instead of Unavailable Removing the company from the applicability line confirms the issue opw-6404884 Forward-Port-Of: odoo/odoo#280312
This fixes French electronic invoice exports so that paid invoices automatically include the required due date, matching the payment date. It helps businesses comply with the latest French invoicing validation rules and reduces the risk of rejected invoice files.
Original PR description
According the schematron v1.4, the cbc:DueDate is required when the move is PAID. "[BR-FR-CO-09/BT-23] : Si le cadre de facturation (BT-23) est B2, S2 ou M2, alors la date d’échéance (BT-9) doit être renseignée et correspondre à la date de paiement." no-task --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286263
Accountants without company access rights can now generate BOE files for Spanish Modelo 115 tax reports without receiving an access error. The change prevents the export wizard from attempting an unnecessary company update, keeping the workflow available to accounting users as intended.
Original PR description
Users who only have accounting rights (not the Settings > Users Companies > Access Rights group) get an access error on the Companies model when generating the BOE file for the Modelo 115 tax…
Users who only have accounting rights (not the Settings > Users Companies > Access Rights group) get an access error on the Companies model when generating the BOE file for the Modelo 115 tax reports, even though exporting a BOE file has nothing to do with editing company configuration and should be available to any accountant. Steps to reproduce: ------------------- * Log in as a user with accounting rights only (not part of the Companies > Access Rights group) * Go to Accounting > Reporting > Tax Return, open the Mod 115 report * Click the gear icon > BOE > Generate BOE > Observation: An AccessError is raised: "You are not allowed to modify 'Companies' (res.company) ... This operation is allowed for the following groups: Access Rights", even though the user is not trying to edit the company. Why the fix: ------------ The BOE wizard shared by Mod 111/115/303 declares a `company_partner_id` field, related to `company_id.partner_id`, with `readonly=False`. That field is invisible in every view and only exists to compute the domain of `partner_bank_id`; it was never meant to be edited by the user. Because it is declared writable, the ORM attaches an inverse to the related field, so saving the wizard (which happens when generating the BOE, since the field, though invisible, is still part of the view and thus of the saved values) writes `company.partner_id` back onto `res.company`, even though the value never actually changes. That implicit write requires write access on res.company, which is only granted to the Access Rights group, causing the error for regular accountants. Dropping `readonly=False` keeps the field as a plain readonly related field, still usable for the bank account domain, without ever triggering that spurious write. opw-6388869 Forward-Port-Of: odoo/enterprise#130168 Forward-Port-Of: odoo/enterprise#126661
Sales order lines for timesheet-based services now update remaining hours when relevant unit or availability details change. This helps keep project and service billing information accurate without relying on unrelated timesheet triggers.
Original PR description
The dependencies of _compute_remaining_hours do not match the fields actually used for the computation: it lists analytic_line_ids, which it never uses, and omits both remaining_hours_available, and product_uom. _compute_remaining_hours_available has the same issue: it uses product_uom but only depends on product_id.service_policy. analytic_line_ids, on the other hand, can be dropped: qty_delivered already depends on it, along with its so_line, unit_amount, product_uom_id and project_id, so the timesheet flow keeps triggering the recomputation. This PR fixes the dependencies for both aforementioned compute methods. Task-4748521 Forward-Port-Of: odoo/odoo#285685 Forward-Port-Of: odoo/odoo#284750
Product thumbnails on ecommerce product pages now stay neatly aligned when automatic image cropping is turned off. This improves the shopping experience by keeping thumbnail rows tidy and ensuring product images are centered properly, even when images have very different shapes.
Original PR description
Steps to reproduce: =================== 1. Add several images to a product, one of them much wider than tall. 2. On the product page, set the image ratio to "Disabled". 3. Move the thumbnails below…
Steps to reproduce: =================== 1. Add several images to a product, one of them much wider than tall. 2. On the product page, set the image ratio to "Disabled". 3. Move the thumbnails below the image. => The wide thumbnail sits at the top of its slot, with blank space under it. Root cause: =========== Thumbnails are given a fixed width of 64px and take their height from `aspect-ratio: var(--o-wsale-product-image-ratio)` [1]. With cropping disabled that variable is `auto`, so each thumbnail keeps the shape of its own image and they no longer share a height. They sit in a flex row, which stretches every slot to the height of the tallest one. The image inside keeps its own height and stays at the top of the slot, so a wide image leaves the rest of its slot empty. The slots are only stretched when the images differ in height, which is why the problem needs cropping to be disabled, and why it does not appear when every image is a landscape one. - [1] sized the thumbnails from the image ratio. Fix: ==== Center the thumbnails in the row so each one keeps the height of its own image instead of being stretched to the tallest. Their width stays at 64px, so a row of wide images still takes the same space as before and none of them is pushed out of the container. [1]: 670b1daa2254 opw-6472484 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283246
This fixes an issue where certain changed and recombined manufacturing orders could incorrectly produce double the intended quantity or fail during valuation. Manufacturing validation now correctly splits quantities across related finished product lines and values them together, helping avoid inventory and costing errors.
Original PR description
When the quantity of a make-to-order manufacturing order is changed, its finished move is copied to propagate the extra quantity downstream. In some cases (after splitting then merging back…
When the quantity of a make-to-order manufacturing order is changed, its finished move is copied to propagate the extra quantity downstream. In some cases (after splitting then merging back productions) that copy is not merged back, so the order ends up with two finished moves for the same product. On validation, two things then go wrong: - _post_inventory writes the produced quantity on each finished move, so both get the full quantity and the production is doubled - mrp_account._cal_price prices the finished move and calls ensure_one(), which raises "Expected singleton" for an average/fifo product, so "Produce All" fails Split the produced quantity across the finished moves with unit_factor (like _set_qty_producing already does), and price them as a whole instead of expecting a single finished move. Steps to reproduce: - Create a BoM for product A with the MTO route, and a component B - Create a Sale Order for 30 units of A, confirm it - Split the MO into 3 productions of 10, merge two of them - On the third, Update Quantity 10 -> 15, then Produce All - The product should be produced once (15, not 30), with A valued in average/fifo it instead of an error. opw-6242504 opw-6310972 opw-6307025 opw-6354739 Forward-Port-Of: odoo/odoo#286173 Forward-Port-Of: odoo/odoo#269254
This fixes date-related tests so they use the same timezone as the Odoo environment. It prevents occasional test failures around midnight in Belgium, improving reliability without changing business functionality.
Original PR description
## Issue By default in Odoo, `datetime.now()` returns the UTC time, which is two hours behind the local time in Belgium. This leads to two tests failing when executed between 00:00 and 02:00 Belgian…
## Issue By default in Odoo, `datetime.now()` returns the UTC time, which is two hours behind the local time in Belgium. This leads to two tests failing when executed between 00:00 and 02:00 Belgian time: `test_ir_sequence_interpolation_dict` and `test_ir_sequence_iso_directives`. The `_interpolate_dict` method (responsible for interpolating the prefix/suffix from the sequences) specifies the tzinfo when calling `datetime.now()`: https://github.com/odoo/odoo/blob/9c67949be529eb86886b3d5bde08e81e048ecfe7/odoo/addons/base/models/ir_sequence.py#L211-L212 Since this is not the case in the tests, the tests evaluate the date using UTC. This creates a two hours difference between the time expected and the time actually used by `next_by_code`. The tests thus fail between 00:00 and 02:00 because the evaluate dates from both `datetime.now` calls differ, leading to a mismatch in the expected prefixes. ## Fix We force the `env.tz` on the `datetime.now()` call, to mimic the behavior from the `_interpolate_dict`. runbot-242662 Forward-Port-Of: odoo/odoo#284955
This fixes a display issue in the website editor where resize controls could be hidden behind the sidebar when editing animated content. Users can now clearly see and resize selected page elements, improving editing accuracy and reducing confusion.
Original PR description
Steps to reproduce: - Drop a few snippets to make the page scrollable - At the bottom, drop the `s_three_columns` snippet - Click on the last Card - Add an animation "onScroll" (Effect - Slide, Intensity - 100) - Scroll top slightly to hide a part of the card behind the sidebar => The resize overlay is partially hidden The elements `.hb-row` have a z-index of 2, so they appear in front of the overlay which has a z-index of 1. It was decided to fully show the overlay to allow resizing. Keeping the overlay visible in front of the sidebar also allow the user to see where animated element is. task-6476269 Forward-Port-Of: odoo/odoo#283842 Forward-Port-Of: odoo/odoo#282796
This fixes the import of Factur-X e-invoices received through Peppol by correctly reading the embedded XML inside the PDF. It prevents missing or empty invoice records and improves detection of self-billed documents, helping French e-invoicing flows process documents reliably.
Original PR description
When importing new documents from Peppol into the database, we determine whether they are self-billed by checking a Type Code in the XML file. Factur-X is an hybrid format where the XML is embedded inside a PDF. Currently, we are not extracting the XML before searching for that Type Code, and it leads to an error that prevents the document from being imported correctly: - V17, V18: An empty invoice is created and linked with the attachment. - V19+: Only the attachment is created. Additionnaly, we only check for InvoiceTypeCode or CreditNoteTypeCode, but the CII XML format embedded inside the hybrid Factur-X format use TypeCode instead. This PR aims at fixing both these issues. Ticket: opw-6417682 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285552 Forward-Port-Of: odoo/odoo#280714
This fixes a website editor issue where deleting a card's cover image could leave the card in an inconsistent state. Users will no longer encounter broken cover image options or related errors when editing card-based website snippets.
Original PR description
It was possible to remove the image inside a card cover while keeping the figure wrapper. The card option would then still consider that there was a cover image even though the image was gone, which could also lead to a traceback. Steps to reproduce: - Insert the `s_three_columns` snippet - Click on the image of one card - Either press "Enter", "Delete", "Backspace" - Hover the "Cover Image" options => The image is removed but the `<figure>` is still there, so the option is still considered active (leading to a traceback) task-6081728 Forward-Port-Of: odoo/odoo#285131 Forward-Port-Of: odoo/odoo#280086
This fix updates an internal test so it consistently includes the required tax information when checking Indonesian e-Faktur behavior. It helps prevent false build failures and supports more reliable delivery of the localization feature, without changing day-to-day user workflows.
Original PR description
Issue: In some build, when creating the invoice line it did not assign the default tax so it raise an error when downloading efaktur Fix: Assign the tax line manually in the unit test instead of relying on default taxes issue-[946227](https://runbot.odoo.com/odoo/error/946227) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285902
The editor no longer shows a non-working magic wand icon when users open the link popover for an image with a link. This removes a confusing control and makes editing linked images clearer.
Original PR description
**Current behavior before PR:** Steps to reproduce the issue: - Add an image - Add a link to the image - Put cursor just right after the image link so that link popover is opened - Notice that there is a wand icon in link popover to replace title, clicking on it does nothing **Desired behavior after PR:** There should be no replace title icon in popover for image-link. task-6420902 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286119 Forward-Port-Of: odoo/odoo#279076
Fixes an issue where the website builder showed an inaccurate preview when changing header width for a specific boxed header style. This makes the setting apply more reliably and avoids misleading previews for website editors.
Original PR description
The header width option is not previewed properly on the header template `template_header_boxed`. This happens because this template is not compatible with the action `previewableWebsiteConfig` (its width can't be previewed by adding a single class). This commit fixes the problem by using the action `websiteConfig` instead of `previewableWebsiteConfig` when this template is set. task-6420611 Forward-Port-Of: odoo/odoo#286292 Forward-Port-Of: odoo/odoo#282311
This fixes a mismatch between SMS delivery error handling and mass SMS mailings. Mass SMS campaigns now recognize the newer failure reason, preventing affected flows from crashing when that error occurs.
Original PR description
This commit fixes an issue with the addition of a new failure_type in the SMS module via [1]. The corresponding failure_type wasn't added in mass_mailing_sms meaning that some flows could crash if the specific error was set. Now, the new failure_type is added to the module. [1]:https://github.com/odoo/odoo/commit/06bab9a82dae911c26fd5dd329cb43a466d13569 Forward-Port-Of: odoo/odoo#286510
The Vietnam accounting report variants now keep the search bar available when users switch to the VAS general journal or general ledger. This lets users filter account lines by name consistently, matching the standard general ledger behavior.
Original PR description
The standard general ledger enables the search bar, but the VAS general journal (S03a-DN) and general ledger (S03b-DN) variants do not, so the search field disappears as soon as the user switches to one of them and the account lines can no longer be filtered by name. Enable the search bar on both variants to match their root report.
This fixes an issue where signatures could disappear from downloaded signed PDFs when the original file had unusual page positioning. Signed documents now place fields within the visible page area, so users can trust that completed PDFs match the preview.
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#127711 Forward-Port-Of: odoo/enterprise#121960
Appraisals now keep the generic template chosen by the user when they are confirmed or reset. This prevents records from being silently reassigned to a different template, so reporting and filtering by appraisal template remain accurate.
Original PR description
Issue: When a user selects a generic appraisal template other than the first one, confirming or resetting the appraisal silently replaces that selection with the first generic template. Filtering…
Issue: When a user selects a generic appraisal template other than the first one, confirming or resetting the appraisal silently replaces that selection with the first generic template. Filtering appraisals by the originally selected template then fails to return the appraisal. Steps to reproduce: * Configure multiple appraisal templates without department restrictions. * Create an appraisal and select a template other than the first one. * Confirm the appraisal. * Filter appraisals by the selected template. Cause: `_compute_appraisal_template()` only preserved templates directly linked to the appraisal's department. Generic templates have no department relation, so a valid selected template was discarded whenever the computation was triggered by a state dependent department recomputation. The generic fallback then stored the first template instead. https://github.com/odoo/enterprise/blob/5c57ccbb13269af28de0a6c7f35454be52424f43/hr_appraisal/models/hr_appraisal.py#L195-L209 Solution: We need to distinguish the generic default loaded on an unsaved form from a compatible generic template already stored on an appraisal. Preserve the latter across recomputations while retaining department template priority during creation and rejecting templates that no longer match the appraisal's department or company. opw-6449041 Forward-Port-Of: odoo/enterprise#129635 Forward-Port-Of: odoo/enterprise#127566
This fix makes an automated restaurant appointment test wait until a cancellation dialog fully closes before ending. It helps prevent intermittent false test failures, improving confidence in release validation without changing user-facing behavior.
Original PR description
Following commit b6a7991a6aaef1be15a27852c2c76737322cdcab, the tour clicks the cancel button (.o_form_button_cancel) to discard unsaved changes. However, as it was the last step of the tour, the test could terminate before the asynchronous discard/dialog closure completed. This caused intermittent test failures with: `AssertionError: Tour finished with a dirty form view being open.` We now add a final step that waits for the dialog to close and the form to no longer be marked as dirty (`body:not(:has(.o_dialog)):not(:has(.o_form_dirty))`) before completing the tour. Forward-Port-Of: odoo/enterprise#129375
This fixes a navigation issue where opening Helpdesk tickets from an email alias could crash because the system reused the wrong background context. Users can now move from an alias to its related Helpdesk team and view tickets normally, improving reliability for support workflows.
Original PR description
### Steps to Reproduce: 1. In Debug mode, go to Aliases 2. Click on any active Alias, ex. customer-care 3. Click on "Open Parent Document" smart button 4. Click on "Tickets" smart button and observe…
### Steps to Reproduce: 1. In Debug mode, go to Aliases 2. Click on any active Alias, ex. customer-care 3. Click on "Open Parent Document" smart button 4. Click on "Tickets" smart button and observe error ### Description of the issue/feature this PR addresses: **Issue:** When navigating from an email alias to its parent document (e.g., a Helpdesk Team), the web client incorrectly retains the `active_id` and `active_model` of the alias in the context. **Solution:** We updated the `action_view_ticket` method in `helpdesk.team` to explicitly inject the correct `active_model` and `active_id` into the context before calling `_for_xml_id`. This overwrites the polluted Alias data before the window action is evaluated. ### Current behavior before PR: Clicking the "Tickets" smart button passes the old alias context into the action. This bad data flows into the ticket view, which attempts to look up a Helpdesk Team using the Alias's ID to generate the empty list help message, resulting in a `MissingError`. ### Desired behavior after PR: The Python action sanitizes the context at the source, ensuring that the XML action and subsequent view evaluations receive the correct Helpdesk Team ID. Ultimately, the view will load normally without crashing. opw-6395638 Forward-Port-Of: odoo/enterprise#130088 Forward-Port-Of: odoo/enterprise#125232
The Helpdesk SLA Status Analysis report now measures Hours Open from ticket creation until closure, matching the main Ticket Analysis report. This prevents tickets that were assigned immediately from showing no open time and gives managers a more accurate view of service performance.
Original PR description
1. Open Helpdesk > Tickets and create a ticket on the team "Customer Care", assigned to yourself 2. More than an hour later, move it to the "Solved" stage to close it 3. Open Helpdesk > Reporting > Ticket Analysis, switch to the pivot view and pick the "Hours Open" measure -> the ticket holds the hour it stayed open 4. Open Helpdesk > Reporting > SLA Status Analysis and pick the "Hours Open" measure as well -> the ticket holds nothing, as it was assigned as soon as it was created odoo/enterprise#47454 added the "Hours Open" measure of the ticket analysis to the SLA status analysis, but computes it up to the assignment date instead of the closing date. The measure therefore holds the hours until the ticket was assigned, which the report already offers as "Working Hours to Assign". With this commit, both reports count the hours from the creation of the ticket to its closing. Forward-Port-Of: odoo/enterprise#130263 Forward-Port-Of: odoo/enterprise#130170
Freezing spreadsheet data now creates the expected data protection log entry. This helps businesses keep a clearer audit trail when spreadsheet content is locked or preserved.
Original PR description
Task: 6389096 Forward-Port-Of: odoo/enterprise#130229 Forward-Port-Of: odoo/enterprise#126461
Fixed an issue in the HTML editor where pressing Enter in a list item containing a table did not split the bullet as expected. This makes editing mixed content in bullet lists more predictable and prevents accidentally moving larger list content out of the list.
Original PR description
### Steps to reproduce: - Insert a bullet list - Inside of the list, insert a table - Write before and/or after the table (in the same list item) - Press enter before and/or after the inserted text - Notice that the bullet is not split like in a normal list ### Root Cause: - On Enter, list plugin checked whether the list item contained unsplittable element. Since the table was inside the list item, it always treated the list item as unsplittable, even when the cursor was outside the table. As a result, the list item could never be split. ### Solution: - Instead of checking the whole list item, walk up from the split target to the list item and look for an unsplittable element along the way. This allows the list item to split normally when the cursor is outside the unsplittable. task-6449843 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286028 Forward-Port-Of: odoo/odoo#280903
The web test suite now ignores assets that do not have a file-based name instead of failing unexpectedly. This keeps JavaScript regression testing reliable when websites use customized themes or when asset paths are invalid.
Original PR description
### Problem `HootCommon` in `addons/web/tests/test_js.py` calls `.endswith()` on `asset['filename']` in two places without checking it for `None`: ```python filename = asset['filename'] if not…
### Problem
`HootCommon` in `addons/web/tests/test_js.py` calls `.endswith()` on
`asset['filename']` in two places without checking it for `None`:
```python
filename = asset['filename']
if not filename.endswith('.test.js'):
```
```python
if asset['filename'].endswith('.test.js')
```
But `filename` is legitimately `None` for assets backed by an `ir.attachment`
rather than a file on disk. `ir_asset.py::_get_paths` sets it that way on
purpose (the "an attachment url most likely" branch).
### Reproduction
Customise a website theme (which creates an `ir.attachment`-backed asset), then
run the core JS suite. Four tests fail with:
```
AttributeError: 'NoneType' object has no attribute 'endswith'
```
The same happens with a simple typo in a manifest's asset path, which produces
`filename = None` with only a warning — so a one-character mistake turns the
whole JS suite red instead of reporting the typo.
### Fix
An asset with no file on disk cannot be a `.test.js`, so the correct response to
`filename is None` is the same as for any other name that does not end in
`.test.js`: skip it.
The suite is currently red permanently on any database with a customised theme,
which is exactly when it stops being useful as a regression signal.This fix prevents already-paid online orders from being reopened as abandoned carts during a short timing window after redirect payments. It helps avoid incorrect order totals and false payment mismatch warnings on the confirmation page, improving checkout reliability for customers using alternate pricelists or currencies.
Original PR description
**Steps to reproduce:** - Install the `website_sale` module. - Configure the Mollie payment provider and publish it. - Enable the PLN currency. - Create a PLN pricelist and make it selectable on the…
**Steps to reproduce:** - Install the `website_sale` module. - Configure the Mollie payment provider and publish it. - Enable the PLN currency. - Create a PLN pricelist and make it selectable on the website. - Open the Mitchell Admin customer record and, under the `Sales & Purchase` tab, assign the USD pricelist. - Go to the website shop, switch the pricelist to PLN, add a product to the cart, and proceed to checkout. - Pay through Mollie and mark the transaction as paid in Mollie. **Issue:** - After a successful redirect payment, the confirmation page displays an amount-mismatch warning, even though the payment was accepted by the provider for the correct amount. **Root cause:** - Mollie's return request and webhook can arrive within milliseconds of each other. Both requests attempt to create a `payment_data` record referencing the same `payment_transaction`. - At the same time, the cron holds a `FOR UPDATE` lock on the transaction while processing the first payload. The `FOR KEY SHARE` lock automatically acquired by PostgreSQL during the foreign-key check of the `payment_data` insertion conflicts with this `FOR UPDATE` lock. This results in a serialization failure and rolls back the post-processing job that would have confirmed the sale order (`draft` → `sale`). - This temporarily leaves the transaction in `done` state while the sale order is still in `draft`. - `sale_reset()` then clears both the session cart key and the selected- pricelist key. When `/shop/confirmation` renders, `request.cart` is resolved through `_get_and_cache_current_cart()`. The abandoned-cart recovery branch finds the still-draft sale order and calls `_update_address()` on it. - Since the selected-pricelist key is no longer present in the session, the customer's default USD pricelist is applied. `_recompute_prices()` then changes the sale order total. However, the payment transaction still contains the original PLN amount, so `_get_status_message()` detects the difference and displays the amount-mismatch warning. **Solution:** - Before calling `_update_address()` and `_verify_cart()` on an abandoned-cart candidate, check the state of its latest transaction. - If the transaction is `pending`, `authorized`, or `done`, discard the candidate and return an empty cart. - This matches the guard already present in the session-cart branch of the same method, keeping both paths consistent. - The serialization failure itself is expected and handled by Odoo's retry mechanism. This fix prevents the resulting side-effect window from allowing an already-paid order to be recovered as an abandoned cart and repriced. opw-6470325 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Fixes a storefront issue where changing options on an out-of-stock product could make the "Add to wishlist" button shift position. This keeps the shopping experience visually stable and avoids confusing customers browsing unavailable product variants.
Original PR description
On an out-of-stock product page where we prevent out-of-stock sale, changing the attribute value moves the "Add to wishlist" button Steps to reproduce: 1. Install eCommerce and Inventory 2. Go to Settings > Website > eCommerce > Inventory Defaults and disable the option "Continue Selling" for Out-of-Stock products 3. Go to Inventory > Products, open product Customizable Desk. In the eCommerce tab, disable option "Sell when Out-of-Stock". 4. In the General Information tab, click on the Quantity On Hand and set all quantities to 0 5. Open the product on the eCommerce 6. Change the Legs attribute to Aluminium 7. The "Add to wishlist" button moves Issue: Changing the combination of the product only removes the `#product_stock_availability` element. However, there can be multiple elements that we need to remove. This was introduced in https://github.com/odoo/odoo/commit/6e72f45f78055de762a24e4a24a82a5565346d7a Solution: Reset the previous behavior opw-6507088
Italian invoice generation no longer fails when a company does not use email or SDI delivery checks. The attachment selection option is also shown more reliably for Italian companies, helping users complete invoice sending without interruptions.
Original PR description
When generating an invoice with an Italian company not checking mail nor SDI, a traceback is raised This commit also update the condition to show attachment selector on `account.move.send` for Italian companies Task [link](https://www.odoo.com/odoo/project.task/6514516) task-6514516
Translated table of contents navigation now keeps plain, consistent link text even when translated headings are styled. Social and sharing snippets also reuse the same styling rules in translation mode, reducing display inconsistencies and maintenance risk.
Original PR description
### [REF] website, *: prevent style in navbar of translated table of content *: html_builder The snippet "Table of Content" copies the content of the title in its navbar, taking care of removing…
### [REF] website, *: prevent style in navbar of translated table of content *: html_builder The snippet "Table of Content" copies the content of the title in its navbar, taking care of removing style to have plain text in the navbar. In translate, to try to achieve this as well, it uses some special logic with `o_translation_without_style`, a second translation hash,... But, if one of the title has no style in the original language, but a translation adds a style, then the term with style is used in the navbar. This commit uses `o_translate_inline` on the links of the navbar. With this, they make together a single translation term which is always distinct from the terms of the titles. The copy of the translated titles is made with the same plugin as in normal mode (with some adaptation to take into account the translation spans). Steps to reproduce: - Open website builder - Drop the "Table of Content" snippet - Save - Open website builder in translate mode - Select text in a title of the "Table of Content" snippet - Change its style: make it bold - Save - Bug: the term in the navbar is bold as well task-6304267 ### [REF] website: define style for translated social snippet in main css The snippets "Social Media" and "Share" needs additional rules to appear correctly in translate mode (if they have `o_translate_inline` on their links). Those were defined in a separate file for inside the builder. This is error prone because the content of those rules needs to be kept in sync with the general rules. To avoid the duplication, this commit moves those additional rules with the normal ones, so they share their content. task-6304267
The mail app now cleans up its internal data store automatically when the app is closed, preventing leftover test subscriptions. This improves test reliability and reduces the chance of hidden side effects between mail-related tests without changing user-facing behavior.
Original PR description
Before this commit, a mail test that mounts its UI without the `start()` helper never disposes the store, so the subscriptions its records registered outlive the test: the chat hub and composer…
Before this commit, a mail test that mounts its UI without the `start()` helper never disposes the store, so the subscriptions its records registered outlive the test: the chat hub and composer service entries of the shared local storage listener, and one for each `localStorage` field of a record. `@mail/discuss/call/peer_to_peer` mounts with `mountWebClient()`. This happens because nothing in src disposes a store: a deleted record runs its dispose functions from the delete queue, and the store is a singleton nothing deletes, so its own teardown had one caller, the `after()` hook of `start()`. Note that hoot rebuilds the module set of a test file, so such a subscription is collected with its file and the memory of the suite does not grow. This commit registers the teardown on the scope of the app that builds the store, the one services start in and that `makeStore` already reads `useApp()` from, so destroying the app runs the store's dispose functions and the tests need no hook of their own.
The website editor now treats forum information links as regular links instead of buttons. This avoids confusing styling options when editing forum pages and keeps the editing experience clearer across desktop and mobile.
Original PR description
Steps to reproduce: - Go to a forum page. - Open the website editor. - Select the "About this forum" link in the sidebar. => Button styling options are shown for a regular link. Before this commit, forum information links used button classes, which made the editor expose button styling options for them. After this commit, the `btn`, `btn-sm`, and `btn-link` classes are replaced with `small` so the editor treats these elements as regular links on desktop and mobile. task-6259086 Forward-Port-Of: odoo/odoo#283156
This change removes an obsolete browser history update from spreadsheet document navigation. It keeps the routing behavior simpler after a previous change introduced a dedicated way to handle shared links with tokens, with no expected impact on normal users.
Original PR description
the replaceState after loading the router patch became useless when we changed the implementation of https://github.com/odoo/enterprise/pull/114484 in favor of a dedicated route to handle urls with a token instead of an id. Task-6485474
The ESG module now cleans up its unit links correctly during uninstall, preventing a reinstall failure. This improves system reliability for customers who remove and reinstall the ESG app or run upgrade and test workflows.
Original PR description
As `relative_uom_id` is on delete cascade, when uninstalling esg module, `uom.product_uom_kwh` is being removed when `esg.product_uom_j` is removed. When reinstalling esg module, we try to override uom.product_uom_kwh but it does not exist anymore, causing the error: Cannot update missing record. To prevent this error, we need to detach the core kWh unit from our own J unit when uninstalling esg module. runbot-error: [946474](https://runbot.odoo.com/odoo/runbot.build.error/946474) version-19.5
The Helpdesk team card now displays the email alias aligned with the team name. This small visual fix makes the card easier to read and keeps the Helpdesk interface looking consistent.
Original PR description
In this commit, we remove the margin before the mail alias, ensuring aligment within the helpdesk team card. task-6416578 Forward-Port-Of: odoo/enterprise#129865
This fix corrects how employee occupations are calculated for Belgian holiday attestations. It helps ensure payroll and departure documents reflect accurate occupation information, reducing the risk of incorrect HR payroll records.
Original PR description
This commit fixes the occupation computations which were wrong. Forward-Port-Of: odoo/enterprise#129837
Swiss payroll payment reports no longer fail when an employee is paid through a Revolut bank account. This keeps ISO20022 payment file generation working after recent bank account data model changes.
Original PR description
res.bank and res.partner.bank.bank_id were removed in saas-19.2: the bank's identity now lives directly on the bank account as bank_bic and bank_name. The Revolut detection added in fba51a6a77a still read bank_account.bank_id, raising an AttributeError when generating the ISO20022 payment report for Swiss payslips. Forward-Port-Of: odoo/enterprise#129915 Forward-Port-Of: odoo/enterprise#129156
This fixes an issue where adding delivery charges could cause Odoo to recalculate the unit of measure and then calculate shipping-related sales line amounts incorrectly. The change keeps the intended unit of measure when the delivery line is created, helping prevent wrong prices or totals on sales orders.
Original PR description
In this PR, https://github.com/odoo/odoo/pull/186250, the `product_uom` field was renamed to `product_uom_id`. However, in the `delivery` module, `product_uom_id` is dropped from the values when the…
In this PR, https://github.com/odoo/odoo/pull/186250, the `product_uom` field was renamed to `product_uom_id`. However, in the `delivery` module, `product_uom_id` is dropped from the values when the delivery line is created. This causes `product_uom_id` to be recomputed. This commit reintroduces `product_uom_id` in the values to prevent the field from being recomputed. **Description of the issue/feature this PR addresses:** For a strange reason, when a module inherits from `sale.order.line` and adds some computed fields with `precompute=True`. `price_unit`, `price_subtotal`, and `price_total` are computed incorrectly. I have attached a module to demonstrate the issue. https://github.com/user-attachments/assets/ebdd8695-c9d8-477b-b5cf-ba6d8d41e84a Without this change, the test fails, and Odoo incorrectly recomputes the fields, as shown in the video. <img width="1232" height="515" alt="image" src="https://github.com/user-attachments/assets/27370f1f-e7b7-4102-a606-0181b9d1a97a" /> When the ORM computes fields marked as `precompute=True`, in this function `_add_precomputed_values` https://github.com/odoo/odoo/blob/0d44f26d9b0fb1c1a5db463cf1f8dd0d3c72ba26/odoo/orm/models.py#L4836, `price_unit` is 0, but the records get `price_unit` from the product. Therefore, when [_compute_amount](https://github.com/odoo/odoo/blob/0d44f26d9b0fb1c1a5db463cf1f8dd0d3c72ba26/addons/sale/models/sale_order_line.py#L855) is called, the values are computed with an incorrect `price_unit`. <img width="1087" height="940" alt="image" src="https://github.com/user-attachments/assets/92feadf0-7f93-4acc-8f1a-931db0655fcc" /> **Steps to reproduce the issue:** - Install the attached module. [sale_precompute.zip](https://github.com/user-attachments/files/31265993/sale_precompute.zip) - Configure a delivery carrier as free for orders over 1, and set the fixed price to 5, for example. - Create a sales order and add a product with a value greater than 1. - Add the shipping method. The price should be 0. In the sales order line, `price_unit` is 0, but `price_subtotal` and `price_total` are equal to 5 (the product's sale price). For more context, this module is a simple example extracted from the OCA `product_secondary_unit` module, which adds a mixin with these fields: https://github.com/OCA/product-attribute/blob/18.0/product_secondary_unit/models/product_secondary_unit_mixin.py. In the `sale_order_secondary_unit` module, `sale.order.line` inherits from this mixin. You can see the error in this PR: https://github.com/OCA/sale-workflow/pull/4535. https://github.com/OCA/sale-workflow/actions/runs/32259842816/job/96090194021?pr=4535#step:8:509 I understand that this requires a deeper investigation into precompute to solve the underlying issue, but I propose setting `product_uom_id` in the `_prepare_delivery_line_vals` method as a temporary solution while the final solution is being investigated. I understand that this field should not have been removed from `_prepare_delivery_line_vals`; the referenced PR only renamed the field and did not intend to remove the value from this method. @Tecnativa @pedrobaeza @kcv-odoo @Feyensv coudl you please review this? --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284316 Forward-Port-Of: odoo/odoo#283551
The kitchen preparation display now correctly chooses an available point-of-sale configuration when it is shared across multiple setups. This prevents failures when no single configuration is selected and keeps shared kitchen displays working reliably, with minor visual adjustments included.
Original PR description
In this commit: ------------------- - We were passing the pos config id when loading the preparation display, but multiple configs can be configured, and no config is set when using all configs. Instead, the config is now resolved within the service from the loaded configs. task: 6512063 Related PR: https://github.com/odoo/odoo/pull/286169
Kitchen and change receipts now use the POS configuration tied to the order, even when multiple configurations share the same kitchen setup. This helps ensure printed receipts show the right store or register details without affecting standard single-configuration POS printing.
Original PR description
In this commit: ------------------- - Use the first loaded `pos_config` for kitchen when kitchen is common across multiple configs and use the order's associated config when printing a change receipt from the kitchen to ensure the correct config details are printed. - For regular POS printing, this remains unchanged since only one config is loaded. task: 6512063 Related PR: https://github.com/odoo/enterprise/pull/130117
The Belgian payroll fleet module is being removed again because it had previously been deleted but was accidentally brought back and expanded. This keeps the product aligned with the intended module set and avoids maintaining functionality that should no longer be available.
Original PR description
Module was originally deleted in #111407 Module was incorrectly reintroduced in #127537 Module was incorrectly expanded in #128941 Kill it again.
This change removes modules and related translation/assets files that had previously been deleted but accidentally returned. It keeps the product codebase clean and avoids exposing unsupported or obsolete functionality.
Original PR description
They got resurrected through foul play and unnatural means, lay them to rest.
Argentina's withholding tax handling is now aligned with Odoo's shared withholding framework, reducing duplicated local code and making future maintenance easier. The change preserves Argentina-specific tax rules, improves payment/check handling, and fixes cases where withholding certificate numbers could be altered or lost.
Original PR description
*: account,l10n_account_withholding_tax,l10n_latam_check Argentina carried its own withholding implementation, written before l10n_account_withholding_tax existed. The generic module covers most of…
*: account,l10n_account_withholding_tax,l10n_latam_check Argentina carried its own withholding implementation, written before l10n_account_withholding_tax existed. The generic module covers most of the needs today, so the parallel implementation only means a lot of overhead. Drop it and keep what the framework cannot know: - Argentine documents declare no withholding, so what is owed comes from the regimes the partner is registered in at the payment date; - the base restates what those documents declare on the proportion the payment settles, on their untaxed or total amount per regime; - earnings regimes accumulate per ARCA code over the month, against a scale and a non-taxable minimum; - checks fix the net amount handed over, so the gross the withholding is levied on has to be searched for. The taxes now follow the generic convention and hold a negative amount. _get_default_withhold is the only part of the generic default the localization replaces: with nothing declared on the documents, the mode depends solely on what is left to pay. Side changes: - add some minimum validation on the l10n_latam_check module. - add a generic empty notebook on the payment registration wizard to ease overrides. task-5865443
WhatsApp channel owners are now consistently prevented from leaving their own channels, including when removals happen through the member list. Bot and AI agent member cleanup is handled more directly, reducing unnecessary leave messages and making channel membership behavior more reliable.
Original PR description
- Move WhatsApp owner leave guard to discuss.channel.member.unlink() - Unlink bot and AI agent members with post_leave_message=False context task-4715497
Argentina withholding reports now use the shared withholding tax structure, keeping reporting aligned with the refactored tax module. A related Peru withholding payment view issue was also corrected so the screen uses the proper underlying dependency.
Original PR description
We're refactoring the Argentina withholding module to use the generic l10n_account_withholding_tax. This commit adapt the reports to use the generic fields instead. task-5865443
This update refreshes internal code used by several Enterprise web interface components to align with the latest framework standards. It improves maintainability and validation behind the scenes without changing day-to-day user workflows.
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The purchase approvals flow was updated to work with supplier information provided in a newer format. This keeps approval requests aligned with recent purchasing changes and avoids issues when supplier details come from past purchase activity rather than a saved supplier record.
Original PR description
product.product._select_seller now returns the seller information as a dict instead of a product.supplierinfo record, since a seller can come from the last confirmed purchase order line, which has no record. Community PR: odoo/odoo#279993 task-5456444
This update modernizes the internal setup of the Unsplash image integration in Odoo. It helps keep the feature compatible with the latest web framework standards without changing how users interact with it.
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The hierarchy view code was updated to use the newer component configuration approach. This keeps the underlying interface code aligned with current standards and helps reduce future maintenance risk without changing user-facing behavior.
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The map view code was updated to use the current component configuration approach. This keeps the feature aligned with the latest framework standards and helps reduce future maintenance risk without changing user-facing behavior.
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update modernizes internal Gantt view components used in planning and scheduling screens. It helps keep the interface compatible with the latest framework standards and improves reliability checks without changing visible business workflows.
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update modernizes internal cohort view code without changing the user experience. It improves validation and removes obsolete definitions, making the module easier to maintain and more reliable for future updates.
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update standardizes how several Odoo interface components react to record changes, replacing a custom internal mechanism with a common framework approach. It should not change business workflows, but helps make the code easier to maintain and more consistent across apps.
Original PR description
* account,html_editor,mass_mailing,purchase_product_matrix,web Replace `useRecordObserver()` hook with the standard `useEffect()` hook and update callback signatures to access records via `this.props.record`.
This update modernizes internal manufacturing screen components as part of Odoo's Owl 3 platform migration. Users should not see functional changes, but the work helps keep manufacturing views maintainable and compatible with future Odoo improvements.
Original PR description
As part of the Owl 3 migration, this pr aims to replace **onWillUpdateProps** hook with the appropriate Owl 3 alternatives. enterprise: https://github.com/odoo/enterprise/pull/123857 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The social posting features were internally updated to stay compatible with the latest Odoo interface framework. This helps keep social and Twitter-related tools stable during the broader Owl 3 migration, without introducing visible workflow changes for users.
Original PR description
*=twitter As part of the Owl 3 migration, replace onWillUpdateProps hook with the appropriate Owl 3 alternatives.
Several Odoo Enterprise apps were updated to use a standard internal method for reacting to record changes. This keeps the codebase aligned with current practices and should improve long-term maintainability without changing day-to-day user workflows.
Original PR description
* iap_extract,knowledge,timer,web_studio Replace `useRecordObserver()` hook with the standard `useEffect()` hook and update callback signatures to access records via `this.props.record`.
This update modernizes part of the manufacturing work order display so it remains compatible with Odoo's newer web framework. It is an internal technical cleanup with no expected change to day-to-day manufacturing workflows.
Original PR description
As part of the Owl 3 migration, this pr aims to replace **onWillUpdateProps** hook with the appropriate Owl 3 alternatives. community: https://github.com/odoo/odoo/pull/275346
The HTML editor's color picker has been updated to use the latest underlying interface technology. This keeps the feature maintainable and aligned with current platform standards without changing how users work with it.
Original PR description
Replaces `proxy`, `useRef`, and `useLayoutEffect` (from `@web/owl2/utils`) with `signal`, `signal(null, t.ref())`, and `useEffect` from `@odoo/owl`. Also updates `t-custom-ref` → `t-ref` in the XML template. WHY: `useRef`, and `useLayoutEffect` are deprecated in OWL3; signals and `useEffect` are the idiomatic replacements. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update refreshes part of the web interface code to align with the next version of Odoo's underlying UI framework. It is an internal cleanup that helps keep the platform maintainable without changing day-to-day user workflows.
Original PR description
Remove useLayoutEffect from transition.js as part of OWL3 migration.
Updated the web code editor to use newer supported component lifecycle behavior, keeping invalid view markers working reliably after framework changes. This is an internal maintenance change that helps prevent editor errors and preserves existing highlighting behavior for users editing views.
Original PR description
Replaced `useLayoutEffect` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. `useEffect` (OWL3's `effect()`) runs synchronously during `setup()`, before mount, so…
Replaced `useLayoutEffect` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. `useEffect` (OWL3's `effect()`) runs synchronously during `setup()`, before mount, so `this.aceEditor` does not exist yet and calling `highlightInvalidLocators` throws. `onMounted` + `onPatched` mirrors what the OWL2-compat `useLayoutEffect` does internally and runs after the parent `CodeEditor`'s setup builds `this.aceEditor`. The highlighting logic is factored into `applyInvalidLocators()` (called from both hooks) which clears then re-adds markers, preserving the old cleanup-before-reapply behaviour. The `useLayoutEffect` refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - @web/views/fields/ir_ui_view_ace_field - Highlight invalid locators in inherited ir.ui.view - with invalid locators (WebSuite.test_unit_desktop) - @web/views/fields/ir_ui_view_ace_field - Highlight invalid locators in inherited ir.ui.view - with invalid locators (MobileWebSuite.test_unit_mobile) see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2624603/build/116553950
This update refreshes the stock inventory quantity widget so it continues to respond correctly when users edit counted quantities. It replaces an outdated internal mechanism with a supported approach, helping keep the interface reliable as the underlying framework evolves.
Original PR description
Replaced `useLayoutEffect` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. The single `useLayoutEffect` only attached `keydown` and `blur` listeners to `inputRef.el`,…
Replaced `useLayoutEffect` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. The single `useLayoutEffect` only attached `keydown` and `blur` listeners to `inputRef.el`, making it a natural candidate for `useListener`. However, `inputRef` is an OWL2-compat `useRef` whose `.el` getter reads the backing signal via `untrack`, so a `useListener(() => inputRef.el, ...)` call (which wraps `useEffect`) never subscribed to element changes — the effect ran once at setup when the readonly cell has no `<input>`, and never re-ran when the input appeared on edit, leaving both events unbound. The correct fix is to bind the two handlers once and (re)attach them in `onMounted` + `onPatched`, which run after each DOM patch and cover the input appearing on edit. `addEventListener` is idempotent for the same `(type, listener)` pair. The useLayoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - `@stock/counted_quantity_widget/Test changing the inventory quantity with the widget` - `@stock/counted_quantity_widget/Test setting the inventory quantity to its default value of 0` - `WebSuite.test_unit_desktop` see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2605076/build/115404428
The WhatsApp message composer was updated to use a newer underlying approach required by the platform framework. This helps keep the feature compatible with future Odoo versions without changing the user experience.
Several internal components were updated to use newer framework patterns so they remain compatible with the next OWL version. This should not change day-to-day behavior, but it helps reduce upgrade risk for WhatsApp, accounting reports, and knowledge features.
Original PR description
Replace the manual async pattern (useLayoutEffect + useState + imperative fetch) with asyncComputed, which handles reactive re-fetching and in-flight request cancellation automatically. The placeholder char field no longer needs its own setup() or useState wrapper since the asyncComputed signals are already reactive and accessible directly via env. WHY: useLayoutEffect is deprecated in OWL3. Community PR: https://github.com/odoo/odoo/pull/267675
This update streamlines how the private card setup in Expenses reacts when secure access details become available. It is an internal cleanup intended to make the experience more reliable without changing day-to-day payroll or expense workflows.
Original PR description
Move ephemeralKey out of useState into a class-level signal and replace useLayoutEffect with effect so the iframe setup triggers reactively when the key is set, without relying on a post-render OWL2 hook.
This update modernizes part of the account reports interface by replacing an older internal rendering approach with the newer platform method. It should not change day-to-day behavior, but helps keep the reporting area easier to maintain and ready for future upgrades.
Original PR description
Remove useLayoutEffect from AccountReturnBaseKanbanRenderer. This is a refactoring step to replace owl2 useLayoutEffect with OWL3 native API.
This update modernizes how monetary input fields keep their displayed value in sync, preparing the web interface for the next version of Odoo's frontend framework. It is an internal cleanup with test coverage and should not change day-to-day user behavior.
Original PR description
Replaced `useLayoutEffect` in `MonetaryField` with a reactive `signal` exposed by `useInputField`, and removed the companion `proxy` state and `onInput` handler. `useLayoutEffect` is deprecated in…
Replaced `useLayoutEffect` in `MonetaryField` with a reactive `signal` exposed
by `useInputField`, and removed the companion `proxy` state and `onInput` handler.
`useLayoutEffect` is deprecated in OWL3.
`useInputField` now creates a `signal("")` (named `inputValue`) and calls
`inputValue.set(...)` at every point it owns the displayed text: the native
`onInput` handler, the `onChange` no-change revert, the patch layout-effect
(model/onchange sync), and the `commitChanges` revert. The signal is attached
to the returned ref as `inputRef.value` so all other `useInputField` consumers
are unaffected. `MonetaryField` replaces `this.state.value` with
`this.inputRef.value()` in the template ghost-sizing span and drops the
`onInput` method entirely.
The `useLayoutEffect` refactored in this PR had test coverage — below are some
tests that failed when the effect was commented out, and are now passing:
- `@web/views/fields/monetary_field/MonetaryField with currency set by an onchange`
- `WebSuite.test_unit_desktop`
- `MobileWebSuite.test_unit_mobile`
see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2624631/build/116554655The web control panel was updated to use a newer internal approach for managing screen updates. This keeps the interface aligned with the latest platform framework and helps maintain long-term reliability without changing day-to-day user workflows.
Original PR description
Remove useLayoutEffect usage in control_panel.js (throwaway commit, will be squashed).
This change modernizes an internal part of the online course quiz form so it aligns with the latest website framework practices. It should not change the visible learning experience, but helps keep the course website code reliable and easier to maintain.
Original PR description
Commenting out useLayoutEffect to break it on purpose and check test coverage.
The website forum code was updated to use a newer supported approach for handling popup click behavior. This keeps the forum feature aligned with the latest platform standards without changing the user experience.
Original PR description
Replaced \`useLayoutEffect\` with \`useEffect\` because \`useLayoutEffect\` is deprecated in OWL3. Used \`useEffect\` because the original code attached/detached a click listener on a DOM element queried from a reactive ref (\`this.modalRef.el\`). \`useEffect\` auto-tracks reactive dependencies and re-runs whenever they change, making it the natural OWL3 replacement for DOM side effects tied to reactive state. This is a CASE 2 commit. There is test coverage — tests failed when the effect was commented out: - FAIL: TestESLint.test_eslint see runbot build: https://runbot.odoo.com/runbot/batch/2596763/build/114855877
This change updates how action buttons are shown in Data Cleaning recycle records so the screen stays compatible with the latest Odoo interface framework. Users should see the same button behavior as before, with lower maintenance risk going forward.
Original PR description
Replaced `useLayoutEffect` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. `useLayoutEffect` without a dependency array runs after every render (both mount and patch).…
Replaced `useLayoutEffect` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. `useLayoutEffect` without a dependency array runs after every render (both mount and patch). The equivalent OWL3 pattern is `onMounted` (called once after the component is first mounted) + `onPatched` (called after each subsequent patch), both delegating to a shared `syncButtonVisibility` helper. When commenting out the useLayoutEffect there was no error, meaning the code we refactored had no test coverage. I tested personally using the following steps: 1. Enable developer mode (Settings → Activate the developer mode) 2. Go to Settings → Technical → Data Cleaning → Recycle Records (or install/open the Data Cleaning app and navigate to Recycle Records) 3. The list view of recycle records opens 4. Select one or more records that are **active** (not yet discarded): - Verify the "Validate" and "Discard" buttons appear in the action bar - Verify the "Undiscard" button is hidden 5. Select one or more records that are **inactive** (already discarded): - Verify the "Undiscard" button appears in the action bar - Verify "Validate" and "Discard" buttons are hidden 6. Select a mix of active and inactive records: - Verify all three action buttons are hidden (no all-active or all-inactive condition met) see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2596766/build/114855977
This change updates the internal implementation of the Point of Sale order display to align with the newer interface framework. It should not change daily cashier workflows, but it helps keep the system easier to maintain and ready for future upgrades.
Original PR description
Remove useLayoutEffect in order_display component, to be replaced with OWL3 native API.
This update modernizes an internal part of the HTML editor to align with the next version of Odoo's user interface framework. There should be no visible change for users, but it helps keep the editor reliable and easier to maintain during the platform migration.
Original PR description
Remove useLayoutEffect from position_hook.js as part of OWL3 migration.
The API documentation sidebar was updated to use the newer internal page behavior approach instead of an older method. This keeps the documentation area aligned with the latest platform standards while minimizing visible changes for users.
Original PR description
Commented out useLayoutEffect in DocSidebar to identify test coverage before replacing with OWL3 API.
This update simplifies the internal code used by the mass mailing email editor. It should not change how users create or edit mailings, but it helps keep the editor easier to maintain and less prone to future issues.
Original PR description
Remove useLayoutEffect in mass_mailing_html_field.
This update adjusts the HTML editor's overlay behavior as part of preparation for the next Odoo web framework version. It is an internal cleanup that should help maintain compatibility without changing how users work with the editor.
Original PR description
Remove useLayoutEffect from overlay.js as part of OWL3 migration.
This change updates internal web interface code to align with the next version of Odoo's front-end framework. It helps keep the web client maintainable and ready for future upgrades without introducing expected user-facing changes.
Original PR description
Remove useLayoutEffect from numpad_decimal_hook.js as part of OWL3 migration.
The website navigation code was updated as part of the move to the newer OWL3 framework. This is an internal cleanup that helps keep the website module compatible and maintainable without changing visible behavior for users.
Original PR description
Remove useLayoutEffect from navbar.js as part of OWL3 migration.
This update makes a small internal cleanup to the Point of Sale test popup by removing an unnecessary implementation detail. It helps keep the code simpler and easier to maintain without changing the user experience.
Original PR description
Remove useLayoutEffect from test_popup component.
The portal chatter code was modernized to use the latest built-in framework approach instead of an older implementation detail. This is an internal cleanup that helps keep the portal easier to maintain without changing the expected user experience.
Original PR description
Remove useLayoutEffect from portal chatter_patch.js, replacing with OWL3 native API.
This change simplifies part of the Point of Sale timing logic without changing the visible workflow for users. It helps keep the underlying code easier to maintain and less likely to cause interface timing issues in future updates.
Original PR description
Remove useLayoutEffect from time_hook.js in point_of_sale addon.
The Point of Sale customer list screen was updated to use the newer built-in application approach. This is an internal cleanup that helps keep the system easier to maintain without changing the user experience.
Original PR description
Remove useLayoutEffect usage in partner_list.js and replace with OWL3 native API.
The stock module was internally updated to align with the next version of Odoo's web interface technology. This keeps stock-related screens easier to maintain and helps reduce future migration risk, with no expected change to day-to-day user workflows.
Original PR description
Remove useLayoutEffect from json_widget.js as part of OWL3 migration.
The sales progress display was updated internally to align with Odoo's upcoming interface framework changes. This keeps the sales module easier to maintain without changing how users interact with it.
Original PR description
Remove useLayoutEffect usage in sale_progressbar_field.js as part of OWL3 migration.
This change updates the web search bar toggler to use Odoo's newer interface approach. It keeps the user experience the same while simplifying the underlying code for easier maintenance and future upgrades.
Original PR description
Remove useLayoutEffect from search_bar_toggler.js in favor of OWL3 native API.
This update refactors part of the calendar view code as part of an internal cleanup. It is not intended to change business workflows or add user-facing functionality, and the described commit is temporary work that will be consolidated later.
Original PR description
Remove useLayoutEffect in calendar_common_renderer by commenting it out. This is an intentionally-broken throwaway commit that will be squashed in Step 5.
This update simplifies the internal handling of the calendar year view in Odoo's web interface. It should not change what users see, but it helps keep the interface code easier to maintain and less likely to cause future issues.
Original PR description
Remove useLayoutEffect from CalendarYearRenderer (throwaway commit, will be squashed).
This update replaces an outdated internal web mechanism with the newer supported approach. It helps keep drag-and-drop interactions reliable after screen updates while reducing future maintenance risk.
Original PR description
Replaced `useLayoutEffect` supplied as `setupHooks.setup` in the draggable hook builder with a native OWL3 `setup` adapter because `useLayoutEffect` is deprecated in OWL3. The draggable builder…
Replaced `useLayoutEffect` supplied as `setupHooks.setup` in the draggable hook builder with a native OWL3 `setup` adapter because `useLayoutEffect` is deprecated in OWL3. The draggable builder passes effects with a two-argument shape `setup(effect, computeDependencies)` that OWL3's single-callback `useEffect` cannot satisfy directly; a `signal(false)` + reactive `useEffect` approach also fails because the params call site returns fresh array references every call, so `useEffect` never re-runs on patch (it sees no reactive subscription changes). A thin `setup` adapter using `onMounted`/`onPatched`/`onWillUnmount` reproduces the compat lifecycle exactly: deps are compared on every patch and the effect is re-run when they change, ensuring pointerenter/leave listeners are re-attached to new pill DOM after each re-render. The use layoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - PasskeyTestTours.test_passkey_login - WebSuite.test_unit_desktop - TestTOTP.test_totp see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2605257/build/115408516
The product name and description area was internally updated as part of the move to the newer OWL framework. This does not add or remove visible features, but helps keep the product interface easier to maintain and ready for future improvements.
Original PR description
Remove useLayoutEffect in product_name_and_description.js as part of OWL3 migration.
This update simplifies the internal code behind the project task form without changing how users work with tasks. It helps keep the project app easier to maintain and reduces the risk of future technical issues.
Original PR description
Remove useLayoutEffect from project_task_form_controller — throwaway commit to be squashed in Step 5.
The web interface code for resizable panels was internally simplified as part of preparation for the next OWL framework version. This should not change day-to-day behavior, but it helps keep the interface maintainable and ready for future upgrades.
Original PR description
Remove useLayoutEffect usage in resizable_panel.js as part of OWL3 migration.
This update replaces an outdated internal web component mechanism with the supported approach in the newer OWL framework. It helps preserve existing drag-and-drop behavior, such as importing files and opening share dialogs, while reducing future maintenance risk.
Original PR description
Replaced `useLayoutEffect` with `onMounted` and `onPatched` because `useLayoutEffect` is deprecated in OWL3. `useLayoutEffect` was used in `useCustomDropzone` to track when the target element…
Replaced `useLayoutEffect` with `onMounted` and `onPatched` because `useLayoutEffect` is deprecated in OWL3. `useLayoutEffect` was used in `useCustomDropzone` to track when the target element appeared (setting `hasTarget` and calling `updateDropzone`). The straightforward OWL3 equivalent would be `useEffect`, but `useEffect` fires before the DOM patch and only re-runs when a signal read inside its body changes. Since `getTargetEl()` accesses the element via a legacy `.el` getter (which untracks the underlying signal), `useEffect` never re-ran on mount and `hasTarget` remained `false`. Using `onMounted` and `onPatched` instead restores the post-patch, re-run-on-every-render semantics of the original `useLayoutEffect`. The use layoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - @base_import/import_action/Import view/drag-and-drop file support - @web_enterprise/webclient/home_menu/Drop file on HomeMenu should trigger the share target dialog if having share target items see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2624610/build/116554030
The celebratory rainbow effect was updated behind the scenes as part of Odoo's ongoing interface modernization. This keeps the web experience aligned with the next version of the underlying framework without changing how users interact with the feature.
Original PR description
Remove useLayoutEffect from rainbow_man.js as part of OWL3 migration.
The Project app has an internal code cleanup to support Odoo's migration to the newer OWL3 framework. This change should not alter day-to-day behavior, but helps keep the project interface compatible and easier to maintain.
Original PR description
Temporarily commenting out useLayoutEffect usage as part of migration to OWL3 native API.
The user switching component was adjusted internally to support Odoo's upcoming interface technology upgrade. This keeps the feature aligned with the new framework while preserving the current user experience.
Original PR description
Remove useLayoutEffect usage in user_switch.js as part of OWL3 migration.
This change adjusts how a web dashboard graph component handles screen updates, with the goal of simplifying internal code. It should not change day-to-day behavior for users, but it may help keep the web interface easier to maintain.
Original PR description
Remove useLayoutEffect in journal_dashboard_graph_field.js — intentionally broken throwaway commit to be squashed away in Step 5.
This change is a temporary internal cleanup in the web module as part of a broader interface framework migration. It does not introduce a new feature and is not expected to affect business workflows once finalized.
Original PR description
Intentionally broken throwaway commit: comments out useLayoutEffect in dropzone.js as part of the OWL3 migration process. Will be squashed in Step 5.
This change updates the web input field internals to align with the next version of Odoo's interface framework. It helps keep the platform maintainable and ready for future upgrades without changing day-to-day user behavior.
Original PR description
Remove useLayoutEffect usage in input_field_hook.js as part of OWL3 migration.
This change updates internal web interface code as part of preparation for the next OWL framework version. It is a technical cleanup with limited direct business impact, but the pull request notes it is intentionally broken and should not be treated as production-ready.
Original PR description
Commenting out useLayoutEffect usage in draggable_hook_builder.js as part of OWL3 migration. This is an intentionally-broken throwaway commit.
The PDF viewer field was internally updated to align with the platform's next web framework migration. This keeps the feature maintainable without changing the user experience.
Original PR description
Remove useLayoutEffect usage in pdf_viewer_field.js as part of OWL3 migration.
This change updates the web module internals as part of the ongoing migration to the next version of Odoo's web framework. It should not change day-to-day behavior for users, but helps keep the interface maintainable and compatible with future platform improvements.
Original PR description
Remove useLayoutEffect in property_definition.js as part of OWL3 migration.
This update simplifies an internal part of Odoo's web report handling by replacing a lower-level browser timing mechanism. Users should not notice any functional change, but the code becomes easier to maintain and less prone to subtle display timing issues.
Original PR description
Remove useLayoutEffect usage in report_hook.js
This change modernizes the web interface code behind multi-selection buttons by replacing an older internal approach with the platform's newer native capability. It should help keep the interface easier to maintain without changing how users interact with it.
Original PR description
Remove useLayoutEffect from multi_selection_buttons.js in favor of OWL3 native API.
The recruitment skills score gauge was updated to use the newer application framework approach. This is an internal cleanup that helps keep the recruitment interface maintainable without changing the visible hiring workflow.
Original PR description
...
This update keeps the spreadsheet version history side panel working as expected after an underlying framework change. The active version still automatically scrolls into view, helping users navigate revisions without disruption.
Original PR description
Replaced `useLayoutEffect` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. The original `useLayoutEffect` had no dependency function, meaning it ran after every…
Replaced `useLayoutEffect` with `onMounted` + `onPatched` because `useLayoutEffect` is deprecated in OWL3. The original `useLayoutEffect` had no dependency function, meaning it ran after every render. Its body checked `this.props.active` (a plain, non-reactive prop) and called `scrollIntoView` on the item DOM element. Because plain props do not trigger OWL3 `useEffect` re-runs, the faithful translation is `onMounted` (initial render) + `onPatched` (every subsequent re-render), both delegating to a new `scrollActiveIntoView()` helper that preserves the original guard and scroll options. When commenting out the useLayoutEffect there was no error, meaning the code we refactored had no test coverage. I tested personally using the following steps: - Open a spreadsheet document (e.g. via the Documents app or Spreadsheet menu) - Click the version history icon (clock icon) in the top toolbar to open the Version History side panel - Verify that the currently active version item is scrolled into view automatically - Click on an older revision to activate it and confirm it scrolls into view see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2596825/build/114857525
The data cleaning merge list view was updated to use the newer Odoo interface framework approach. This is an internal technical cleanup that preserves existing behavior while improving compatibility with the latest platform version.
Original PR description
Remove useLayoutEffect usage in data_merge_list_view.js to replace with OWL3 native API.
The map view was updated to use newer internal page-loading behavior required by the next version of Odoo's web framework. This keeps the feature maintainable and helps avoid future compatibility issues without changing the user experience.
Original PR description
Replaces useLayoutEffect with onMounted and onPatched WHY: UseLayoutEffect is deprecated in OWL3
This update changes internal page-loading code in the account reports area without changing the visible workflow. It helps keep the screen compatible with newer platform standards while reducing the risk of future maintenance issues.
Original PR description
Remove useLayoutEffect in AccountReturnCheckKanbanController by commenting out the effect body to verify no tests break.
The Documents app was adjusted behind the scenes to align with the next version of Odoo's interface framework. This keeps the document kanban view maintainable and helps reduce migration risk without changing day-to-day user workflows.
Original PR description
Remove useLayoutEffect from documents_kanban_record.js as part of OWL3 migration.
The planning schedule view was adjusted internally to reduce reliance on older interface behavior. This prepares the module for a future framework upgrade while keeping the visible user experience unchanged.
Original PR description
Remove useLayoutEffect from planning_gantt_renderer.js by commenting out its content. This is a first step to replace useLayoutEffect with OWL3 native API.
This internal cleanup makes list and kanban view components react more reliably when their page elements change. It prepares accounting, documents, marketing, social, and studio screens for future performance improvements without changing day-to-day workflows.
Original PR description
Makes listrenderer root reference reactive using signals and update hooks to accept ref or signals. WHY: To remove a useLayoutEffect in a later commit we need to have root reactive Community PR: https://github.com/odoo/odoo/pull/269130
This internal update replaces deprecated interface code in the Data Cleaning list view so it remains compatible with the latest Odoo web framework. Users should see the same Validate, Discard, and Undiscard buttons appear correctly based on selected records, with no expected change in daily workflows.
Original PR description
Replaced `useLayoutEffect` with `onMounted` + `onPatched` (from `@odoo/owl`) because `useLayoutEffect` is deprecated in OWL3. The effect was a bare `useLayoutEffect` with no dependency function, so…
Replaced `useLayoutEffect` with `onMounted` + `onPatched` (from `@odoo/owl`) because `useLayoutEffect` is deprecated in OWL3. The effect was a bare `useLayoutEffect` with no dependency function, so it ran synchronous DOM side-effects after every render — toggling the visibility of the control-panel action buttons (Validate / Discard / Undiscard) based on the active state of the current selection. The faithful OWL3 equivalent of "run after mount and after every re-render" is a single callback registered with both `onMounted` and `onPatched`. I also checked whether `this.model.root.selection` is reactive, to consider replacing the hooks with computed values + a single `useEffect`. It is not: the web relational model pushes updates explicitly via `model.notify()` -> `render()` rather than OWL `reactive()` proxies (`record.selected` is a plain boolean, and `selection` is a plain `records.filter(...)` getter). So `onMounted` + `onPatched` remains the correct faithful replacement. This is a CASE 1 commit. When commenting out the useLayoutEffect there was no error, meaning the code we refactored had no test coverage. I tested personally using the following steps: - Open the Data Cleaning app - Navigate to the Data Cleaning list view (Records menu) - Select one or more records that have `active = true` - Verify that the "Validate" and "Discard" buttons are visible and "Undiscard" is hidden - Select records with `active = false` (archived/discarded) - Verify that "Undiscard" is visible and "Validate"/"Discard" are hidden
The appointment calendar’s internal code was updated to align with Odoo’s newer interface framework. This helps keep the appointment experience reliable and easier to maintain without changing how users schedule or manage appointments.
Original PR description
Remove useLayoutEffect usage in appointment calendar hooks to migrate to OWL3 native API.
The project planning timeline code was updated to use the newer internal framework approach. This is a behind-the-scenes change intended to keep the feature compatible and easier to maintain, with no expected change for day-to-day users.
Original PR description
Commented out useLayoutEffect body to test coverage before replacement with OWL3 API.
The Twitter/X social media integration was updated internally to prepare for a newer interface framework. This helps keep the feature maintainable and reduces future upgrade risk without changing day-to-day user workflows.
Original PR description
Commented out useLayoutEffect calls to test coverage before OWL3 replacement.
This change adjusts internal code for the Sales Commission chart without adding or removing business functionality. It is intended to validate test coverage around the chart behavior, so day-to-day users should not notice a change if existing safeguards are working.
Original PR description
Commenting out useLayoutEffect to break it on purpose, to check if there is test coverage.
A small internal change was made in the Project app's task scheduling view as part of preparation for the next web framework migration. This helps reduce future upgrade risk without changing business functionality for users.
Original PR description
Commented out useLayoutEffect in task_gantt_renderer_common.js to break the effect on purpose, as part of the OWL3 migration process.
The push notification request component was updated to use the newer internal framework approach. This keeps the feature aligned with platform changes and helps maintain reliability without changing the user-facing experience.
Original PR description
Commented out useLayoutEffect to verify test coverage before applying OWL3 replacement.
This update adjusts the Social app’s internal code to align with the next version of Odoo’s front-end framework. It does not change visible features, but helps keep the app maintainable and ready for future upgrades.
Original PR description
Remove useLayoutEffect usage in stream_post_kanban_controller.js as part of OWL3 migration.
The stock barcode form was adjusted to use the newer interface approach required for the next Odoo web framework version. This is an internal cleanup that helps keep barcode inventory workflows stable and maintainable without changing user-facing behavior.
Original PR description
Remove useLayoutEffect usage in stock_barcode_sml_form.js as part of OWL3 migration.
This change updates the enterprise pivot report view to use the newer built-in framework approach instead of an older internal mechanism. It should help keep the reporting interface easier to maintain with minimal visible impact for users.
Original PR description
Remove useLayoutEffect usage in pivot_renderer by replacing with OWL3 native API.
The Documents file viewer was internally updated to align with the next version of Odoo's interface framework. This helps keep the Documents app maintainable and ready for future upgrades without changing day-to-day user behavior.
Original PR description
Remove useLayoutEffect from documents_file_viewer.js as part of OWL3 migration.
The barcode stock movement widget was updated to use the newer platform approach instead of an older internal mechanism. This keeps the inventory barcode experience aligned with the current Odoo framework and helps maintain long-term reliability without changing user workflows.
Original PR description
Remove useLayoutEffect from set_quant_stock_move_line widget and replace with OWL3 native API.
The spreadsheet version history side panel was updated as part of ongoing platform modernization work. This internal change helps keep the feature compatible with the next Odoo web framework version without changing the user experience.
Original PR description
Remove useLayoutEffect usage in version_history_side_panel.js as part of OWL3 migration.
This update refreshes an internal part of the Timesheets grid to align with the latest platform approach. It should not change how users work with timesheets, but helps keep the feature easier to maintain and compatible over time.
Original PR description
Automated PR to replace useLayoutEffect with OWL3 native API in timesheet_grid.
This change updates the enterprise navigation bar internals without adding or removing user-facing features. It is a low-impact maintenance change intended to simplify the implementation and support future work.
Original PR description
Remove useLayoutEffect usage in EnterpriseNavBar. This is an intentionally-broken throwaway commit that will be squashed in a later step.
The report editor was updated to use the platform's newer internal approach for screen update handling. This keeps the Studio report editing experience aligned with the latest framework standards and helps maintain reliability without changing user-facing behavior.
Original PR description
Remove useLayoutEffect usage in report_editor_xml.js and replace with OWL3 native API.
This change updates internal web interface code to use a newer event-listening approach that is compatible with the next version of Odoo's front-end framework. It helps keep expense, mail, accounting, and common web views maintainable without changing day-to-day user workflows.
Original PR description
Replaces useRefListener with useListener which doesn't use a useLayoutEffect under the hood WHY: UseLayoutEffect is deprecated in OWL3 Enterprise PR: https://github.com/odoo/enterprise/pull/119988 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Odoo now stores only the user's active search choices in page links, rather than the full internal view state. This makes navigation links lighter, less cluttered, and easier to restore reliably when reloading pages or working offline.
Original PR description
Only the search performed by the user (the active facets) needs to end up in the url, not the whole internal state of the view. Pushing the complete state was heavier than necessary and leaked more detail into the url than a search really is. A lightweight representation of "what the user searched for" already existed, introduced for reapplying a search when working offline. Reusing it here avoids maintaining two different ways to describe a search, and pushed us to make that representation a bit more robust so it can be trusted for both purposes. Finally, deciding what belongs in the url is the search model's responsibility, not the action service's: the model is the one that actually knows what a facet is. Moving that decision there removes an indirection the action service had no real reason to carry.
Search pages now keep only the user's active search choices in the browser URL instead of storing extra internal page details. This makes URLs lighter, cleaner, and easier to maintain while preserving normal navigation behavior such as back and forward.
Original PR description
Only the search performed by the user (the active facets) needs to end up in the url, not the whole internal state of the view. Pushing the complete state was heavier than necessary and leaked more detail into the url than a search really is. A lightweight representation of "what the user searched for" already existed, introduced for reapplying a search when working offline. Reusing it here avoids maintaining two different ways to describe a search, and pushed us to make that representation a bit more robust so it can be trusted for both purposes. Finally, deciding what belongs in the url is the search model's responsibility, not the action service's: the model is the one that actually knows what a facet is. Moving that decision there removes an indirection the action service had no real reason to carry.
Web Serial device handling has been moved out of Point of Sale into a shared module. This makes it easier to support serial-connected devices, such as scales, in other Odoo apps without duplicating work.
Original PR description
Enterprise PR: <https://github.com/odoo/enterprise/pull/129510> Before this commit, the code was interfacing with a Web Serial scale was included directly in the Point of Sale module. After this commit, the Web Serial code is extracted into a new module `iot_webserial`, which `point_of_sale` now depends on. This allows Web Serial devices to be used in other modules without duplicating the code. task-6485996 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr