Daily updates from Odoo
Tuesday, July 14, 2026
11 changes · 18.0
Enhancements to existing features
The Peru e-invoicing localization now includes and activates product classification codes required by SUNAT's upcoming 2026 validation rules. This helps Peruvian companies avoid rejected e-invoices for affected goods while keeping Peru-specific codes limited to databases using the Peru localization.
Original PR description
SUNAT is updating its validation rules 2026-08-01, adding three mandatory annexes (25.1, 25.2, 25.3) to Product Catalog N25. E-invoices for these goods are rejected when the required UNSPSC code is not available in the database. Most of the required codes already exist and are active. The rest are handled here: two missing UNSPSC codes were added to the shared catalog, while the fourteen codes that exist but are inactive and the SUNAT-only code 11111111 (which is not part of the UNSPSC standard) are activated from the Peru localization instead. Doing the Peru-specific part in the l10n_pe_edi install hook and upgrade script, the way l10n_mx_edi and l10n_ke_edi_oscu do for their own codes, keeps these activations out of databases that do not use the Peruvian localization. Task-6366907 Forward-Port-Of: odoo/enterprise#123577
Resolved issues and error corrections
Vendor bill tax amounts entered manually are no longer overwritten when AvaTax is configured. This ensures accounting teams can make necessary tax adjustments and confirm bills without losing their changes.
Original PR description
Currently, when an user manually modify the tax amount, the system automatically resets it based on the configured tax percentage. Steps to reproduce: - Setup up Avatax - Create a Vendor Bill to an US partner - Add a line with tax - Click on the pencil icon and edit the tax amount - Save and Confirm Issue: Tax amount will revert to the original amount Analysis: It occurs because we set is_tax_computed_externally to True for all moves with an AvaTax fiscal position, including vendor bills. This triggers the reset of tax totals values to the original values, partially overriding the user change. opw-6312346
Barcode scanning in inventory now handles cases where a user starts editing a picking while a scan is still being processed, such as on a slow connection. This prevents a crash and ensures the scanned line is still assigned to the current user as expected.
Original PR description
…e when component is dead In the barcode client action, scan a barcode that matches a stock_picking_line that doesn't belong to you On a slow network and during the processing of the barcode, click on the pencil to modify the picking. Before this commit, there was a crash After this commit, there is no crash, and we commit all the time the fact that the line now belongs to the user. runbot-error-190608
Swiss QR-IBAN payment references are now cleaned before payment files are generated. This prevents unsupported characters from causing ISO 20022 files to be rejected by Swiss banks.
Original PR description
**Steps to reproduce:** * Configure a Swiss company with the Swiss accounting localization. * Install `account_sepa`. * Configure a bank journal with a valid Swiss **QR-IBAN**. * Create a vendor with…
**Steps to reproduce:** * Configure a Swiss company with the Swiss accounting localization. * Install `account_sepa`. * Configure a bank journal with a valid Swiss **QR-IBAN**. * Create a vendor with a valid Swiss bank account. * Under **Accounting -> Configuration -> Settings** enable QR Payments. * Go to the vendor and enter the correct QR-IBAN number under the Accounting Section. * Navigate to **Accounting -> Configuration -> Journals** and in the **bank** journal, add the account number of QR-IBAN. * Create and post a vendor payment using the bank journal. * Set the payment reference (`ref`) to contain the `°` character. * Add the payment to a batch payment and generate the ISO 20022 payment file. * Inspect the generated XML. **Observed Behaviour:** The `°` character is preserved in the payment reference for QR-IBAN payments, producing an ISO 20022 file that may be rejected by Swiss banks because it does not comply with the EPC minimum character set. **Cause:** The QR-IBAN branch validates the structured reference before sanitizing it, allowing unsupported characters to remain in the generated XML. **Fix:** Sanitize the payment reference before validating it as a QR structured reference, ensuring invalid characters are removed while preserving valid QR references. opw - 6350931 Forward-Port-Of: odoo/enterprise#123267
This update resolves two issues impacting the web push subscription process. Specifically, it corrects a logic error in how device ownership is checked and ensures the correct key is used when sending subscription information to the server, preventing duplicate device creation. This enhances the overall reliability of the web push functionality.
Original PR description
This fixes two bugs in the web push subscription flow:
- register_devices() compared partner records with 'is not' instead of '!='. Records loaded via sudo() live in a different environment than self.env.user, so 'is not' was always True and the ownership guard never behaved as intended. Use '!=', which compares record identity by model and id as Odoo's ORM intends.
- webclient.js sent the previous subscription endpoint under the snake_case key 'previous_endpoint', while the server reads it as 'previousEndpoint' (kw.get('previousEndpoint', endpoint)). The mismatch meant the lookup always fell back to the new endpoint, so a refreshed subscription created a duplicate device instead of updating the existing one. Send the camelCase key to match the server.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update ensures notification sounds play correctly on touch devices (smartphones, tablets, and laptops with touchscreens) by utilizing the device's native push notification system instead of the browser's audio channel. This resolves an issue where notifications were unexpectedly playing through the device's speaker even when the device was muted.
Original PR description
On touch devices (smartphones, tablets), the in-browser notification sound plays through the media audio channel, which is not affected by the device's silent mode. This causes unexpected sound playback when the device is set to silent. Suppress _playSound() on devices with maxTouchPoints > 1 (touch/mobile). Push notifications handle alerts on mobile and properly respect the device's silent mode. The side effect is that also laptops with touch screen are affected and need to use web push notifications in order to get notification sounds played. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where a sale order item remained linked to a timesheet after switching to a non-billable project. The fix ensures that the 'is_so_line_edited' field is reset, preventing incorrect item associations and improving data accuracy within the timesheet reporting.
Original PR description
## Steps to reproduce: - Install sale_timesheet - Create a timesheet with a Sale order item linked to it - Change the sale order item on that timesheet - Change the project linked to the timesheet to a non-billable project - Notice the sale order item still linked to the timesheet ## Cause: When computing the so_line we filter out the records that has is_so_line_edited as true, so when changing the SOL before changing the project we don't reset so_line field when setting a non-billable project. ## Fix: We reset the is_so_line_edited field to false when changing the project to a non-billable one. opw-6311549
This update fixes a potential issue where the cloud storage migration process could delete attachments used in core business operations, such as invoice stamping. The fix now filters out attachments linked to specific models, ensuring these important files remain accessible within Odoo.
Original PR description
**PROBLEM** `_cron_migrate_local_to_cloud_storage()` is used to migrate attachment to a cloud storage. It delete the attachment from the database, rendering it innacessible from the server-side. The…
**PROBLEM** `_cron_migrate_local_to_cloud_storage()` is used to migrate attachment to a cloud storage. It delete the attachment from the database, rendering it innacessible from the server-side. The problem is it can delete attachment used in business logic. **STEP TO REPRODUCE** 1. Install and configure cloud_storage + a provider (e.g. cloud_storage_google) and cloud_storage_migration. 2. Install l10n_mx_edi and stamp a customer invoice. The CFDI XML is stored as an ir.attachment that: - is referenced by a business Many2one l10n_mx_edi.document.attachment_id (copied into account.move.l10n_mx_edi_cfdi_attachment_id), - has res_field = NULL (record attachment, not a field binary), - is posted to the chatter → it has a row in message_attachment_rel. 3. Add account.move to cloud_storage_migration_message_models and set a low enough cloud_storage_min_file_size. 4. Run the cron _cron_migrate_local_to_cloud_storage. 5. Open the invoice and trigger any recompute of the EDI chain (e.g. Update Payments, a reconciliation, or re-stamping). **FIX** Filters out attachment linked to a model listed by the already existing function `_get_cloud_storage_unsupported_models()` opw-6347198
This update resolves an issue where Odoo incorrectly identified valid invoices with negative tax amounts as credit notes during import. By updating the import logic to use TaxInclusiveAmount (UBL) and GrandTotalAmount (Factur-X), the system now accurately determines invoice status, preventing misclassification.
Original PR description
Before this commit: - When importing a **UBL** or **Factur-X (CII)** invoice, Odoo determines whether the document should be imported as an invoice or a credit note based on the `TaxExclusiveAmount…
Before this commit: - When importing a **UBL** or **Factur-X (CII)** invoice, Odoo determines whether the document should be imported as an invoice or a credit note based on the `TaxExclusiveAmount (UBL)` /` TaxBasisTotalAmount (Factur-X)`. - In some rare cases, a valid invoice can contain a negative `TaxExclusiveAmount` / `TaxBasisTotalAmount` while still having a positive `TaxInclusiveAmount` / `GrandTotalAmount`. - In such situations, Odoo incorrectly imports the document as a credit note. Technical reason: - The method `_get_import_document_amount_sign()` uses `TaxExclusiveAmount` / `TaxBasisTotalAmount `to determine whether the imported document is an invoice or a refund. After this commit: - **UBL** now uses `TaxInclusiveAmount` instead of `TaxExclusiveAmount`, and **Factur-X** now uses `GrandTotalAmount `instead of `TaxBasisTotalAmount` to determine whether the document should be imported as an invoice or a credit note. - Prevent valid invoices with negative `TaxExclusiveAmount` / `TaxBasisTotalAmount` from being incorrectly converted into credit notes. Task-6321262 Forward-Port-Of: odoo/odoo#271829
This update corrects a visual issue in the resource scheduling module where flexible working hours caused unpredictable weekend days on timesheets and calendars. By restoring a weekly Monday anchor, the system now consistently displays standard workdays (Monday-Friday) on these views, ensuring accurate scheduling and reporting.
Original PR description
### Description of the issue/feature this PR addresses: This PR fixes an issue in the `resource` module where flexible working hours cause unpredictable and shifting non-working (greyed-out) days on…
### Description of the issue/feature this PR addresses: This PR fixes an issue in the `resource` module where flexible working hours cause unpredictable and shifting non-working (greyed-out) days on the Timesheets and Calendar views. It restores the weekly Monday anchor for flexible hour calculations while safely preserving a prior fix for partial-day work entries on public holidays. ### Current behavior before PR: In `_attendance_intervals_batch`, the calculation for flexible schedules sets `current_start_day = start_date`. Because `start_date` is often passed as the first day of the month or a requested period (which can fall on any day of the week), the 7-day calculation cycle becomes unanchored. Odoo blindly allocates 8 hours to the first 5 days of this arbitrary period and leaves the 6th and 7th days empty. This results in the visual "weekend" shifting randomly month-to-month (e.g., greying out Wednesdays and Thursdays instead of Saturdays and Sundays). ### Desired behavior after PR is merged: The `current_start_day` is correctly anchored back to Monday using `start_date - timedelta(days=start_date.weekday())`. This ensures the 5-day allocation always consistently spans Monday through Friday, keeping Saturday and Sunday as the standard non-working days on the UI grids. Furthermore, because the `min()` clamp on `remaining_hours` is retained, partial-day Work Entry generation (like a 2-hour gap on a Wednesday public holiday) continues to calculate correctly without attempting to over-allocate the remaining weekly hours. opw-6370301 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update corrects a bug in how overtime is calculated for employees with flexible work schedules. Specifically, it resolves a discrepancy in the week's starting day, leading to incorrect overtime calculations when tolerance time is adjusted. The fix ensures accurate overtime reporting for employees with varied working hours.
Original PR description
# How to reproduce - Set an employee's work schedule to flexible 40hrs/week with 8hrs of work per day - Create a new attendance for that employee that : - Is the very first attendance of that…
# How to reproduce - Set an employee's work schedule to flexible 40hrs/week with 8hrs of work per day - Create a new attendance for that employee that : - Is the very first attendance of that employee - Is not on a monday (e.g. a Friday) - Create a second attendance for that employee that : - Is atleast one week after the first attendance - Is one of the two days of the week before the day of the week of the first attendance (e.g. a Wednesday or a Thursday) - Go to the settings, update the value for "Tolerance Time In Favor Of Company" and save - Come back to the second attendance # The problem The Extra Hours have changed and are equal to the worked time # Cause When we update the tolerance time, we recompute the overtime of every attendance of every employee. In this recomputation, we compute the `expected_attendance` of every employee and transforms them into a dict of the expected working time for each day : https://github.com/odoo/odoo/blob/281658e86971687656f3235ac1ff8afcb52f2908/addons/hr_attendance/models/hr_attendance.py#L349-L356 Later, if an attendace of the employee was not in their expected working days, then we consider that all hours worked were overtime : https://github.com/odoo/odoo/blob/281658e86971687656f3235ac1ff8afcb52f2908/addons/hr_attendance/models/hr_attendance.py#L381-L384 This makes sense but our issue is that days in the middle of the week are considered "time-off" when they should not. That's because for flexible working schedules, we emulate the expected working hours based on the total hours per week and the maximum hours per day : https://github.com/odoo/odoo/blob/281658e86971687656f3235ac1ff8afcb52f2908/addons/resource/models/resource_calendar.py#L384-L386 For every "week", we start from the first day and continue forward by greedily using all hours for that day until there is no more hours for the week. The problem is that since this PR, we don't start "weeks" on mondays, but on the `start_datime` : https://github.com/odoo/odoo/commit/af36e73108cef4326f6125c3af491b07a51534fe And in our case, `start_datetime` is the very first attendance day of the employee : https://github.com/odoo/odoo/blob/281658e86971687656f3235ac1ff8afcb52f2908/addons/hr_attendance/models/hr_attendance.py#L344 So our expected working days are desynched with the days of the week # Proposed solution We partly revert https://github.com/odoo/odoo/commit/af36e73108cef4326f6125c3af491b07a51534fe opw-6289079