Thursday, September 3, 2026
15 changes · 18.0
Resolved issues and error corrections
French electronic invoices for paid transactions now automatically include the required due date, matching the payment date. This helps businesses comply with French e-invoicing validation rules and reduces the risk of invoice export rejection.
Original PR description
According the schematron v1.4, the cbc:DueDate is required when the move is PAID. "[BR-FR-CO-09/BT-23] : Si le cadre de facturation (BT-23) est B2, S2 ou M2, alors la date d’échéance (BT-9) doit être renseignée et correspondre à la date de paiement." no-task --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Inventory forecasts now correctly handle receipts recorded in a different unit of measure than the product's main unit. This prevents misleading historical forecast values, helping teams rely on accurate stock planning information.
Original PR description
When using a different uom for a receipt than the uom of the product, the forecast will not take it into account correctly. Steps to reproduce: ------------------- * Create a product AA and track it…
When using a different uom for a receipt than the uom of the product, the forecast will not take it into account correctly. Steps to reproduce: ------------------- * Create a product AA and track it by Kg * Create and confirm a receipts for 10 000g of AA -> On the product AA forecast, the value from the past start a -9990. Observation: ------------- To load the forecast it will create a ReportStockQuantity, all the forecast operation will be done on the sql query: https://github.com/odoo/odoo/blob/427d398880c381981e088f7001f855a10d1cd581/addons/stock/report/report_stock_quantity.py#L47 In this query it will calculate the quantity of product and it will reconstruct the history of the inventory. For dates intervals before the move date it will use quantity (the actual quantity moved), for moves after it will use product_qty (the expected quantity to be moved): https://github.com/odoo/odoo/blob/427d398880c381981e088f7001f855a10d1cd581/addons/stock/report/report_stock_quantity.py#L152-L160 Since it is reconstructing the history of the inventory, for the dates before the move happend, it remove the quantity from the inventory: https://github.com/odoo/odoo/blob/427d398880c381981e088f7001f855a10d1cd581/addons/stock/report/report_stock_quantity.py#L161-L166 The issue is that quantity is not in the same uom as product_qty, product_qty is in the uom of the product and quantity of the stock move. opw-6401941
The spreadsheet template dialog in Documents now keeps the search bar visible even when no templates match a search. Users can also add a custom filter without the dialog crashing, making template selection smoother and more reliable.
Original PR description
- templates searchbar disappear when the search has no match - Clicking "Add a custom filter' in the searchbar crashes Task-6526322
Paid point-of-sale orders reopened from the ticket screen now include the related products and customer information needed to display them correctly. This prevents order lines from disappearing and helps staff process refunds or invoices without reselecting the customer.
Original PR description
Steps to reproduce: - More products/customers than the loading limits (or a product made unavailable in PoS after its order was placed) - Sell such a product to such a customer, close the order -…
Steps to reproduce:
- More products/customers than the loading limits (or a product made unavailable in PoS after its order was placed)
- Sell such a product to such a customer, close the order
- Reopen the ticket screen in a fresh session and open the paid order
Issue:
The order shows without its orderlines (silently deleted), so it cannot be refunded correctly. Its customer is blank: a refund loses the partner and invoicing asks to pick a customer again.
Cause:
Since 64ca0e5e924a the ticket screen fetches paid orders through `callRelated("pos.order", "get_ticket_screen_order_data")` instead of `data.read("pos.order", ids)`. `read` is part of
`autoLoadedOrmMethods`, so `missingRecursive()` fetched the products and partners referenced by the orders; `callRelated` loads the payload as-is, and `read_pos_data()` includes neither `product.product` nor
`res.partner` records. An orderline whose product is not in the store is deleted by its `setup()`, and an unknown `partner_id` stays unresolved.
Fix:
Send the orderlines' products and the orders' partners along in `get_ticket_screen_order_data()`: `loadData()` links the records before the orderlines' `setup()` runs, so the frontend keeps them. Server-side only, no API change; 19.0 already loads missing records through `read_pos_orders` + `missingRecursive` (f12407c2cf31), so the forward-port is a no-op.
opw-6524807
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prRefunds for purchased stock items in a foreign currency now avoid posting exchange rate differences to the stock valuation account during returns. This keeps inventory valuation cleaner and prevents currency movements from distorting stock value when products are refunded after exchange rates change.
Original PR description
When refunding the purchase of a valued product that was received in a foreign currency. If the rate of the currency has changed between the purchase and the refund, the exchange difference line was impacting the valuation account. Steps to reproduce: ------------------- * Activate any other currency * Create a valued product and set a cost price * Create a purchase order in the foreign currency for the product * Confirm the purchase order and receive the product * Change the rate of the foreign currency * Create a return for the product and validate it > Observation: An exchange difference line is created and impacting the valuation account. Why the fix: ------------ When selecting the exchange account to use, we now check if we are in a return context. If it's he case we do not use the stock valuation account. opw-6313904
The event booth registration page now ignores outdated booth results when visitors switch categories quickly. This prevents the page from showing the wrong booth list and helps exhibitors complete registration without needing to reload.
Original PR description
Before this commit, the "Get A Booth" page of an event could keep listing the booths of the category checked on load after the visitor picks another one. Only a page reload brought the right ones…
Before this commit, the "Get A Booth" page of an event could keep listing the booths of the category checked on load after the visitor picks another one. Only a page reload brought the right ones back. The tour webooth_exhibitor_register timed out on that list: FAILED: [5/13] Tour webooth_exhibitor_register -> Step Choose Booth (trigger: .o_wbooth_booths div:contains(OpenWood Demonstrator 2) input:not(:visible)). TIMEOUT step failed to complete within 10000 ms. This happens because the page fetches the booths of the category checked on load, and clicking another category fetches its booths while that first answer is still on its way. The answer coming back last fills the list, and the widget caches it under the category active on arrival, so the booths of the first category land in the cache of the clicked one. This commit fixes the issue by caching an answer under the category it was asked for, and by filling the list only while that category is still the chosen one. https://runbot.odoo.com/odoo/error/110527 https://runbot.odoo.com/odoo/error/161834
Fixed an issue in Discuss where the emoji picker could crash after users selected emojis during a search and then cleared the search field. This keeps chat interactions smooth and prevents an unexpected error in a common messaging workflow.
Original PR description
Steps to reproduce: - open Discuss, open any chat, open the emoji picker (no 'Frequently used' emojis) - search a term and select emojis without closing the picker (shift+click on desktop, plain…
Steps to reproduce:
- open Discuss, open any chat, open the emoji picker (no 'Frequently used'
emojis)
- search a term and select emojis without closing the picker (shift+click on
desktop, plain click on mobile)
- clear the search with backspace
=> traceback: 'Cannot read properties of null (reading
`getBoundingClientRect`)' in adaptNavbar().
This happens because when we clear the search input it calls
`highlightActiveCategory()`, which sets `categoryId` to the topmost category of
the grid, which is now the 'Frequently used' category (sortId 0), added to the
picker since the emojis we just picked updated the recent state. To update the
navbar, `currentNavbarPanel` then looks for the panel holding it in
`emojiNavbarRepr`, but that representation is only built in `adaptNavbar()`,
which runs on mount and from the `ResizeObserver` only, so it was built without
the 'Frequently used' category and no panel contains it. It returns undefined,
the navbar renders empty, its size change wakes the `ResizeObserver`, and
`adaptNavbar()` crashes on querySelector('.o-Emoji').getBoundingClientRect()`.
This commit solves the issue by rendering the `recentEmojis` from a snapshot
taken when the picker is opened, so they are not added to the picker while the
while `emojiNavbarRepr` does not contain their category id.
partial backported PR: https://github.com/odoo/odoo/pull/281104
Task-[6204249](https://www.odoo.com/odoo/project/1519/tasks/6204249)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prInvoices and POS receipts in Saudi Arabia and the UAE now use the special GCC tax layout only when the company has a VAT number. This helps unregistered businesses avoid issuing tax-style documents they are not legally allowed to issue, while leaving other GCC countries unchanged.
Original PR description
…tempalts for VAT unregistered Companies In Saudi Arabia (ZATCA), a business's legal authority to issue tax documents is dictated by annual revenue thresholds: registration is mandatory above SAR…
…tempalts for VAT unregistered Companies In Saudi Arabia (ZATCA), a business's legal authority to issue tax documents is dictated by annual revenue thresholds: registration is mandatory above SAR 375,000, voluntary between SAR 187,500 and SAR 375,000, and exempt below SAR 187,500. Per Article 53 of the KSA VAT Implementing Regulations, only a registered "Taxable Person" may issue a Tax Invoice (B2B) or a Simplified Tax Invoice (B2C). In the UAE, the Federal Tax Authority (FTA) imposes the same registration prerequisite. Previously the bilingual GCC tax layout was chosen purely from the company's country, on both the invoice report and the POS receipt. For SA and AE, we now only use the GCC report templates when the company actually has a VAT number; otherwise we fall back to the standard report template. The remaining GCC countries (BH, OM, QA, KW) are unaffected. The POS receipt flag `is_gcc_country` is renamed to `use_gcc_report` to enhance code readability task-6326221 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#279377
Users with attendance management rights can now remove themselves as an employee's attendance manager without triggering an error. This prevents a confusing access issue and keeps attendance administration workflows running smoothly.
Original PR description
Issue: ---------------------------------------- When a user removes themselves as Attendance manager on the last employee on which they're set an error pops up. Steps to reproduce:…
Issue: ---------------------------------------- When a user removes themselves as Attendance manager on the last employee on which they're set an error pops up. Steps to reproduce: ---------------------------------------- - Connect as a user with the group `group_hr_attendance_manager` - Install hr_attendance - Don't be the attendance manager of any employee - Go to an employee form, add yourself as attendance manager - Try removing yourself as attendance manager - Error Cause: ---------------------------------------- When removing someone as Attendance manager, `_clean_attendance_officers()` is called to remove the group `group_hr_attendance_officer` from any user without any employee to manage. But the field `attendance_manager_id` itself is only accessible to users with the group `group_hr_attendance_officer`. So during the `web_read` after the `write`, the user doesn't have access to the field and an access error is thrown. Solution: ---------------------------------------- `group_hr_attendance_officer` is implied by `group_hr_attendance_manager`. So a user should never have only `group_hr_attendance_manager`. We modify `_clean_attendance_officers()` to not remove `group_hr_attendance_officer` when the user has `group_hr_attendance_manager`. opw-6471482
This corrects internal documentation for temporary records so it matches how access permissions have worked for several versions. There is no product behavior change, but clearer documentation helps administrators and developers understand security rules correctly.
Original PR description
Since 6d8688bb124d, TransientModel records use the regular access rights mechanisms instead of being implicitly restricted to their creator. The docstring was not updated with that change and has therefore incorrectly documented creator-only access since 14.0. Forward-Port-Of: odoo/odoo#286251
This fix ensures Odoo reads the right information from Adyen payment messages. It helps prevent payment processing issues caused by using incorrect values from the payment provider response.
Original PR description
opw-6512723 Forward-Port-Of: odoo/odoo#284773
Fixes Colombian withholding reports so partial vendor credit notes reduce the taxable payment base correctly instead of increasing it. This helps businesses generate accurate withholding certificates and related tax reports after refunds or credits.
Original PR description
**STEP TO REPRODUCE** 1. install l10n_co_reports and account_accountant 2. Create a bill, with a line with a retention tax (3.50% RteFte). 3. Create a partial credit note (unit price less than what's on the bill). 4. Goes to the report 'Certificado de Renteciòn en Fuente', and notice the Monto del Pago Sujeto Retenciòn is not correct. **CAUSE** The sql query multiply tax_base_amount by -1 if debit > 0, which means (because we are dealing with vendor bills) the line is from a credit note, but tax_base_amount is already a signed value so credit notes ends up contributing to the tax base amount while they should reduce it. opw-6235830 Forward-Port-Of: odoo/enterprise#119716
This fixes an issue where gift card lines in Spanish POS TicketBAI reporting could be shown as positive amounts instead of refunds. The correction keeps reported line totals consistent with the overall order total, reducing accounting and compliance discrepancies.
Original PR description
The issue fixed in commit[1] is again reproducible after commit [2] the pos order line for gift card is now not considered as a refund Step to reproduce: - Install pos_loyalty and…
The issue fixed in commit[1] is again reproducible after commit [2] the pos order line for gift card is now not considered as a refund Step to reproduce: - Install pos_loyalty and l10n_es_edi_tbai_pos with demo data - Create a gift card (add a tax to the discount product, any 0%) - start pos, add a product and use the gift card - fulfill the order - go to backend and open that order - In the TicketBAI XML, the values for the giftcard product will be positive, causing an inconsistency between the product line total and the invoice total [1] https://github.com/odoo/odoo/commit/0bbc5ebdcc7e014d87130b2ff9cee98e3aa7479a [2] https://github.com/odoo/odoo/commit/b17c9713e7a3305c240298fa54fcf1bc87a9bb8c FIX - we used to determine `sign` based on each order line's `is_refund` property - this property is quite sensitive as it depends on factors like line's qty, price, is reward or not. - so its better to depend on order's refund property for sign reversal https://github.com/odoo/odoo/blob/4fef2c5b69fac10594fac81b149d542ee4621b13/addons/point_of_sale/models/pos_order.py#L1768 opw-6226003 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Financial reports now count grouped information more accurately when preparing report data. This helps avoid misleading totals in reports, improving confidence in accounting insights and decision-making.
Original PR description
… in SQL query
Express checkout with Apple Pay or Google Pay can now continue when Starshipit cannot quote shipping from the partial address provided by the wallet. Instead of blocking all delivery options, Starshipit is skipped and other available carriers can still be offered to the customer.
Original PR description
#### Description of the issue/feature this PR addresses: Rating a Starshipit shipment for an incomplete delivery address makes the whole rating loop fail instead of skipping that carrier. This breaks…
#### Description of the issue/feature this PR addresses:
Rating a Starshipit shipment for an incomplete delivery address makes the whole rating loop fail instead of skipping that carrier. This breaks express checkout (Apple Pay / Google Pay), where the wallet only discloses a partial address before authorization: the customer gets "update postal address" and cannot pay, while manual checkout works.
#### Current behavior before PR:
delivery_starshipit is the only connector that rates a shipment without validating the addresses first, and it ignores the express_checkout_partial_delivery_address context key set by website_sale. The empty street is sent to /api/rates, which answers 200 with {"success": false, "errors": [{"details": "street parameter value is required"}]}, and _send_request turns that into a UserError. As starshipit_rate_shipment lets it propagate, it aborts the rating of every carrier instead of only this one, so no delivery method reaches the wallet. The same happens for errors only the api can report, such as invalid credentials.
#### Desired behavior after PR is merged:
Both the recipient and the warehouse address are validated before the api is called, as the other connectors already do, and the message is returned as an unsuccessful rate rather than raised. Starshipit requires the street, so a streetless address is still refused, but with a neutral message in the express checkout flow since the customer cannot complete it before paying. The Starshipit carrier is simply not proposed among the wallet's options, the other carriers are rated normally, and express checkout completes.
opw-6393393
Forward-Port-Of: odoo/enterprise#125117