Tuesday, August 25, 2026
29 changes · saas-19.2
Resolved issues and error corrections
The Inventory Valuation report now includes accounting balances for products that currently have no quantity on hand, when those balances still need reconciliation. This helps finance teams see all valuation and variation account differences before generating balancing entries, without bringing back slower full value calculations for zero-stock products.
Original PR description
## Problem If multiple valuation/variation accounts are used, the Inventory Valuation report will not show the balance of accounts attached to products that have 0 quantity available if a different…
## Problem If multiple valuation/variation accounts are used, the Inventory Valuation report will not show the balance of accounts attached to products that have 0 quantity available if a different account has quantity. ## Solution In order to maintain the performance improvements intended by the commit that introduced the `qty_available != 0` filter, we will avoid calculating `total_value` for products with 0 quantity. We will still run `stock_accounting_value` on these products in order to capture interim accounting value on the Inventory Valuation report. ## Steps to Reproduce (Runbot v19) (defer to the test for more info) 1. Create an extra set of valuation/variation accounts 2. Create a product, avco perpetual accounting the default valuation/variation accounts 3. Create a second product, avco perpetual accounting the new valuation/variation accounts 4. Purchase 1 unit of each of the products and receive, bill both 5. Sell 1 unit of the product attached to the new valuation/variation 6. Go to Accounting > Review > Inventory Valuation, and note that the new valuation/variation accounts are not present. If you click Generate Entry, you will see that these accounts need to be balanced opw-6473319 Forward-Port-Of: odoo/odoo#282819
Belgian payroll reporting now allocates severance periods based on the employee's actual departure date through the theoretical notice end date. This helps ensure multi-quarter severance is reported correctly and prevents manually adjusted departure dates from being overwritten.
Original PR description
- previously, the termination period was split from notice period start to actual departure date, ignoring the theoretical notice duration. Now, it correctly splits from actual departure date to theoretical end date, ensuring proper multi-quarter severance (Code 003) allocation. - Preserve departure_date if after dismissal_date, else default to theoretical notice end. previously the compute always overwrote any user input, ignoring manual adjustments task: 5407737
Belgian Acerta payroll exports now include weekend days when they are covered by certain employee leave periods, such as sick leave. This prevents incomplete reports and helps payroll data match Acerta's expected reporting rules.
Original PR description
## Steps to reproduce: - Install l10n_be_hr_payroll_acerta - Create an employee in a belgian company - Create a sick time off for the created employee that overlaps with a weekend - Export acerta report for the employee - Notice the weekend that overlaps with the time off is not present in the report ## Cause: While exporting the report file we only loop over the created work entries' dates and since weekends doesn't have work entries we don't consider them in the report. ## Fix: When generating the line of a leave's start date we check if the leave overlaps with a WE, we fetch the WE's date and we generate a line for each day of the WE. According to Acerta this is the correct behavior for their reports for specific types of leaves. **opw-6313534** Forward-Port-Of: odoo/enterprise#128548 Forward-Port-Of: odoo/enterprise#124500
This fix prevents an error that could block customers from generating batch payments. It restores the correct payment address handling so ISO 20022 payment files can be created without a system traceback.
Original PR description
The aim of this commit is to allow customer to make their batch payment without facing a Traceback. Context: odoo/enterprise@35f5341b9b44cc16eaea311295a064189dd802cb introduced bug during a badly…
The aim of this commit is to allow customer to make their batch payment
without facing a Traceback.
Context:
odoo/enterprise@35f5341b9b44cc16eaea311295a064189dd802cb introduced bug
during a badly handled forward port.
The method was removed in saas-18.3 in favor of a function. The forward-port
was half handled and now surfaces to Odoo's own production.
Generating a batch payment could generates the following Traceback:
```py
File "/home/odoo/src/enterprise/saas-19.3/account_iso20022/models/account_journal_sepa_ct.py", line 69, in _get_PstlAdr
return super()._get_PstlAdr(partner_id, payment_method_code)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.3/account_iso20022/models/account_journal.py", line 501, in _get_PstlAdr
CtrySubDvsn.text = self._sepa_sanitize_communication(partner_address['state'][:35])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'account.journal' object has no attribute '_sepa_sanitize_communication'
```
Task-id: None (internal issue)
Forward-Port-Of: odoo/enterprise#129084
Forward-Port-Of: odoo/enterprise#129006The pickup point search no longer pre-fills a visitor’s ZIP code based on imprecise location guessing, reducing the chance of showing inconvenient pickup options. The search field is clearer, and the country selector behaves more cleanly when only one country is available.
Original PR description
GeoIP guesses a visitor's location is not precise resulting in showing pickup points that are not close to the customer. Drop the GeoIP zip prefill.
Also clarify the search placeholder ("Zip or City") and hide the country dropdown's caret when there's only one option to pick. Safely fallback on the first country in the selector.Inventory forecasts now correctly handle transfers entered with zero demand quantity, avoiding incorrect negative quantities in past forecast views. This helps businesses rely on historical and forecasted stock figures when reviewing inventory movements involving internal, virtual, or production locations.
Original PR description
**Problem:** When creating a transfer that moves out a product with zero demand quantity, it will change the forecasted quantity of that product in the past. **Cause:** The query filtered out the stock move with zero demand quantity, which preventing the system from accounting for unplanned physical transfers when retroactively calculating past inventory balances **Steps to reproduce the issue:** 1. Create a stock picking with 0 demand quantity that moves a product from an internal location to a virtual location or production location. 2. The forecasted quantity of the product becomes negative in the past. **Fix:** Add another check in the query to include stock moves with zero demand quantity. **Notes:** Since the forecast report is made from a SQL view, this will require a -u to update the report. opw-6462883 Forward-Port-Of: odoo/odoo#284000 Forward-Port-Of: odoo/odoo#283577
This fix removes an unnecessary requirement to create a Bill of Materials when a manufacturing route is already configured on a product. It also prevents draft make-to-order manufacturing orders from being counted in replenishment, helping users avoid incorrect stock planning and extra setup friction.
Original PR description
This reverts commit 2fcb7ca06fdda69164596d675840582c20e85e05. We don't want this behavior. The user already configured its route to be configured on the product and we don't want to force him creating a BoM on top of that. It's just a useless friction. Instead we will just fix the initial bug and avoid counting draft MO from MTO in replenishment opw-6174886 Forward-Port-Of: odoo/odoo#274087
Receipt emails sent after paid self-order purchases now include the requested receipt image attachment. This ensures customers receive a complete proof of purchase by email, while draft orders remain unaffected.
Original PR description
Before this commit: ======================== * Receipt emails were sent without attachments for both paid and draft orders. * `fullTicketImage` and `basicTicketImage` were hardcoded to `false`. * As a result, paid orders were also sent without a receipt attachment. After this commit: ====================== * Receipt emails for paid orders now include the generated receipt image. * `fullTicketImage` and `basicTicketImage` are correctly handled to generate and attach the requested receipt image. Task-5353350 Forward-Port-Of: odoo/odoo#281782 Forward-Port-Of: odoo/odoo#237688
The Point of Sale now automatically selects the only available option when a product attribute has just one choice and does not use multi-select. This prevents unnecessary prompts and lets cashiers add affected products to an order without extra interaction.
Original PR description
Before this commit: ----------- - When a product attribute had only one available value, it was not automatically selected for display types other than multi. After this commit: ------------ - Automatically select the attribute value when an attribute has a single available value and its display type is not multi, allowing the product to be added without any additional user interaction. Task-6327371 Forward-Port-Of: odoo/odoo#282350 Forward-Port-Of: odoo/odoo#272437
When someone is mentioned in a discussion, Odoo now sends the inbox notification to an active user linked to that person instead of potentially choosing an archived account. This helps ensure mentioned employees actually see relevant notifications.
Original PR description
Before this commit, mentioning a partner that has an archived user sent the inbox notification to that archived user, so the mentioned person never saw the mention. This happens because the query picking the user of a recipient joins res_users without filtering on active, and keeps one row per partner with DISTINCT ON and no ORDER BY, so which row survives is arbitrary. One solution could have been to keep every active user of the partner, which is what we want as each of them has its own notification type, but a notification is stored per partner, so the type of a single user applies to all of them. Picking one user is a current limitation. This commit fixes the issue by taking the first active user of each partner in a lateral join, ordered as mail.followers._get_recipient_data already does: internal users first, then the lowest id. Forward-Port-Of: odoo/odoo#284214 Forward-Port-Of: odoo/odoo#283806
Odoo now keeps tax usage indicators up to date when related accounting, expenses, point of sale, or purchase records change. This helps prevent outdated tax settings from appearing available or unused when they are already tied to business transactions.
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
Stripe refund webhooks now recognize refunds that were already created from Odoo after a manual capture. This prevents duplicate refund transactions from appearing for the same Stripe refund, keeping payment records cleaner and more accurate.
Original PR description
Steps to reproduce: - Configure Stripe with manual capture. - Authorize and capture an online payment. - Refund the captured payment from Odoo. - Let the `charge.refunded` webhook be processed. The refund initiated from Odoo is created as a child of the capture transaction, while the webhook resolves the charge to the source transaction. The webhook only checked direct refund children of that source transaction, so it missed the existing refund and created a second refund transaction with the same Stripe refund reference. Look up existing Stripe refund transactions in the child and grandchild transactions of the source transaction before creating webhook refund transactions, so the webhook recognizes refunds already created under capture children. opw-6359020 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276154
Website pages now refresh their cached version when a visitor changes cookie consent from denied to accepted. This helps ensure visitors see the correct page behavior after updating their privacy preferences, instead of an outdated cached page.
Original PR description
Initially with [commit 958b41c4], when cookies were denied (the page is cached a 1st time), then accepted (the page cache must be invalidated), cached pages would be computed again. This behavior was lost with [6c8a90ec], since which website pages are cached more aggressively. [commit 958b41c4]: https://github.com/odoo/odoo/commit/958b41c4acec7e1700ca4d6e0b25ee0ad2aac9f1 [6c8a90ec]: https://www.github.com/odoo/odoo/commit/6c8a90ecba45fb99addf1b86fe237fd626fba650 task-6471290 Forward-Port-Of: odoo/odoo#283863 Forward-Port-Of: odoo/odoo#282737
This fix ensures that when an employee adds leave for a day with an automatically generated missed-attendance record, the related negative extra hours are cleared correctly. It prevents employees from keeping incorrect overtime balances when approved leave covers an absence day.
Original PR description
Before this commit: --- When [`absence_management`](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/res_company.py#L42) is enabled, a [scheduled…
Before this commit:
---
When [`absence_management`](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/res_company.py#L42) is enabled, a [scheduled action](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/hr_attendance.py#L645) automatically creates an attendance record at [**12:00:00 AM**](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/hr_attendance.py#L649) to mark negative extra hours for employees with missing attendance.
<img width="1147" height="474" alt="image" src="https://github.com/user-attachments/assets/833a4387-bc20-4bb7-817d-9ebe9afa7d71" />
If an employee later creates a leave covering this autogenerated attendance, the extra hours should be reset to `0`. However, this does not happen.
#### Video demonstration:
https://drive.google.com/file/d/1DTNQuQ3uV5nOUVMBazCDo0hBZbKJZUIW/view
This happens because the [domain](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_holidays_attendance/models/resource_calendar_leaves.py#L8) used to fetch attendances for [`_update_overtime`](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_holidays_attendance/models/resource_calendar_leaves.py#L34) compares the attendance `check_in` and `check_out` datetimes with the leave `date_from` and `date_to` datetimes.
The leave datetimes are aligned with the employee's working schedule. For example, if the working hours are **8:00 AM–5:00 PM**, the leave is stored from `{date, 8:00 AM}` to `{date, 5:00 PM}`. In contrast, the scheduled action creates the autogenerated absence attendance at **12:00:00 AM** (in the user's timezone). Since this attendance falls outside the leave datetime range, it is excluded from the domain, and `_update_overtime` is never called for it.
After this fix:
---
Instead of building the domain using the leave datetime range, the domain is built using the leave date range. This ensures that all attendances for the affected dates, including autogenerated absence attendances created at midnight, are included and their extra hours are updated correctly.
OPW: 6385811
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#281123This fix prevents Helpdesk tickets from crashing when incoming emails contain unusual figure blocks, such as figures without images or with multiple images. The editor now skips unsupported figure captions instead of raising an error, improving reliability when processing customer emails.
Original PR description
**Steps to reproduce:** - Install Helpdesk - Create an email with a figure that has no image - Send it to Helpdesk email alias - Open up auto-created ticket from the email - `OwlError` is raised on `CaptionPlugin.addImageCaption` **Issue:** `CaptionPlugin` [1] was designed for `<figure>` elements with a single `<img>` and a single `<figcaption>` (mainly for editor direct interactions). But the HTML specifications also allow `<figure>` with 0 or more than 1 `<img>` element(s), in which case an error is raised (or some elements are removed). (see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/figure) **Fix:** Ignore such `<figure>` for now as it would require a rework of the plugin. [1] https://github.com/odoo/odoo/commit/b9d112a5800cfe11dc434caa0d335fa3f3db7178 opw-6413422 Forward-Port-Of: odoo/odoo#279981
Pricing rules created from a product variant now remain linked to that specific variant instead of being applied to the broader product template. This helps businesses keep variant-specific prices accurate and avoids unintended pricing changes across related products.
Original PR description
Issue: --- When you apply pricing on product variant form, pricing is instead applied on product template. Steps to reproduce: 1- Open a product variant. 2- From prices tab, add a pricelist rule. Save the variant. 3- Re-open pricelist rule. As you see, the variant is not set. Cause & Fix: --- This is because `applied_on` is changed to `1_product` when `display_applied_on` is set to `1_product`. However, `display_applied_on` is also set to `1_product` when item is created from variant. We can check that case using `default_product_id`. opw-6421193 Forward-Port-Of: odoo/odoo#282376 Forward-Port-Of: odoo/odoo#280303
This fixes an issue where adding shipping to a sales order could cause Odoo to recalculate the delivery line's unit of measure and produce incorrect pricing totals in some customized setups. By keeping the intended unit information when the delivery line is created, sales order amounts remain reliable.
Original PR description
In this PR, https://github.com/odoo/odoo/pull/186250, the `product_uom` field was renamed to `product_uom_id`. However, in the `delivery` module, `product_uom_id` is dropped from the values when the…
In this PR, https://github.com/odoo/odoo/pull/186250, the `product_uom` field was renamed to `product_uom_id`. However, in the `delivery` module, `product_uom_id` is dropped from the values when the delivery line is created. This causes `product_uom_id` to be recomputed. This commit reintroduces `product_uom_id` in the values to prevent the field from being recomputed. **Description of the issue/feature this PR addresses:** For a strange reason, when a module inherits from `sale.order.line` and adds some computed fields with `precompute=True`. `price_unit`, `price_subtotal`, and `price_total` are computed incorrectly. I have attached a module to demonstrate the issue. https://github.com/user-attachments/assets/ebdd8695-c9d8-477b-b5cf-ba6d8d41e84a Without this change, the test fails, and Odoo incorrectly recomputes the fields, as shown in the video. <img width="1232" height="515" alt="image" src="https://github.com/user-attachments/assets/27370f1f-e7b7-4102-a606-0181b9d1a97a" /> When the ORM computes fields marked as `precompute=True`, in this function `_add_precomputed_values` https://github.com/odoo/odoo/blob/0d44f26d9b0fb1c1a5db463cf1f8dd0d3c72ba26/odoo/orm/models.py#L4836, `price_unit` is 0, but the records get `price_unit` from the product. Therefore, when [_compute_amount](https://github.com/odoo/odoo/blob/0d44f26d9b0fb1c1a5db463cf1f8dd0d3c72ba26/addons/sale/models/sale_order_line.py#L855) is called, the values are computed with an incorrect `price_unit`. <img width="1087" height="940" alt="image" src="https://github.com/user-attachments/assets/92feadf0-7f93-4acc-8f1a-931db0655fcc" /> **Steps to reproduce the issue:** - Install the attached module. [sale_precompute.zip](https://github.com/user-attachments/files/31265993/sale_precompute.zip) - Configure a delivery carrier as free for orders over 1, and set the fixed price to 5, for example. - Create a sales order and add a product with a value greater than 1. - Add the shipping method. The price should be 0. In the sales order line, `price_unit` is 0, but `price_subtotal` and `price_total` are equal to 5 (the product's sale price). For more context, this module is a simple example extracted from the OCA `product_secondary_unit` module, which adds a mixin with these fields: https://github.com/OCA/product-attribute/blob/18.0/product_secondary_unit/models/product_secondary_unit_mixin.py. In the `sale_order_secondary_unit` module, `sale.order.line` inherits from this mixin. You can see the error in this PR: https://github.com/OCA/sale-workflow/pull/4535. https://github.com/OCA/sale-workflow/actions/runs/32259842816/job/96090194021?pr=4535#step:8:509 I understand that this requires a deeper investigation into precompute to solve the underlying issue, but I propose setting `product_uom_id` in the `_prepare_delivery_line_vals` method as a temporary solution while the final solution is being investigated. I understand that this field should not have been removed from `_prepare_delivery_line_vals`; the referenced PR only renamed the field and did not intend to remove the value from this method. @Tecnativa @pedrobaeza @kcv-odoo @Feyensv coudl you please review this? --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283551
This fixes a rounding issue where POS payments using eWallets or gift cards could discount the order by one cent less than the amount removed from the card. The change ensures the redeemed amount and customer discount stay aligned even when taxes are configured with special tax-excluded overrides.
Original PR description
When paying with an eWallet or gift card in POS, the reward line could end up 0.01 short of the actual card balance if the discount product's tax is configured as tax-excluded through a per-tax…
When paying with an eWallet or gift card in POS, the reward line could end up 0.01 short of the actual card balance if the discount product's tax is configured as tax-excluded through a per-tax override, regardless of the tax's own default configuration. The card is still debited for the full balance, but the order is only discounted by one cent less, so the amount charged to the customer no longer matches the amount consumed from the card. Steps to reproduce: ------------------- * Top up an eWallet (or gift card) with a balance of 10.00 * On the eWallet/gift card program's discount product, set an 18% tax whose Tax Computation is overridden to "Excluded" (price_include_override = tax_excluded), independently of the company's default tax configuration * In POS, add a product to an order and pay (partly) with that eWallet/gift card > Observation: Only 9.99 is deducted from the order total, while the backend correctly shows 10 consumed on the wallet/gift card. Why the fix: ------------ The reward line's price_unit was reconstructed from a one-time backward tax computation, then kept only the tax amount for taxes whose price_include field was true, dropping it for any tax forced excluded. That price_unit was later re-taxed forward using the tax's real (excluded) configuration, and the two roundings don't agree for rates like 18%, losing a cent. We now force special_mode "total_included" whenever an eWallet/gift card reward line's taxes are computed, not just at creation, so its tax-included total always equals the exact redeemed amount regardless of how the tax is configured, and store price_unit as that target amount directly. opw-5819389 Forward-Port-Of: odoo/odoo#278568
This fix prevents changes made to a new subcontracting manufacturing order from incorrectly updating quantities on earlier receipt records. Businesses using subcontracted purchasing get more accurate delivered quantities and avoid confusion when purchase quantities are increased after an initial receipt.
Original PR description
**STEP TO REPRODUCE** 1. Create a purchase order for a subcontracted product. 2. validate the picking. 3. Return to the PO, and increase the purchased qty and save, this should create a new picking. 4. On the new picking, click on the smart button to see the subcontracting MO details. 5. Change the product quantity on the MO and save. 6. Return to the first picking, and notice the delivered quantity was changed, this should not be the case. **CAUSE** When creating a new MO, its `move_finished_ids` is linked to the moves of all previous pickings when we create the MO. It should only be linked to the new picking move. opw-6320704 Forward-Port-Of: odoo/odoo#271556
Cloud-stored file download links can now be created with a longer valid period for external services that retrieve files later. Existing behavior remains unchanged by default, reducing failed delayed downloads without disrupting current workflows.
Original PR description
Some features hand a cloud storage download URL to an external service that may fetch it later. The default five-minute lifetime is too short for those flows. ### Steps to reproduce 1. Configure a cloud storage provider (e.g. cloud_storage_google). 2. Upload a large file from the web client, so it is stored in the cloud. 3. Generate a download URL for a consumer that may fetch it after five minutes. 4. The URL expires before the consumer fetches it. ### Cause The Google and Azure providers always use the default download URL lifetime, so callers cannot request a longer-lived URL. ### Fix Read an optional cloud_storage_download_url_time_to_expiry context value when generating a download URL. Keep the existing five-minute lifetime as the default for all current callers. opw-5424132 Related Enterprise PR: odoo/enterprise#105967 Forward-Port-Of: odoo/odoo#246443
The stock forecast now avoids counting subcontractor-related external movements as already reserved for outgoing demand. This prevents manufacturing teams from seeing components marked as available before subcontracted goods have actually been received or properly reserved.
Original PR description
### Steps to reproduce: - Enable Multi-Steps Routes, subcontracting and unarchive the MTO route - Create 3 products: Final Product (FP), Subcontracted Component (SB), Component (COMP) and put SB in…
### Steps to reproduce: - Enable Multi-Steps Routes, subcontracting and unarchive the MTO route - Create 3 products: Final Product (FP), Subcontracted Component (SB), Component (COMP) and put SB in MTO - Create a BOM for FP: 1 x SB - Create a subcontracted BOM for SB: 1 x COMP - Create and confirm an MO for 1 unit of FP > This generates a subcontracted MO for 1 unit of SB - Confrim the subcontracted PO and go back to the MO of FP #### > The component move forecast appears "Available" even if the SB unit is neither received nor 'pre-reserved' (the quantity of the move raw is still 0). ### Cause of the issue: The `forecast_widget` displays an available status in case the demand of the move is expected to be fulfilled and there is no `forecastExpectedDate`: https://github.com/odoo/odoo/blob/a46cdcd9d0b575eb668ed738565637f346bbdf7b/addons/stock/static/src/widgets/forecast_widget.xml#L1-L19 https://github.com/odoo/odoo/blob/4fbd88ad3ac2d92b47b024b96f1c40ed4b3f97e3/addons/stock/static/src/widgets/forecast_widget.js#L15-L26 Now, the issue is that this `forecastExpectedDate` is currently unreliable in this use case as the `forecast_expected_date` of the SB component move is incorrectly computed to be False rather than matching its subcontracted receipt counter part. To be more precise, the `forecast_expected_date` is computed based on the report lines: https://github.com/odoo/odoo/blob/8b8b99e371fcf214b9c55fb2fbfca20f2ee66f53/addons/stock/models/stock_move.py#L579-L581 https://github.com/odoo/odoo/blob/8b8b99e371fcf214b9c55fb2fbfca20f2ee66f53/addons/stock/models/stock_move.py#L2701 The component move is an out move of SB from Stock to Production and is linked to the finished subcontracted move of SB from Production to Subcontracting. In particular, this finished subcontracted move (which is assigned) contributes to the 'reserved' out qties on the get go and leads to an already reserved out quantity of 1.0 even thought the move is purely external and linked to the subcontractor process: https://github.com/odoo/odoo/blob/ef89bc530ffae93a553003559ca9078b7a9d0653/addons/stock/report/stock_forecasted.py#L241-L268 In turn, the `demand_out` matched its `reserved_out` (even thought this reserved_out should be 0) so that no `in_transit` move is provided to provide an `expected_date`: https://github.com/odoo/odoo/blob/ef89bc530ffae93a553003559ca9078b7a9d0653/addons/stock/report/stock_forecasted.py#L426-L435 opw-6445209 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283177
Fixes credit notes created through “Reverse and Create Invoice” so they correctly generate exchange difference and cash basis tax entries when foreign currency rates change. This removes the need for accountants to reset and repost credit notes manually, improving accuracy for multi-currency cash basis accounting.
Original PR description
### Issue before this commit: When using the "Reverse and Create Invoice" feature on a posted invoice with a foreign currency and Cash Basis enabled, the expected Exchange Difference and Cash Basis…
### Issue before this commit: When using the "Reverse and Create Invoice" feature on a posted invoice with a foreign currency and Cash Basis enabled, the expected Exchange Difference and Cash Basis tax entries are not generated upon the automatic reconciliation. The credit note is successfully created and reconciled with the original invoice, but the P&L exchange difference and the cash basis transition lines are completely missing. Currently, the only workaround is to manually reset the generated credit note to draft and re-post it, which forces the system to correctly calculate the currency rate differences and generate the missing entries. ### Steps to reproduce the issue: 1. Download Accounting 2. Go to Settings > Cash basis. Tick it and set as 'Base Tax Received Account' an account like 201000 Current Liabilities 3. Go to Chart of Accounts > search your account (ex. 201000 Current Liabilities) and be sure the flag of 'Allow Reconciliation' is on 4. Go to Taxes > 15% sales > set 'Tax Exigibility' as Based on Payment and 'Cash Basis Transition Account' always as 201000 Current Liabilities 5. Go to Currencies and set a new currency like MXN inserting tax rates as: 1. 1 july 2026: 20$ 2. 15 july 2026: 15$ 6. Create a new invoice with price 100 and 15% tax, set MXN as currency for the journal, set the date as 1 july and confirm it 7. Click on 'Credit Note', then 'Reverse and Create Invoice' and confirm it 8. go back to the invoice and see that after the total amount there is a new line 'Reversed on...' 9. After that line there should also be the line with the Exchange Difference since the tax rates for MXN currency were different at the moment of the invoice and at the moment of the credit note. This is only created by resetting to draft the credit note and confirm it again. ### Cause of the issue: In the account.move.reversal wizard, when is_modify = True (Reverse and Create), the system triggers _reverse_moves with cancel=True. At the end of the _reverse_moves method, the newly created reverse moves are automatically posted and reconciled. However, this automatic posting is executed with move_reverse_cancel=True injected into the context: reverse_moves.with_context(move_reverse_cancel=cancel)._post(soft=False). When the reconciliation engine (_reconcile_plan_with_sync and _create_exchange_difference_moves) detects this specific context key, it intentionally bypasses the creation of both the exchange difference P&L moves and the cash basis entries, treating the reversal as a pure administrative cancellation rather than a financial operation with currency fluctuations. ### Reason to introduce the fix: To ensure financial accuracy and compliance, especially when cash basis and multi-currency are involved, a reversal on a different date must reflect the actual exchange rate fluctuations and properly trigger cash basis rules. By removing the move_reverse_cancel context injection during the automatic posting of the reverse moves, we allow the native reconciliation engine to evaluate the newly computed balance (based on the credit note's date) against the original invoice. This ensures that exchange differences and cash basis journal entries are automatically and accurately generated on the first attempt. opw-6399867 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283306 Forward-Port-Of: odoo/odoo#281498
The Point of Sale product variant popup now shows the truly available stock after reservations, matching the quantity shown elsewhere in the POS. This prevents staff from seeing stock as available when it has already been reserved by confirmed sales orders.
Original PR description
## Steps to reproduce: - Create another warehouse - Create a product with a variant, like Color, values black and white - Track the product, add a qty on hand of 50 on the black product - Go to the…
## Steps to reproduce: - Create another warehouse - Create a product with a variant, like Color, values black and white - Track the product, add a qty on hand of 50 on the black product - Go to the sales app, make a quotation of 50 for the black product - Confirm the quotation - Go to the PoS, click on the product, check the available qty in the popup - It is still 50, even though the forecasted is correct at 0 ## Why the fix: Having the actual free qty was added in this commit 682bc82 to be able to check the qty that was really free instead of the available qty. This means that we subtract the reserved_qty from the qty_available to get the free_qty. The variant popup was forgotten in this commit, so it was still displaying the qty_available. This is why there was a difference in the qty if we press the product normally or if we long press it, because the variant popup was forgotten in said commit. opw-6382845 Forward-Port-Of: odoo/odoo#283659 Forward-Port-Of: odoo/odoo#280330
Fixed an issue that could prevent customers or staff from opening the Field Service section from a helpdesk ticket preview. The intervention list now loads correctly, avoiding an error page and preserving access to completed service visit information.
Original PR description
*=helpdesk_planning_field_service{,_sale_timesheet} Steps to reproduce: ------------------------- 1. Install helpdesk_planning_field_service_sale_timesheet with demo data. 2. Open a helpdesk team…
*=helpdesk_planning_field_service{,_sale_timesheet}
Steps to reproduce:
-------------------------
1. Install helpdesk_planning_field_service_sale_timesheet with demo data.
2. Open a helpdesk team (e.g., Customer Care) and enable field service planning.
3. Create a new ticket in Customer Care, plan two interventions, and mark them as completed.
4. Click the cog menu of the helpdesk ticket and click Preview.
5. In preview mode, click **Field Service** in the left sidebar.
Issue:
---------
A traceback occurs:
```python
File "/home/odoo/odoo/community/odoo/addons/base/models/ir_qweb.py", line 875, in _render_iterall
raise QWebError(qweb_error_info) from error
odoo.addons.base.models.ir_qweb.QWebError: Error while rendering the template:
KeyError: 'format_datetime'
Template: planning_field_service.portal_my_field_service_report_list
Reference: 866
Path: /t/t/t[3]/t/tbody/t/tr/td[1]/a/t
Element: <t t-out="format_datetime(intervention.start_datetime, dt_format='MMM d, YYYY')"/>
```
Cause:
---------
https://github.com/odoo/enterprise/blob/28637781cd3ffc4c3dc0c2016dd5d6051793f641/helpdesk_planning_field_service/controllers/portal.py#L59-L63
After this 6857d1a, date formatting was changed to use `format_datetime`, and [planning_field_service](https://github.com/odoo/enterprise/blob/28637781cd3ffc4c3dc0c2016dd5d6051793f641/planning_field_service/controllers/portal.py#L42) was updated accordingly. However, `helpdesk_planning_field_service` was not updated to pass `format_datetime` in the template values, causing a **KeyError** when opening the field service intervention list.
Solution:
-----------
Pass `format_datetime` in the template values, following the same approach used in `planning_field_service`.
opw-6467400This fixes an issue in Odoo Studio approvals so delegation can be enabled as intended. Businesses using approval flows can now rely on delegated approval responsibilities working correctly, reducing blockers when the original approver is unavailable.
Original PR description
opw-6321766 Forward-Port-Of: odoo/enterprise#128666 Forward-Port-Of: odoo/enterprise#122441
Partial barcode receipts no longer remove the pending operation-level quality check when users leave the Barcode app before completing the full receipt. This ensures required quality controls remain in place until the whole transfer is cancelled or completed, reducing the risk of missed inspections.
Original PR description
Steps to reproduce --- 1. Create a quality control point on the Receipts operation type with Control per set to Operation. 2. Confirm a receipt of 2 units of the product: one pending operation…
Steps to reproduce --- 1. Create a quality control point on the Receipts operation type with Control per set to Operation. 2. Confirm a receipt of 2 units of the product: one pending operation quality check is created. 3. In the Barcode app, receive 1 unit and go back to the transfer with the back button. 4. The pending operation quality check is gone. Issue --- Going back from the Barcode app calls `post_barcode_process`, which on a partial reception splits the picked move into a done move and a remaining move, then merges the transient duplicate back with `_merge_moves`. https://github.com/odoo/enterprise/blob/b89614661682ecbd131d940539aac8afdd9d7289/stock_barcode/models/stock_move.py#L57-L60 `_merge_moves` cancels that transient duplicate through `_action_cancel` before unlinking it. https://github.com/odoo/odoo/blob/8f3100ca597559945cc42d9ef9517edbb40a900b/addons/stock/models/stock_move.py#L1400-L1401 The `quality_control` override of `_action_cancel`, picks the pending checks to drop from `is_product_canceled`, a `defaultdict(lambda: True)` keyed by `(picking, product_id)`. An operation check has no `product_id`, so its key is never computed by the loop and reads back the `True` default, so it is deleted even though the transfer still has a live move. Since an operation check covers the whole transfer, it must be dropped only when every move of its picking is cancelled. https://github.com/odoo/enterprise/blob/b89614661682ecbd131d940539aac8afdd9d7289/quality_control/models/stock_move.py#L68-L76 opw-6439179 Forward-Port-Of: odoo/enterprise#128767 Forward-Port-Of: odoo/enterprise#127427
Aged Receivables and Aged Payables now calculate aging periods correctly when horizontal groups are applied. This prevents misleading amounts in the Older period, helping finance teams rely on grouped overdue balances for collections and payment follow-up.
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
This fixes an issue where files sent through WhatsApp could arrive empty when stored in cloud storage. Cloud-stored files are now shared through a proper link, while locally stored files continue to be sent as before.
Original PR description
WhatsApp attachments were delivered as empty (0 byte) files when they were stored through the cloud_storage module. ### Steps to reproduce 1. Install and set up whatsapp and a cloud storage module (e.g. cloud_storage_google). 2. Send a file through WhatsApp. 3. The recipient receives an empty file. ### Cause A cloud stored attachment keeps only a reference to its remote data, so its raw field holds no bytes. The integration uploaded those empty bytes to WhatsApp. ### Fix Use the attachment HTTP stream to generate a long-lived cloud storage URL and pass it to WhatsApp as the media link. Pass ordinary remote attachment URLs directly, and keep uploading local attachment bytes as before. opw-5424132 Related Community PR: odoo/odoo#246443 Forward-Port-Of: odoo/enterprise#105967
The Peruvian sales ledger now reports the full gross sales amount when a 3% IGV withholding applies. This keeps reports aligned with SUNAT expectations, since the withholding is handled as a payment mechanism rather than a reduction of the sale value.
Original PR description
The 3% IGV withholding is a negative sale tax, so it reduced amount_total and the 14.4 ledger reported a net total. SUNAT expects the gross total of the operation, the withholding being a payment-time mechanism. task-5935227 Forward-Port-Of: odoo/enterprise#128849