Thursday, September 17, 2026
58 changes · master
New functionality added to Odoo
This update introduces Owl 3 and starts adapting Odoo's Hoot testing tools to work with it. It matters because it prepares the web platform and its automated tests for the next generation of the user interface framework, helping future development move forward more reliably.
Original PR description
### [ADD] Owl 3 ### [WIP] convert Hoot to Owl 3 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Enhancements to existing features
Vendor invoice imports now better recognize reverse charge taxes even when electronic invoice files list them as 0%. This helps keep imported tax and analytic information more accurate, reducing manual correction work for accounting teams.
Original PR description
Reverse charge taxes can be reported as 0% in the XML, meaning that we wouldn't be able to predict them even if e already set it right on a previous invoice for the same partner.Description of the issue/feature this PR addresses: Forward-Port-Of: odoo/odoo#287476
Resolved issues and error corrections
Sales teams can now use Studio to edit the list view for sales order lines without running into an error. This restores the ability to customize columns and add fields on sales orders, reducing disruption for users configuring their sales workflow.
Original PR description
Before this change: When opening Studio on a Sales Order with existing line items, clicking "Edit List View" on the order lines component triggered a JavaScript error. This prevented users from customizing columns or adding custom fields to the sale order line list view. To reproduce: 1. Open the Sales app and create a new Sales Order with at least one product line. 2. Toggle Studio on. 3. Select the Sale Order Lines list component and click "Edit List View". After this change: Clicking "Edit List View" on sale order lines in Studio works as intended without throwing errors, allowing standard view customizations. opw-6545970 Forward-Port-Of: odoo/odoo#288171
Installing the Colombian electronic invoicing module is made faster for companies with large accounting histories. The change avoids time-consuming recalculation of existing invoice data during setup while keeping normal behavior for new and updated records.
Original PR description
- Use the `init_storage` field attribute to initialize the stored computed column `l10n_co_edi_type`, `l10n_co_edi_cufe_cude_ref`, `l10n_co_edi_state`, `l10n_co_edi_operation_type`,…
- Use the `init_storage` field attribute to initialize the stored computed column `l10n_co_edi_type`, `l10n_co_edi_cufe_cude_ref`, `l10n_co_edi_state`, `l10n_co_edi_operation_type`, `l10n_co_edi_commercial_state` directly in the database. - This prevents Odoo from computing and writing the field for all existing `account.move` records when installing `l10n_co_edi`. - This is particularly important for large databases with a high volume of Colombian accounting moves, where the initial computation can take too long and cause the module installation to hit the time limit. - Keep the compute method unchanged so the field continues to be computed normally for subsequent record creation or dependency changes. - Remove the `default` from `l10n_co_edi_commercial_state` since the `default` sets the field to `pending` while the compute sets it to `False` when no accepted EDI document exists. Move `pending` to `default_get` to preserve the current behavior while keeping the initialization consistent with the compute. **opw-6451331** Forward-Port-Of: odoo/enterprise#130808 Forward-Port-Of: odoo/enterprise#129507
Payroll now shows warnings about employee profile changes more broadly, including on the payroll dashboard and employee form. This helps payroll teams notice when an employee's data changed after a payslip was created, reducing the risk of processing outdated payroll information.
Original PR description
When you update an employee profile or create a new version covering a period of time already covered by a payslip, if you re-open the payslip, you'll see this warning: The employee's data has been updated since this payslip was created. -> Making it visible from the payroll dashboard and the employee's form. Warnings on `hr.employee` and having `warning_type == 'python'` were grouped by versions. Making them visible only if the right version was selected. Updating `_compute_issues()` so that if model is `hr.employee`, the warning is visible no matter the selected version. Task: 6435032
The point of sale receipt popup now uses standard notifications to show sending progress, success, or errors instead of messages inside the popup. The dialog also has a clearer title, making it easier for cashiers to understand and act on receipt-sending steps.
Original PR description
Previously, the receipt popup displayed its status (success, error, loading) using inline text elements directly inside the dialog. This commit replaces these inline text notices with standard Odoo toaster notifications. Additionally, a title was added to the dialog to make its purpose immediately clear. Task-6496757
Studio now supports configuring AI behavior directly on existing fields, making AI setup more consistent and easier to manage. The update also cleans up related prompts and dialog text so users get clearer guidance when working with AI fields and Studio promotion messages.
Employee kanban cards now show an issues tag when payroll-related problems need attention, helping payroll teams identify cases that require follow-up more quickly. The update also removes outdated employee issue fields and filters, and improves Belgian payroll warning text handling for more accurate messages.
Original PR description
task-id: 6530918
Payslip validation errors now show more helpful details, including both the error title and description when available. When several issues are found, they are displayed as a numbered list so payroll users can understand and resolve them more easily.
Original PR description
Validating a payslip for an employee can raise errors (regarding salary configuration for example.) The validation message providing insights to the user used to be a list of the titles of errors. Some of these validation errors may have a description as well, which would be useful for the user. The errors message has been adapted to display title and description if any. If more than one error is shown, the message format is also adapted as a numbered list. task-6526610
Payroll users can now update Premium Pay options for several existing leave records at once from the Gantt view, instead of opening each leave individually. This speeds up payroll preparation while ensuring options are only applied where the leave type supports them, and leaves with active options are easier to spot via the currency symbol shown on the schedule.
Original PR description
Allow users to apply Premium Pay options across multiple leave records at once in the Gantt view instead of configuring them individually. An "Options" action is added to the Gantt multi-selection button bar when selecting cells with existing leaves. Clicking this action displays applicable m2m options inside a popover view using a form layout with an inline `add_circle` icon indicator. When updated, selected options are executed on the server side and applied strictly to leave types whose underlying work entry types support them. Additionally, leaves with active options now render the company currency symbol directly on their Gantt pills. task-6542141
Belgian payroll now warns when a payslip uses the adapted work schedule leave code after an employee has been continuously sick for more than 12 months or had related long-term illness leave. This helps payroll teams apply the correct leave code and avoid incorrect salary assimilation calculations.
Original PR description
When an employee has been continuously sick for more than 12 months, returning on an adapted working schedule must use LEAVE12305 instead of LEAVE281, as the absence is no longer assimilated. Add a Python payroll warning to flag payslips using LEAVE281 when the employee's continuous illness exceeds 12 months or includes LEAVE280, and update assimilation computations accordingly. Task-ID: 6484739
Payroll structure types are now handled more automatically, reducing the need for users to manage them directly. This makes payroll configuration clearer and helps prevent inconsistent pay schedule settings when creating or updating Belgian payroll records.
Original PR description
- made `type_id` hidden in the payroll structure form view and made it computed so it takes a value when the user creates a new type or change the county of an existing one. - made `schedule_pay` not related to structure type - removed the menu for structure types task-6569952
The AI app now offers a clearer interface for choosing which subagents an AI agent can use, making setup easier and reducing configuration mistakes. The update also prevents unnecessary warning messages when website styling refreshes successfully.
Original PR description
task-[6578342](https://www.odoo.com/odoo/2366/tasks/6578342)
Meetings held in Discuss can now be automatically recorded on the related document when they were planned from that document, so teams no longer need to manually note that a call happened. The log includes the call duration and links back to the call, with indicators for recordings and transcripts when available.
Original PR description
A meeting held in Discuss left no trace outside of its own channel: whoever just spent an hour on a call had to write that fact down by hand on the lead or the task it was about. A…
A meeting held in Discuss left no trace outside of its own channel: whoever just spent an hour on a call had to write that fact down by hand on the lead or the task it was about. A discuss.call.history can now be tied to a mail.activity, the way a voip.call already is. It happens on its own when the meeting was planned from a document: the call taking place in it is logged on the activity that planned it, so that marking that activity done posts "Meeting done (1h 23m 45s)" in the chatter of that document, linking back to the call and telling whether it was recorded and transcribed. A call nobody planned is logged by hand from the Call History, through the wizard voip contributed and mail now owns. The duration wording shared by both call models moves to mail.tools.call, and ai contributes the transcript icon to that message the way it already does for a voip.call. Join Meeting opens the Discuss channel of the meeting for an attendee who is already a member of it, instead of navigating away to the invitation link. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Meetings held in Discuss can now be automatically recorded in the chatter of the related document when they were planned from that document, including duration, recording, and transcript details. This gives teams a clear history of customer or project conversations without manually writing notes after each call.
Original PR description
A meeting held in Discuss left no trace outside of its own channel: whoever just spent an hour on a call had to write that fact down by hand on the lead or the task it was about. A…
A meeting held in Discuss left no trace outside of its own channel: whoever just spent an hour on a call had to write that fact down by hand on the lead or the task it was about. A discuss.call.history can now be tied to a mail.activity, the way a voip.call already is. It happens on its own when the meeting was planned from a document: the call taking place in it is logged on the activity that planned it, so that marking that activity done posts "Meeting done (1h 23m 45s)" in the chatter of that document, linking back to the call and telling whether it was recorded and transcribed. A call nobody planned is logged by hand from the Call History, through the wizard voip contributed and mail now owns. The duration wording shared by both call models moves to mail.tools.call, and ai contributes the transcript icon to that message the way it already does for a voip.call. Join Meeting opens the Discuss channel of the meeting for an attendee who is already a member of it, instead of navigating away to the invitation link. https://github.com/odoo/odoo/pull/285269
This update improves the online shopping experience by adding clearer country-related options and better handling of currency and pricelist choices. It helps shoppers see the right regional settings while avoiding unexpected price changes in the cart.
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
Customer lists now show reminder levels and include filters for overdue accounts and reminder status. This helps teams quickly identify which customers need follow-up and prioritize collection activities.
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#130440 task-6501327 Forward-Port-Of: odoo/odoo#286688
Users can now add a separate personal message when sending survey invitations, so their notes are preserved even if recipients are changed. Invalid email addresses are shown directly below the email field, making invitation errors easier to understand and fix.
Original PR description
Purpose ======== On the survey invitation wizard, when a user tries to put comments on the mail body, it recomputes and erases the user message when the recipient field is altered. Specification ============== - It adds a new field to allow users to send additional messages when inviting users to survey. - It displays an error message below the email field for invalid emails instead of UserError. Task-3753800
Event badges now better support folded A4 printing by keeping key instructions and QR codes visible for easier check-in. Event session planning was also simplified with clearer wording, fewer unnecessary notifications, and improved wishlist access, making the attendee experience smoother.
Original PR description
Several diff for OXP [IMP] event: improve A4 foldable badge -> required for oxp kenya - if you have ticket instruction, use it on badge + add qr code always visible [IMP] event: don't show tag (question reply) if only one choice -> fix case of "yes, agree" show on badge as tag "yes" [IMP] website_event_track: typo and make it less verbose -> FP quick pass usability [IMP] website_event_track: replace fa-bell by fa-star -> why ? not sure better after... but FP request -> + add menu whishlist directly in event sub menu ## deploy ``` views = [ 'website_event_track.agenda_main_track', 'website_event_track.track_card', 'website_event_track.tracks_search', 'website_event_track.event_track_aside_other_track', 'website_event_track.track_widget_reminder', ] from odoo.upgrade import util for xmlid in views: util.update_record_from_xml(env.cr, xmlid) ``` Forward-Port-Of: odoo/odoo#285915
This update adds guided sandbox answer tools for Belgian DRS and Flexi@Work payroll-related declarations. It helps teams test and validate Belgian payroll workflows more reliably before using them in real processes.
Original PR description
…andbox answer wizards Task: 6558927
Users can now see reminder levels directly in partner lists and filter customers by overdue status or reminder level. This helps finance teams prioritize follow-ups and find accounts needing attention more quickly.
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#286688 task-6501327 Forward-Port-Of: odoo/enterprise#130440
Appointment screens and messages have been polished to make booking details clearer for users. Confirmation emails now use a more reliable greeting, default reminders are set one day before appointments, and calendar labels and popovers are cleaner and less confusing.
Original PR description
This commit improves the UI of appointment: * To improve the readability of the "total_capacity_reserved" field in the records of the kanban view, its background color is lightened. * The default alarm of the appointment type is set to 1 day. * The name of the appointment booker is no longer used for the greeting in the confirmation email since it is not set if the appointment is done from the backend. Instead of it, the first of the attendees is used and if they do not exist, the organizer is used. * The popover is improved. Margins are placed between the buttons in the footer, to avoid having them stuck to each other. A maximal width is set for the videocall_location field, this way it does not impact the size of the popover. * To avoid a technical label, the default falsy label of CalendarEvent.resource_ids, which is "Undefined Attendee", is replaced by "Unassigned". Community PR: https://github.com/odoo/odoo/pull/288517 Task-6566639
This update improves small on-screen interactions to make the product feel more responsive and polished. These refinements help users better understand actions and feedback while working, without changing core workflows.
Original PR description
commu-PR: https://github.com/odoo/odoo/pull/286205
Odoo Studio users can now rearrange pages and groups in form layouts by dragging and dropping them. This makes it easier to customize forms visually and organize business information without relying on technical changes.
Users can now create serial or lot records directly from the Customers smart button on a customer profile. This streamlines field service stock workflows by reducing navigation and making equipment tracking setup faster.
Original PR description
After this commit, users can create serial/lot records directly from the Customers smart button on the partner form view. task-6417443
Serial and lot records can now have their linked customers updated manually, making it easier to reflect real-world service relationships such as separate installer and maintenance customers. Customer links are also kept consistent with company ownership by automatically removing mismatched associations.
Original PR description
Before this commit, the customers linked to a serial/lot were computed and could not be edited. This prevented handling cases where the installer and maintenance customer differ, as no sales order exists to link the serial number to the maintenance customer. After this commit: - `partner_ids` on serial/lot records is editable. - If a partner's company is changed and no longer matches the company of the serial/lot, the link between the partner and the serial/lot is automatically removed (and vice versa). task-6417443
Cancelling an Adyen card payment from the Point of Sale now sends the cancellation to the correct payment request. This prevents payment terminals from continuing to wait for a customer payment after the cashier has cancelled it in Odoo.
Original PR description
Steps to reproduce: - Configure a POS with an Adyen payment terminal - Open the POS, add a product and go to the payment screen - Select the Adyen payment method and click Send - Wait at least 5 seconds - Cancel the payment from the POS - => The terminal keep waiting for the payment (it's not canceled) `_adyenCancel` read `most_recent_service_id` but this value is overwritten by the `_adyenCheckPaymentStatus` polling after 5s, so we try to cancel the wrong payment. We now read the ServiceID from the payment line instead of using `most_recent_service_id`. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288874
Vendor bill lists in Accounting now load quickly again after a recent change caused severe slowdowns. The database lookup used to detect duplicate bills was updated so it also covers vendor receipts, restoring the expected performance for users viewing bills.
Original PR description
commit https://github.com/odoo-dev/odoo/commit/391278237dc4fdbf48039bb269f1377d83bbc54d introduced a performance regression.
Go to Accounting > Vendors > Bills
On odoo.com:
| | Time | Query plan |
|--------|--------|--------|
| Before | ~600ms | https://explain.dalibo.com/plan/3ge1afa2aa632be9 |
| Now | 44s | https://explain.dalibo.com/plan/99e847h8d1c38dfd |
After this commit, we're back with the same query plan :)
The reason is the condition `.move_type in ('in_invoice', 'in_refund')`
which was changed to include 'in_receipt':
`.move_type in ('in_invoice', 'in_refund', 'in_receipt')`
Because of that, the query can no longer use the partial index
`_duplicate_bills_idx` because it doesn't include 'in_receipt'.
This commit adapts the index to include moves with type 'in_receipt'.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#288481Fixes French PDP partner lookup so it works when a company endpoint uses a personalized SIREN or SIRET with an added suffix. This helps affected businesses find and validate partners reliably instead of being blocked by overly strict identifier length checks.
Original PR description
In PDP the lookup didn't work if the endpoint is of any length other than 9 or 14 characters, however personalised SIREN/SIRET can have a higher length, this pr fixes that by allowing a SIREN/SIRET suffix in the lookup following the format 'SIRET_SUFFIX' no task id Forward-Port-Of: odoo/odoo#288509
This fixes an issue where status steps could incorrectly collapse into a single “More” dropdown when users viewed records at certain browser zoom or display scaling settings. Users on high-resolution screens should now see the full statusbar when there is enough space, making record stages easier to read and navigate.
Original PR description
`areItemsWrapping` decides whether the statusbar buttons fit on one line by comparing `getBoundingClientRect()` heights. Those rects are rounded to physical pixels, so depending on the zoom/DPI ratio…
`areItemsWrapping` decides whether the statusbar buttons fit on one line by comparing `getBoundingClientRect()` heights. Those rects are rounded to physical pixels, so depending on the zoom/DPI ratio a single-line height can come out a fraction of a pixel taller than the reference button height, even though nothing actually wraps. That false positive made the whole statusbar collapse into a single dropdown at some (but not all) browser zoom levels, most noticeable on high-DPI screens where OS scaling and browser zoom combine into non-integer ratios. Steps to reproduce: 1. On a high-DPI screen (e.g. 4K) with OS display scaling enabled. 2. Open any record with a statusbar field (e.g. a CRM opportunity). 3. Set the browser zoom to a value close to 100%. 4. The statusbar collapses into a single "More" dropdown instead of showing every stage inline, even though there is enough room. Round both heights before comparing to ignore that sub-pixel noise while still detecting genuine wrapping. Regression introduced by 7e77b99d2845. task-6545990 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#288194
This fix prevents sale orders from failing when a user saves immediately after reordering order lines. Odoo now pauses saving while the line reorder action finishes, making the Sales workflow more reliable for quotations and orders with multiple lines.
Original PR description
When we save a sale order just after reordering its sale order lines, there's a chance that an error is thrown Steps to reproduce: 1. Install Sales 2. Go to Sales and open any quotation that has…
When we save a sale order just after reordering its sale order lines, there's a chance that an error is thrown Steps to reproduce: 1. Install Sales 2. Go to Sales and open any quotation that has multiple sale order lines 3. Reorder a sale order line and immediately save (there's more chance to reproduce if you have a lot of sol and if you use the shortcut `ALT + S`) 4. An error is thrown Issue: It is possible that the save takes place during the execution of super.sortDrop. This reassigns the id of all the records in this.props.list.records Therefore, calling `_handleQuantityAdjustment` with the recordMap computed before the save uses an id that has disappeard from this.props.list.records so we cannot find it at https://github.com/odoo/odoo/blob/4973903252865a6a7a2da235bc3a01675dbbff4d/addons/sale_management/static/src/fields/sale_order_line_field/sale_order_line_field.js#L263 which eventually throws an error Solution: Suspend any save mechanism when sortDrop starts and resume it when sortDrop has finished opw-6483206 Forward-Port-Of: odoo/odoo#288370 Forward-Port-Of: odoo/odoo#286787
This fixes an access error that could stop warehouse users from creating backorders during multi-step deliveries when the original sales order belonged to another user. It restores the expected workflow so inventory teams can validate transfers and create backorders without unnecessary sales order permissions.
Original PR description
Multi-step deliveries backorders may create a new picking when processed by a user who only has access to their own sales orders. But, `_key_assign_picking` reads from the related sales order that they don’t have access to. Previously, these moves were confirmed with superuser rights, so this read did not trigger the sales order record rule. Since 19.2, the `sudo()` was removed. The fix would be to add this back in so the access rights error would not be raised. Steps to reproduce on Runbot: 1. Log in as User A (Admin) Turn on Multi-Step Routes Set the warehouse to use 2-step delivery (Pick then Deliver) 2. Create a Sales Order for a product with demand more than stock available and confirm it. 3. Log in as User B with (Demo): Sales: User: Own Documents Only Inventory: User 4. Open the picking transfer generated from User A’s Sales Order. 5. Click Validate and choose Create Backorder. Related: opw-6509032 Forward-Port-Of: odoo/odoo#285778
Fixes a crash when exporting the Peruvian "Inventory and Balance" General Ledger report. The report now generates successfully while preserving the required SUNAT file format, preventing disruption for users preparing compliance reports.
Original PR description
### Description of the issue/feature this PR addresses: This PR fixes a server crash in the Peruvian localization (l10n_pe_reports_lib) that occurs when generating the "Inventory and Balance" General…
### Description of the issue/feature this PR addresses: This PR fixes a server crash in the Peruvian localization (l10n_pe_reports_lib) that occurs when generating the "Inventory and Balance" General Ledger report. The crash is triggered by strict validation rules within Python's csv module, which rejects the custom line terminator used to fulfill the SUNAT PLE formatting requirements. ### Current behavior before PR: When a user attempts to generate and export the "Inventory and Balance" report, the server crashes with a ValueError: bad delimiter or lineterminator value. This happens because the csv.DictWriter is initialized with lineterminator='|\n' to ensure every row ends with a pipe. Python's underlying csv implementation rejects this, as it expects standard line endings (\r, \n, or \r\n) and throws an error if the delimiter character (|) is included in the terminator string. ### Desired behavior after PR is merged: The "Inventory and Balance" report generates successfully without server errors. The code now uses the standard lineterminator='\n' to satisfy Python's validation rules. To maintain the mandatory trailing pipe (|) at the end of each row required by SUNAT, a dummy empty column (['']) is appended to the field names with restval=''. This prompts the writer to naturally append the final pipe as a column delimiter before the newline, resulting in the exact |\n output format required, safely and reliably. opw-6509674 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#131302 Forward-Port-Of: odoo/enterprise#129636
This fixes naming and selection issues in marketing automation views introduced by a recent revamp. Users should no longer see crashes or be sent to the wrong screen when opening server actions or trigger forms in campaign flows.
Original PR description
This commit fixes issues that were introduced with the new marketing automation revamp. Some views were either wrongly renamed or no longer used to display server actions or trigger form views in the flow view. Which is an issue as this would either create a crash or open the wrong view entirely. Now the views are correctly renamed and used. task-6559148
Fixed an issue where one-time purchases of recurring products were treated like ongoing subscriptions in stock forecasts. This prevents misleading future demand and helps replenishment planning reflect actual sales commitments.
Original PR description
When a recurring product (with `allow_one_time_sale = True`) is sold as a one-time purchase (no subscription plan), the stock forecast report and replenishment logic incorrectly treat it as an active…
When a recurring product (with `allow_one_time_sale = True`) is sold as a one-time purchase (no subscription plan), the stock forecast report and replenishment logic incorrectly treat it as an active subscription. This results in infinite projected future outgoing moves for standard sales. This occurs because the logic only checks if `recurring_invoice` is True on the product, ignoring whether the parent order actually has a `plan_id`. This commit fixes the issue by: 1. Updating `_get_stock_subscription_lines` in `sale.order.line` to filter out lines using `_subscription_is_one_time_sale()`. 2. Updating the domains in `stock.forecasted_product_product` to require `order_id.plan_id != False` for subscription forecasts, while correctly routing one-time sales (`order_id.plan_id == False`) back to the standard sale domain. 3. Adapting existing tests to verify that one-time sales do not generate future subscription stock forecasts. Task-6193648 Forward-Port-Of: odoo/enterprise#128018 Forward-Port-Of: odoo/enterprise#116889
Vendor bills now keep the manually selected recipient bank account when using Auto-Complete, as long as the bill currency has not actually changed. This prevents accidental payment detail changes for vendors with multiple bank accounts.
Original PR description
### Issue: When a bank account is manually set on a bill for a partner with multiple bank accounts, using the Auto-Complete feature could reset the manual selection even without a currency change ###…
### Issue: When a bank account is manually set on a bill for a partner with multiple bank accounts, using the Auto-Complete feature could reset the manual selection even without a currency change ### Cause: When `invoice_vendor_bill_id` is set, an onchange assigns `currency_id` unconditionally, even when it is the same value This triggers `_compute_partner_bank_id`, which always recomputes the best matching bank account from scratch without considering the currently set value If the currency did not change, this recompute is unnecessary and silently overrides the manual selection ### Steps to reproduce: - Install `account` - Create a Vendor with 2 bank accounts (keep default values to have equal priority on all accounts) - Create and post a Bill for this vendor with at least one line - Create a new Bill for the same vendor - Set the Recipient Bank to the second account in the list - In Auto-Complete, select the first Bill Before the fix, the Recipient Bank is reset to the first account opw-6210414 Forward-Port-Of: odoo/odoo#288386 Forward-Port-Of: odoo/odoo#283479
This fix ensures that when a past point-of-sale order is later invoiced, the cancellation sent to the Spanish tax authority targets the original simplified receipt instead of the newly created full invoice. This prevents incorrect electronic tax records and helps businesses keep Verifactu POS reporting accurate.
Original PR description
When creating an invoice for a previous POS order, the data sent to AEAT cancels the full invoice instead of the order's simplified invoice. Steps to reproduce: - Open a POS and make a sale without invoicing it; - In the POS, go to the Order tab; - Select the order and fully invoice it. Issue: The AEAT cancellation line added to the pos order actually cancels the full invoice just created [opw-6471927](https://www.odoo.com/odoo/project/49/tasks/6471927) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284277
Colombian Point of Sale orders no longer fail when a company has several DIAN obligation types configured. Receipts can now be generated and printed correctly by listing all applicable obligation descriptions instead of assuming only one exists.
Original PR description
Steps to reproduce: - Colombian company with DIAN electronic invoicing enabled in PoS - On the company contact, set more than one obligation type (e.g. O-13, O-15 and O-23) - Open a PoS session, sell…
Steps to reproduce: - Colombian company with DIAN electronic invoicing enabled in PoS - On the company contact, set more than one obligation type (e.g. O-13, O-15 and O-23) - Open a PoS session, sell a product and pay Issue: The order fails to sync with "Expected singleton: l10n_co_edi.type_code(x, y, z)" as soon as the DIAN document is accepted, and the receipt cannot be printed. On 18.0 to saas-19.1 the same crash happens when the receipt data is generated for printing. Cause: `_compute_l10n_co_edi_pos_receipt_data` fills `obligation_type_description` by reading `description` directly on `l10n_co_edi_obligation_type_ids`, which is a many2many. The read only works when the company carries exactly one obligation type, while a Colombian company commonly has several (they are all sent to the DIAN in `TaxLevelCode`). Fix: Join the descriptions of all obligation types, the same way the DIAN invoice PDF report already does. opw-6576523 Forward-Port-Of: odoo/enterprise#131747
GCC Arabic-English invoice PDFs no longer fail when an invoice includes section or note lines. This prevents internal server errors during invoice preview or printing, making invoice generation more reliable for affected businesses.
Original PR description
## Problem When rendering PDF invoices that contain **section** or **note** lines, the `l10n_gcc_invoice.arabic_english_invoice` QWeb template raises: ``` TypeError: argument of type 'bool' is not…
## Problem When rendering PDF invoices that contain **section** or **note** lines, the `l10n_gcc_invoice.arabic_english_invoice` QWeb template raises: ``` TypeError: argument of type 'bool' is not iterable ``` This happens because `account.move.line` records of type `line_section` or `line_note` have `name = False`. The template evaluates `arabic_name not in line.name` (and the same for `english_name`), which fails because Python cannot apply the `in` operator on a boolean value. ## Fix Add a `line.name and` guard before each `not in` check: ```xml <!-- Before --> <span t-if="arabic_name not in line.name" .../> <span t-if="(english_name != arabic_name) and (english_name not in line.name)" .../> <!-- After --> <span t-if="line.name and arabic_name not in line.name" .../> <span t-if="line.name and (english_name != arabic_name) and (english_name not in line.name)" .../> ``` ## Steps to reproduce 1. Install `l10n_gcc_invoice` on an Odoo 16.0 instance. 2. Create a customer invoice and add a **Section** line. 3. Print/preview the invoice PDF. 4. Observe `Internal Server Error` / `TypeError: argument of type 'bool' is not iterable`. Forward-Port-Of: odoo/odoo#278887 Forward-Port-Of: odoo/odoo#267147
This fix prevents Argentina electronic invoices from sending zero-value VAT details when advance payments fully offset the invoice. It helps $0 final invoices pass ARCA validation instead of being rejected, supporting the standard 100% down payment workflow.
Original PR description
## Description of the issue When an Argentinian invoice contains advance-payment deduction lines that exactly cancel the product lines (net taxable base = 0 for a given VAT aliquot), the invoice is…
## Description of the issue
When an Argentinian invoice contains advance-payment deduction lines that exactly cancel the product lines (net taxable base = 0 for a given VAT aliquot), the invoice is rejected by the ARCA (AFIP) WSFE web service with:
> **Error 10018**: "Si ImpIva es igual a 0 el objeto Iva y AlicIva son obligatorios. Id iva = 3 (iva 0)"
This is the standard "100% down payment" flow: the customer is invoiced an advance for the full amount, and the final invoice deducts that advance, resulting in a $0 invoice that must still be validated against ARCA.
This is a forward-port to 19.0 of #270846 (same fix, targeted at 18.0, closed unmerged). The bug is still present in 19.0: `_get_vat()` in `addons/l10n_ar/models/account_move.py` evaluates its filter on the raw unrounded aggregated floats.
## Steps to reproduce
1. On a company with the Argentinian localization (`l10n_ar_edi`) configured for electronic invoicing (WSFE), create a sale order with one or more product lines taxed at IVA 21% (e.g. total $121,000).
2. Create a **down payment invoice for 100%** of the order and validate it against ARCA (this one succeeds).
3. Create the final invoice from the sale order: it contains the product lines (positive) and the down-payment deduction line (negative), both at IVA 21%. Total to pay: **$0.00**.
4. Confirm the invoice and send it to ARCA.
5. **Current behavior (bug):** ARCA rejects the request with error 10018. Inspecting the generated WSFE request shows `ImpNeto=0.0`, `ImpIVA=0.0`, `ImpTotal=0.0` and an `Iva` block containing an all-zero aliquot, e.g. `{'AlicIva': [{'Id': '5', 'BaseImp': 0.0, 'Importe': 0.0}]}` — instead of `Iva: null`.
6. **Expected behavior (after fix):** no zero-amount aliquot is sent (`Iva` is `null`) and ARCA approves the $0 invoice.
## Root cause
In `_get_vat()`, the positive product lines and the negative down-payment deduction line share the same VAT aliquot, so the aggregation by `vat_afip_code` nets the group to zero. However, floating-point accumulation in the aggregated tax details leaves a tiny residual (~1e-12) in `base_amount_currency` / `tax_amount_currency`. The filter condition checks the **raw unrounded** values:
```python
if grouping_key['vat_afip_code'] not in (False, '0', '1', '2') and (values['base_amount_currency'] or values['tax_amount_currency']):
```
The ~1e-12 residual is truthy in Python, so the aliquot entry is kept — even though both `BaseImp` and `Importe` are rounded to `0.00` two lines below when building the entry. The WSFE request therefore carries a non-null `Iva` block with all-zero amounts, which ARCA rejects with error 10018.
## Fix
Round `BaseImp` and `Importe` to 2 decimals **before** evaluating the filter condition, so an aliquot whose amounts cancel out is excluded from the `Iva` array (the same rounded values are then reused when building the entry, keeping the sent amounts unchanged for every other case):
```python
base_imp = float_round(amount_sign * values['base_amount_currency'], precision_digits=2)
importe = float_round(amount_sign * values['tax_amount_currency'], precision_digits=2)
if grouping_key['vat_afip_code'] not in (False, '0', '1', '2') and (base_imp or importe):
```
Behavior is unchanged for every invoice whose aliquots round to a non-zero base or tax amount.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#286005Vehicle imports now better understand the expected brand/model format when creating vehicle model records. This helps manually created fleet vehicles import more reliably and reduces avoidable errors during data migration or updates.
Original PR description
The name has a specific format `<brand>/<model>`, hence the fix overwrites the `name_create` function called when the import tries to create new model records, so that the name passed to that function can be correctly interpreted. Errors will occur for vehicles from the demo data (because of their external ID) but should work for any vehicle created manually. task-6578351
Fixes an issue where editing certain Kanban cards in Odoo Studio, such as Project tasks, could fail when adding or removing fields. This lets users customize those views reliably without save errors, while leaving other views unchanged.
Original PR description
Issue: Editing the Project task Kanban with Studio fails with an "element cannot be located in parent view" error. This affects Kanban views whose card architecture is provided through `card_id`.…
Issue: Editing the Project task Kanban with Studio fails with an "element cannot be located in parent view" error. This affects Kanban views whose card architecture is provided through `card_id`. Adding or removing a field produces an XPath targeting the inlined `<card>`, but that node cannot be found when the Studio customization is saved. Steps to reproduce: * Open Project > Tasks > My Tasks in Kanban view. * Open Studio. * Add or remove a field from the card. Cause: The client receives a postprocessed Kanban architecture in which the view referenced by `card_id` has already been appended as a `<card>` node: https://github.com/odoo/odoo/blob/1aa1f1967c7b9c8fd2c941fbc0c7b4c563698e46/odoo/addons/base/models/ir_ui_view.py#L3138-L3140 Studio therefore generates paths containing `/kanban/card`. However, Studio normalization applies those paths to the pre-postprocessed architecture, which still contains only the `card_id` attribute: https://github.com/odoo/enterprise/blob/42aa8fafdef159476d708f91467cba6f7fb2c6d3/web_studio/models/ir_ui_view.py#L667-L671 As `<card>` does not exist in that source tree, the inheritance engine cannot locate the target. Solution: We need to inline the referenced card before applying or normalizing Studio customization specifications. This makes Studio operate on the same architecture shape that was presented to the client. The `card_id` attribute is then removed from that temporary source to prevent regular post processing from appending the card a second time. The behavior is limited to Studio customization views and is a no op for Kanban views without `card_id`, preserving the existing inheritance flow for other views. opw-6445398 Forward-Port-Of: odoo/enterprise#127393
This change restores the previous way Mexican electronic payment complements calculate amounts, following updated guidance from the certification provider after consultation with the government. It helps reduce compliance and validation issues by using the maximum allowed decimal precision for payment amounts.
Original PR description
Quadrum reverted their changes because > Derived from a consultation with the government we reverted to our previous behavior, we recommend using the maximum number of decimals allowed Reverts commit https://github.com/odoo-dev/enterprise/commit/f13d204dacf9eae98c78de26e9f2e54387a0eaee as well opw-6561617 Forward-Port-Of: odoo/enterprise#131640 Forward-Port-Of: odoo/enterprise#131581
Fixes a VoIP call flow editor issue that prevented users from moving an existing connection to a new destination. This helps teams update call routing flows without losing connectors or being blocked by connection limits.
Original PR description
An output port that already has a connection couldn't be rewired to a new target: grabbing it looked for another output port instead of an input port, so the old connector was removed and never replaced. Dropping a new connection onto an output port that was already at its connection limit was rejected outright instead of replacing the existing connection.
This fix makes Belgian payroll time off allocations more consistent and accurate, especially when employees have multiple contract changes or working schedule updates. It also improves the schedule change process and adds clearer explanations in the interface so payroll teams can better understand allocation values.
Original PR description
Time off allocation fixes:
- Fixed rounding of time off allocations: some parts of the code rounded to full days, while others rounded to half-days.
- Fixed the calculation of time off from holiday attestations, which was done differently in different parts of the code.
- Fixed allocation calculations for employees with multiple contract versions, ensuring that each version is only taken into account for its actual effective period.
- Fixed the Working Schedule Change wizard:
-- allocations were not found when the work entry types had the same code but different records (generic vs. Belgian);
-- the calculated allocation was not correctly displayed in the wizard;
-- fixed the allocation update for working schedule changes starting in the future.
- Added a tooltip to explain the time off allocation values in the UI.
task: 6452166This update fixes cases where some screens could behave as if the user was not on a small device, which could affect mobile layouts in areas like accounting, imports, mail, and navigation. It also adds safeguards so outdated internal references fail visibly during testing instead of causing quiet display issues later.
Original PR description
Removes depracated `env.isSmall` and `env.debug` and make it throw if used (to prevent forward port mistakes) Enterprise PR: https://github.com/odoo/enterprise/pull/130698
EU OSS sales are now reported correctly in French PDP Flow 10 by excluding destination-country VAT from French VAT rate checks. This keeps the invoice and accounting VAT intact while reporting the taxable amount in the appropriate non-French VAT category, reducing reporting rejections.
Original PR description
OSS sales are taxed in the customer's Member State but are not subject to French VAT. They must therefore be reported under TNT1, while the Flow 10 Schematron only accepts French VAT rates. Identify taxes generated for the EU OSS scheme through their OSS tag. Keep the destination VAT on the invoice and in accounting, but report the taxable base under TNT1 with a zero tax rate and amount. Continue rejecting unsupported rates for regular taxes and invalid OSS rates. no task id Forward-Port-Of: odoo/odoo#288013
This update fixes screens and menus that could show the wrong layout on phones or hide certain options because they were checking outdated system values. It improves reliability for mobile users and restores expected menu behavior in apps such as Accounting, Documents, Appointments, Spreadsheets, ESG, and Time Off.
Original PR description
Removes depracated `env.isSmall` and `env.debug` and make it throw if used (to prevent forward port mistakes) Community PR: https://github.com/odoo/odoo/pull/287002
Belgian payroll now applies the correct train pass reimbursement rate for employees under Joint Committee 302 from February 2026. This prevents employees from being under-reimbursed because the sector table values already include the legally required calculation.
Original PR description
Previously, the system was applying an additional 80% reduction ratio on top of the CP 302 train allowance values. However, the rates listed in the official CP 302 sectoral table already incorporate the legally applicable 71.8% calculation. Applying an extra 80% factor resulted in an under-reimbursement of train transport costs for employees under Joint Committee 302. **What:** - Added the missing rule parameter value record _`rule_parameter_cp302_train_reimbursement_ratio_2026`_ setting the ratio factor to 1 (100%) effective from February 1, 2026. task-6532036 Forward-Port-Of: odoo/enterprise#131583 Forward-Port-Of: odoo/enterprise#130291
This fix prevents users from opening additional shop floor menu dialogs while a manufacturing order is already loading. It avoids an error that could appear on slower connections, making shop floor navigation more reliable for manufacturing users.
Original PR description
**Steps to reproduce:** * Install the **Manufacturing** module with **Work Orders** enabled. * Create and confirm a Manufacturing Order with at least one Work Order. * Open the **Shop Floor** view. *…
**Steps to reproduce:** * Install the **Manufacturing** module with **Work Orders** enabled. * Create and confirm a Manufacturing Order with at least one Work Order. * Open the **Shop Floor** view. * On a work order card, click the **gear** icon to open the menu dialog. * Click **Open Manufacturing Order** on a slow network connection. * Before the MO form view finishes loading, quickly click the **gear** icon again and open another dialog (e.g. Log Note). * The MO form view loads, destroying the shop floor component. * Close the Log Note dialog. **Observed behavior:** * An `UncaughtPromiseError: Component is destroyed` error is thrown because the dialog tries to interact with the shop floor component that has already been destroyed by the navigation to the MO form view. **Cause:** * When the user clicks "Open Manufacturing Order", `doAction` is called to navigate to the MO form view, and `props.close()` immediately closes the menu dialog. However, the shop floor component is still visible while the new view is loading. * During this gap, the gear button remains clickable. If the user opens another dialog (e.g. Log Note), that dialog holds a reference to the shop floor component. When the MO form view finishes mounting, the shop floor is destroyed, and closing the stale dialog triggers operations on the destroyed component. **Fix:** * Add an `actionPending` state flag to `MrpDisplayRecord`. When the user selects "Open Manufacturing Order" from the menu dialog, an `onSelect` callback sets `actionPending` to `true`, which disables the gear button and prevents any new dialog from being opened. * The flag is only set for `openMO` (which navigates away and destroys the component), not for other menu actions like Scrap, Add Component, or Log Note which open wizard dialogs and return to the shop floor. opw-6107579 Forward-Port-Of: odoo/enterprise#131538 Forward-Port-Of: odoo/enterprise#123490
This fix ensures rental orders keep track of serial numbers when pickups and returns are handled through stock transfers. It prevents the return wizard from opening without available serial numbers after a partial return, allowing staff to complete subsequent rental returns reliably.
Original PR description
**Issue** When rental transfers are enabled and rental pickups/returns are processed through stock pickings, it may become impossible to perform a subsequent rental return through the rental return…
**Issue** When rental transfers are enabled and rental pickups/returns are processed through stock pickings, it may become impossible to perform a subsequent rental return through the rental return wizard. **Steps to reproduce** - Activate "Rental Transfers" in the settings - Create a rental product P, tracked by serial number - Create two serial numbers for P - Create and confirm a rental order for 2 units of P - Validate the pickup transfer - Partially validate the return transfer without creating a backorder - Open the rental order and click on "Return" -> The return wizard opens without any available serial number and validation fails with a serial number-related error. **Cause** When clicking on "Return", if there is no pending pickup/return transfer: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/models/sale_order.py#L62-L68 the rental return wizard is opened directly: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/models/sale_order.py#L316 No serial number is prefilled in the wizard because `returned_lot_ids` is empty: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L122-L124 This is because `returnable_lot_ids` is empty as well. `returnable_lot_ids` is computed while generating the wizard lines: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/wizard/rental_processing.py#L38 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_renting/wizard/rental_processing.py#L47-L48 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L99-L106 and `returnable_lots` is empty because both `pickedup_lots` and `returned_lots` are. Those fields are currently only populated through the rental wizard flow: https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L42-L43 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L160-L161 https://github.com/odoo/enterprise/blob/d1ba2417affb81c4351ab9f86bc0a6ad5ceb8caf/sale_stock_renting/wizard/rental_processing.py#L166-L167 Since this flow uses stock pickings instead of the rental wizard, those fields are never updated, preventing the wizard from determining any returnable serial number. opw-6150305 Forward-Port-Of: odoo/enterprise#127590 Forward-Port-Of: odoo/enterprise#119257
Belgian payroll now correctly handles the Special Social Contribution when generating a 13th month payslip. If there is no regular monthly payslip for the same period, the contribution is set to zero, helping avoid incorrect payroll deductions.
Original PR description
When we generate a 13th month payslip, we need to check if there is a monthly pay payslip in the same period. If not, the Special Social Contribution will be 0. task-6512347
Italian point-of-sale refunds can now be processed from a different trusted POS without receipt printing failures. The system keeps the original printer details with the order, so refund receipts use the correct fiscal printer information.
Original PR description
Steps to reproduce: - Set up two POS configurations and add each to "Trusted POS"; - Connect a different fiscal printer to each POS configuration; - Process an order on POS A; - Refund that order on POS B. **Issue**: The refund receipt fails to print. The system currently transmits the serial number of the active POS configuration's printer instead of the printer that processed the original order. As a result, POS B's printer receives its own serial number alongside order identifiers that do not exist in its local fiscal memory. **Solution**: Store the processing printer's serial number directly on the `pos_order model` to ensure the correct serial number is transmitted during cross-POS refunds. [opw-6499079](https://www.odoo.com/odoo/project/49/tasks/6499079)
Rounded point-of-sale payments are now recorded correctly even when the stock app is not installed. This prevents accounting imbalances when closing PoS sessions, reducing disruption for retailers using cash rounding.
Original PR description
Before this commit: = - The rounding move line creation was moved from point_of_sale to pos_stock while removing the dependency of stock on point_of_sale. - As a result, when pos_stock was not installed, no rounding move lines were created for rounded PoS payments, leading to unbalanced journal entries during session closing. After this commit: = - Restored the rounding move line creation in point_of_sale so that rounded payments are correctly handled. task-6214240 runbot-error-242920 Forward-Port-Of: odoo/odoo#264288
AI agents now manage their URL-based attachments more reliably, so each agent keeps the right linked content separate from others. This helps prevent mix-ups between agents and supports smoother background processing of URL content.
Original PR description
Many2one URL attachments' fixes to ensure each agent has its own URL attachments.
Point of Sale now avoids errors when opening a session if the browser has old cached data for models that were renamed or removed. This helps users resume POS work without needing a manual data reload after module changes or upgrades.
Original PR description
In PR-#[225341](https://github.com/odoo/odoo/pull/225341) we started passing all the models which are cached on the front end directly to the back end, but if the database existed before and the front end cached models which no longer exist, either because the model name changes (such as pos.product.template.snooze -> pos.snooze), or because a module was uninstalled (removing pos_restaurant_appointment), the front end would ask the back end for models which no longer exist, and that would error. When we do the reload data, all the local cache would be deleted and then we could launch the POS. To fix it, now the back end will check whether the model exists before trying to filter on it, and just ignore it if it doesn't exist Task-[6562705](https://www.odoo.com/odoo/project/1737/tasks/6562705) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Inter-company purchase receipts are no longer marked as already picked when they are created from a confirmed sales order. This lets warehouse teams process the receipt normally in the Barcode app and avoids confusion or skipped handling steps.
Original PR description
Issue ----- When confirming a SO, the corresponding PO picking should not have its' MLs set as `picked` to allow treating the transfer in the barcode app. Steps to reproduce ----- - Create 2 companies A & B - Settings > Inter-Company Transactions - Create Purchase Orders - Set the created PO to be "Validated" by default - Create a SO from company A to B - Validate the OUT picking in company A - Open the PO in company B - Go to its' picking and open it in barcode > The line is already picked ----- Ticket: opw-6481828 Forward-Port-Of: odoo/enterprise#131391
New Singapore companies will now be created with the correct accounting configuration for inventory purchases. This ensures price differences between product cost and purchase price are posted to the expected account, improving the accuracy of vendor bills and stock valuation.
Original PR description
Singaporean companies didn't have the anglo saxon accounting enabled. Price difference account was then not hit when buying a product with a different price than the one in the product page. Steps to reproduce: ------------------- * Create a product P * Set the costing method to "Standard Price" and the inventory valuation to "Perpetual (automated)" * Make sure a price difference account is set in the product category * Create a RFQ for P and set a different price than the one in the product page * Confirm the RFQ and receive the product * Create a vendor bill for the RFQ and validate it > Observation: If you check the lines in the bill there is no price difference account hit. Why the fix: ------------ We set anglo saxon accounting to True so that all new companies have the correct setup. opw-6525817 Forward-Port-Of: odoo/odoo#288261