Wednesday, August 26, 2026
29 changes · saas-18.3
Enhancements to existing features
This update makes an internal mail test helper safer when test data contains unusual values. It helps prevent automated test runs from crashing in parallel environments, improving reliability for developers without changing customer-facing behavior.
Original PR description
If the value needs to be serialized for IPC (cough cough pytest-xdist) and a weirdo sets recordsets as message values, the serialization fails and the test suite crashes. Since this is just subtest identification it shouldn't be too much of an issue. Forward-Port-Of: odoo/odoo#284178
Resolved issues and error corrections
This fix ensures expenses or vendor bill lines linked through shared or multiple analytic accounts are correctly matched to the relevant sales order for reinvoicing. It prevents valid project links from being missed, so customers are billed more reliably for reinvoiceable costs.
Original PR description
### Before this fix --- The `_get_so_mapping_from_project()` method returns a mapping where the key is the move line ID and the value is a `sale.order` record (or `None`). Because of the issues…
### Before this fix
---
The `_get_so_mapping_from_project()` method returns a mapping where the key is
the move line ID and the value is a `sale.order` record (or `None`).
Because of the issues described below, a valid `sale.order` could be available
for reinvoicing, but the corresponding move line might still not be mapped to
that sale order. As a result, the move line is not added to the reinvoiceable
sale order.
However, the implementation has two issues:
#### 1. Projects are overwritten when they share the same analytic account
`project_per_accounts` is built as a dictionary mapping an analytic account ID
to a single project. If multiple projects reference the same analytic account,
each new assignment replaces the previous one. As a result, only the last
project associated with a given analytic account is retained.
**Example:**
* Analytic Account **AA1** is linked to **Project A** and **Project B**.
* The dictionary becomes `{AA1: Project B}`.
* **Project A** is lost, even though it also references **AA1**.
**Steps to reproduce:**
1. Create an analytic account **AA1**.
2. Create **Project A** and **Project B**, both linked to **AA1**.
3. Create **Sale Order SO1** linked only to **Project A**.
4. Create a vendor bill (or expense) that generates an AML using **AA1** for a
product configured with **Reinvoice Costs = At Sales Price**.
5. Validate the document.
**Expected behavior:**
The product should be added to **SO1** for reinvoicing.
**Actual behavior:**
The move line is not mapped to **SO1**, so no sale order line is created.
#### 2. Previously found projects are overwritten during iteration
The `project` variable is reassigned on every iteration of the loop. After the
loop completes, it only contains the project (or lack of one) corresponding to
the last processed analytic account. This can cause valid projects found earlier
in the loop to be discarded.
**Example:**
* Move line has analytic accounts **AA1** and **AA2**.
* **AA1** maps to **Project A**.
* **AA2** has no linked project.
* After the loop, `project` is `None`, even though **Project A** was found.
**Steps to reproduce:**
1. Create analytic accounts **AA1** and **AA2**.
2. Create **Project A** linked to **AA1** only.
3. Create **Sale Order SO1** linked to **Project A**.
4. Create a vendor bill (or expense) whose AML is distributed between **AA1**
and **AA2**, where **AA2** is processed after **AA1**.
5. Validate the document.
**Expected behavior:**
The move line should still be mapped to **SO1** because **AA1** references
**Project A**.
**Actual behavior:**
The last processed analytic account (**AA2**) overwrites the previously found
project, causing the move line not to be linked to **SO1**.
### After this fix
---
* `project_per_accounts` stores **all** projects associated with each analytic
account instead of keeping only the last one.
* The project lookup preserves all valid project candidates instead of
overwriting previously found results during iteration.
* As a result, the method can resolve the related `sale.order` in more cases,
improving the overall accuracy of the mapping.
> **Note:** This change prevents valid project associations from being lost
> when multiple projects share an analytic account or when multiple analytic
> accounts are processed for the same move line.
**OPW:** 6294615
Forward-Port-Of: odoo/odoo#277110The French e-invoicing flow now shows a clearer message when a credit note cannot be generated for EDI. This helps users understand the problem faster and reduces confusion during document sending.
Original PR description
Steps to reproduce: - Install `l10n_fr_pdp` module > Switch to `FR Company` - Activate `French e-invoicing` (Demo mode) - Create a New `Credit Note` with `FR Customer` > Send Issue: The system currently displays a confusing error message during EDI document generation. We are making the error message clearer and more user-friendly. opw-6412521 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284189
This fix makes an automated mail test wait for the correct mention suggestion list instead of an unrelated status update. It reduces false failures in the testing pipeline, helping keep releases stable without changing user-facing behavior.
Original PR description
Before this commit, the test "select @ mention from the suggestion list being filtered" could fail on runbot, on the check that follows the first "@": Failed to find 2 of ".o-mail-Composer-suggestion" (Timeout of 10 seconds). Found 0 instead. This happens because the test holds a render open on ImStatus, a component the member list renders as well as the composer. The composer tells the server that the user is typing, the bus sends the status back, and the member list re-renders its ImStatus with another class. The hold catches that render, the one that also brings the suggestions on screen. This commit gives the children of NavigableList an inNavigableList environment flag, and holds the render only on an ImStatus that has it. https://runbot.odoo.com/odoo/error/946282
This fix prevents invoice printing from crashing when an Argentine company's tax ID is present but not valid as a local CUIT. It helps users complete invoice printing reliably even when partner VAT data comes from another country format.
Original PR description
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR)…
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR) Exento`` Company - Go to Invoicing > Configuration > Journals > Open ``Ventas Preimpreso`` journal > ARCA POS System: ``Electronic Invoice - Web Service`` > Save - Create a new invoice with ``ADHOC SA`` partner > Confirm the invoice - Open the ``(AR) Exento`` partner and set the VAT to ``BE0477472701`` - Open the Invoice > print Traceback: ```py ValueError: invalid literal for int() with base 10: 'BE0477472701' ``` After this [commit], companies outside the EU can use European VAT numbers. Consequently, an Argentine partner can have a CUIT number such as ``BE0477472701``, which is valid as a Belgian VAT number but not as a CUIT. When printing the invoice, the ``l10n_ar_vat`` field is computed from the partner's VAT and its value is passed to ``int()``, causing a traceback at the following line: https://github.com/odoo/enterprise/blob/d55486866d09f8aa87c2003dab722cfa323068b4/l10n_ar_edi/models/account_move.py#L138 [commit]: https://github.com/odoo/odoo/commit/a2afe3292e1cd0a4f339dc47707e469653d13ea0 Enterprise PR: https://github.com/odoo/enterprise/pull/127820 sentry-7666042143 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix ensures Odoo only suggests a Buy route that is valid for the user's active company access when creating products. It prevents access errors and avoids assigning purchasing routes from another company in multi-company setups.
Original PR description
## **Steps to reproduce:** 1. Install the Inventory and Purchase module and enable Multi-Step Routes. 2. Open the Buy route and set Company A as its company. 3. Create a user who has access only to…
## **Steps to reproduce:** 1. Install the Inventory and Purchase module and enable Multi-Step Routes. 2. Open the Buy route and set Company A as its company. 3. Create a user who has access only to Company B. 4. Log in as this user and navigate to Products. 5. Click New to create a product. 6. An AccessError is raised because the Buy route belongs to Company A, which is not accessible to the user. ## **Issue:** The buy route returned by `env.ref` is not necessarily applicable to the current company. Returning `buy_route.ids` directly can therefore cause issues when creating a product in a multi-company environment. When the user has access to multiple companies, the buy route belonging to another company can be selected during product creation. When the user does not have access to the company of the buy route, this can instead result in an AccessError. The previous implementation performed an ORM search on `stock.route`, which implicitly filtered the route according to the current environment. However, that query was removed as part of this pr https://github.com/odoo/odoo/pull/276554. ## **Solution:** Filter the route returned by env.ref against the companies available in the current environment before returning its ID. Use sudo() while filtering so that the route's company_id can be read even when the route belongs to a company inaccessible to the current user. The route is still explicitly checked against env.companies, so sudo() does not allow an inaccessible company's route to be returned. opw-6448497 Runbot Video : [Video](https://drive.google.com/file/d/1qQyJrPNwXuHtu6GXyC_78dtd_A24khFR/view?usp=sharing) Forward-Port-Of: odoo/odoo#284179 Forward-Port-Of: odoo/odoo#283199
This update prevents warning messages and potential compatibility issues when Odoo loads email and certificate keys with newer system versions of a security library. It helps deployments using operating system packages continue to run cleanly without changing business workflows.
Original PR description
pyOpenSSL 24.3.0 deprecated passing its own X509/PKey objects to Context.use_certificate()/use_privatekey(), and started accepting cryptography objects instead. Odoo pins pyopenssl 24.1.0, but the distro builds run the version shipped by the OS: since the test added by f0fb287c6502 covers that path, they now add a warning in the logs. Load the certificate and the key as cryptography objects when the installed pyOpenSSL supports them, keep the previous loaders otherwise. Reference: https://github.com/pyca/pyopenssl/commit/b0cb4b4 This fix is based on https://github.com/odoo/odoo/blob/a2b4f618328f3ce3f654fd2c1ee4410365706a7e/odoo/addons/base/models/ir_mail_server.py#L34-L46 runbot-944176 Forward-Port-Of: odoo/odoo#277449
Copying an image that is already attached to another record now reuses the existing file instead of leaving behind an unnecessary duplicate. This helps keep stored files cleaner and avoids extra clutter from repeated image copies.
Original PR description
Copying an image attachment already linked to another record could leave a redundant duplicate behind instead of reusing the existing one. opw-6463012 Forward-Port-Of: odoo/odoo#283221 Forward-Port-Of: odoo/odoo#282287
This fix prevents invoice printing from crashing when an Argentine company record contains an invalid CUIT tax identifier. Users can now avoid an unexpected error during invoice printing, improving reliability for Argentine electronic invoicing workflows.
Original PR description
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR)…
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR) Exento`` Company - Go to Invoicing > Configuration > Journals > Open ``Ventas Preimpreso`` journal > ARCA POS System: ``Electronic Invoice - Web Service`` > Save - Create a new invoice with ``ADHOC SA`` partner > Confirm the invoice - Open the ``(AR) Exento`` partner and set the VAT to ``BE0477472701`` - Open the Invoice > print Traceback: ```py ValueError: invalid literal for int() with base 10: 'BE0477472701' ``` The issue occurs because when the partner's identification type is CUIT, At [1] ``_run_check_identification()`` method does not include partners whose identification type has ``is_vat=True``. As a result, CUIT is not validated by ``_run_check_identification()`` method in ``l10n_ar`` module at [2]. So, partner's ``l10n_ar_vat`` field can be computed as ``BE0477472701``. Passing this value to ``int()`` raises the traceback during invoice printing at below line. https://github.com/odoo/enterprise/blob/d55486866d09f8aa87c2003dab722cfa323068b4/l10n_ar_edi/models/account_move.py#L138 [1]:https://github.com/odoo/odoo/blob/c2a39085ba0fbcf8a0e6a55228191e764499caea/addons/l10n_latam_base/models/res_partner.py#L24-L30 [2]:https://github.com/odoo/odoo/blob/c2a39085ba0fbcf8a0e6a55228191e764499caea/addons/l10n_ar/models/res_partner.py#L55-L65 Community PR: https://github.com/odoo/odoo/pull/282454 sentry-7666042143
The Edit option on appointment pages now opens the selected appointment record correctly from the kanban view. This removes a dead-end for website administrators managing appointment pages and makes editing appointments more reliable.
Original PR description
Steps to reproduce: 1. Install website_appointment 2. Website > site > appointment > kanban view 3. On a record, open the dropdown menu and click Edit. Issue: The Edit button does nothing. Cause: The Website appointment pages action only defines list,kanban views. When the kanban Edit action is triggered, the web client tries to switch to a form view, but no form view is available in the action, so nothing happens. Solution: Add the `appointment_type_view_form` to the Website appointment pages action and include form in its view_mode, so kanban Edit can open the selected appointment type correctly. opw-6197438 Forward-Port-Of: odoo/enterprise#117381
Swedish ISO20022 payment batches now generate files that correctly match the selected pain.001.001.09 format. This prevents compliant vendor payment files from being rejected by banks when businesses use the Swedish payment method.
Original PR description
**Steps to reproduce:** - Install Accounting and l10n_se - Switch to a Swedish company (e.g. SE Company) - In Accounting settings, set "Identification" with anything - In Bank journal: * Set an…
**Steps to reproduce:** - Install Accounting and l10n_se - Switch to a Swedish company (e.g. SE Company) - In Accounting settings, set "Identification" with anything - In Bank journal: * Set an account number * Make sure "Swedish ISO20022" is available in "Outgoing Payments" * Set "pain.001.001.09" as "XML Format" in "Outgoing Payments" - Create a vendor payment: * Vendor: [a vendor with a trusted bank account] * Payment Method: Swedish ISO20022 * Amount: [any] - Confirm the payment - From the payments list, select the payment and create a batch - Validate the batch payment **Issue:** When the batch is validated, a `pain.001.001.09` file should be generated. However, its content is that of a `pain.001.001.03` file, even if the version reported in the file is `pain.001.001.09`. For example, `<ReqdExctnDt>` should contains a subnode `<Dt>` in `001.001.09`, which is not the case. It leads to the file being rejected as non-compliant to `pain.001.001.09`. opw-6472050 Forward-Port-Of: odoo/enterprise#128598
When users drill into accounting report figures, they can now review the related journal items using all available view modes, such as pivot, graph, kanban, and list. This makes financial audit analysis more flexible and easier to explore without being limited to a single list view.
Original PR description
Problem: When auditing reports, the audit cell action was only showing the journal items in the list view, and not enabling other view modes (pivot, graph, kanban). Steps to reproduce: 1. Go to Accounting > Reporting > Balance Sheet 2. Click on any cell with a number in the report 3. Notice how the journal items are only shown in the list view, and you cannot switch to other view modes. Cause: The action was hardcoded to only show the list view. opw-6403704 Forward-Port-Of: odoo/enterprise#128563
The accounting app now better prevents companies from creating a fiscal year that fully contains an already existing fiscal year. This helps avoid confusing or incorrect financial period setup that could affect reporting and year-end processes.
Original PR description
Before this commit: - The current constraint for overlap check allows if we define a new, larger fiscal year that completely swallows an existing smaller one (e.g., creating Aug 2025 - Nov 2026 when Sept 2025 - Oct 2026 already exists). After this commit: - The constrain domain was changed to consider the above missed case. no task Forward-Port-Of: odoo/enterprise#128942
This fix makes a sales timesheet profitability test ignore unrelated pricelist data that may be installed by other modules. It helps ensure automated test results are consistent and prevents false failures caused by unexpected discounts.
Original PR description
The project profitability test assumes that the service product is sold at its list price. However, some modules such as `pos_pricer` add a globally applicable pricelist in their data. In 18.0, this pricelist can be selected for the test partner even when the pricelist feature is disabled, causing a discount to be applied and the expected profitability amount to differ. The fix is to remove existing pricelists in the test, as done in other tests affected by the same issue, so that the sale order price is deterministic. [error-944526](https://runbot.odoo.com/odoo/error/944526) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282712
Employees can now mark multiple appraisals as done from the list view without triggering an error. The system sends and posts completion messages separately for each appraisal, improving reliability during bulk updates.
Original PR description
Steps to reproduce: - select multiple appraisals and try to mark as done from list view. Issue: - The completion notification uses an appraisal variable assigned by a previous loop, raising an UnboundLocalError. Furthermore, message_notify() requires a singleton. Fix: - notify and post the completion message for each appraisal explicitly. task-6479018 Forward-Port-Of: odoo/enterprise#128207
Saudi e-invoices in SAR now avoid adding a duplicate tax total in the generated XML. This prevents ZATCA validation warnings or errors for common Saudi invoices and helps keep electronic invoicing compliant.
Original PR description
Steps to reproduce: - Create an invoice in a Saudi company (currency SAR) - Process it with ZATCA and review the generated XML file - ZATCA reports a validation error/notification for duplicate tax values, because the XML contains two cac:TaxTotal elements holding the same amount and currency Cause of the issue: _l10n_sa_get_additional_tax_total_vals always appended a second TaxTotal node regardless of the invoice's currency. this extra node is only valid when the invoice currency differs from the company's accounting currency (SAR). Since most Saudi invoices are issued in SAR (same as the company currency), the second TaxTotal was an exact duplicate of the first one's total amount. Solution: Only add the additional TaxTotal node when the invoice currency differs from the company currency opw-6409881 Forward-Port-Of: odoo/odoo#281667 Forward-Port-Of: odoo/odoo#279929
Argentine localization users can now create invoices for foreign customers even when export journals are unavailable or archived. Instead of stopping the workflow with an error, the system falls back to a standard Invoice B document type so invoicing can continue.
Original PR description
### Issue before this commit: Before this commit, users were completely blocked from creating an invoice for a foreign partner (e.g., "Cliente del Exterior") if all exportation journals were archived…
### Issue before this commit: Before this commit, users were completely blocked from creating an invoice for a foreign partner (e.g., "Cliente del Exterior") if all exportation journals were archived or unavailable, as the system would immediately trigger a RedirectWarning error. ### Steps to reproduce the issue: 1. Download Accounting and l10n_ar 2. Go to contacts and create a new one with: 1. Country as United States 2. VAT number ex. 55000002126 3. AFIP Responsibility Type as Cliente del Exterior 3. Go to Journals, filter for sales journals and archive: 1. Electronic Exportation Invoice (FEX) 2. Expo Sales Journal 4. Go to invoices and create a new one for the client you just created 5. As soon as you insert the client you will receive the error: You are trying to create an invoice for foreign partner but you don't have an exportation journal ### Cause of the issue: https://github.com/odoo/odoo/blob/014d58e3204d17db6dcba3c8ab7d8ad35003300e/addons/l10n_ar/models/account_move.py#L186-L189 The _onchange_partner_journal method rigidly enforced the use of an exportation journal for foreign AFIP responsibility types (codes 8, 9, and 10). If the query failed to find an active export journal, the code intentionally threw a hard error instead of providing a fallback mechanism. ### Reason to introduce the fix: This fix is introduced to prevent unnecessary workflow blocks. By catching the missing journal and defaulting the document type to "Invoice B" (code 6), the user can now successfully generate the invoice using a standard domestic sales journal without being forced to configure an exportation journal. opw-6442501 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282971
This fixes an error that could block journal item reconciliation when users worked with multiple related companies selected at the same time. Accounting teams can now reconcile matching entries across company and branch contexts without the process failing due to currency conversion handling.
Original PR description
When having multiple companies selected at the same time, _get_conversion_rate returns: File "/data/build/odoo/odoo/orm/fields_misc.py", line 114, in get raise ValueError("Expected singleton: %s" %…
When having multiple companies selected at the same time, _get_conversion_rate returns:
File "/data/build/odoo/odoo/orm/fields_misc.py", line 114, in get
raise ValueError("Expected singleton: %s" % record)
1 - Create a new company with currency EUR.
2 - Create a branch company underneath the main company.
3 - In Accounting, install fiscal localization, e.g. Belgian Companies on the company configuration settings.
4 - Select an account like 600000 Raw Materials, and enable Allow Reconciliation on this account. The exact account isn't important, only that we can make credits / debits to it to be reconciled.
5 - With only the top level company selected, make a debit of 100 USD, e.g. Vendor Bill, set in currency USD to the account 600000.
6 - Now with only the branch level company selected, make a credit of 100EUR, e.g. Customers Invoices, set in currency EUR to the same account with an amount equal to the credit in step 5. (if 1USD == 1EUR, 1-1), so that there is no residual amount, i.e. credit == debit.
7 - Now select both the top level company and the sub branch company in the company context.
8 - In Journal Items, reconcile the unreconciled journal items for the Account 600000.
With this commit we select the first company of the aml instead of every companies on the amls.
opw-6290703
Forward-Port-Of: odoo/enterprise#123774Helpdesk ticket forms on websites now keep their translations when they are created for a team. This ensures customers see the form in the website or visitor language, regardless of the language used by the employee who configured the helpdesk team.
Original PR description
When a helpdesk team has its website form enabled, a dedicated qweb view is generated from the `ticket_submit_form` template. The arch was read in the language of the user creating or editing the…
When a helpdesk team has its website form enabled, a dedicated qweb view is generated from the `ticket_submit_form` template. The arch was read in the language of the user creating or editing the team, so a team set up by an English user language produced an English form even when the website served another language. Steps to reproduce ================== 1. Set a language other than English as the website default language. 2. While your user language is English, create a helpdesk team with the website form enabled. 3. Open the team form on the website. => The form is rendered in English instead of the website language. Root cause ========== `_ensure_submit_form_view` read the template arch without forcing a language, so it used the current user's language and stored only that value on the generated per-team view. Fix === Read the template arch in the default language of the team's website, so the generated form matches the website language regardless of the user's own language. opw-6303903 Forward-Port-Of: odoo/enterprise#121164
Credit notes created from existing customer invoices in Turkish accounting now use the dedicated sales return account from the journal. This keeps sales and returns reported in the correct separate accounts while preserving exact reversals used for cancellations.
Original PR description
The Turkish chart of accounts keeps sales and sales returns on separate accounts, and the sales journal carries the account to use for returns. A credit note typed in by hand already lands on it, but one created from an existing customer invoice did not. Reversing an invoice copies `account_id` over from the invoice line, and since that field is a stored compute without depends, nothing ever recomputes it, so the return kept the sales account. Set the journal account on the copied product lines instead. Reversals made to cancel an entry are left alone, as those have to mirror the original move exactly for the two to net out, and a plain duplicate is untouched. Task-6438412 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282858
This fixes an issue where submitting expenses across multiple companies could send duplicate emails. It helps keep expense notifications cleaner and avoids confusing repeated messages for employees and approvers.
Original PR description
Fix a small issue resulting in mail duplication when submitting expenses from multiple companies that appeared in the infamous 704a5a19 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
This fix ensures tax records correctly update their usage status when related accounting, expense, point of sale, or purchase records change. This helps prevent outdated tax information from appearing in business workflows and reports.
Original PR description
Currently, `is_used` is computed using queries on `account.move.line`, `account.reconcile.model.line`, etc. As a result, it has no depends and is not automatically updated when records in either model are created, modified, or deleted. This commit reverse M2M fields for respective models and use it as dependency to `_compute_is_used`. It also adds a missing dependency of `is_used` to `_compute_repartition_lines_str`. Forward-Port-Of: odoo/odoo#283406
Fixed an issue where some employee attendance records could lose their link to work entries when early or batch-created attendances crossed UTC day boundaries. This helps keep payroll and attendance data correctly connected and avoids incorrect cleanup of unrelated work entries.
Original PR description
When an early attendance starts on the previous UTC day, the cleanup uses full UTC days as boundaries. This can include an unrelated work entry and remove its attendance link. Use the generated work entries as cleanup boundaries so only entries that can overlap the new entries are considered. opw-6412221 Forward-Port-Of: odoo/enterprise#127040
Fixes an accounting issue where undoing a payment reconciliation could place the reversing cash basis tax entry in the current period instead of the original tax period. This keeps tax reports balanced in the correct month, preventing misleading tax amounts after unreconciliation.
Original PR description
When unreconciling a payment from an invoice with a cash basis tax, the tax cash basis (CABA) entry is reversed. The reversal is supposed to land in the same period as the origin entry so the tax…
When unreconciling a payment from an invoice with a cash basis tax, the tax cash basis (CABA) entry is reversed. The reversal is supposed to land in the same period as the origin entry so the tax report nets to zero for that period. Steps to reproduce: - Enable cash basis and create a cash basis tax (exigibility on payment) - Post an invoice dated in the past with that tax - Reconcile a bank statement line to the invoice - Resequence the cash basis entry so the month is dropped from the name (CABA/08/2026/0001 -> CABA/2026/0001) - Unreconcile the statement line Issue: The reversal CABA entry created on the last unreconcile is dated today instead of the origin entry's month. In the tax report the original tax amount stays in the statement's month while the reversal amount appears in the current month, so the two no longer cancel out. Analysis: While under a monthly journal sequence a past date returns the last day of that month, under a yearly sequence a past date within the current year returns the latter between the move date and today, moving the reversal out of the origin period. opw-6301553 Forward-Port-Of: odoo/odoo#281250
Aged Receivables and Aged Payables now calculate aging periods correctly when horizontal groups are applied. This prevents incorrect amounts from appearing in older periods, giving finance teams more reliable reporting views.
Original PR description
Problem: When using horizontal groups in Aged Receivables / Aged Payables reports, the amounts shown in the Older periods are incorrect. Steps to reproduce: 1. Activate debug mode 2. Go to Accounting…
Problem: When using horizontal groups in Aged Receivables / Aged Payables reports, the amounts shown in the Older periods are incorrect. Steps to reproduce: 1. Activate debug mode 2. Go to Accounting > Configuration > Horizontal Groups 3. Add a new horizontal group that results in at least 2 groups 4. Go to Accounting > Reporting > Aged Receivables / Aged Payables 5. Apply the horizontal group created 6. Notice how the amount in the Older period is incorrect, different from before applying the horizontal group. (It may be coincidentally correct, you can check by applying different aging intervals until you find one that shows the issue) Cause: The periods were not correctly calculated. The number of periods was calculated based on the number of period columns, without taking into account the number of column groups. When using horizontal groups, period columns are duplicated for each group that exists after applying the horziontal group. This is not considered when calculating the number of periods, which results in calculating too many periods and therefore having incorrect durations for each period. opw-6374639 Forward-Port-Of: odoo/enterprise#127570
Deleting an active project will no longer move document folders belonging to archived projects into the trash. This protects existing project documents from being accidentally hidden or disrupted when other projects are removed.
Original PR description
Deleting a project also sends the folders of every archived project to the trash. ### Steps to reproduce - Install `documents_project`, where each project has its own Documents folder linked through…
Deleting a project also sends the folders of every archived project to the trash.
### Steps to reproduce
- Install `documents_project`, where each project has its own Documents folder linked through `project.project.documents_folder_id`.
- Create `Project 1`, `Project 2`, and `Project 3`, then archive the first two.
- Delete `Project 3`.
- The folders of `Project 1` and `Project 2` are moved to the trash with their contents, although both projects still exist and still reference them.
### Cause
`_archive_folder_on_projects_unlinked` only archives folders that are no longer used by any project. This was checked through a `documents.document` domain on `project_ids`.
The domain mixed two conditions on the same relation:
- `('project_ids', '!=', False)` checks that a folder has users,
- `('project_ids', 'not any', [('id', 'not in', self.ids)])` checks that it has no users outside the projects being deleted.
Those conditions are not evaluated the same way by the ORM. The first one keeps archived projects visible by disabling `active_test` internally, while the second one searches `project.project` normally and hides archived projects.
An archived project can therefore be counted as a folder user by one condition and ignored by the other, causing its folder to be archived.
### Fix
Check remaining users directly on `project.project` with `active_test=False`, so archived projects are included. Since only folders of deleted projects can become unused, the search starts from those folders instead of scanning all Documents.
opw-6442976Gantt charts using a weekly view now place tasks in the correct week based on the user's locale, such as weeks starting on Sunday. This prevents extra empty columns and keeps scheduling views aligned with local business expectations without changing standard day, month, or year views.
Original PR description
In Gantt views, for a given focus date, the appropriate time interval is displayed by finding its start and end date, based on the scale. For example, if I focus on 18 may 2026 with a month scale,…
In Gantt views, for a given focus date, the appropriate time interval is displayed by finding its start and end date, based on the scale. For example, if I focus on 18 may 2026 with a month scale, then the whole month of may is displayed. The behaviour was as expected in standard code, because all localisations agree on the beginning of the available scales (day, month, year). In custom code, however, some customer requires to see the gantt charts with a weekly scale. The differences in start of the week based on the localisations and the inconsistencies of use of localStartOf breaks the view. For example, if the localization has the start of the week on a sunday, and a task on the first column starts on a sunday as well, it will get assigned to column before (because it considers sunday as the last day of the previous week). The column before the first column does not exist, so one empty column is created to put the task in it. This commit fixes these inconsistencies so that GanttRenderer behaves as expected with weekly scales, without changing the standard behaviour. Tests are written to check both that the task is assigned to the proper localized week (starting on Sunday) and column (1, not 0). Forward-Port-Of: odoo/enterprise#118625
This update replaces an older loop syntax with the preferred modern form in core background services. It helps keep automated quality checks passing and reduces maintenance friction, with no expected change for end users.
Original PR description
Ruff checks on runbot flagged `while 1:` Preferred syntax is to use `while True` [UP048](https://docs.astral.sh/ruff/rules/while-one) runbot-945983 Forward-Port-Of: odoo/odoo#284009 Forward-Port-Of: odoo/odoo#283962
This fixes an intermittent issue in the Lunch app's automated order check by ensuring the test selects the intended product after changing location. It helps avoid false failures caused by outdated demo products appearing briefly during data reloads, improving confidence in release validation.
Original PR description
The lunch order tour selects `Farm 1` before ordering a product. However, it only waits for the location input to be updated before clicking the first kanban record. With demo data installed, a product from the previous location can still be displayed while the product model is being reloaded. The tour can therefore order a demo product instead of the product created by the test. This notably fails during weekends when the corresponding demo vendor is unavailable. To fix we need to wait for the product created by the test before clicking it. Besides selecting the intended product, this also ensures that the product reload following the location change has completed. [error-181572 ](https://runbot.odoo.com/odoo/error/181572) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281753