Monday, August 24, 2026
19 changes · 18.0
Resolved issues and error corrections
Credit notes created from existing Turkish customer invoices now use the sales return account set on the journal, matching manually entered credit notes. This keeps sales and returns separated correctly in Turkish accounting reports while preserving exact reversals used to cancel entries.
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
French VAT XML submissions now handle long holder names by splitting them into two allowed parts. This prevents report submissions from being rejected when a company or account holder name exceeds the official 35-character limit.
Original PR description
The XSD for XML-EDI does not allow strings longer than 35 for TitulaireDesignation This commit splits the holder name in 2 parts when it is more than 35 characters task-6476440
Odoo now recognizes newer search, social, and AI crawler tools so they are not repeatedly redirected away from default-language website pages. This helps pages be inspected and indexed correctly while keeping normal visitor language behavior unchanged.
Original PR description
Modern crawlers now send an `Accept-Language` header (for example, `en-US,en;q=0.9`), whereas historically they did not. When that language differs from the website's default language,…
Modern crawlers now send an `Accept-Language` header (for example, `en-US,en;q=0.9`), whereas historically they did not. When that language differs from the website's default language, `ir.http._match()` issues a 303 redirect from `/page` to `/<lang>/page`. Since crawlers do not retain cookies, unrecognized agents are redirected on every request and never reach the default-language page. Customers reported that Google Search Console URL Inspection live tests only receive a redirect and that pages remain unindexed. Googlebot itself is not affected because it already matches the existing `bot` token. `_match()` already skips language redirects for recognized bots by serving the default-language page directly. Extend the `bots` user-agent list with modern crawler identifiers, each verified against vendor documentation: * `google-inspectiontool`: Search Console URL Inspection / Rich Results Test * `googleother`: Google generic crawler (`GoogleOther`, `GoogleOther-Image`, `GoogleOther-Video`) * `meta-external`: `meta-externalagent`, `meta-externalfetcher`, and `meta-externalads`, successors to the already-listed `facebookexternalhit` * `meta-webindexer`: Meta AI search indexer * `chatgpt-user`: OpenAI user-request fetcher (currently matched only through the `bot` substring in its info URL, which is fragile) * `claude-user`: Anthropic user-request fetcher * `perplexity-user`: Perplexity user-request fetcher The redirect behavior remains unchanged for human visitors. Localized pages continue to be crawlable through their own URLs (for example, `/fr/page`) via `hreflang` alternates. As a side effect, `link_tracker` and `mass_mailing_sms` no longer count clicks from these crawlers, and website visitor tracking skips them. task-6213245
Invoices for timesheet-based services now use the actual timesheet period selected during invoice creation instead of defaulting to the invoice and due dates. This improves accuracy in Factur-X/CII XML exports and helps customers receive billing documents that reflect the real service period.
Original PR description
### Issue before this commit: Invoices generated from timesheet-based service products show the wrong billing period in the Factur-X/CII XML BillingSpecifiedPeriod — the invoice date (and due date)…
### Issue before this commit: Invoices generated from timesheet-based service products show the wrong billing period in the Factur-X/CII XML BillingSpecifiedPeriod — the invoice date (and due date) instead of the actual timesheet period s elected by the user. ### Steps to reproduce the issue: 1. Download Sales, Timesheets and l10n_de 2. Go to products, find a service product (like flooring service) and set: 1. Create on order as 'project' 2. Invoicing policy as 'Based on Timesheets' 3. Go to sales and create a new quotation with that product, confirm it, and record some hours for July through the smart button 4. Click 'create invoice' and select from 1 July till 30 July 5. Send it and check factur-x.xml 6. The tag BillingSpecifiedPeriod is wrong and report the date of the invoice instead of the selected dates ### Cause of the issue: deferred_start_date/deferred_end_date are never populated when an invoice line is generated from a timesheet-based sale order line. ### Reason to introduce the fix: The wizard already captures the intended timesheet period (timesheet_start_date/timesheet_end_date in the context) but never forwards it to the invoice line, so the correct data is available but unused. Populating deferred_start_date/deferred_end_date from that context, and giving line-level dates priority over document-level fallback dates, ensures the exported XML accurately reflects the billed period. opw-6391359 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Customers using point of sale loyalty rewards will now see next-order coupons on receipts even after the page is refreshed or data is reloaded. This keeps receipts accurate when staff reprint past orders and helps avoid missed customer rewards.
Original PR description
Step to reproduce: = - Complete order with Next order coupon - Open Order and print receipt (This time coupon is visible) - Refresh page Or Reload Data - Same order > Print receipt Issue: = - Next time on-wards next order coupon will not shown on the receipt. Reason: = - Loyalty program data is stored in the uistate which destroyed on refresh page OR reload data. Fix: = - Fetched data from the server when uistate doent have any loyalty program data for that order while receipt printing only. task-5890998 related pr: https://github.com/odoo/enterprise/pull/128730
This fix prevents Shop Floor users from accidentally applying the same added component quantity to every matching manufacturing move when a product appears on multiple BoM lines. Those multi-line products are now read-only in the catalog, reducing incorrect material demand and production adjustments.
Original PR description
**Issue** In an MO, if a product is spread across multiple moves, adding consumption from the Shop Floor app, adds the entered quantity to each of those moves instead of once in total. **Steps to…
**Issue** In an MO, if a product is spread across multiple moves, adding consumption from the Shop Floor app, adds the entered quantity to each of those moves instead of once in total. **Steps to reproduce** - Configure a BoM with multiple component lines that have the same product. - Start a MO with the BoM, then go to the Shop Floor app and choose the "Add Components" option. - Select the product with multiple lines in the catalog and add any amount. - Go back to the MO. -> The amount added in Shop Floor is applied to each line individually, instead of increasing the total demand by that amount. **Cause** By default, editing the consumption from the Shop Floor catalog is not read-only: https://github.com/odoo/odoo/blob/fc7bd92cc52f366a0d8730bca066b757aefe870c/addons/stock/models/stock_move.py#L2615 When the quantity is updated, the controller calls `_update_order_line_info`, which fetches every stock move linked to that product: https://github.com/odoo/odoo/blob/fc7bd92cc52f366a0d8730bca066b757aefe870c/addons/product/controllers/catalog.py#L32-L46 https://github.com/odoo/odoo/blob/fc7bd92cc52f366a0d8730bca066b757aefe870c/addons/mrp/models/mrp_production.py#L3028 The new quantity is then applied to all of them at once: https://github.com/odoo/odoo/blob/fc7bd92cc52f366a0d8730bca066b757aefe870c/addons/mrp/models/mrp_production.py#L3031 https://github.com/odoo/odoo/blob/fc7bd92cc52f366a0d8730bca066b757aefe870c/addons/mrp/models/mrp_production.py#L3046-L3047 **Solution** Backport the fix made in 19.0, which makes those lines read-only: https://github.com/odoo/odoo/commit/c7a894dfbc025eb27528a383f33e9aebbf4bd54e opw-6479210
This fix keeps certificate handling working smoothly across both older and newer server environments. It prevents compatibility warnings or errors caused by changes in a third-party security library, reducing upgrade friction for deployments on recent operating systems.
Original PR description
Starting in pyOpenSSL 24.3.0, the library began phasing out legacy `OpenSSL.crypto` wrapper objects in favor of native `cryptography` primitives. On newer operating systems (such as Debian Trixie or recent Ubuntu releases), passing `OpenSSL.crypto` objects emits a `DeprecationWarning`. However, directly adopting native `cryptography` objects creates a breaking change for older environments (pyOpenSSL < 24.3.0), which strictly expect `OpenSSL.crypto` instances and raise a `TypeError` otherwise. To maintain compatibility across both legacy and modern environments, the adapter needs to detect the installed pyOpenSSL version at import time and provide the corresponding object type expected by the underlying library. Additionally, the local `x509` variable in `init_poolmanager` is renamed to `x509_cert` to prevent namespace shadowing with the `cryptography.x509` module. runbot-944176
The project profitability report now correctly displays cost of goods sold for delivered products when Anglo-Saxon accounting and analytic accounting are enabled. This ensures project managers see the true product cost impact instead of having costs hidden by offsetting accounting entries.
Original PR description
**Problem:** Since this PR https://github.com/odoo/odoo/pull/261798, both cogs lines have an analytic account, which causes the cogs to not appear on the project profitability report because cogs…
**Problem:** Since this PR https://github.com/odoo/odoo/pull/261798, both cogs lines have an analytic account, which causes the cogs to not appear on the project profitability report because cogs lines balance each other **Steps to reproduce:** - enable 'anglo saxon accounting' and 'analytic accounting' settings - create a storable product with automated std category, a cost of 10 and on hand quantity - create a service product and set the 'create on order' field to 'project' - confirm a SO for 1 unit of the product and 1 unit of the service - validate the delivery and create and confirm invoice - from the sale order, click on the project smart button - from the project click on the dashboard smart button **Current behavior:** the cogs section don't appear in the profitability report **Expected behavior:** it should appear with a line with a value of -10 **Cause of the issue:** since this PR https://github.com/odoo/odoo/pull/261798, both cogs line are linked to the analytic account. That's the expected behaviour but in the case of the project profitability reports, it prevents the user the see the cost of the product in the cogs section. That's because, inside the _get_revenues_items_from_invoices() method, bot cogs_line are added to the cogs_line list. https://github.com/odoo/odoo/blob/141cb292dc5e456161119e19f7a91665feaa0198/addons/sale_project/models/project_project.py#L699-L700 So when computing the amount_to_invoice for the costs ml_type, the balance of the lines will zero out each other and amount_to_invoice will be 0. https://github.com/odoo/odoo/blob/141cb292dc5e456161119e19f7a91665feaa0198/addons/sale_project/models/project_project.py#L703-L716 As a consequence, the cost of goods sold section won't be created https://github.com/odoo/odoo/blob/141cb292dc5e456161119e19f7a91665feaa0198/addons/sale_project/models/project_project.py#L718-L719 **fix:** only the line with an account of internal type 'expense' reflects the actual cost of the product sold in the context of the project. So when computing the profitability report that's the only line we should consider **test:** test_report_invoice_items_anglo_saxon_automatic_valuation checks that the cogs section is well displayed in the project profitability report. In the PR (mentionned above) which sets the analytic account on the stock cogs line, lines were added in the test to manually remove the analytic account on the stock cogs line to make the test pass. With the fix of this PR we can remove those additional lines in the test and it will check our use case well again. opw-6412409
Phone and mobile numbers are now formatted whenever partner records are created or updated, not only when edited through a form. This keeps contact data consistent across website checkout, imports, API updates, and other entry points while leaving invalid numbers unchanged.
Original PR description
Phone and mobile numbers were only formatted via @api.onchange, which fires solely in the interactive form view. Numbers set through other write paths (website checkout, data import, RPC/API, other controllers) were stored unformatted. Core was also inconsistent: website_crm's form controller reformats numbers before saving while website_sale checkout and plain ORM writes did not. This fixes the inconsistency and now every write path behaves consistently. Invalid/unparseable numbers are left untouched. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Self-billing invoices received through Peppol can again be imported into the dedicated self-billing sales journal. The change also avoids an error screen for databases where the self-billing module is not installed, improving reliability for affected users.
Original PR description
This PR https://github.com/odoo/odoo/pull/277239 has been merged before being rebased on https://github.com/odoo/odoo/pull/259935/changes/568e3e1d4f100e22bd5e724a6afa6d0437f56830 This commit restores the possibility of importing a self-billing invoice into a dedicated self-billing sale journal, and prevents a traceback from being shown in case the user's DB has no `account_peppol_selfbilling` module installed (which is auto-installed with `account_peppol` by default, but we got a feedback of a user having this issue). task-no feedback : https://www.odoo.com/odoo/project/49/tasks/6481452 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283581
This fix prevents images set to full width in email templates from being duplicated in Outlook-specific HTML during mailing conversion. It keeps saved email content cleaner and avoids displaying or storing unnecessary duplicate image markup.
Original PR description
Problem: An `img-fluid` image ended up duplicated twice inside `[if mso]` comments instead of once when converting a mailing body to inline HTML. `classToStyle` resets the image's `width` attribute back to `100%` after the img-fluid fix already hid it and added its Outlook clone, making it match `enforceImagesResponsivity`'s selector again and get duplicated a second time. Solution: Mark images already handled by the img-fluid fix with a dedicated `mso-hidden` class and exclude them from `enforceImagesResponsivity`'s selector. Steps to reproduce: - Add an image in a new email template. - Set its width to "100%". - Save. - Observe the saved HTML has two mso comments for one image. opw-6411348 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282199
Export invoices in the Argentine electronic invoicing flow now send the correct recipient identification information for QR validation. This lets businesses verify these invoices as legal documents on the ARCA/AFIP validation page and avoids incorrect identification labels.
Original PR description
Before this change we were sending id type code 0 and this generate two problems * ARCA verification page it was wrongly taking "CI Policia Federal" as the identification type of the receptor * We were not able to validate the expo invoice, we get always an error With this change the expo invoice can be checked as a real legal document in the ARCA page https://servicioscf.afip.gob.ar/publico/comprobantes/cae.aspx
This fix updates a Mexican electronic invoicing point of sale test so the product is properly available in the POS flow. It helps ensure refunded orders with discounts display correctly during automated checks, reducing the risk of regressions in that workflow.
Original PR description
Before this commit: * `available_in_pos` was not set on the product in the test, causing it to be missing from the ticket screen when fetching paid orders using `callRelated`. After this commit: * Set `available_in_pos` on the product so it is loaded correctly and appears in the ticket screen when fetching paid orders, fixes test case `test_mx_pos_refund_discount_order`. task-5890998 related pr: https://github.com/odoo/odoo/pull/247127
Vendor bills uploaded for OCR from a project now keep the project's cost allocation when the OCR result is applied later. This prevents bills from appearing disconnected from the project and avoids the need for users to manually reload AI data.
Original PR description
Issue: Vendor bills uploaded for OCR from a project's Vendor Bills view do not receive the project's analytic distribution. As a result, the bill is not linked to the project until the user clicks…
Issue: Vendor bills uploaded for OCR from a project's Vendor Bills view do not receive the project's analytic distribution. As a result, the bill is not linked to the project until the user clicks Reload AI Data. Steps to reproduce: * Create a billable project with an analytic account. * Open the project's Tasks and select Vendor Bills. * Upload a vendor bill for OCR. * Wait for the extraction result. Cause: The project is provided through the vendor bill action context, but OCR results are applied asynchronously from a webhook or cron. The invoice is browsed again without that context, and `_save_form()` creates the extracted lines with only their labels: https://github.com/odoo/enterprise/blob/039012c15aa97f51e29502265b2146356bd4dc0f/account_invoice_extract/models/account_invoice.py#L862-L874 The project analytic computation can therefore no longer determine which distribution should be assigned to the extracted lines. Solution: We need to preserve the effective analytic distribution when the document is uploaded, while its originating context is still available, and use it as a default when the extracted lines are later created. Storing the computed distribution instead of the project context keeps OCR independent of Project, supports other analytic default sources, and leaves invoices without an upload time distribution unchanged. opw-6412993
Gantt charts using a weekly view now place tasks in the correct week according to the user's locale, such as weeks starting on Sunday. This prevents unexpected empty columns and keeps planning timelines aligned with local business practices without changing existing standard 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).
This fixes an error that could block reconciliation when users work with a parent company and branch company at the same time. The accounting reconciliation process now uses the relevant journal item company for currency conversion, helping users complete matching entries without interruption.
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-6290703This fix prevents subscription billing from crashing when an automatic payment fails and the related payment record is rolled back. It also avoids incorrectly detaching invoices after successful payments, helping recurring invoicing continue more reliably.
Original PR description
Step to reproduce: - create a faulty token that won't work and link it to a subscription - launch the recurring invoice cron - the following traceback occurs ``` last_tx_sudo = (self.transaction_ids…
Step to reproduce:
- create a faulty token that won't work and link it to a subscription
- launch the recurring invoice cron
- the following traceback occurs
```
last_tx_sudo = (self.transaction_ids - existing_transactions).sudo()
```
When the payment fails, the system rollback and we store the last_tx_sudo value in a dedicated variable. After rollback, the record does not exists anymore. Therefore, accessing the value fails.
```
File "/home/odoo/src/enterprise/saas-18.2/sale_subscription/models/sale_order.py", line 1703, in _handle_automatic_invoices
if not last_tx_sudo or last_tx_sudo.renewal_state in ['pending', 'authorized']:
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-18.2/odoo/orm/fields.py", line 1439, in __get__
self.compute_value(record)
File "/home/odoo/src/odoo/saas-18.2/odoo/orm/fields.py", line 1603, in compute_value
records._compute_field_value(self)
File "/home/odoo/src/odoo/saas-18.2/odoo/orm/models.py", line 4575, in _compute_field_value
determine(field.compute, self)
File "/home/odoo/src/odoo/saas-18.2/odoo/orm/fields.py", line 69, in determine
return needle(*args)
^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-18.2/sale_subscription/models/payment_transaction.py", line 25, in _compute_renewal_state
if tx.state in ['draft', 'pending']:
^^^^^^^^
File "/home/odoo/src/odoo/saas-18.2/odoo/orm/fields.py", line 1406, in __get__
raise MissingError("\n".join([
odoo.exceptions.MissingError: Record does not exist or has been deleted.
```
Moreover, since https://github.com/odoo/enterprise/pull/45236/files#diff-c36fd7952cc2bef40716419a668de41963d49e1aa4177d9319d503fc260da588R1678-R1682
```
if not last_tx_sudo or not last_tx_sudo.renewal_state not in ['pending', 'authorized']:
```
has become
```
if not last_tx_sudo or last_tx_sudo.renewal_state in ['pending', 'authorized']:
```
But it feels strange to unlink the invoice when the payment succeed.
This PR fixes it.This update corrects several issues in SAF-T/FAIA reports, including invalid negative tax amounts, overly long software version values, incorrect foreign-currency tax amounts, and invoice customer/supplier data conflicts. These fixes help Luxembourg and Romania accounting reports pass audit and schema checks more reliably.
Original PR description
This is one of many errors fixing the FAIA report, which is the SAF-T report for Luxembourg. See PR #113316 for a list of similar PRs. ### Error 1: Negative tax amounts Auditors from Luxemborg…
This is one of many errors fixing the FAIA report, which is the SAF-T report for Luxembourg. See PR #113316 for a list of similar PRs. ### Error 1: Negative tax amounts Auditors from Luxemborg provided one Odoo user with analysis files of their FAIA xml report. The following discrepancy was present in more than 300 lines: `[TaxInformation/TaxAmount/Amount] # is negative. Only postive values are admitted. The sign is automatically determined by the corresponding CreditAmount (-) Or DebitAmount (+) on the same Line.` This discrepancy was caused by two different scenarios. The first was a negative `unit_price` line, such as a Discount product. The second was a tax with negative and positive repartition lines, such as a tax with xml ID `lu_2015_tax_AP-EC-17`. Luxembourg officials confirmed the following behavior: 1. The TaxInformation/TaxAmount/Amount element must be positive. 2. The TaxInformationTotals/TaxAmount/Amount element may be negative. 3. There may only be one TaxInformationTotals element per TaxCode in an Invoice element. This commit ensures that these conditions are met for the FAIA report. I'm not sure if the TaxInformation changes should also be applied to the base `account_saft saft_report.xml` file. ### Error 2: SoftwareVersion The SoftwareVersion element is limited to 18 characters. The relevant error from a customer's analysis file is below. Error: Value exceeds maxLength of "18". ### Error 3: CurrencyAmount The `account_saft` method `GeneralLedgerCustomHandler._saft_fill_report_tax_details_values()` does not report the amount of tax in foreign currency, instead replacing this value with the amount in company currency. No errors prompted this change; it just seems wrong on its face. ### Error 4: PR #113720 ensured that the TaxType element is always TVA. This means that the TaxType should no longer should be ignored in our example documents. ### Error 5: Schema validation failure The elements Inovice/CustomerInfo and Invoice/SupplierInfo are defined with the element `<xs:choice>` in the XSD file linked below. Only one can be present at any time, not both. https://pfi.public.lu/dam-assets/backup/FAIA/FAIA/XSD_Files.zip. note: currently the link is broken. PR #100749 allowed many parts of SAF-T code to display both customer and supplier data, including these elements. This commit ensures that the elements are mutually exclusive. opw-6344914 [Link](https://www.odoo.com/odoo/project.task/6344914) Forward-Port-Of: odoo/enterprise#126121
The LinkedIn integration now handles cases where LinkedIn returns no account statistics during a refresh. This prevents an unexpected crash and keeps social account data updates running smoothly.
Original PR description
Bug === When the LinkedIn API returns no statistics for the account, the refresh crashes. Task-6425391 Forward-Port-Of: odoo/enterprise#126326