Daily updates from Odoo
Tuesday, August 4, 2026
10 changes · 19.0
Enhancements to existing features
Large SEPA direct debit batches now validate faster by reducing repeated data processing and lookups. This helps businesses process hundreds or thousands of payments more reliably, with shorter waiting times and fewer timeout risks.
Original PR description
- Replace the `id:recordset` aggregation in `_get_expiry_date_per_mandate()` with `date:max` to compute the latest payment date directly in SQL. - Render `email_from` for all payments in batch and cache the computed authors by sender email to avoid repeated partner lookups during SDD pre-notification. This reduces ORM/cache overhead when validating large SEPA batches containing thousands of payments. Measured on a production-sized database: | metric | before | after | factor | |--------|-------:|------:|-------:| | `_get_expiry_date_per_mandate` (500 payments) | 564 ms | 111 ms | ~5x | | `_send_after_validation` notification (500 payments) | 92.9 s | 55.7 s | ~1.7x | | `_get_expiry_date_per_mandate` (1000 payments) | 890 ms | 178 ms | ~5x | | `_send_after_validation` notification (1000 payments) | timed out (>159 s) | 108.9 s | completed | OPW-6377340 Forward-Port-Of: odoo/enterprise#126429 Forward-Port-Of: odoo/enterprise#125439
Resolved issues and error corrections
Fixes an issue where rental returns could fail after items were picked up or returned through stock transfers instead of the rental wizard. The system now keeps the serial number history needed to offer the correct items for return, reducing blocked rental workflows.
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
Cancelled Mexican CFDI invoices can now be reprinted with their required fiscal information, including QR codes, digital stamps, and fiscal folio details. This ensures businesses retain compliant proof that an invoice was issued and later cancelled.
Original PR description
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR…
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR code, digital stamps, fiscal folio/UUID, etc.), even though the signed CFDI attachment is still present on the invoice. ### Steps to reproduce the issue: 1. Download Accounting and l10n_mx 2. Create an invoice and send it to CFDI 3. Select 'Request for cancel' 4. Wait and click retry button in the CFDI tab until the invoice is marked as cancelled 5. Print the invoice again 6. See PDF does not show fiscal information (QR, fiscal folio, etc.) ### Cause of the issue: https://github.com/odoo/enterprise/blob/f6c94d4ca3ef4211a5ab00bf0b39f6a7675c8f79/l10n_mx_edi/models/account_move.py#L904-L909 Once the CFDI is cancelled, the computed field switches to 'cancel', so the condition fails and the method falls back to the generic account.report_invoice_document template, which has no knowledge of CFDI fiscal fields. ### Reason to introduce the fix: A cancelled CFDI invoice is still a legally relevant fiscal document in Mexico and must be reprintable with its fiscal data intact (to prove it was issued and later cancelled). The fix extends the condition to also cover the 'cancel' state, ensuring the CFDI-specific report template is used whenever a valid attachment exists, regardless of whether the CFDI is currently signed or cancelled. opw-6393656
The pivot field popup now hides date and datetime fields once all available time options have already been added. This prevents duplicate entries and avoids confusing drag-and-drop behavior for spreadsheet pivot users.
Original PR description
Current behavior before PR: - Date and datetime fields remained visible even when all their granularities were already added to the pivot. - Users could add the same field with the same granularity multiple times, creating duplicate IDs and causing unexpected drag and drop behavior. Desired behavior after PR is merged: - Hide date and datetime fields from the popup once all available granularities have already been added to the pivot. - This prevents duplicate field IDs and keeps the popup behavior consistent with spreadsheet pivots during drag-and-drop. Task: [6295794](https://www.odoo.com/odoo/project/2328/tasks/6295794)
User-facing messages and warnings now show translated selection field labels instead of untranslated internal text. This improves clarity for users working in languages other than English across accounting, payroll, recruitment, appointments, IoT, and localization features.
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed.
Quotations created from helpdesk repair orders now correctly use the salesperson assigned to the customer. This prevents missing sales ownership on follow-up quotes, helping teams keep accountability and reporting accurate.
Original PR description
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to…
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to Reproduce:** - Install `helpdesk_repair`. - Go to `Helpdesk` > `Configuration` > `Helpdesk Teams`. - Open a team recod and enable `Repairs`. - Create a `contact/customer` with a `salesperson` assigned. - Go to `Helpdesk`, create a ticket for that `customer`, and select the `helpdesk team` configured above. - Click `Repair`, then click `Create Quotation`. - Open the quotation and check the `Salesperson` field in the `Other Info` tab. **Current behavior:** The Salesperson field on the quotation remains empty. **Expected behavior:** The Salesperson field on the quotation should inherit the salesperson assigned to the selected customer/contact. **Cause of the issue:** When a repair order is created from a helpdesk ticket, default_user_id [1] is passed in the context . This value is propagated when creating the repair order [2] . Later, when creating the quotation from the repair order [3], the same context is reused. Because default_user_id is already present in the context, it overrides the precomputation of user_id from the customer. As a result, user_id is initialized with an empty value and remains unset. **Fix:** This commit ensures that default_user_id is removed from the context before creating the sale order. Without a default value for user_id, the field is correctly precomputed from the selected customer, and the salesperson is properly assigned. [1]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L52 [2]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L36-L40 [3]: https://github.com/odoo/odoo/blob/29328b8fccff833c14de317b51f3b4e5a8c40f75/addons/repair/models/repair.py#L357 opw-6344939 Forward-Port-Of: odoo/enterprise#126310 Forward-Port-Of: odoo/enterprise#122980
Fixed an issue in the Barcode app where two delivery lines could appear selected at the same time when an operation mixed packaged and unpackaged products. This helps warehouse users avoid confusion and process deliveries more reliably when moving entire packages.
Original PR description
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty…
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty of 1 - Make a delivery that has both of those products, requested qty of 1 for both - Mark it as todo - Go to the barcode app, select the delivery - Select the line with product B - Select the line with product A --> The line with product B is not unselected **Why the fix:** When we have a mix of packaged products and products without a package on the same operation, they are handled separately. The products without a package are handled in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L388-L392 that calls https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1277-L1284 But as you can see, there are no mention of the selected package line, which is stored in **this.lastScanned.packageId**. As we do not touch this variable, the selected package line stays selected. The same is true for the other way around, when we select a package line we call https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L394-L398 This function does not care for the **selectedLineVirtualId** which represents the selected line without a package. To avoid this and make it so that only one line is selected even if they have different package, we now set the corresponding value to false to unselect the other line in all situation. This is basically how it's done in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1202-L1208 to unselect every line regardless of packages. opw-6266203 Forward-Port-Of: odoo/enterprise#125356 Forward-Port-Of: odoo/enterprise#122038
Opening bank reconciliation directly from a saved URL now behaves the same as opening it from the Accounting dashboard. Automatic matching runs as expected, and upload options stay hidden for journals connected to online bank synchronization.
Original PR description
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized…
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized journals ### Cause: `_action_open_bank_reconciliation_widget` injects two context keys: - `auto_statement_processing`: triggers auto-reconciliation on statement creation - `bank_statements_source`: hides the upload button for synchronized journals When the view is accessed directly, these keys are not present, causing the UI to ignore them `auto_statement_processing` is now set directly in the user context via `onWillRender`/`onWillDestroy` in `BankRecKanbanController` `bank_statements_source` requires an ORM call to fetch the journal's value and is resolved via `fetchBankStatementsSourceInto` on startup Notes: The fix for `bank_statements_source` was added opportunistically while addressing `auto_statement_processing` Steps to reproduce: - Install `accountant` with demo data - Duplicate the Bank Journal and set Bank Feeds to Online Synchronization - Open the Accounting Dashboard and open the Bank (copy) - Create a transaction (Label: Test, any amount) and click Add & Close - In the 3 dots menu, choose Manage Models - Create a Reconciliation Model (Label contains: Test, Lines: any account, default values) - Click Automate - Go back to the Bank Reconciliation page and verify: -- The transaction is reconciled automatically -- No Upload button is displayed - Create a new transaction, it should be reconciled automatically - Copy the URL and open it in a new tab - Create a new transaction Before the fix, the transaction is not reconciled and the Upload button is present opw-6391107
Employee unavailable time is now calculated consistently across Attendance and Time Off planning views. Days outside an employee contract, including employees without contracts, are clearly shown as unavailable, while flexible schedules are handled more accurately.
Original PR description
…ty of employees purpose: 1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out…
…ty of employees
purpose:
1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days, flexible and fully flexibe employees. 2- In time off calendar view, if the employee does not have a contract at all, the current working schedule will appear in the calendar and it will not be greyed out. This is inconsistent with the behavior of the attendance application.
Fix:
1:
- implemented `_get_employee_unavailable_intervals` in employee model to be used in both time off and attendance.
- more optimized than the old implementation in time off as it calls `_work_intervals_batch` once per calendar instead of calling it for each contract in `_unavailable_intervals_batch`
- greys out "out of contract" periods
- for flexible and fully flexible employees, the whole period is considered available except leave periods
- made `_get_calendar_periods` use version date start instead of contract date start and corrected a bug in tz conversion 2:
- made `_get_unusual_days` return True for all the days outside of contracts for the employee instead of not returning anything for them or getting values from the working schedule of the employee (means that they will be greyed out in the callendar view) and added a test for it
task-id: 5473055Customer balances in Point of Sale now show the correct Total Due when the company currency differs from the PoS currency. This prevents Pay Later amounts from being converted twice, so staff see the expected customer debt amount.
Original PR description
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any…
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any outstanding balance - open the PoS, create an order of USD 100 and validate it with the Customer Account (Pay Later) payment method - open the Customers screen and look at the Total Due of that customer Issue: The Total Due shows about USD 55.56, i.e. the amount converted once too many, instead of the expected USD 100. Cause: get_total_due() sums two amounts that are not expressed in the same currency before converting them. partner.total_due comes from the accounting entries, it is the sum of account.move.line.amount_residual and is therefore in company currency, while total_settled is the sum of pos.payment.amount of the still open sessions, which is in the currency of the order, so the PoS one. The addition is done first and the result is then converted from the company currency to the PoS one, so the pay later payments end up converted a second time. opw-6403320 Forward-Port-Of: odoo/enterprise#126290 Forward-Port-Of: odoo/enterprise#125798