Monday, September 28, 2026
8 changes · 18.0
Enhancements to existing features
When importing Peppol or UBL invoices, Odoo now gives priority to the default tax set on the selected account when it matches the invoice data. This helps businesses apply the intended tax more reliably when several similar taxes exist, while keeping the existing behavior when no suitable account default tax is found.
Original PR description
Before this commit: - When importing a Peppol/UBL invoice, Odoo selects the account that will be used on the invoice line. - If that account has a default tax configured, it is ignored during tax matching. When multiple taxes in the database match the tax information from the XML, it selects the first matching tax. After this commit: - If the selected account has a default tax matching the tax information from the XML, it uses that tax instead of the first matching tax in the database. - If the account has no matching default tax, it keeps the existing tax matching logic. Task-6345661
Resolved issues and error corrections
Peruvian credit and debit notes in foreign currency now use the exchange rate from the original invoice they modify, instead of the note's own date. This keeps PEN tax amounts aligned with SUNAT rules and reduces incorrect exchange differences and reporting mismatches.
Original PR description
Description of the issue/feature this PR addresses: In Peru, foreign currency operations are converted to PEN with the exchange rate of the date on which the IGV obligation arises (article 5, numeral…
Description of the issue/feature this PR addresses: In Peru, foreign currency operations are converted to PEN with the exchange rate of the date on which the IGV obligation arises (article 5, numeral 17 of the IGV Law Regulation). SUNAT considers that a credit or debit note only changes the amount of the operation it modifies, not the date on which that obligation arose, so the note has to be converted with the exchange rate of the modified document (Oficio N.° 024-2000-K00000 on a credit note, Informe N.° 118-2016-SUNAT/5D0000 on a debit note subject to the SPOT system). The SIRE proposals apply the same rule (RVIE: note 3 of Annex 2 of RS N.° 112-2021/SUNAT, as amended by RS N.° 000138-2023/SUNAT; RCE: notes 1 and 4 of Annex 8 of RS N.° 040-2022/SUNAT). Legal basis (official SUNAT sources): - IGV Law Regulation, article 5, numeral 17: https://www.sunat.gob.pe/legislacion/igv/regla/cap4.htm - Oficio N.° 024-2000-K00000: https://www.sunat.gob.pe/legislacion/oficios/2000/oficios/o0242000.htm - Informe N.° 118-2016-SUNAT/5D0000: https://www.sunat.gob.pe/legislacion/oficios/2016/informe-oficios/i118-2016.pdf - RVIE, Annex 2, note 3 (RS N.° 000138-2023/SUNAT): https://www.sunat.gob.pe/legislacion/superin/2023/anexoII-000138-2023.pdf - RCE, Annex 8, notes 1 and 4 (RS N.° 040-2022/SUNAT, p. 28): https://www.sunat.gob.pe/legislacion/superin/2022/anexo-040-2022.pdf Current behavior before PR: Credit and debit notes currently use the rate of their own invoice date, so: - their PEN amounts (base and IGV) differ from the ones of the modified invoice; - an exchange difference entry is created when they are reconciled with the modified invoice; - the rate reported in the PLE/SIRE files differs from the SUNAT proposal. Steps to reproduce: - PE company with USD rates of 4.00 PEN on 2024-01-01 and 5.00 PEN on 2024-02-01 - Post a USD invoice of 1,000.00 dated 2024-01-15 - Add a credit note dated 2024-02-15 - The credit note is converted at 5.00 (5,000.00 PEN) instead of 4.00 (4,000.00 PEN) Desired behavior after PR is merged: For PE companies, the date used to compute the currency rate of a credit or debit note linked to the document it modifies is now the rate date of that document, as done for l10n_cz and l10n_hu_edi in 063dba210a39. As that date is taken recursively, a note of a note keeps the rate of the first document, so that a note and its reversal share the same rate. The link fields are added as dependencies of the rate computations, so that the rate is recomputed when a note is linked after its creation. The rate date is adapted instead of copying the rate of the modified document because the rule refers to the rate published on that date, and because the expected rate then stays equal to the invoice rate, so the rate is not displayed as manually modified. 17.0 counterpart: odoo/odoo#288654. In 17.0 the currency rate is computed on each invoice line, so the fix is done on `account.move.line._get_rate_date` (as in d5a772458d4e) and forward-port is disabled there. This PR follows the normal forward-port. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Users expanding a record from views such as Gantt now see the intended form instead of a generic default form. This helps portal and shared project users land on the right screen, reducing confusion and keeping the workflow consistent.
Original PR description
When a user expands the form view (e.g., from the Gantt view),
a default low-priority form view is opened because the
specific form view ID is not passed during dialog initialization.
This commit introduces the expandedFormRef props to FormViewDialog,
allowing users to specify the exact form view to be used when expanding.
Use case:
In project task sharing, when a portal user expands a task from
the Gantt view, we want to open the project sharing form view
instead of the default backend view.By passing the expandedFormRef
(form view ID) while opening the dialog, we ensure the correct view
is used.
this.dialogService.add(
FormViewDialog,
{
title,
resModel,
...
context: {
expandedFormRef: formViewId,
}
}
);
backport-https://github.com/odoo/odoo/pull/199912/changes/4f71fbbd26b428e57943d974e8441bef295cdef1
task-6356431This fix prevents cards from jumping away from the cursor when users drag them near the edge of wide kanban-style views in right-to-left languages. It improves usability for teams working in RTL interfaces by keeping dragged items aligned with the user's pointer.
Original PR description
Before this commit, dragging an element (e.g. a kanban card) close to the edge of a horizontally overflowing container in a RTL language made it jump away from the cursor instead of following it. This is because `updateRects()` computes the horizontal bounds used to clamp the dragged element's position by assuming overflowing content always extends to the *right* of the container. (`containerRect.left + container.scrollWidth`). This holds in LTR, but in RTL a flex row starts from the right, so overflowing content extends to the left of the container's box instead. The container's own computed direction is now used to anchor the overflow calculation on the correct edge. opw-6488992
Expanding a timesheet row now opens the intended timesheet form instead of a more generic analytic line form. This prevents confusion for users and keeps them in the correct workflow when reviewing or editing timesheet entries.
Original PR description
Steps: ------ - Install timesheet_grid. - Go to my timesheets and add a line. - Click the expand button. Issue: --------- When a user expanded form view , the wrong timesheet form view is opened. Cause: --------- The system opens the view with the lowest sequence. As a result, the analytic line form view is opened instead of the timesheet form view. Fix: -------- Pass the reference of the expanded form view so that the correct timesheet form view is opened instead of the view with the lowest sequence. task-6356431
This fixes an issue where attachments with apostrophes or other special characters in the filename could download as a text file containing a link instead of the real file. Users can now download these attachments normally, reducing confusion and failed file access in everyday workflows.
Original PR description
**Description of the issue/feature this PR addresses:** When downloading an attachment with an apostrophe in its name (e.g., file'name.zip), the system incorrectly downloads a text file containing…
**Description of the issue/feature this PR addresses:** When downloading an attachment with an apostrophe in its name (e.g., file'name.zip), the system incorrectly downloads a text file containing the URL instead of the actual file. This occurs because of the current url validation check: `if (anchor.href.indexOf(url) !== -1)`. When the raw URL is assigned to the anchor's href attribute, the browser automatically normalizes special characters (converting the literal ' to %27). The strict string comparison then fails, causing the script to skip the XHR request and fall back to generating a Blob from the raw URL string. This commit resolves the issue by removing the overly strict indexOf check. Based on the function's description, if it is called with only one argument (no filename and no mimetype), the system already expects that argument to be a URL. By removing the check, we proceed directly to the XHR request. If the payload is a valid URL (even with normalized characters), the download succeeds. If raw contents are passed by mistake, the system will now fail loudly with an XHR error that is easy to debug, rather than silently downloading a text file named after its own contents. **Steps to reproduce:** - Discuss > choose any chat and upload any file containing an apostrophe > attempt to download the file > observe incorrect text file containing the URL string **Current behavior before PR:** - Downloading attachments with special characters such as apostrophes results in a text file containing the URL instead of the actual file **Desired behavior after PR is merged:** - Downloading attachments with special characters such as apostrophes results in the actual file opw-6580287
When securing accounting entries, users can now open draft entries directly from the review list. This makes it easier to inspect and resolve draft items that block the secure entries process, especially before they receive an official number.
Original PR description
Steps to reproduce --------------------- - Install accountant module; - Create a draft entry; - Go to Accounting > Secure Entries; - Select a date after the draft entry's date; - A warning is displayed about the draft entry; - Click on "Review"; - You cannot open the entry from the list view. It is difficult to retrieve those specific entries from the global list view as they don't have a number because they are in draft. Why is it happening -------------------- The returned action only contains 'list' as 'view_mode' value. opw-6535730 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Invoices sent through Peppol are no longer blocked when a line has a quantity of zero. This prevents valid invoices from being incorrectly rejected as missing quantity information, helping businesses send special-case or adjustment invoices without manual workarounds.
Original PR description
Fixes #289575. ### Impacted versions 18.0 and 19.0. The constraint arrived with 081221a4cc2ff72f16be0e1d073112b938de0f19 ("[FIX] account_edi_ubl_cii, account_peppol: make PINT use UBL export",…
Fixes #289575.
### Impacted versions
18.0 and 19.0. The constraint arrived with 081221a4cc2ff72f16be0e1d073112b938de0f19 ("[FIX] account_edi_ubl_cii, account_peppol: make PINT use UBL export", 2026-08-20).
master is not affected: the IBR constraint block was dropped from `account_edi_ubl_pint.py` there, so nothing checks the quantity.
### Steps to reproduce
1. A company with Peppol enabled, and a customer with a Peppol endpoint.
2. Create a customer invoice and set the **quantity to 0** on one line, leaving its unit price set.
3. Confirm, then **Print & Send** over Peppol.
### Current behavior
Sending is refused with `Line 1: Invoiced quantity is missing [IBR-022]`, although the quantity is there: `cbc:InvoicedQuantity` is built for every line and renders as `0.0`.
`account_edi_ubl_pint.py` read
```python
qty_node = line['cbc:InvoicedQuantity'] if is_invoice else line.get('cbc:CreditedQuantity', {})
if qty_node.get('_text') in [None, False]:
```
and `_text` holds the raw float taken from `base_line['quantity']` in `_ubl_add_line_invoiced_quantity_node`. Since `0.0 == False` in python, `0.0 in [None, False]` is `True`, so a present quantity of 0 is treated as missing.
`account.edi.xml.ubl_bis3` inherits `account.edi.ubl_pint_eu`, so this refuses plain Peppol BIS Billing 3.0 exports too, not only PINT.
### Expected behavior
The line exports and sends. A quantity of 0 is a value, and EN16931 BR-22 asks for the invoiced quantity to be present, not to be non-zero.
### About the fix
Absence is tested by identity, so 0 passes while a missing or `False` value is still reported:
| `_text` | before | after |
|---|---|---|
| `0.0` | reported missing | accepted |
| `0` | reported missing | accepted |
| `1.0` | accepted | accepted |
| `None` | reported missing | reported missing |
| `False` | reported missing | reported missing |
`isinstance(qty_text, (int, float))` would have been the shorter test but `isinstance(False, int)` is `True` in python, so `False` would no longer be caught.
The neighbouring constraints in that method do not share the problem. Nine of them read string values, where falsiness is the intended test, and the only other numeric one checks `isinstance(line['cbc:LineExtensionAmount']['_text'], FloatFmt)`, which no value of 0 can fail. `in [None, False]` occurs nowhere else under `addons/`.
### Test
`TestUblExportBis3BE.test_ubl_line_with_zero_quantity`, next to the existing `test_ubl_line_without_product_name`, which it follows. It asserts only on the quantity constraint, so the other constraints a minimal test invoice raises do not mask it.
Verified both ways on 18.0:
- without the fix: `AssertionError: ['Line 1: Invoiced quantity is missing [IBR-022].'] is not false`
- with the fix: `0 failed, 0 error(s) of 1 tests`
### Credit
Reported and diagnosed by @Robrechtc in #289575, including the cause and the suggested fix.