Daily updates from Odoo
Monday, April 20, 2026
22 changes · 18.0
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
This update makes workcenter graph data much faster to generate, especially when there are many related work orders. It reduces repeated database lookups by checking work orders more efficiently and reusing calendar calculations when several workcenters share the same schedule.
Original PR description
Before this commit, calling the method `_prepare_graph_data` with a recordset of workcenters, would traverse the recordset and then check if all the workcenters has at least one workorder by fetching…
Before this commit, calling the method `_prepare_graph_data` with a recordset of workcenters, would traverse the recordset and then check if all the workcenters has at least one workorder by fetching the field `order_ids` for all the workcenters. This can be too slow in cases where the workcenters have a lot of workorders and in addition to that there is no need to do this repeatedly for every workcenter. In this commit, I have modified the check by invoking a `search_count` on the workorders before iterating over the recordset and in addition to that I have pre-computed the sum of the duration hours of the attendances related to a `resource_calendar` as multiple workcenters might have the same `resource_calendar` The benchmark done below, was on a database that contained 78 workcenters. | Workorders | Before | After | | :--- | :--- | :--- | | 1380828 | 12s | 0.16s | | 138082 | 1.21s | 0.14s | | 13808 | 0.21s | 0.09s | opw-6040077 --- 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 makes an unstable HR leave test run consistently by fixing the date it uses during execution. It prevents random failures caused by weekends or existing demo data, so automated checks are more reliable.
Original PR description
### Issue before this commit: The test test_manager_can_approve_from_leave_report_calendar is unstable and fails depending on the execution date or existing demo data. ### Cause of the issue: The test lacks temporal isolation. Odoo's constraint logic triggers a ValidationError when a leave is requested on a non-working day or overlaps with existing records: odoo.exceptions.ValidationError: The following employees are not supposed to work during that period: David Employee. Commit that caused the error: https://github.com/odoo/odoo/commit/83d5c84fa0ead1557fbb6eff6855f77ee4771dc4 ### Reason to introduce the fix: To ensure test determinism by using @freeze_time. Freezing the date to a known working weekday prevents intermittent failures caused by the real-time calendar and ensures the focus remains on validating the manager's approval flow. runbot-242574 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
We fixed an automated test in the salary package module so it no longer depends on demo-only sample data. This makes the test more reliable and helps avoid failures in environments where demo data is not available.
Original PR description
### Issue: - We were referring an existing XML ID in our test case, but that record is only created in demo data. ### Fix: - No need to use the demo record Id, instead, create a new record. Task: 6115762
This 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 updates the Mexican e-invoicing test so it matches the restored rounding behavior. It helps prevent false test failures and keeps the validation aligned with how invoices are now calculated.
Original PR description
https://github.com/odoo/odoo/pull/255574 change the rounding mode back to mixed. This break the test modified in this PR. opw-5963855
This change restores the previous way child contact names are shown in invoices and related customer records. It helps ensure contact names appear as expected for users who work with company contact hierarchies.
Original PR description
This reverts commit 0ef4c1d06fdf999ad5cdad696069aec8f2f943c5. opw-5900567 Forward-Port-Of: odoo/odoo#260065
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
This change updates Sendcloud delivery tests so they are no longer treated as external-only checks. As a result, issues in these tests will be caught earlier in normal CI instead of only appearing in nightly runs, improving reliability of delivery-related updates.
Original PR description
Test class was tagged as external although calls are mocked. This means errors were only caught in nightly and not by CI. Removing the tag requires fixing some of the tests. For `test_multicollo`, we send the average weight of packages instead of the total since 97f82442c9fee7dcb3e8c5e9bacddcd6bb864e11.
This update corrects the account identifiers used in the Luxembourg FAIA XML export so they match the official ledger account codes. It helps ensure the exported file is valid and accepted by downstream systems without manual fixes.
Original PR description
This is one of several commits fixing the FAIA xml export. The Invoice/Line/AccountID element in SourceDocuments/SalesInvoices and SourceDocuments/PurchaseInvoices must match an account defined in MasterFiles/GeneralLedgerAccounts/Account/AccountID. As the latter uses account_code since PR #65221, the former should too. opw-5427296 [Link](https://www.odoo.com/odoo/unassigned-tasks/5427296) Forward-Port-Of: odoo/enterprise#113455
This update corrects a missing parameter in the project task kanban view logic. It helps ensure task information is passed properly, reducing the chance of errors or unexpected behavior when users work with project tasks.
Original PR description
This commit adds a missing parameters to the parent call. task-5498274 Forward-Port-Of: odoo/odoo#260143