Daily updates from Odoo
Monday, April 20, 2026
131 changes
12 changes
Resolved issues and error corrections
This update prevents an error when incoming Chilean electronic invoices are processed without a specific LATAM purchase journal configured. It ensures the system selects a valid default journal so invoices can be created and recorded normally.
Original PR description
Currently, when receiving a DTE XML fetched by the fetchmail server, if there is no purchase journal with `l10n_latam_use_documents` enabled, an empty recordset (account.journal()) is set in the default context values. This prevents the proper computation of the field and raises an error, since the `journal_id` is mandatory on account moves. Steps to reproduce: - Ensure you have no purchase journal with `l10n_latam_use_documents` enabled - Simulate the reception of a DTE XML via the fetchmail server - Observe the error: "NotNullViolation: null value in column 'journal_id'" opw-5950116 opw-6111041 Forward-Port-Of: odoo/enterprise#112168
This change corrects how landed costs are calculated when a bill is entered in a different currency than the company’s currency. It prevents the amount from being overstated, so the landed cost now matches the intended purchase price and avoids incorrect inventory costing.
Original PR description
Issue introduced by commit daf196e365f481ffcc8b56664fa361fa9c9bbda9
Steps to reproduce:
- Enable two currencies (e.g., USD and EUR)
- Set exchange rate: 2 EUR = 1 USD
- Set current company currency to USD
- Create a service product "Landed Cost":
- Purchase tab:
- Mark as "Is a Landed Cost"
- Cost: $10
- Create a bill:
- Vendor: any vendor
- Currency: EUR
- Add 1 unit of "Landed Cost" → correctly shows 20 EUR
- Click the "Create Landed Cost" button
Expected behavior:
Landed cost should be calculated as $10
Actual behavior:
Landed cost is incorrectly calculated as $40, because the AML (Account Move Line) price subtotal is multiplied by the currency exchange rate (2) instead of dividing.
opw-6121706
opw-6121407
Opw-6124771
Opw-6123193
Forward-Port-Of: odoo/odoo#259632When users save certain website snippets as custom snippets, they will now appear both in the block list and in the inner content list when appropriate. This restores the expected behavior and makes reusable snippets easier to find and use while editing a website.
Original PR description
Steps to reproduce: 1. Go to Website > Edit mode. 2. Drag and drop a `Map` from `Inner Content` snippets. 3. Save it as a custom snippet. Current behavior: - The custom snippet is saved only as inner content and does not appear as a block in custom snippets. Expected behavior: - The snippet should be available both as a block and as inner content, consistent with behavior in `saas-18.3`. Issue: - Custom inner content snippets were systematically extracted from `snippet_custom`. As a result, snippets that can serve both purposes were only kept as inner content, preventing their usage as blocks. Solution: - Update the logic to: 1. Keep dual-purpose snippets in `snippet_custom` (block usage). 2. Also add them to `snippet_custom_content` (inner content usage). 3. Remove only inner-only snippets from the block category to avoid display issues. task-6064917 Forward-Port-Of: odoo/odoo#259588 Forward-Port-Of: odoo/odoo#256777
This change prevents database synchronization from failing with an error when the user no longer has access, when a new document arrives from a remote database, or when the remote database cannot be reached. Instead, the sync now finishes cleanly and correctly reflects any loss of access from the remote side.
Original PR description
The aim of this commit is to allow a db_user to synchronize a database without facing a Traceback. Context: - A new document has been received by a remote db and we try to synchronize it. - The current user access has been removed from the remote db. - The database is unreachable. Before this commit: In all 3 previous cases, an access error would be raised because a db_user can't write on a database. After this commit: The synchronization finish gracefully and the db_user should have lost his access if it was removed from the remote db. task-id: 6046087 Forward-Port-Of: odoo/enterprise#114129 Forward-Port-Of: odoo/enterprise#113826
This change updates the rules for creating asset entries so they depend on how an account is configured, not on whether it was used in older records. This prevents customers with legacy asset data from being blocked from creating new assets, and also keeps certain configured accounts out of the depreciation selection list.
Original PR description
This commit fixes the `can_create_asset` flag on accounts to limit the creation of asset based on if account is used as an accumulated depreciation on another account, instead of used by an asset. This requirement came after users with old assets couldn't create assets using some accounts because they were used by the old assets with no possible way to change that. Better to limit on configuration data instead of business data. Also now, accounts that have models set do not show up in the accumulated depreciation dropdown. no-task
This change prevents an employee holiday pay field from being read too early during payroll updates. As a result, the value is now calculated at the right time, which avoids incorrect payroll results and related test failures.
Original PR description
…ield The computed, non-stored field `l10n_be_holiday_pay_recovered_n1` had tracking enabled. When writing to any field on the employee, the `write` method calls `_track_prepare` for tracked fields if `mail_notrack` is not set in the context. `_track_prepare` reads the current value of tracked fields to store initial values. Because `l10n_be_holiday_pay_recovered_n1` is non-stored with no dependencies, this triggered a computation at the very beginning of the test, before payslips existed. Later, when payslips were created, the field was never recomputed, causing incorrect values and test failures. Previously, the `tracking_disable` context prevented early computation. The fix removes the tracking attribute entirely, so the field is only computed when accessed, avoiding premature reads and fixing the tests. task: 6095445 Forward-Port-Of: odoo/enterprise#114063 Forward-Port-Of: odoo/enterprise#113015
The Point of Sale session report now calculates discount amounts more accurately when fiscal positions change the taxes applied to an order. This ensures the report matches the real sales data and avoids incorrect discount figures in end-of-session summaries.
Original PR description
Steps: ---- - Create a fiscal position with 2 different taxes - Add a line in POS - Apply fiscal position and add line discount - Finish the order cycle - Download the session report Issue: ---- - The discount amount was calculated incorrectly in the session report Cause: ---- - The discount amount calculation used taxes before applying the fiscal position Fix: ---- - Used `tax_ids_after_fiscal_position` for tax calculation while computing the discount amount task-5421215 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#256704 Forward-Port-Of: odoo/odoo#244650
This change prevents discounts from being recalculated and cleared on optional sales lines when a portal customer updates the quantity. It helps preserve the expected pricing on quotes and avoids confusing changes for customers and sales teams.
Original PR description
Issue: --- Discount compute depends on `product_uom_qty`. On optional lines, this recompute will reset the discount on lines, when portal user updates the quanity. Cause: --- `discount` needs to depend on `product_uom_qty` because discount needs to be computed based on the quantity due to pricelist rules. Fix: --- We can prevent this compute if the quantity update comes from portal. opw-6078083 Forward-Port-Of: odoo/odoo#259696
This change fixes an issue where exporting account reports could fail when a fiscal year date was included. Users will now be able to export these reports without encountering a JSON processing error.
Original PR description
When calling export_file with a fiscal year set we pass a fiscal year into it. This function then calls json.dumps with the date object passed into it through a dictionary, which json.dumps cannot process and users experience an error. https://drive.google.com/file/d/1VBOIAxuzcXT5b5BBnLDqd6ibWqOPxe4P/view?usp=drive_link
The website editor now correctly treats buttons with size or shape classes as custom buttons. This prevents the wrong style from being shown in the button settings popover and keeps the editor behavior aligned with how those buttons are actually built.
Original PR description
Before this commit: Since the removal of button style options for the preset primary and secondary styling, the type of a primary/secondary button with size or shape defined in the class should be "custom". The fix is made to saas-18.4 cause the custom button option is removed in saas-18.3 and reintroduced only from saas-18.4. The button option removal commit: https://github.com/odoo/odoo/commit/a7b71d700e4997e4a2f646e2ae12f58f20058dc4 The button custom option reintroduction: https://github.com/odoo/odoo/commit/ea22b28bbae009c9eab4ff397affa9a3cb71037a After this commit: when the button has size or shape classes, we consider it as "custom" button. task-6061443 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#257410 Forward-Port-Of: odoo/odoo#256015
Users can now edit website profiles from mobile devices without encountering an error. This aligns the mobile experience with the desktop flow, so profile updates work consistently across devices.
Original PR description
# How to reproduce - Install the eLearning module - On the website, go to the Courses tab - View a user (Administrator for example) - In mobile view, click on Edit # The problem An traceback is shown and the user cannot edit their profile # Why This commit (https://github.com/odoo/odoo/commit/69785c1a64d61f2831804bcdcc4887ad43d27fbb) improved the profile edition. It is mentioned that they moved away from the simple bootstrap modal and used an OWL view instead. However, for the mobile view, they left a call to a modal that does not exist. This fix removes the call to the undefined modal and replaces it with the same OWL Dialog used in the desktop view (thanks to the .o_wprofile_editor class) opw-5960586 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#251503
This change prevents a rare error that could happen when Odoo reloads payment-related records after an internal cache refresh. It improves stability during payment registration and related accounting flows, so users are less likely to encounter interruptions when processing payments.
Original PR description
The issue originates from `_get_batches` in `account_payment_register`, where a prefetch collection is built using `OrderedSet`. After an ORM cache invalidation, accessing fields on the resulting records could raise an error because `with_prefetch()` expects the iterable of IDs to be reversible, which `OrderedSet` does not support. This commit implements `__reversed__` on it, making it compatible with `with_prefetch()` while preserving its intended behavior. A unit test is also added in `l10n_account_withholding_tax` to cover the prefetch traversal scenario. task-[6108453](https://www.odoo.com/odoo/project/967/tasks/6108453)
17 changes
Resolved issues and error corrections
This update corrects a problem with the message right-click menu so it behaves as expected again. It helps users quickly access message options without interruptions or unexpected behavior.
This fix allows Belgian companies to change their fiscal localization from Companies to Associations and Foundations without failing during the chart update. It removes hidden links to old accounting settings first, so the change completes successfully and existing cash rounding remains intact.
Original PR description
### Issue before this commit: Switching the fiscal localization of a Belgian company from "Companies" to "Associations and Foundations" caused a traceback during the chart reload process. The…
### Issue before this commit:
Switching the fiscal localization of a Belgian company from "Companies" to "Associations and Foundations" caused a traceback during the chart reload process. The operation failed because some accounts from the previous localization could not be deleted.
### Steps to reproduce the issue:
1. Download Accounting
2. Create a new Belgian company
3. Switch to that company
4. Go into Settings -> Fiscal Localization
5. Switch to Associations and Foundations
6. Traceback: The operation cannot be completed: Another model is using the record you are trying to delete. The troublemaker is: 'Account Cash Rounding' (account.cash.rounding). Thanks to the following constraint: 'Profit Account' (profit_account_id). How about archiving the record instead?
### Cause of the issue:
The Belgian localization creates a default cash rounding method ("Round to 0.05") linked to specific profit and loss accounts. When switching localization, it was tried to delete the old chart of accounts, but these accounts are still referenced by account.cash.rounding through profit_account_id and loss_account_id, which use ondelete='restrict'. This prevents account deletion and blocks the localization change. Commit that caused the issue: https://github.com/odoo/odoo/commit/412fc9bed36645dd950c9a60d9b6ffdd9b4bce67
### Reason to introduce the fix:
Before reloading the Belgian chart template, the fix clears the profit_account_id and loss_account_id on the existing cash rounding records. This removes the blocking references, allows the old accounts to be deleted safely, and lets the fiscal localization switch complete successfully without affecting existing cash rounding configurations.
opw-6050537
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis fix prevents Mercado Pago webhook calls from failing when the linked invoice reference contains slashes, such as INV/2026/00001. As a result, payments and invoice updates can be processed correctly instead of being rejected with a 404 error.
Original PR description
Currently, the mercado_pago_webhook http route only takes into consideration 1 url segment. This means that invoices with references like INV/2026/00001 don't match any defined route and the server returns a 404. /payment/mercado_pago/webhook/S00001 => OK /payment/mercado_pago/webhook/INV/2026/00001 => KO This commit allows references with slashes to be matched by the route by capturing the entire remaining url path including the slashes. /payment/mercado_pago/webhook/S00001 => OK /payment/mercado_pago/webhook/INV/2026/00001 => OK opw-6035161 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#259530 Forward-Port-Of: odoo/odoo#259378
This change prevents a checkout failure that could happen when buying an event booth using a company account. If one of the company’s contacts already has an active user, Odoo now avoids archiving that partner incorrectly, so payment can complete normally.
Original PR description
Use case: - considering a database where `website_event_booth_sale` is installed - considering a company (ACME Corp., email: info@acme.example.net) and it's contact `Roger` (which have a valid user). then: - As an anonymous user, go to an event with some booth to register - register a booth and enter the company information (important: use the company email: info@acme.example.net, this way the cart is created the company as the `partner_id` !!!) - you are redirected to the cart - try to pay it, and upon payment you have the following error: ``` You cannot archive contacts linked to an active user. You first need to archive their associated user. ``` This commit ensure we also check if any contact of the commercial partner have any user before trying to archive them all. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix prevents discounts on optional sales lines from being recalculated unexpectedly when portal users change quantities. It helps preserve the intended pricing shown to customers and avoids discount values being reset during updates.
Original PR description
Issue: --- Discount compute depends on `product_uom_qty`. On optional lines, this recompute will reset the discount on lines, when portal user updates the quanity. Cause: --- `discount` needs to depend on `product_uom_qty` because discount needs to be computed based on the quantity due to pricelist rules. Fix: --- We can prevent this compute if the quantity update comes from portal. opw-6078083 Forward-Port-Of: odoo/odoo#259696
This change prevents an employee payroll field from being calculated too early, before the necessary payslip data exists. As a result, Belgian holiday pay values are now computed at the right time, avoiding incorrect results and test failures.
Original PR description
…ield The computed, non-stored field `l10n_be_holiday_pay_recovered_n1` had tracking enabled. When writing to any field on the employee, the `write` method calls `_track_prepare` for tracked fields if `mail_notrack` is not set in the context. `_track_prepare` reads the current value of tracked fields to store initial values. Because `l10n_be_holiday_pay_recovered_n1` is non-stored with no dependencies, this triggered a computation at the very beginning of the test, before payslips existed. Later, when payslips were created, the field was never recomputed, causing incorrect values and test failures. Previously, the `tracking_disable` context prevented early computation. The fix removes the tracking attribute entirely, so the field is only computed when accessed, avoiding premature reads and fixing the tests. task: 6095445 Forward-Port-Of: odoo/enterprise#114063 Forward-Port-Of: odoo/enterprise#113015
The rental report now shows the correct date on each daily line for rental orders. This fixes a display issue where every line was using the same start date, making the report harder to read and less accurate.
Original PR description
The rental report is a daily report with x rows by rental order, with x the days between the start and return dates. With generate_series inside the select, the query was creating x rows with the same id, resulting in the date field not being correctly displayed (one unique date, the start date). This fix corrects the generation of the report to display the real date on each row. opw-5266525 Forward-Port-Of: odoo/enterprise#106088 Forward-Port-Of: odoo/enterprise#104764
The color picker now stays open when users change the color of an inserted icon. This fixes a frustrating issue in the note editor where hovering a color would close the picker immediately instead of applying the selection.
Original PR description
Commit [1] did already fix this problem, but commit [2] broke it again. This commit restores the condition that was removed by [2] but adapts it slightly in order to only take into account the direct children of the node, instead of any sub-node when checking for the presence of icons. Steps to reproduce: - Go to a "To do" note - Insert an icon with /media - Select the icon - Open the color picker - Hover a color => Color picker closed right away [1]: https://github.com/odoo/odoo/commit/1adfd9b9daf09c26ad642faf411574123110b9be [2]: https://github.com/odoo/odoo/commit/85688ffd11a3a988bf32c8c923a4628a89b57f87 task-6128069 Forward-Port-Of: odoo/odoo#259644
The BoM Overview now handles companies that do not yet have a warehouse configured, instead of showing an error. In that case, product availability is shown as not available, which keeps the overview usable and avoids a blocked workflow.
Original PR description
**Steps to Reproduce:** - Install MRP module. - Create a new company and switch to it. - Create a new BoM. - Click on the "BoM Overview" smart button. **Error:** `IndexError - list index out of range` **Cause:** When a new company is created, no warehouse is automatically generated for it. If no warehouse is configured for the company, the list is empty, causing an error. **Fix:** This commit raises a redirection warning if no warehouse is linked with the company. sentry-7286332859 Forward-Port-Of: odoo/odoo#250602
This update prevents duplicate payment instruction IDs in SEPA files when one payslip is split across multiple bank accounts. It helps ensure payment files comply with bank requirements and avoids export issues, while leaving single-account salary payments unchanged.
Original PR description
### Issue: If a payslip is split into multiple bank accounts (Salary Allocation), the generated SEPA file contains duplicate <InstrId> tags ### Cause: The `_get_payments_vals` method, `InstrId` is…
### Issue: If a payslip is split into multiple bank accounts (Salary Allocation), the generated SEPA file contains duplicate <InstrId> tags ### Cause: The `_get_payments_vals` method, `InstrId` is based on the payslip ID When a single payslip generates multiple transaction blocks, this ID is duplicated, violating the ISO 20022 requirement for unique instruction identifiers https://knowledge.xmldation.com/support/iso20022/general_rules/instrid This commit adds a unique suffix (e.g., -1, -2) to the `InstrId` for each transaction generated from the same payslip to ensure technical uniqueness Nothing change when you only have one account This is the part of the code that use the payment name: https://github.com/odoo/enterprise/blob/194a8d35ef3e9b47ff566479b0c35c0f963fb42d/account_iso20022/models/account_journal.py#L294-L299 ### Steps to reproduce: - Install `hr_payroll_account_iso20022` with demo data - On the Bank Journal, set a valid IBAN (e.g. BE04957751619131) for `Bank Account Number` - Open the Employee page for Abigail Peterson - In the Personal tab, add 2 Bank Accounts (Send Money: True, Account Number: any) - Click on Salary Allocation and Save (You'll have a 50/50 ratio) - Create a new Pay Run (for Abigail Peterson) - Open the last PaySlip and Validate - Create Payment Report (Export Format: SEPA) - Download the Payment Report and check the <InstrId> tags opw-6069670 Forward-Port-Of: odoo/enterprise#113113
LinkedIn account imports now skip image records that do not include a download link instead of crashing. This prevents the connection process from stopping unexpectedly and helps more LinkedIn accounts connect successfully.
Original PR description
When importing a LinkedIn account, Odoo fetches the image metadata of the organization page and expects each returned image to contain `downloadUrl`. For some LinkedIn accounts this key is missing from the image response, which makes the callback crash with `KeyError: 'downloadUrl'` and prevents the account from being connected. LinkedIn's current Images API documentation describes `downloadUrl` as an optional field, so the import flow should not assume it is always present. This patch skips image entries without `downloadUrl` instead of crashing. opw-6099244 Forward-Port-Of: odoo/enterprise#113812
The CRM onboarding tour was adjusted so the extra lead-generation steps run at the end instead of in the middle. This prevents the tour from getting stuck repeating steps, making the guided experience more reliable for users.
Original PR description
The crm_iap_mine module extended the crm tour, by adding steps to introduce the lead generation feature. These steps were inserted in the middle of the tour, which caused the tour to backtrack and…
The crm_iap_mine module extended the crm tour, by adding steps to introduce the lead generation feature. These steps were inserted in the middle of the tour, which caused the tour to backtrack and loop on itself. Why? For the tour to wait for the next step, we specify the selectors it should look for. In this case, because the modal redirects to the same page (with an updated domain), we cannot specify a selector that would be unique to the new page -> the target is found before the redirect -> after the redirect happens, the tour backtracks to try and recover, causing the loop. Moving the steps to the end of the tour fixes the issue. The disadvantage of this is that no the last step of the tour is not deterministic - it can fail if the user selects a combination of countries and industries which have no valid leads (Antarctica...) or if the user doesn't have enough IAP credits. In this case, the 'Congrats' rainbowman is shown even if the generation failed. Task-5386684 Forward-Port-Of: odoo/odoo#249733
Fixed an issue that could stop password reset instructions from being sent when several users were selected at once. This makes the user management flow more reliable and avoids an unexpected error during a common admin action.
Original PR description
Currently, an error occurs when sending the password reset link to multiple users. **Steps to Reproduce:** - Install `auth_signup` module. - Go to `Users` and make sure there are at least two user…
Currently, an error occurs when sending the password reset link to multiple users.
**Steps to Reproduce:**
- Install `auth_signup` module.
- Go to `Users` and make sure there are at least two user records.
- In the `list view`, select both users.
- Go to `Actions` > click `Send Password Reset Instructions`.
`ValueError: ValueError('Expected singleton: res.users(24, 23)') while evaluating 'records.action_reset_password()'`
This error occurs when generating the email body_html [1]. It passes multiple user
records (self) as the context record, but _render_encapsulate expects a single user
record to render the email body. which raise the error here[2].
This commit passes a single user record when rendering body_html.
[1]: https://github.com/odoo/odoo/blob/39c6e3a2578c4f7058dddb6acf12231d8716e7fd/addons/auth_signup/models/res_users.py#L214
[2]: https://github.com/odoo/odoo/blob/39c6e3a2578c4f7058dddb6acf12231d8716e7fd/addons/mail/models/mail_render_mixin.py#L187
sentry-7271437735
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update stops invoice creation from failing when aggregate withholding is enabled but its period has been cleared. The required period is now enforced so users cannot save an incomplete setup that would later cause an error.
Original PR description
Previously, if `is_aggregate_limit` was set to True while `aggregate_period` was left empty, it would raise a traceback during invoice creation. Although `aggregate_period` has a default value, it can still be manually cleared. With this commit, `aggregate_period` is enforced as mandatory whenever `is_aggregate_limit` is enabled, preventing such errors. Forward-Port-Of: odoo/odoo#259737 Forward-Port-Of: odoo/odoo#259634
This fix prevents a payroll error that could occur when an employee’s schedule pay is removed while a wage is defined. It keeps the payroll screen working normally instead of showing an unexpected error, helping users update employee pay details safely.
Original PR description
This error occurs when the schedule pay is removed from an employee contract with a defined wage. Steps to reproduce: - Install `l10n_au_hr_payroll` module with demo data - Switch to `My Australian…
This error occurs when the schedule pay is removed from an employee contract with a defined wage.
Steps to reproduce:
- Install `l10n_au_hr_payroll` module with demo data
- Switch to `My Australian Company`
- Open any Employee > Payroll > `Wage` remove `schedule pay`
Traceback:
```py
File "/home/odoo/src/enterprise/saas-19.2/l10n_au_hr_payroll/models/hr_version.py", line 549, in _compute_wage
version.wage = Payslip._l10n_au_convert_amount(daily_wage, "daily", version.schedule_pay)
File "/home/odoo/src/enterprise/saas-19.2/l10n_au_hr_payroll/models/hr_payslip.py", line 511, in _l10n_au_convert_amount
coefficient = PERIODS_PER_YEAR[period_from] / PERIODS_PER_YEAR[period_to]
KeyError: False
```
We are encountering this error because the `schedule pay` is removed, causing the field to become `False`. This False value is then passed to the `_l10n_au_convert_amount` [method], resulting in a `KeyError`.
[method]: https://github.com/odoo/enterprise/blob/92c584cc1426ac70f6f77aa8216c17004fa42d35/l10n_au_hr_payroll/models/hr_payslip.py#L500-L509
sentry-7401189447
Forward-Port-Of: odoo/enterprise#113623The Italian e-invoicing export now keeps VAT numbers intact when they do not start with a real country prefix. This prevents valid customer tax IDs, such as some Spanish numbers, from being shortened or corrupted in the XML sent to the Tax Agency.
Original PR description
**Steps to reproduce:** * Install `l10n_it_edi` module. * Create a partner with country **Spain** and VAT `A95758389`. * Create an invoice and send it to the Tax Agency, and download XML. **Observed behavior:** * The exported XML contains `5758389` in <IdCodice> instead of `A95758389` — the first two characters of the VAT are silently dropped. **Cause:** * In `_l10n_it_edi_get_values`, the EU branch that strips the country-code prefix used a bare `else` after the `isdecimal()` check, unconditionally removing the first two characters of any VAT that does not start with two digits. Spanish NIFs like `A95758389` start with `A9` (letter + digit), which is not a country-code prefix but was treated as one, corrupting the value. **Fix:** * Remove country prefix from normalized VAT by `removeprefix(normalized_country)` Instead of removing the first two characters. It will ensure that only the country prefix will be removed. opw-6089198 Forward-Port-Of: odoo/odoo#258626
New apps created in Studio will now show the correct activity filters when chatter is enabled. This fixes the clock menu so users can quickly see records that are late, due today, or upcoming instead of seeing all records at once.
Original PR description
Steps to reproduce
==================
- Install studio
- Create a new app
- Create a new model
- Keep the Chatter toggled (use_mail)
- Exit studio
- Create three records, one with an activity in the past, one today and one in the future
- Click on the clock status icon in the top right
- There should be a section with the new model
- Click on 1 Late => every records is displayed
- Same for Today and Future
Cause of the issue
==================
https://github.com/odoo/odoo/blob/b6434b91a7f94075e1372ec827787504ef7aa4f0/addons/mail/static/src/core/web/activity_menu.js#L39-L77
For this feature to work, the activities_{overdue,today,upcoming_all} filter should be present
Solution
========
We add them to the search view. They are all pretty much implemented the same way in every model.
opw-6069150
Forward-Port-Of: odoo/enterprise#113792
Forward-Port-Of: odoo/enterprise#1130119 changes
Enhancements to existing features
This update improves how tax amounts are calculated for Argentine electronic invoicing and related reports. It helps ensure totals are computed more consistently and displayed with the right precision, reducing rounding differences and improving the reliability of generated tax data.
Original PR description
- Rewrite all tax amounts calculations on `_get_tributes` and `_get_line_details` to properly use the tax computation engine helpers (`base_line`, and aggregating methods) - Ensure that all final amounts from the calculation are formatted with `float_repr` with appropriate precision. related-community-PR: https://github.com/odoo/odoo/pull/223393 task-4891206 Forward-Port-Of: odoo/enterprise#92639
The invoice import process was updated so records are matched more reliably, especially when partner information is involved. This helps reduce inconsistencies during BIS3/UBL invoice imports and improves the accuracy of imported data.
Original PR description
This commit is part of a bigger commit on the community side- to refactor the import code of BIS3 Invoice to fix various unsynchronized values issues. task-id: 5058687 Forward-Port-Of: odoo/enterprise#113719 Forward-Port-Of: odoo/enterprise#108356
Resolved issues and error corrections
The comparison view in tax reports now works correctly even when a report line contains text instead of only numbers. This prevents the report from crashing when users compare against one past period, so they can review results without interruption.
Original PR description
To reproduce: - Create a company in LU - Open the annual tax report for LU - Click on the comparison filter, compare with 1 period in the past ==> Traceback. This happens because that report contains a string value (an editable one, but it's not important here). Since there are only 2 comparison periods, we try creating the "%" column, comparing their amounts. The condition checking whether or not to display "N/A" was wrong, as it considered the values could only be int/float or None. Here, they are strings, so we don't enter that condition and crash when trying to evaluate float_is_zero on a string. Forward-Port-Of: odoo/enterprise#113330 Forward-Port-Of: odoo/enterprise#112619
This update corrects ISO20022 payment files so currencies like JPY are exported with the proper number of decimal places. It prevents bank rejections caused by amounts being formatted with two decimals when the currency should not have them.
Original PR description
Steps to reproduce: ------------------- 1. Activate JPY and create a JPY bank journal with ISO20022 as an outgoing payment method 2. Create a vendor (with a country) and add a trusted bank account 3.…
Steps to reproduce: ------------------- 1. Activate JPY and create a JPY bank journal with ISO20022 as an outgoing payment method 2. Create a vendor (with a country) and add a trusted bank account 3. Create and confirm a vendor bill in JPY (e.g. ¥1000), and pay it using the ISO20022 method on the JPY journal 4. Create a batch payment containing that payment, with Batch Type Outbound, on the JPY journal, with ISO20022 as payment method 5. Validate the batch — the XML file is generated and attached 6. Download it -> The `<InstdAmt Ccy="JPY">` node outputs `1000.00`, while JPY has no decimals. The file is rejected by banks. The fix: -------- Backport of 8da91d94ed1e8fad0e827f96172e3785e9f0e28d: > Generating the xml file for iso20022 always generates the amount with two decimals which is hard coded and can cause error for currencies without decimals for example JPY. > The fix is to have the currency decimal number dynamically set through the currency decimal places field. opw-6103849 Forward-Port-Of: odoo/enterprise#113296
This change removes a tracking setting from a payroll field so it is no longer read too early in the employee update flow. As a result, holiday pay values are calculated at the right time and payroll tests and outputs stay accurate.
Original PR description
…ield The computed, non-stored field `l10n_be_holiday_pay_recovered_n1` had tracking enabled. When writing to any field on the employee, the `write` method calls `_track_prepare` for tracked fields if `mail_notrack` is not set in the context. `_track_prepare` reads the current value of tracked fields to store initial values. Because `l10n_be_holiday_pay_recovered_n1` is non-stored with no dependencies, this triggered a computation at the very beginning of the test, before payslips existed. Later, when payslips were created, the field was never recomputed, causing incorrect values and test failures. Previously, the `tracking_disable` context prevented early computation. The fix removes the tracking attribute entirely, so the field is only computed when accessed, avoiding premature reads and fixing the tests. task: 6095445 Forward-Port-Of: odoo/enterprise#114063 Forward-Port-Of: odoo/enterprise#113015
The manufacturing report now converts unit quantities correctly when products are tracked in different units of measure. This fixes incorrect totals and averages in report groupings, so production figures and cost analysis are reliable again.
Original PR description
Steps to reproduce:
- Create a product W1 with UoM = Kg with the following BoM:
- Component C1: 1 unit, cost = $1
- Create and confirm MO1:
- Produce 1 Kg of W1 → total cost = $1
- Create and confirm MO2:
- Produce 1 Ton of W1 → total cost = $1000
- Open the Manufacturing Report and group results
Problem:
- qty_produced ≈ 1.001 instead of 1001
- unit_cost average ≈ 1000 instead of 1
Expected behavior:
- qty_produced = 1001
- unit_cost average = 1 (consistent across MOs)
The manufacturing report (`mrp.report`) incorrectly converts quantities from move UoM to product UoM, leading to wrong `qty_produced` and `qty_demanded` values when different units of measure are used
The current implementation uses:
sm.quantity / uom.factor * uom_prod.factor
This inverts the conversion ratio. As a result:
- 1 Ton is converted to 0.001 Kg instead of 1000 Kg
opw-6097098
Forward-Port-Of: odoo/enterprise#113979When a delivery is scanned using a packaging barcode, the system now correctly keeps the due date from the barcode when creating the lot. This avoids lots being created with the wrong expiration date and helps ensure inventory tracking stays accurate.
Original PR description
Issue
-----
Scanning a GS1 barcode containing:
- packaging
- lot
- due date
disregards the due date when creating the new lot.
Steps to reproduce
-----
- Enable GS1 nomenclature & packagings
- Create a product
- barcode 23456789012344
- packaging with barcode 01234567890128
- some on hand quantity
- Create a delivery for a full packaging of the product
- Open the delivery in barcode
- Scan 02 01234567890128 15 270101 10 LOT1
- Validate
- Open the lot
> Expiration date is set to today
Cause
-----
The code expects the product be scanned, there is no logic to retrieve it from the packaging when missing.
-----
Ticket:
opw-6073489
Forward-Port-Of: odoo/enterprise#113136
Forward-Port-Of: odoo/enterprise#112490When a subscription payment is processed through certain bank settings, the related invoice could stay marked as unpaid even though the payment succeeded. This fix ensures the invoice is properly matched with the payment so customers and teams see the correct payment status.
Original PR description
Currently, when a subscription payment is processed through a provider configured to use as outstanding account the bank default account, the resulting invoice may remain in an 'open' state even…
Currently, when a subscription payment is processed through a provider configured to use as outstanding account the bank default account, the resulting invoice may remain in an 'open' state even though the payment transaction is 'done'. This type of configuration is usually done when users want to skip the bank reconciliation process, and just create payments without the need to reconcile the payments with transactions. Steps to reproduce: - In Settings, under Sales > Invoicing, disable Automatic Invoice - Activate demo payment method - In the main Bank account add the default account as outstanding account for demo payment method. - Create a sales order with a subscription product - Open Preview - Pay - Go back to the sales order and open the created invoice Issue: The invoice is created and the payment is registered, but the invoice remains 'Not Paid'. Analysis: The invoice and the payment move lines are not automatically reconciled during the post-processing of the transaction, leaving the invoice unbalanced. opw-5869303 Forward-Port-Of: odoo/enterprise#110656
This update prevents Documents files from being disrupted when a sign template is created or deleted. It also keeps signature requests correctly linked back to the original document even when multiple templates are created from the same file.
Original PR description
Steps to reproduce: Bug 1 (The Crash): 1. Open Documents app, select a PDF, and click Action > Sign. 2. In the Sign app, delete the newly created Sign Template. 3. Return to the Documents app. 4. A…
Steps to reproduce:
Bug 1 (The Crash):
1. Open Documents app, select a PDF, and click Action > Sign.
2. In the Sign app, delete the newly created Sign Template.
3. Return to the Documents app.
4. A traceback occurs (`KeyError: <document_id>`) in `web_read`.
Bug 2 (The Broken Lineage):
1. Create two separate Sign Templates from the exact same Document.
2. Send a signature request from the second template.
3. The `reference_doc` on the signature request fails to link back to the original Document.
Current behavior:
When creating a sign template from a document, `documents_sign` intentionally unlinks the original `ir.attachment` (`res_model = False`) to pass custody to `sign.document`. If the template is deleted, the attachment is orphaned, permanently corrupting the original `documents.document` and crashing the UI.
Furthermore, the lineage tracking (`reference_doc`) relies strictly on a 1:1 shared `attachment_id`. If a user creates multiple templates from one document, the system is forced to make a copy for the second template, natively breaking the lineage tracking because the IDs no longer match.
Expected behavior:
Documents should not be corrupted when generating or deleting sign templates. Furthermore, lineage tracking (`reference_doc`) should successfully link back to the original document regardless of how many templates have been generated from it.
Fix:
1. Replaced the `res_model = False` custody-handoff hack in `documents_sign` with a safe `.copy({'original_id': attachment.id})`. This sandboxes the Sign app's files, completely preventing the deletion crash and the multi-template conflicts.
2. Updated the `reference_doc` computation in `sign.request` to dynamically search for both the current `attachment_id` AND its `original_id` (utilizing a minimal-diff recordset union `|`). This perfectly preserves the lineage tracking for all templates without requiring database schema changes.
Task: 5432116
Forward-Port-Of: odoo/enterprise#11316710 changes
Enhancements to existing features
This change improves how tax amounts are calculated for Argentine electronic documents, making the results more consistent and reliable. It also formats the final values with the right precision, which helps avoid rounding issues in invoices and reports.
Original PR description
- Rewrite all tax amounts calculations on `_get_tributes` and `_get_line_details` to properly use the tax computation engine helpers (`base_line`, and aggregating methods) - Ensure that all final amounts from the calculation are formatted with `float_repr` with appropriate precision. related-community-PR: https://github.com/odoo/odoo/pull/223393 task-4891206 Forward-Port-Of: odoo/enterprise#92639
This change updates how Argentina-specific tax amounts are calculated so they rely on Odoo’s standard tax computation methods instead of custom line queries. It makes the calculation logic more reliable and prepares the system for future improvements in tax handling.
Original PR description
This commit refactors the tax amount calculations on the `_get_vat` and `_l10n_ar_get_amounts` method so that it uses the tax computation engine helpers properly, to prepare for any future fixes done on how Argentina tax calculations differs from all other localizations. This replaces all move line queries with the proper `base_line` calculation, with the proper aggregating methods. related-enterprise-PR: https://github.com/odoo/enterprise/pull/92639 task-4891206 Forward-Port-Of: odoo/odoo#223393
Resolved issues and error corrections
This change ensures that when aggregate withholding is turned on, the aggregation period must also be filled in. It prevents invoice creation from failing with an error if that required field was left empty.
Original PR description
Previously, if `is_aggregate_limit` was set to True while `aggregate_period` was left empty, it would raise a traceback during invoice creation. Although `aggregate_period` has a default value, it can still be manually cleared. With this commit, `aggregate_period` is enforced as mandatory whenever `is_aggregate_limit` is enabled, preventing such errors. Forward-Port-Of: odoo/odoo#259737 Forward-Port-Of: odoo/odoo#259634
When a GS1 barcode includes a product packaging, lot number, and due date, the system now correctly keeps the due date when creating the lot. This avoids setting the expiration date to today by mistake and helps warehouse teams record product expiry information accurately.
Original PR description
Issue
-----
Scanning a GS1 barcode containing:
- packaging
- lot
- due date
disregards the due date when creating the new lot.
Steps to reproduce
-----
- Enable GS1 nomenclature & packagings
- Create a product
- barcode 23456789012344
- packaging with barcode 01234567890128
- some on hand quantity
- Create a delivery for a full packaging of the product
- Open the delivery in barcode
- Scan 02 01234567890128 15 270101 10 LOT1
- Validate
- Open the lot
> Expiration date is set to today
Cause
-----
The code expects the product be scanned, there is no logic to retrieve it from the packaging when missing.
-----
Ticket:
opw-6073489
Forward-Port-Of: odoo/enterprise#113136
Forward-Port-Of: odoo/enterprise#112490This change removes automatic tracking from a payroll field that was being read too early during employee updates. As a result, holiday pay values are now computed at the right time, preventing incorrect payroll calculations and related test failures.
Original PR description
…ield The computed, non-stored field `l10n_be_holiday_pay_recovered_n1` had tracking enabled. When writing to any field on the employee, the `write` method calls `_track_prepare` for tracked fields if `mail_notrack` is not set in the context. `_track_prepare` reads the current value of tracked fields to store initial values. Because `l10n_be_holiday_pay_recovered_n1` is non-stored with no dependencies, this triggered a computation at the very beginning of the test, before payslips existed. Later, when payslips were created, the field was never recomputed, causing incorrect values and test failures. Previously, the `tracking_disable` context prevented early computation. The fix removes the tracking attribute entirely, so the field is only computed when accessed, avoiding premature reads and fixing the tests. task: 6095445 Forward-Port-Of: odoo/enterprise#114063 Forward-Port-Of: odoo/enterprise#113015
The Bill of Materials overview now handles companies that do not have a warehouse configured. Instead of showing an error, it displays product availability as “Not available” and warns the user about the missing setup.
Original PR description
**Steps to Reproduce:** - Install MRP module. - Create a new company and switch to it. - Create a new BoM. - Click on the "BoM Overview" smart button. **Error:** `IndexError - list index out of range` **Cause:** When a new company is created, no warehouse is automatically generated for it. If no warehouse is configured for the company, the list is empty, causing an error. **Fix:** This commit raises a redirection warning if no warehouse is linked with the company. sentry-7286332859 Forward-Port-Of: odoo/odoo#250602
When invoice lines are grouped during UBL/CII import, the tax total is now adjusted so it stays accurate after grouping. This prevents small but important discrepancies in reported tax amounts and improves the reliability of imported invoices.
Original PR description
[FIX] account_edi_ubl_cii: correct tax amount when grouping lines When the user group lines of a move, the tax amount is now corrected if there's a difference in the tax amount before and after grouping This commit also removes the `ungroup_lines` context key, as the flow was changed in odoo/odoo#252458 Reword the `test_import_and_group_lines_by_tax` test: use belgian company and belgian taxes task-5993555 Forward-Port-Of: odoo/odoo#257581 Forward-Port-Of: odoo/odoo#252719
This update fixes where the 12% I tax amount appears in the Philippine SLSP report. It now shows under "Purchase of Other than Capital Goods" instead of "Purchase of Capital Goods," helping ensure the report matches the correct category.
Original PR description
Before this commit: - The amount of tax '12% I' is shown under 'Purchase of Capital Goods'. After this commit: - The amount of tax '12% I' is shown under 'Purchase of Other than Capital Goods'. task-6092566 Forward-Port-Of: odoo/enterprise#113810
This fix ensures that preparation printers display the correct attribute value for instant variants selected within a combo. As a result, kitchen or prep staff can see the exact variant ordered instead of only the base product name, reducing confusion and order mistakes.
Original PR description
Before this commit, the preparation printer did not display the attribute value for an instant variant added inside a combo choice. This occurred because the attribute value was not properly set on the variant order line. Steps to reproduce: * Create a PoS product with multiple variants. * Create a combo product with a choice containing the variants. * Configure a preparation printer. * Open a PoS session and order the combo. * The printer displays only the base product name. opw-5949132
The Point of Sale now correctly handles event tickets that have no limit when an event uses multiple slots. This prevents customers from seeing a false “all slots are booked” message and allows unlimited tickets to be sold as expected.
Original PR description
**Steps to reproduce:** - Make an event, put it to announced state - Allow multi slots and create a product - Go to the pos and try to order it - "All slots are booked out for this event" appears **Why the fix:** When we set 0 as a maximum quantity for an event slot, the quantity is unlimited, in the code, the availability is set to a string "unlimited". This was not taken into account in the case of multi slots, as we only checked if the availability was a number greater than 0. As "unlimited" is not a number, we thought we didn't have any slots available and returned the error that said all slots were full. We now add the unlimited tickets to the availability list. opw-6006696
3 changes
Enhancements to existing features
This update fixes how tax amounts are calculated for Argentine electronic invoices and related reports. It helps ensure totals are computed consistently and displayed with the right precision, reducing rounding issues and mismatches in generated tax documents.
Original PR description
- Rewrite all tax amounts calculations on `_get_tributes` and `_get_line_details` to properly use the tax computation engine helpers (`base_line`, and aggregating methods) - Ensure that all final amounts from the calculation are formatted with `float_repr` with appropriate precision. related-community-PR: https://github.com/odoo/odoo/pull/223393 task-4891206 Forward-Port-Of: odoo/enterprise#92639
Resolved issues and error corrections
This fix prevents Point of Sale from crashing when a payment is cancelled directly on the payment terminal instead of in the POS screen. It improves reliability for cashiers by handling this cancellation case cleanly and avoiding an error message.
Original PR description
Currently if you cancel a transaction on the terminal (not in pos) this lead to a traceback TypeError: this.cancel_resolve is not a function at Proxy._waitingPayment (https://varoconsult-be-itve.odoo.com/web/assets/4473ba8/point_of_sale.assets_prod.min.js:16764:298) at Proxy._onValueChange (https://varoconsult-be-itve.odoo.com/web/assets/4473ba8/point_of_sale.assets_prod.min.js:16758:184) at Proxy._onSuccess (https://varoconsult-be-itve.odoo.com/web/assets/4473ba8/point_of_sale.assets_prod.min.js:16674:190) at Proxy._onSuccess (https://varoconsult-be-itve.odoo.com/web/assets/4473ba8/point_of_sale.assets_prod.min.js:16778:1228) at https://varoconsult-be-itve.odoo.com/web/assets/4473ba8/point_of_sale.assets_prod.min.js:16672:417 This PR fixes the issue to ensure the scenario when the pos didnt ask for cancellation is managed Forward-Port-Of: odoo/enterprise#114215
This update moves the tax amount for “12% I” to the correct section of the Philippine SLSP report. It now appears under “Purchase of Other than Capital Goods” instead of “Purchase of Capital Goods,” ensuring the report is more accurate for business reporting and compliance.
Original PR description
Before this commit: - The amount of tax '12% I' is shown under 'Purchase of Capital Goods'. After this commit: - The amount of tax '12% I' is shown under 'Purchase of Other than Capital Goods'. task-6092566 Forward-Port-Of: odoo/enterprise#113810
23 changes
New functionality added to Odoo
Rental orders created from a sales opportunity now automatically keep the related project attached. This helps teams maintain a clear link between the customer opportunity, the rental order, and project work without manual updates.
Original PR description
This commit links the project, CRM, and rental by setting the project on rental orders created from an opportunity. Task-6024387
Enhancements to existing features
The Belgian salary configurator and employee offer view now present company car options in a simpler, clearer way. This makes it easier for employees and HR teams to understand and choose fleet-related salary benefits.
Original PR description
-Introducing some UX changes in salary configurator and employee's offer view to simplify car options.
Manufacturing teams get clearer and more flexible work order planning screens, including a kanban option, richer Gantt popovers, and a cleaner form header. These updates make it easier to review work orders and related manufacturing orders during production planning.
Original PR description
- add kanban to work orders views list - add infos in gantt view popover - adapt form view header - fix test task: 5990446 See odoo/odoo#257900
Quality checks can now target the exact bill of materials line or by-product line instead of only the product, preventing duplicate or incorrect checks when the same component appears multiple times. BoM revision reviews also better reflect by-product unit changes and Studio-edited forms keep component and by-product change tracking consistent.
Original PR description
_* = quality_mrp_workorders - When the same component is used multiple times in a BoM, it is not possible to specify exactly which one to use in Product to Register, and quality checks are created for each occurrence of that component unnecessarily. - This change replaces product selection with BoM lines and by-product lines with the Product to Register field of the Quality Point, ensuring that quality checks are created for the specific BoM line during operations and preventing duplicate or unnecessary checks. - Solve the issue where changing the UoM of a by-product in a BoM revision was not reflected in the By-Product Changes, ensuring a consistent and reliable revision review. - Adds missing dependencies so that when the form view is made editable via Studio, changes are still correctly reflected in Component Changes and By-Product Changes. Com PR https://github.com/odoo/odoo/pull/239243 task-5365739
This update improves how company cars are handled in Belgian salary package offers, including related configuration, employee views, and offer presentation. It helps HR teams present and manage fleet-related benefits more clearly during contract and salary negotiations.
The Discuss command palette has been improved for AI App and WhatsApp-related conversations, making actions easier to find and use. This should create a smoother messaging experience for users who rely on these channels in Odoo.
Original PR description
part of task-5867464 community: https://github.com/odoo/odoo/pull/258588
Belgian payroll DMFA reporting now uses the ONSS social security amounts already calculated on payslips, reducing the risk of differences between payroll and reporting. The report also flags mismatches when payslip amounts do not align with expected DMFA calculations, helping payroll teams spot issues before submission.
Original PR description
For the DMFA, directly use the ONSS amounts from the payslips. This commit also adds a list of alert on the DMFA report and adds an alert if the amount from payslips does not match the expected amount computed in the DMFA. task-5976407
Progress bars in Gantt-style planning, project, manufacturing, and scheduling views have been redesigned to be easier to read and less cluttered. The update improves hover behavior, row spacing, and mobile layout so users can more clearly understand progress at a glance.
Original PR description
Before this PR, the progress bar was not easy to read due to overlapping text and colors. The hover also changed from the whole row to only the header. The height of each row increased to allow…
Before this PR, the progress bar was not easy to read due to overlapping text and colors. The hover also changed from the whole row to only the header. The height of each row increased to allow better visibility of the progress bar. In mobile view, the display from the progress bar goes below the avatar name to allow clearer view. Some tests selectors doesn't exist anymore so they got adjusted. Com PR: https://github.com/odoo/odoo/pull/252295 **Dense Mode** | | Before | After | |--------|--------|--------| | Normal state | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 18 13" src="https://github.com/user-attachments/assets/74f3c8ad-5462-424f-a0de-a085e4600005" /> | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 16 26" src="https://github.com/user-attachments/assets/e73a9f69-0dd8-40b5-a347-98f76d7dbf13" /> | | Hover Red | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 18 18" src="https://github.com/user-attachments/assets/08671dc1-efd7-4823-8439-02ed5d066685" /> | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 16 36" src="https://github.com/user-attachments/assets/fe0e058a-a208-4457-a6aa-9b92ecd41ee3" /> | | Hover Green | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 18 21" src="https://github.com/user-attachments/assets/d4d519d6-eefa-4a00-9ef5-998a7ba41045" /> | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 16 50" src="https://github.com/user-attachments/assets/55319df3-93d7-46db-beff-fd68f1b2cab1" /> | **Sparse Mode** | | Before | After | |--------|--------|--------| | Normal state | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 18 32" src="https://github.com/user-attachments/assets/844d3dcd-41fb-4a64-bfc2-df98656fbbb0" /> | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 17 06" src="https://github.com/user-attachments/assets/450e831f-d912-4a2c-b51a-00c00750dff4" /> | | Hover Red | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 18 37" src="https://github.com/user-attachments/assets/b54b63dc-8a50-4c1e-99fd-1d9145e03540" /> | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 17 12" src="https://github.com/user-attachments/assets/372c1311-d621-4b77-861f-83d676e1d14c" /> | | Hover Green | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 18 41" src="https://github.com/user-attachments/assets/313b22de-1c79-4fd5-babd-44bad66ed992" /> | <img width="313" height="744" alt="Screenshot 2026-04-07 at 16 17 19" src="https://github.com/user-attachments/assets/332b6c5a-9288-4762-bb3b-d07d88005e8f" /> | **Mobile View** | | Before | After | |--------|--------|--------| | Sparse Mode | <img width="405" height="705" alt="Screenshot 2026-04-07 at 16 22 01" src="https://github.com/user-attachments/assets/58209c32-d7ad-4e59-8226-15742cb7f46e" /> | <img width="405" height="705" alt="Screenshot 2026-04-07 at 16 22 22" src="https://github.com/user-attachments/assets/8bade56a-b48d-461e-8832-ac8b09fdd035" /> | | Dense Mode | <img width="405" height="705" alt="Screenshot 2026-04-07 at 16 22 06" src="https://github.com/user-attachments/assets/d9c461ac-f521-4a70-84f6-0d70d8240f97" /> | <img width="405" height="705" alt="Screenshot 2026-04-07 at 16 22 27" src="https://github.com/user-attachments/assets/1aba1990-b84f-46cf-aa8d-ea9ecc788162" /> | task-3630380
When companies trade with each other, vendor bills created automatically are now linked back to the original purchase order lines. This helps keep purchasing, billing, and reconciliation aligned without extra manual matching.
Original PR description
Conside the following flow: 1) Activate intercompany transactions between company A & company B for both SO and Bills 2) Create a PO in company A with vendor as company B 3) The SO is created in company B, Validate it 4) Create the invoice in company B, post it 5) The Vendor Bill is created in company A The flow is still missing one last step: the PO matching. This commit ensures that the lines of the vendor bill created in company A are matched with the lines of the original PO. task-6075588
Financial reports can now group aggregated results, enabling richer reporting views and supporting future reporting capabilities such as snapshots and tax closing improvements. Report line foldability was also standardized so reports behave more consistently when users expand or collapse sections.
Original PR description
### [IMP] account_reports: foldability as selection field * Adapt AccountReportLineData, _get_groupby, and tests to the new 'foldability' selection. * Apply upgrade_code script for removing the…
### [IMP] account_reports: foldability as selection field
* Adapt AccountReportLineData, _get_groupby, and tests to the new 'foldability' selection.
* Apply upgrade_code script for removing the unnecessary foldable field in reports data files if they
will be correctly computed.
* For inconsistencies reported by the script, manually set the foldable values on the reports and tests.
### [IMP] account_reports: Support groupby on aggregations
The aggregation engine didn't support groupby before due to limitations
existed from the beginning of Reportalypse.
With the removal of the 'load more'<sup>1</sup> feature, other engines don't run a SQL LIMIT anymore.
Resulting on the aggregation engine can obtain the full result, and
'groupby' calculation be done.
That support will help with incoming improvements: Snapshot feature<sup>2</sup> and
Tax closing computation refactoring
<sup>1</sup> : https://github.com/odoo/enterprise/commit/ff2895144ecfc66d2b23bb872b39f5b446ae0da6
<sup>2</sup> : https://github.com/odoo/enterprise/pull/113677
task-5891053The Barcode app now matches the standard inventory flow when validating incomplete transfers, letting users decide whether to create a backorder when the setting asks for confirmation. It also gives clearer warnings and quantity details for incomplete transfers, with a cleaner mobile popup to reduce mistakes and extra follow-up work.
Original PR description
- Currently, when the operation type was configured to `Ask` for creating backorders, the Barcode app always treated it as backorder would always be created, since it only showed `Validate` and `Stay…
- Currently, when the operation type was configured to `Ask` for creating backorders, the Barcode app always treated it as backorder would always be created, since it only showed `Validate` and `Stay on Transfer` options. This behavior was inconsistent with the backend flow and forced users who did not wish to create a backorder. Users had to manually cancel the backorder afterwards, adding unnecessary steps and extra effort. - Also, when the operation type is configured to `Always` or `Never` for creating backorders, users are not clearly warned that the transfer is incomplete and receive no visible indication of how many products have been processed or how many remain, leaving users without a clear indication that some products remain unprocessed during validation. - Additionally, the backorder popup on `mobile screens` appeared cluttered, as product rows and quantities were not clearly aligned on small screens, leading to a `poor user experience`. These changes ensure that when the operation type is set to `Ask`, users can choose whether to create a backorder or not during validation, avoiding unwanted backorders and manual cancellation. They also ensure that when set to `Always` or `Never`, users are clearly warned if the transfer is incomplete and shown how many products have been processed and how many remain. The mobile layout is improved to provide a cleaner and more `organized view`, and when set to Never, missing items are highlighted in red with a clear label, helping them to make more informed validation decisions. TaskID-4797752
The work order form has been reorganized to make key information and actions easier to find. Users now get a cleaner status selection, more accessible action buttons, larger work order names, visible quality checks, and a communication area for follow-up discussions.
Original PR description
This commit rearange the blocks of the workorder form view: - change the statusbar widget by the dropdown widget - move the buttons from the header to stat button - increase name size Task: 5936292
Planning materials can now be linked to a specific employee. When that employee is added to a planning slot, their assigned material is automatically added as a resource and scheduled with the shift, reducing manual setup and improving resource accuracy.
Original PR description
In this commit, we add a field "Assigned To" to materials. This allow users to assign one employee to the material. With that, when adding an employee to a planning slot, its assigned material will automatically added to the resources, and a shift will be assigned to it. task-5259038
Warehouse barcode scanning now better handles packages that include non-stored products during deliveries and receipts. This helps operators complete prepared package transfers without unnecessary backorder prompts or manual quantity updates.
Original PR description
When dealing with multi-step deliveries, it can happen to pack a non-stored good in an earlier step (e.g. PICK). This means that the package will be set as source & destination for the following transfers. However when scanning the package in those transfers, since we're only checking the quants of the package (i.e. so the effective stored content), the non-stored goods are never picked, and at transfer validation it would ask for backorders, which makes little sense. Now also selects all non-stored goods that have the scanned package as source. --- For receptions, if packages are already set through the back-end on the move lines, when processing the receipt in barcode, we can now simply scan the prepared package to automatically fill its content. Task-5266021
Resolved issues and error corrections
Payment reminder emails for subscriptions now avoid showing the exact automatic cancellation date until the final 24-hour reminder. This helps encourage earlier payment while also fixing cases where a zero-day grace period was incorrectly treated as the default delay.
Original PR description
- Hide close date until final 24h payment reminder: This commit updates the payment reminder logic to only expose the contract closing date precisely 24 hours before the subscription is automatically cancelled. By hiding the date during the earlier standard reminders, we create urgency without encouraging procrastination. It also fixes a native Python evaluation bug where an auto-close limit explicitly set to zero days would be treated as "falsy" and incorrectly default to a 15-day grace period. Both manual payments and tokenized payment failures have been updated to follow these new rules. task: 5902221
Payments dated in the future are now excluded from Mexico CFDI payment signing, preventing users from accidentally submitting documents that government rules do not allow. The invoice action to update payments will not appear when only future payments exist, and future payments are ignored when eligible payments are processed.
Original PR description
To sign a payment registered in the future is not allowed by the government. See http://omawww.sat.gob.mx/tramitesyservicios/Paginas/documentos/Guia_llenado_pagos.pdf Steps: - Create a PDD invoice (the due date should be at least 1 month later than the invoice date) - Send it to CFDI - Register a payment in the future -> We have the 'Update payments' button that appear on the invoice view, if you clik on it the payment will be signed With this commit, we filter out the payments with a future date, that way we don't have the 'Update Payments' button if there are only future payments, or the future payments won't be taken into account when clicking on the button. opw-5934753 Forward-Port-Of: odoo/enterprise#114074 Forward-Port-Of: odoo/enterprise#112320
Subscription payments using a bank default account are now automatically matched with the related invoice. This prevents paid subscription invoices from incorrectly remaining marked as not paid, reducing manual follow-up for finance teams.
Original PR description
Currently, when a subscription payment is processed through a provider configured to use as outstanding account the bank default account, the resulting invoice may remain in an 'open' state even…
Currently, when a subscription payment is processed through a provider configured to use as outstanding account the bank default account, the resulting invoice may remain in an 'open' state even though the payment transaction is 'done'. This type of configuration is usually done when users want to skip the bank reconciliation process, and just create payments without the need to reconcile the payments with transactions. Steps to reproduce: - In Settings, under Sales > Invoicing, disable Automatic Invoice - Activate demo payment method - In the main Bank account add the default account as outstanding account for demo payment method. - Create a sales order with a subscription product - Open Preview - Pay - Go back to the sales order and open the created invoice Issue: The invoice is created and the payment is registered, but the invoice remains 'Not Paid'. Analysis: The invoice and the payment move lines are not automatically reconciled during the post-processing of the transaction, leaving the invoice unbalanced. opw-5869303 Forward-Port-Of: odoo/enterprise#110656
Asset creation eligibility for accounts is now based on whether an account is configured as accumulated depreciation on another account, rather than whether it was used by existing assets. This prevents legacy asset records from blocking valid new asset creation and keeps depreciation account choices clearer.
Original PR description
This commit fixes the `can_create_asset` flag on accounts to limit the creation of asset based on if account is used as an accumulated depreciation on another account, instead of used by an asset. This requirement came after users with old assets couldn't create assets using some accounts because they were used by the old assets with no possible way to change that. Better to limit on configuration data instead of business data. Also now, accounts that have models set do not show up in the accumulated depreciation dropdown. no-task Forward-Port-Of: odoo/enterprise#114096
The Documents mobile search panel now opens folder sections correctly again, including company and other grouped values. This also restores missing section icons and improves styling and keyboard navigation for a smoother mobile experience.
Original PR description
Follows the changes made in community and fixup some styling introduced in commit[1] - remove unneccessary styling - rescope styling in right files - fixup the searchpanel inside the bottom sheet task-6090140 [1]: odoo/enterprise@c573cd168e2e01bb9390ef7aae714688100fb2ae Community PR: https://github.com/odoo/odoo/pull/257378
Database synchronization no longer fails with an error when a user loses access, receives a new remote document, or the remote database cannot be reached. This helps users complete synchronization cleanly and ensures removed access is reflected without a disruptive traceback.
Original PR description
The aim of this commit is to allow a db_user to synchronize a database without facing a Traceback. Context: - A new document has been received by a remote db and we try to synchronize it. - The current user access has been removed from the remote db. - The database is unreachable. Before this commit: In all 3 previous cases, an access error would be raised because a db_user can't write on a database. After this commit: The synchronization finish gracefully and the db_user should have lost his access if it was removed from the remote db. task-id: 6046087 Forward-Port-Of: odoo/enterprise#114204 Forward-Port-Of: odoo/enterprise#113826
Unpaid work entry types are now properly linked to the Belgium monthly employee pay structure. This prevents unpaid absences from being incorrectly included in payslip payments, improving payroll accuracy for Belgian employees.
Original PR description
Work entry types with "unpaid" in their name were not linked to the "Belgium: Employees Monthly Pay" structure, causing them to still be paid during payslip computation. task-6123817
Customers booking appointments can use quick checkout by default, avoiding repeated requests for full billing address details. This improves the booking and payment experience where taxes are typically based on the event or appointment location rather than the customer address.
Original PR description
Forward-Port-Of: odoo/enterprise#114205 Forward-Port-Of: odoo/enterprise#113575
Studio-created models with Chatter enabled now get the activity filters needed for the activity menu. This means users clicking Late, Today, or Future activities see the correct records instead of all records.
Original PR description
Steps to reproduce
==================
- Install studio
- Create a new app
- Create a new model
- Keep the Chatter toggled (use_mail)
- Exit studio
- Create three records, one with an activity in the past, one today and one in the future
- Click on the clock status icon in the top right
- There should be a section with the new model
- Click on 1 Late => every records is displayed
- Same for Today and Future
Cause of the issue
==================
https://github.com/odoo/odoo/blob/b6434b91a7f94075e1372ec827787504ef7aa4f0/addons/mail/static/src/core/web/activity_menu.js#L39-L77
For this feature to work, the activities_{overdue,today,upcoming_all} filter should be present
Solution
========
We add them to the search view. They are all pretty much implemented the same way in every model.
opw-6069150
Forward-Port-Of: odoo/enterprise#114217
Forward-Port-Of: odoo/enterprise#1130119 changes
Enhancements to existing features
This update corrects how tax amounts are calculated in Argentine electronic invoicing and related reports. It helps ensure invoice totals and tax breakdowns are more precise and consistently formatted, reducing mismatches in printed or reported amounts.
Original PR description
- Rewrite all tax amounts calculations on `_get_tributes` and `_get_line_details` to properly use the tax computation engine helpers (`base_line`, and aggregating methods) - Ensure that all final amounts from the calculation are formatted with `float_repr` with appropriate precision. related-community-PR: https://github.com/odoo/odoo/pull/223393 task-4891206 Forward-Port-Of: odoo/enterprise#92639
Resolved issues and error corrections
This update prevents an error when saving an appointment that has no organizer assigned but includes a Google Meet link. It also stops template previews from failing in the same situation, improving reliability for users who manage appointments without a linked user.
Original PR description
Currently an error is generated when the user tries to save an appointment as follows: - Install the appointment_google_calendar module without demo data - Create a new appointment as below: - Remove…
Currently an error is generated when the user tries to save an
appointment as follows:
- Install the appointment_google_calendar module without demo data
- Create a new appointment as below:
- Remove Organizer (user_id)
- Set the Google Meet link inside VideocallURL, e.g., https://meet.google.com/aaa-aaa-aaa
- An error occurs in the log and a message is shown to the user when save the record
- Also, an error occurs when trying to preview `Appointment: Attendee Invitation`
after creating appointment as follows:
- Set the Google Meet link inside Videocall URL > save
- Remove Organizer (user_id)
Error:
```
test odoo.addons.mail.models.mail_render_mixin: Failed to render QWeb template for Mail Template: 'Appointment: Appointment Booked' (ID: 12) - Context language:en_US
Target Model: calendar.event
Error: Error while render the template
ValueError: Expected singleton: res.users()
```
This is because the method `is_google_calendar_synced` expected a single
record, but since we removed `user_id` from the event (appointment),
it will generate a singleton error.
This commit will fix the above issue by not calling `is_google_calendar_synced`
when the event does not have `user_id`.
sentry-7393595716
Forward-Port-Of: odoo/enterprise#113966This update ensures that salary payments split across multiple bank accounts receive unique identifiers in the SEPA export. It prevents invalid payment files and helps payroll exports process correctly without affecting employees who use only one bank account.
Original PR description
### Issue: If a payslip is split into multiple bank accounts (Salary Allocation), the generated SEPA file contains duplicate <InstrId> tags ### Cause: The `_get_payments_vals` method, `InstrId` is…
### Issue: If a payslip is split into multiple bank accounts (Salary Allocation), the generated SEPA file contains duplicate <InstrId> tags ### Cause: The `_get_payments_vals` method, `InstrId` is based on the payslip ID When a single payslip generates multiple transaction blocks, this ID is duplicated, violating the ISO 20022 requirement for unique instruction identifiers https://knowledge.xmldation.com/support/iso20022/general_rules/instrid This commit adds a unique suffix (e.g., -1, -2) to the `InstrId` for each transaction generated from the same payslip to ensure technical uniqueness Nothing change when you only have one account This is the part of the code that use the payment name: https://github.com/odoo/enterprise/blob/194a8d35ef3e9b47ff566479b0c35c0f963fb42d/account_iso20022/models/account_journal.py#L294-L299 ### Steps to reproduce: - Install `hr_payroll_account_iso20022` with demo data - On the Bank Journal, set a valid IBAN (e.g. BE04957751619131) for `Bank Account Number` - Open the Employee page for Abigail Peterson - In the Personal tab, add 2 Bank Accounts (Send Money: True, Account Number: any) - Click on Salary Allocation and Save (You'll have a 50/50 ratio) - Create a new Pay Run (for Abigail Peterson) - Open the last PaySlip and Validate - Create Payment Report (Export Format: SEPA) - Download the Payment Report and check the <InstrId> tags opw-6069670
This update prevents a crash when users compare a tax report against one past period, including cases where the report contains text values. It makes the comparison view more reliable and avoids an error when Odoo calculates percentage columns.
Original PR description
To reproduce: - Create a company in LU - Open the annual tax report for LU - Click on the comparison filter, compare with 1 period in the past ==> Traceback. This happens because that report contains a string value (an editable one, but it's not important here). Since there are only 2 comparison periods, we try creating the "%" column, comparing their amounts. The condition checking whether or not to display "N/A" was wrong, as it considered the values could only be int/float or None. Here, they are strings, so we don't enter that condition and crash when trying to evaluate float_is_zero on a string. Forward-Port-Of: odoo/enterprise#113330 Forward-Port-Of: odoo/enterprise#112619
This change prevents an error that could appear when a user removes the scope from an emission source. It keeps the ESG form working smoothly and avoids interruption while editing records.
Original PR description
Currently, an error occurs when the user removes the scope of the emission source. **Steps to Reproduce:** - Install the `esg` module. - Create an `emission source` record or open an `existing one`.…
Currently, an error occurs when the user removes the scope of the emission source. **Steps to Reproduce:** - Install the `esg` module. - Create an `emission source` record or open an `existing one`. - Remove the `scope` value and click anywhere. `ValueError: Compute method failed to assign esg.emission.source(<NewId origin=1>,).activity_flow_direct_indirect` **Cause:** Error started occurring in 19.0 due to a change in selection field behavior. Since from [commit](https://github.com/odoo/odoo/pull/214422/commits/8d2a42ac419fdf7943a0c11beb8c5de6c6f85bef), selection fields no longer display an “empty” value. To remove a value from a selection field, the user must clear the field, similar to a many2one field. when the user removes the scope value, The system attempts to compute the activity flow, but since the scope is False, it does not match any case [1]. As a result, the method fails to assign a value to activity_flow_direct_indirect, raising an error. This commit ensures that the activity flow and activity flow direct indirect are initialized to False. If no condition matches, the field remains False, preventing the assignment failure. [1]: https://github.com/odoo/enterprise/blob/eaf4b7559b8eb6c538820d6e54f583a41077ac3d/esg/models/esg_emission_source.py#L79-L89
This change removes automatic tracking from a payroll field that should only be calculated when needed. It prevents the value from being read too early, which was causing incorrect holiday pay results and failed payroll tests.
Original PR description
…ield The computed, non-stored field `l10n_be_holiday_pay_recovered_n1` had tracking enabled. When writing to any field on the employee, the `write` method calls `_track_prepare` for tracked fields if `mail_notrack` is not set in the context. `_track_prepare` reads the current value of tracked fields to store initial values. Because `l10n_be_holiday_pay_recovered_n1` is non-stored with no dependencies, this triggered a computation at the very beginning of the test, before payslips existed. Later, when payslips were created, the field was never recomputed, causing incorrect values and test failures. Previously, the `tracking_disable` context prevented early computation. The fix removes the tracking attribute entirely, so the field is only computed when accessed, avoiding premature reads and fixing the tests. task: 6095445 Forward-Port-Of: odoo/enterprise#114063 Forward-Port-Of: odoo/enterprise#113015
Printing accounting reports like customer statements could split a negative amount across two lines, with the minus sign separated from the number. This fix keeps negative values on one line so printed PDFs remain clear and readable.
Original PR description
When printing accounting reports such as customer statements, a negative number may be split across two lines, leaving the minus sign on the first line and the amount on the second. Steps to reproduce: - Make an invoice for [Partner] with a total of 10.0 - Make another invoice for [Partner] with a total of 100.0 - Create a credit note for this last invoice - Open the customer statement report for [Partner] - Print PDF Issue: The first line of the partner section has fewer digits than the amounts of the subsequent journal items. On pdf, the column width is based on the smaller line, causing the longer negative strings to wrap and separate the minus sign from the amount. opw-5951300 Forward-Port-Of: odoo/enterprise#113727
Copying helpdesk tickets no longer fails for users who do not have stock permissions. This makes it easier for support teams to duplicate tickets without needing broader access rights, while keeping stock-related information out of the copy when appropriate.
Original PR description
Steps to reproduce: - Install helpdesk_sale_timesheet. - Create a Helpdesk Ticket and set its sale_line_id. - Log in as a user without stock.group_stock_user access. - Try to duplicate the ticket. Issue: Duplicating a ticket raises an AccessError because the user lacks stock rights required when copying the product_id. Fix: Set `product_id` to False during duplication for non-stock users. Reference: https://github.com/odoo/enterprise/pull/9100 task-5356318 Forward-Port-Of: odoo/enterprise#113564 Forward-Port-Of: odoo/enterprise#101338
This fix ensures that when a subscription payment is completed through a payment setup that skips bank reconciliation, the related invoice is automatically matched with the payment. As a result, invoices no longer stay marked as unpaid after the transaction is done, which avoids confusion and manual follow-up.
Original PR description
Currently, when a subscription payment is processed through a provider configured to use as outstanding account the bank default account, the resulting invoice may remain in an 'open' state even…
Currently, when a subscription payment is processed through a provider configured to use as outstanding account the bank default account, the resulting invoice may remain in an 'open' state even though the payment transaction is 'done'. This type of configuration is usually done when users want to skip the bank reconciliation process, and just create payments without the need to reconcile the payments with transactions. Steps to reproduce: - In Settings, under Sales > Invoicing, disable Automatic Invoice - Activate demo payment method - In the main Bank account add the default account as outstanding account for demo payment method. - Create a sales order with a subscription product - Open Preview - Pay - Go back to the sales order and open the created invoice Issue: The invoice is created and the payment is registered, but the invoice remains 'Not Paid'. Analysis: The invoice and the payment move lines are not automatically reconciled during the post-processing of the transaction, leaving the invoice unbalanced. opw-5869303 Forward-Port-Of: odoo/enterprise#110656
14 changes
Enhancements to existing features
The French chart of accounts now separates account 649 into two new accounts, 6491 and 6492. This helps produce a more accurate Profit and Loss report by distinguishing social security charges from salaries.
Original PR description
Splitting account 649 into two new accounts (6491 and 6492) is necessary to handle the Profit and Loss report properly. This ensures we can accurately separate social security charges from salaries in the report. Reference: ANC PCG 2026, page 445, note (h) https://www.anc.gouv.fr/files/anc/files/1_Normes_fran%C3%A7aises/recueil/RECEUIL-PCG-2026-AVEC-COUVERTURE.pdf task-6053784 Forward-Port-Of: odoo/odoo#255038
The French accounting report now separates account 649 into two new accounts, 6491 and 6492. This helps the Profit and Loss report distinguish social security charges from salaries more accurately, improving the quality of financial reporting.
Original PR description
Splitting account 649 into two new accounts (6491 and 6492) is necessary to handle the Profit and Loss report properly. This ensures we can accurately separate social security charges from salaries in the report. Reference: ANC PCG 2026, page 445, note (h) https://www.anc.gouv.fr/files/anc/files/1_Normes_fran%C3%A7aises/recueil/RECEUIL-PCG-2026-AVEC-COUVERTURE.pdf task-6053784 Forward-Port-Of: odoo/enterprise#111420
This update ensures the digital VAT book file includes the required operation code even when the VAT rate is zero. It helps prevent validation errors when uploading the file to ARCA and keeps the report compliant with local tax specifications.
Original PR description
**Description of the issue/feature this PR addresses**: When uploading the digital VAT book txt file to ARCA, the operation code must be reported when the VAT rate is zero. Validation file: https://www.afip.gob.ar/iva/documentos/Libro-IVA-Digital-Especificaciones.pdf page 10, "Campo 20: Código de operación." Specification: https://www.afip.gob.ar/iva/documentos/libro-iva-digital-diseno-registros.pdf (page 4 "Diseño de Registro Compras e Importación de Bienes- Cabecera"). **Current behavior before PR**: The operation code is not being reported in the digital VAT book txt file when the VAT rate is zero. **Desired behavior after PR is merged**: The operation code is being reported in the digital VAT book txt file when the VAT rate is zero. _Task Adhoc side_: 55146 _Task latam side_: 1357
This update ensures the operation code is included in the Argentine digital VAT book file even when the VAT rate is zero. It helps prevent validation errors when submitting the file to the tax authority, making VAT reporting more reliable.
Original PR description
**Description of the issue/feature this PR addresses**: When uploading the digital VAT book txt file to ARCA, the operation code must be reported when the VAT rate is zero. Validation file: https://www.arca.gob.ar/iva/documentos/Libro-IVA-Digital-Especificaciones.pdf page 10, "Campo 20: Código de operación." Specification: https://www.arca.gob.ar/iva/documentos/libro-iva-digital-diseno-registros.pdf (page 4 "Diseño de Registro Compras e Importación de Bienes- Cabecera"). **Current behavior before PR**: The operation code is not being reported in the digital VAT book txt file when the VAT rate is zero. **Desired behavior after PR is merged**: The operation code is being reported in the digital VAT book txt file when the VAT rate is zero. _Task Adhoc side_: 55146 _Task latam side_: 1357 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
Mobile users can no longer select combo products directly on the sales order line form. This avoids creating incomplete zero-price lines without the required child items, which could cause errors or incorrect orders.
Original PR description
Combo products bypasses the configurator in mobile view, resulting in a 0-price line with no child lines. Exclude them via domain on the field. opw-5999935
This update fixes an error that could prevent users from generating a W2 CSV file when the End Date field was left blank. If no end date is provided, the system now uses the current year in the file name so the export completes successfully.
Original PR description
Currently, an error occurs when user tries to create a csv for w2 form with no end date defined. Steps to replicate: - Install `l10n_us_hr_payroll`. - Open Payroll > Reporting > W2 Report. - Click…
Currently, an error occurs when user tries to create a csv for w2 form with no end date defined.
Steps to replicate:
- Install `l10n_us_hr_payroll`.
- Open Payroll > Reporting > W2 Report.
- Click `New` > Remove value from `End Date` and click Generate.
Error:
```
File '/home/odoo/odoo19/enterprise/l10n_us_hr_payroll/models/l10n_us_w2.py', line 249, in action_generate_csv
self.csv_filename = f'form_w2_{self.date_end.year or date.today().year}.csv'
^^^^^^^^^^^^^^^^^^
AttributeError: 'bool' object has no attribute 'year'
```
Cause:
- As the user did not give any value for `End Date`, False was passed and when the execution flow reached [here] `self.end_date` is False and attempting to access `self.end_date.year` results in this error.
Solution:
- If we do not receive the `self.end_date` while generating the CSV, we will use the current year to generate the CSV file name.
[here]: https://github.com/odoo/enterprise/blob/01be8d6e9384bcb340559847d529b4887e073519/l10n_us_hr_payroll/models/l10n_us_w2.py#L248
No IDThis update prevents the Attendance kiosk from failing when users search for an employee after selecting a department. It improves reliability by skipping invalid search conditions that could previously cause the kiosk to crash.
Original PR description
**Steps to Reproduce:**
1. Install `hr_attendance` module with demo data.
2. Go to Attendances > Kiosk Mode > Identify Manually.
3. Select any department.
4. Try searching for an employee.
**Error:**
`ValueError - not enough values to unpack (expected 3, got 1)`
**Cause:**
The `employees_infos()` controller assumes that every item in the domain is a valid triplet (field, operator, value). However, the domain may also contain logical operators ('&'), which are not triplets. And then trying to unpack such entries leads to a ValueError.
**Fix:**
Add a validation to ensure the condition is a proper triplet before unpacking. Non-conforming entries (logical operators) are skipped.
sentry-7401444075
opw-6113268This update preserves the green link styling in frozen shared spreadsheets while still preventing those links from being clicked. It matters because dashboard layouts keep their intended look without exposing internal navigation from public views.
Original PR description
Since https://github.com/odoo/odoo/pull/166843, we remove the odoo links entirely from the spreadsheet on `freeze and share`. While it is true that the link is not usable from a public page (and that…
Since https://github.com/odoo/odoo/pull/166843, we remove the odoo links entirely from the spreadsheet on `freeze and share`. While it is true that the link is not usable from a public page (and that we'd somehow leak internal views information in the links), cells with links benefit from a specific style that is not hardcoded on the cell but rather computed based on their content. By removing the links from teh cells altogether, the greenish link style is lost on those cells and we actually rely on that style for our dashboards layout. To preserve the intension of https://github.com/odoo/odoo/pull/166843, we introduce a new type of links `neutralized` which allows the cell to be recognized as a link (and benefit from the style) while disabling their behaviour (no click). Task-6063301 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#256357
This update fixes the Documents app so the browser back button returns users to the previous folder or list instead of reopening the same page. It improves navigation flow and helps users move around Documents more reliably without losing their place.
Original PR description
Bug === When going back in the kanban / list view of the documents module, it reload the same page. Technical ========= They are 2 bugs in reality, not one: - The web client pushes the state in the router when the controller is mounted. This is fine for most Odoo views, but for documents it mean that the kanban view will be restored without the access token in the URL. - When going back, the search model "toggle the category" of the current folder. But, that current folder is not the previous one, and so it re-open the same folder just after redirecting to the previous URL. Task-6050772
This update corrects an issue in the Mexico localization where invoices could end up off by one cent when certain included-tax rates were combined. It restores the expected rounding behavior so totals match the entered price, reducing billing discrepancies for users in Mexico.
Original PR description
**STEP TO REPRODUCE** 1. Install l10n_mx. 2. Change the included in price settings to 'Tax included' for a 16% tax and a 53% tax. 3. Create a invoice with a product with a unit price of 360, add the 53% tax and then the 16% tax. 4. Notice the total of the invoice is 360.01 instead of 360. The issue was discussed with (las), l10n_mx_edi should no longer require to override the rounding mode for taxes. opw-5963855
This change corrects the untaxed amount shown on sales orders and invoices when an early payment discount is used with taxes included in the price. It ensures the discount is treated consistently so customers and accounting teams see the right totals.
Original PR description
Steps to produce: --- - Install the `Sales` module. - Go to `Invoicing > Configuration > Payment Terms`. - Open `Immediate Payment` and enable Early Discount. - Set `Reduced Tax` to `Always (upon…
Steps to produce: --- - Install the `Sales` module. - Go to `Invoicing > Configuration > Payment Terms`. - Open `Immediate Payment` and enable Early Discount. - Set `Reduced Tax` to `Always (upon invoice)`. - Go to Invoicing > Configuration > Taxes. - Create a 21% tax with `Tax included`. - Create a product with a sale price of 7.50 and assign the tax. - Create a Sale Order with this product > Set Immediate Payment as payment term. Issue: --- - The untaxed amount is computed as 6.22 instead of 6.20. Root cause: --- - At [1], in `_add_base_lines_for_early_payment_discount`, the base lines generated for early payment discount were missing the `special_mode='total_excluded'`. - Consequently, the tax engine interpreted these amounts as tax-included and attempted to recompute the untaxed base, resulting in an incorrect untaxed amount. Solution: --- - Add `special_mode='total_excluded'` to the base lines created for early payment discount computation. - This ensures the discount amounts are treated as already tax-excluded. [1]https://github.com/odoo/odoo/blob/a2b4f618328f3ce3f654fd2c1ee4410365706a7e/addons/sale/models/sale_order.py#L515-L550 opw-6023472 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes a bug in Discuss where removing items could sometimes corrupt the internal message list and cause a crash. It improves how records are handled behind the scenes so messages and threads are deleted reliably without breaking the user experience.
Original PR description
Backport of https://github.com/odoo/odoo/pull/251769 Before this commit, Discuss code may crash with the following error: ```js TypeError: Cannot read properties of undefined (reading '_raw') ```…
Backport of https://github.com/odoo/odoo/pull/251769 Before this commit, Discuss code may crash with the following error: ```js TypeError: Cannot read properties of undefined (reading '_raw') ``` This happens because delete operations in JS models could lead to inconsistent state of record lists. Deletion of a record is done internally as follow: ```js const index = recordList.indexOf(record); recordList.splice(index, 1); ``` This is done that way as to reuse custom methods of `RecordList`, especially the `splice()` that is used by many methods that mutate the record list. Internal code of the custom `splice` method does `slice()`, which is used to retrieve some records without mutating the record list. In practice, these `.slice()` were accidentally mutating the list, because they invoke the `Proxy.getter` of the `RecordList`, and when the list is flagged for `computeOnNeed` / `sortOnNeed`, invoking this `Proxy.getter` would mistakenly enable the `computeInNeed` / `sortInNeed` flags and thus mutate the list, e.g. with a sort, which may change the order of items and mess up the `index` computed in `indexOf()` step. This is what might happen with deletion of any item in record list. For example, let's have `menuThreads` that have this value: ```js menuThread = ["thread_1", "thread_2", "thread_3"]; ``` With the removal of `thread_2`, the `.indexOf()` is `1`, but due to `.slice()` triggering the sort, the list was changed to: ```js menuThread = ["thread_2", "thread_1", "thread_3"]; ``` ... And it instead removed `thread_1` but kept `thread_2` in list. This introduce 2 problems: - `thread_1` is mistakenly removed from relation when it shouldn't - `thread_2` is kept, but since this is a local id with no actual record in store, `recordList[index]` would return `undefined` as there's no existing record matching this local id. This commit fixes the issue by improving internal code of record list methods to avoid accidental triggering of lazy re-compute and re-sort. The accidental re-compute and re-sort come from invoking non-implemented array methods on the proxy of record, such as: - `recordProxy.at()` - `recordProxy.slice()` These methods were just used meant to retrieve records from the record list, and they did so by using accessing through `recordProxy`. This approach has the benefit to look good as this is exactly the same as the external API, but it has the unintended side-effect of the re-compute / re-sort of lazy fields. Instead of using these methods, records are retrieved with: - raw access to get local ids in relation - convert local ids to raw records through raw access in `store.recordByLocalId` This approach, while uglier, has the benefit to not accidentally trigger the re-compute / re-sort. Task-4793779
Invoices sent to KSeF will now be accepted even when the buyer does not have an email address or phone number. The export no longer includes empty contact fields, which prevents KSeF validation errors and avoids rejected invoices.
Original PR description
Before this commit: Steps 1. Create a Polish company 2. Create and send an invoice to KSeF where the buyer has no email or no phone number 3. KSeF rejects the invoice with error code 450 (semantic verification error) This happens because `Email` and `Telefon` elements are always rendered inside `DaneKontaktowe`, even when their values are empty, producing invalid empty tags. After this commit: Add `t-if="buyer.email"` and `t-if="buyer.phone"` guards on each field so that `Email` and `Telefon` are only rendered when a value is present. opw-6124187
This fix makes permission error messages more accurate when a user opens an archived record they are not allowed to see. Instead of wrongly suggesting a company-related issue, the system now reports the real rule that blocks access, which should reduce confusion and support requests.
Original PR description
When accessing an archived record directly, if access is prevented by a record rule other than a multi-company global rule, the error message incorrectly reports that all rules are failing, suggesting a company issue even though it is not the actual cause. The problem is that when access is denied, the diagnostic method `_get_failing` is used to determine which rules are failing. This method performs several count queries with different rule domains. However, `active_test` is True by default, excluding archived records from the count, causing the rule evaluation to miss some records and incorrectly mark rules as failing. With this commit, `_get_failing` evaluates rules with `active_test=False`, ensuring that only actually failing rules are reported. Forward-Port-Of: odoo/odoo#259344
3 changes
Enhancements to existing features
This update removes Odoo’s hard dependency on an outdated Python packaging helper that is being phased out. It helps the system stay compatible with newer Python setups and reduces the risk of installation or startup issues as those tools evolve.
Original PR description
pkg_resources is deprecated as a library. It's use becomes problematic as, for instance, since setuptools 71, importing pkg_resources makes all vendored dependencies of setuptools visible on sys.path. pkg_resources is even entirely removed since setuptools 81. This commit keeps pkg_resources as a primary approach for compatibility reason but provides a fallback when not present (like with an up-to-date setuptools) without changing the current requirements (i.e. no additional dependency on `packaging`). Note: while not a backport, this is inspired by odoo/odoo#181768
Resolved issues and error corrections
This change rolls back a previous update that altered how child contact names were shown in invoices and partner records. It helps restore the prior display behavior for customers and prevents unexpected name formatting changes in business documents.
Original PR description
This reverts commit 0ef4c1d06fdf999ad5cdad696069aec8f2f943c5. opw-5900567
The system now decides whether to add the co-contractant tax exemption note based on the invoice’s fiscal position instead of the customer’s. This avoids inconsistencies in exported invoice data and helps ensure the legal note matches the actual invoice setup.
Original PR description
The decision to add a tax exemption reason for co-contractant fiscal position was being decided by the FP of the customer which could cause inconsistencies, instead, it is now tied to the FP of the invoice related-task-id-5905176