Daily updates from Odoo
Navigate
Branch
Sunday, July 5, 2026
17 changes
5 changes
Resolved issues and error corrections
PDF form fields are now locked during the signing process instead of being flattened in a way that could change how the document looks. This keeps signed documents visually consistent for users while preventing fields from being edited during signing.
Original PR description
Currently, we flatten fields in a naive way which does not handle many edge cases and can alter the PDF appearance for users. We could use pypdf to handle production-grade flattening, but Odoo's `pypdf` dependency (5.4.0) does not support native form field flattening (which was introduced in 5.8.0). To resolve this, rather than flattening, we lock the interactive fields so they are no longer editable while signing, which perfectly maintains the original appearance. In the future, when we support higher pypdf versions, we can truly flatten the PDF to provide a better user experience. task-6037759 Forward-Port-Of: odoo/enterprise#122966 Forward-Port-Of: odoo/enterprise#112351
This fixes an error that could prevent AI Studio fields from being filled in appraisal forms when prompts referenced employee feedback. The AI feature now passes field information in the expected format, improving reliability for users configuring AI-assisted forms.
Original PR description
**STEPS TO REPRODUCE** 1. Add an AI Studio field in the employee appraisal form view (can be a regular text field or other) 2. Add `employee_feedback` to the prompt using '/' 3. Click the AI button to populate the field 4. Error occurs: `TypeError: unsupported operand type(s) for +: 'OrderedSet' and 'list'` **CAUSE** In any model, the read function expects the argument `fields` to be a list. When using AI fields in Studio, the fields argument is stored as an OrderedSet instead of a list, causing errors when performing operations. opw-5954203 Forward-Port-Of: odoo/enterprise#121981 Forward-Port-Of: odoo/enterprise#120799
This update resolves issues where scanning employee badges within the Point of Sale (PoS) system wasn't working correctly, specifically when entering a PIN. The fix ensures badge scanning seamlessly integrates with the PIN input, allowing users to log in and process transactions reliably. It also corrects a bug where scanning another cashier's badge didn't switch the active cashier.
Original PR description
See commit messages. [[FIX] pos_hr: scanning badge should work with PIN input focused](https://github.com/odoo/odoo/commit/95d9329674e81b2659445e2021a35b21bbbc81a3) [[FIX] point_of_sale: scanning a badge should not auto confirm the PIN](https://github.com/odoo/odoo/commit/d59fb1f6fe27d117579b3945c5bba400d17d0014) (Note: this is only needed up to saas-18.4 included -- 19.0 already has this diff) [[FIX] pos_hr: scanning another cashier's badge switches to that cashier](https://github.com/odoo/odoo/commit/c812fe596694b16a494e3dcf908d17f621f7ce92) opw-6125029 Forward-Port-Of: odoo/odoo#274259 Forward-Port-Of: odoo/odoo#262474
This update ensures that return stock moves now correctly display the reference for the return picking itself (WH/OUT/000XX) instead of the original receipt. Previously, the reference was incorrectly linked to the original order, causing confusion in tracking returned items. This change clarifies the stock movement process and improves inventory accuracy.
Original PR description
Steps to reproduce: ------------------- - Install `stock` - Create a receipt for a product with `x` quantity - Validate the receipt - Click `Return` and create a return picking - Validate the return…
Steps to reproduce:
-------------------
- Install `stock`
- Create a receipt for a product with `x` quantity
- Validate the receipt
- Click `Return` and create a return picking
- Validate the return picking
- Open the Moves History
Issue:
------
The stock move line generated by the return operation still displays the
original receipt reference (`WH/IN/000XX`) in the Reference column
instead of the return picking reference (`WH/OUT/000XX`).
As a result, the return move appears to belong to the original receipt
rather than being identified as a separate stock operation.
Cause:
--------
In this [commit](https://github.com/odoo-dev/odoo/commit/1c7d80a10b5d7db1c4163166bf52b3f3c77044ba
) `reference` is become editable field (readonly=False)
Now `stock.move.reference` is a stored, editable computed field
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/addons/stock/models/stock_move.py#L182
Since `_compute_reference` derives its value from `move.picking_id.name
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/addons/stock/models/stock_move.py#L383
Because the field is both `store=True` and `readonly=False`, the
field-setup logic in `Field._setup_attrs_` no longer applies its usual
default of disabling `copy` for computed fields
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/odoo/orm/fields.py#L460-461
With `store=True` and `readonly=False`, this condition evaluates to
`False`, so the line is skipped and `copy` falls back to the base
`Field` default of `True` instead of `False`.
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/odoo/orm/fields.py#L286
When the return wizard duplicates the original move with
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/addons/stock/wizard/stock_picking_return.py#L53
therefore copies the *old* stored `reference` value ("WH/IN/000XX") into the
`create()` vals of the new move, alongside the new `picking_id`.
`BaseModel.create()` then protects editable computed fields that
receive an explicit value in `vals` from being recomputed.
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/odoo/orm/models.py#L3996-L3999
Since `reference` is present in `vals` and `readonly=False`, it is
added to the `protected` set, so `_compute_reference` never runs for
the new move even though its `picking_id` now points to the new
return picking. The stale value from the original receipt is kept
as-is, and propagates to the move line via the related field
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/addons/stock/models/stock_move_line.py#L89
Fix:
----
Set `copy=False` explicitly on `stock.move.reference`, restoring the
behaviour it had before `readonly=False` was added (when `readonly`
defaulted to True, `copy` was already False automatically). This
keeps the field editable in the UI while preventing the stale value
from being carried over on `copy()`, so it is correctly recomputed
from the new move's own `picking_id`.
---
opw-6293019
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#270473This update resolves a rare technical issue within the Odoo web interface that could cause a component to be destroyed during testing. The fix adds a simple step to ensure popovers are properly closed, preventing errors related to RPC calls while components are being shut down. This improves the stability of our testing process.
Original PR description
Add an extra step to close the popover and prevent the `Component is destroyed` error[1], which can happen during hoots cleanup, similar to the issue we see when some dialogs perform RPCs as they are being destroyed. [1]: https://runbot.odoo.com/runbot/build/115972540 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273826 Forward-Port-Of: odoo/odoo#273085
5 changes
Resolved issues and error corrections
Signed PDF documents now keep their original form field appearance more reliably. Instead of trying to flatten fields in a way that could visually alter documents, the signing process locks those fields so users cannot edit them while preserving how the PDF looks.
Original PR description
Currently, we flatten fields in a naive way which does not handle many edge cases and can alter the PDF appearance for users. We could use pypdf to handle production-grade flattening, but Odoo's `pypdf` dependency (5.4.0) does not support native form field flattening (which was introduced in 5.8.0). To resolve this, rather than flattening, we lock the interactive fields so they are no longer editable while signing, which perfectly maintains the original appearance. In the future, when we support higher pypdf versions, we can truly flatten the PDF to provide a better user experience. task-6037759 Forward-Port-Of: odoo/enterprise#122914 Forward-Port-Of: odoo/enterprise#112351
This update ensures that return stock moves now correctly display the reference for the return picking itself (WH/OUT/000XX) instead of the original receipt. Previously, the reference was incorrectly showing the original receipt information, leading to confusion about which operation the move belonged to. This fix clarifies the tracking of returned stock.
Original PR description
Steps to reproduce: ------------------- - Install `stock` - Create a receipt for a product with `x` quantity - Validate the receipt - Click `Return` and create a return picking - Validate the return…
Steps to reproduce:
-------------------
- Install `stock`
- Create a receipt for a product with `x` quantity
- Validate the receipt
- Click `Return` and create a return picking
- Validate the return picking
- Open the Moves History
Issue:
------
The stock move line generated by the return operation still displays the
original receipt reference (`WH/IN/000XX`) in the Reference column
instead of the return picking reference (`WH/OUT/000XX`).
As a result, the return move appears to belong to the original receipt
rather than being identified as a separate stock operation.
Cause:
--------
In this [commit](https://github.com/odoo-dev/odoo/commit/1c7d80a10b5d7db1c4163166bf52b3f3c77044ba
) `reference` is become editable field (readonly=False)
Now `stock.move.reference` is a stored, editable computed field
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/addons/stock/models/stock_move.py#L182
Since `_compute_reference` derives its value from `move.picking_id.name
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/addons/stock/models/stock_move.py#L383
Because the field is both `store=True` and `readonly=False`, the
field-setup logic in `Field._setup_attrs_` no longer applies its usual
default of disabling `copy` for computed fields
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/odoo/orm/fields.py#L460-461
With `store=True` and `readonly=False`, this condition evaluates to
`False`, so the line is skipped and `copy` falls back to the base
`Field` default of `True` instead of `False`.
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/odoo/orm/fields.py#L286
When the return wizard duplicates the original move with
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/addons/stock/wizard/stock_picking_return.py#L53
therefore copies the *old* stored `reference` value ("WH/IN/000XX") into the
`create()` vals of the new move, alongside the new `picking_id`.
`BaseModel.create()` then protects editable computed fields that
receive an explicit value in `vals` from being recomputed.
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/odoo/orm/models.py#L3996-L3999
Since `reference` is present in `vals` and `readonly=False`, it is
added to the `protected` set, so `_compute_reference` never runs for
the new move even though its `picking_id` now points to the new
return picking. The stale value from the original receipt is kept
as-is, and propagates to the move line via the related field
https://github.com/odoo/odoo/blob/53cbd4ee7e6ddc1994607d457dfff3fd03e82418/addons/stock/models/stock_move_line.py#L89
Fix:
----
Set `copy=False` explicitly on `stock.move.reference`, restoring the
behaviour it had before `readonly=False` was added (when `readonly`
defaulted to True, `copy` was already False automatically). This
keeps the field editable in the UI while preventing the stale value
from being carried over on `copy()`, so it is correctly recomputed
from the new move's own `picking_id`.
---
opw-6293019
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#270473This update corrects a discrepancy in the manufacturing order forecast report. Previously, the forecast incorrectly showed incoming quantities for finished products destined for a different warehouse. The fix ensures that the forecast accurately reflects the actual movement of materials across warehouses, providing a more reliable view of inventory needs.
Original PR description
Version: ---------- - 18.0+ Steps to reproduce: ---------------------- 1. Install `mrp`, create two warehouses A and B. 2. Create a storable product with Track Inventory True. 3. Create a…
Version: ---------- - 18.0+ Steps to reproduce: ---------------------- 1. Install `mrp`, create two warehouses A and B. 2. Create a storable product with Track Inventory True. 3. Create a Manufacturing Order for 10 qty with(Miscellaneous tab): - Components location = Warehouse A (raw materials) - Finished product Location = Warehouse B 4. Confirm the MO. 5. Open the Forecast report for the product. Issue: ------- - Warehouse B forecast shows the MO under the replenishment detail lines (correctly, via `location_dest_id`) but the header displays "0 Incoming", "0 Outgoing", "0 Forecasted". - Warehouse A forecast incorrectly shows "10 Incoming" in the header, even though no finished product is going there. Cause: ------- - When we create MO for finished Product move is created if there no `location_final_id` then it set mo.warehouse_id.lot_stock_id` as the `location_final_id`. https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/mrp/models/stock_move.py#L466-L467 which is introduce in this [commit](https://github.com/odoo-dev/odoo/commit/95ce0ed97a160e3465c313ed6b9bef938d61586b) - The problem is that `mo.warehouse_id` is a related field computed from `mo.location_src_id.warehouse_id` https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/mrp/models/mrp_production.py#L110 - this warehouse that supplies the **raw materials** (Warehouse A). When the user sets `location_dest_id` to Warehouse B's stock, `mo.warehouse_id` is still Warehouse A, so `location_final_id` is stamped with Warehouse A's stock location. - `product.incoming_qty` (used by the forecast header) evaluates non-done moves using `location_final_id` first (if set), falling back to `location_dest_id` only when `location_final_id` is False: https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/stock/models/product.py#L331-L335 - Because `location_final_id` is set (to WH-A) and non-False, the second clause (which would pick up `location_dest_id` = WH-B) is never evaluated. The result: the move is counted as incoming in Warehouse A and ignored in Warehouse B. - The forecast detail *lines* use only `location_dest_id` to classify moves, so they correctly show the MO as incoming for Warehouse B — producing the inconsistency the user observes. https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/stock/report/stock_forecasted.py#L42-L46 Fix: ---- - Replace `mo.warehouse_id.lot_stock_id.id` with `mo.location_dest_id.id`: - `location_final_id` is meant to track where the product ultimately ends up when the immediate destination is intermediate. The correct "final" location for a finished-product move is exactly what the user chose as `location_dest_id` on the MO — not the stock location of the warehouse that happens to supply the raw materials. - For the standard single-warehouse case, `mo.location_dest_id` equals `mo.warehouse_id.lot_stock_id`, so the behaviour is unchanged. For cross-warehouse MOs (destination = WH-B), `location_final_id` is now stamped with WH-B's stock, making `product.incoming_qty` and the forecast header consistent with the detail lines. ---- opw-6294479 Forward-Port-Of: odoo/odoo#270089
This update resolves a rare technical problem within the Odoo web interface that could occasionally cause a test to fail. The fix ensures that popovers are properly closed, preventing errors that arise when components are destroyed during the testing process. This improves the stability of the web interface.
Original PR description
Add an extra step to close the popover and prevent the `Component is destroyed` error[1], which can happen during hoots cleanup, similar to the issue we see when some dialogs perform RPCs as they are being destroyed. [1]: https://runbot.odoo.com/runbot/build/115972540 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273826 Forward-Port-Of: odoo/odoo#273085
This update resolves an issue where reloading the Odoo server could cause it to crash due to a race condition when handling `SIGHUP` signals. The fix ensures the server remains stable during reload operations, preventing downtime and improving reliability. This primarily impacts users utilizing the 'reload' feature in development mode.
Original PR description
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP`…
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP` into `KeyboardInterrupt`, which `ThreadedServer.run()`'s wait-loop catches. The catch is too narrow — a reload `SIGHUP` can kill the process through **three** windows that all sit outside the wait-loop's `try/except`, so the exception escapes `run()`/`main()`. Under Docker's default `restart: no`, PID 1 dies and the container stays down. ### The three windows 1. **Teardown duplicate (exit 130).** One file change can emit several FS events; the FSWatcher's `if not odoo.phoenix:` dedup races across threads and fires more than one `SIGHUP`. The first begins the phoenix teardown; the second lands during `stop()` / `watcher.stop()` / `_reexec()` and `KeyboardInterrupt` escapes. 2. **Exec-gap (exit 129).** `os.execve()` resets caught signal handlers to their default disposition (`SIGHUP` terminates) but preserves `SIG_IGN`; a `SIGHUP` arriving after the exec but before the re-exec'd process re-installs its handler kills the process outright. 3. **Startup (exit 130).** In the re-exec'd process, a `SIGHUP` anywhere in the startup section that precedes the wait-loop — `start()`, `preload_registries()` **and** `cron_spawn()` — escapes `run()`. ### Reproducer (deterministic) Boot a `ThreadedServer` (`--workers 0`) on any initialised db, then signal PID 1 a few times in quick succession: ```bash docker exec <container> sh -c 'i=0; while [ $i -lt 8 ]; do kill -HUP 1; sleep 0.1; i=$((i+1)); done' ``` Unpatched the process exits 130 or 129. Patched it stays up after one clean phoenix reload. Verified live on 17.0 and 18.0: stock `server.py` dies; the patched `server.py` survives sustained bursts (20/20 across repeated reload cycles on each version); `SIGINT`/`SIGTERM` still exit 0. ### Fix Minimal, in `signal_handler` + `run()` + `_reexec()`; `SIGINT`/`SIGTERM` untouched; one new instance attribute, no new module globals: - **Teardown duplicate:** ignore a `SIGHUP` once `quit_signals_received` is set (a restart/shutdown is already pending; the re-exec reloads fresh code). - **Startup:** a per-instance `in_preload` flag marks the entire startup section (`start()` + `preload_registries()` + `cron_spawn()`); a `SIGHUP` there sets the phoenix flag + counter and returns instead of raising, so the wait-loop exits right after startup and runs the normal restart. - **Exec-gap:** `signal.signal(signal.SIGHUP, signal.SIG_IGN)` just before `os.execve` so a `SIGHUP` in the gap is dropped rather than terminating the process. ### Related - #21209 (merged) — introduced the phoenix flag; did not guard these windows. - #206898 (merged), #207930 (open) — PreforkServer reload. ### CLA Covered by Codeforward B.V.'s corporate CLA; #269240 adds me to its contributor list (pending merge). Forward-Port-Of: odoo/odoo#273895 Forward-Port-Of: odoo/odoo#269247
3 changes
Resolved issues and error corrections
The Timesheets app now correctly marks a user's non-working days as unavailable when they open My Timesheet. This helps employees avoid entering time on days that were removed from their work schedule.
Original PR description
To reproduce: ============= - modify Mitchel Admin's working schedule and remove a day of work - open timesheet app as Mitchel Admin - the removed day is not grayed out as unavailable Porblem: ======== the method `get_unavailabily` was handling only the case when calling it with `groupby=employee_id` otherwise it returns the company's unvailability Solution: ========= when the "My Timesheet" action is opened, the method `get_unavailabily` is now called with a specific context key, allowing to return the current user's unavailability instead of the company's one. opw-5949236 Forward-Port-Of: odoo/enterprise#122720 Forward-Port-Of: odoo/enterprise#113984
This update corrects a discrepancy in the manufacturing order forecast report. Previously, the forecast incorrectly showed incorrect incoming quantities for finished products moving between warehouses. The fix ensures the forecast accurately reflects the actual movement of materials, resolving inconsistencies between the forecast header and detail lines.
Original PR description
Version: ---------- - 18.0+ Steps to reproduce: ---------------------- 1. Install `mrp`, create two warehouses A and B. 2. Create a storable product with Track Inventory True. 3. Create a…
Version: ---------- - 18.0+ Steps to reproduce: ---------------------- 1. Install `mrp`, create two warehouses A and B. 2. Create a storable product with Track Inventory True. 3. Create a Manufacturing Order for 10 qty with(Miscellaneous tab): - Components location = Warehouse A (raw materials) - Finished product Location = Warehouse B 4. Confirm the MO. 5. Open the Forecast report for the product. Issue: ------- - Warehouse B forecast shows the MO under the replenishment detail lines (correctly, via `location_dest_id`) but the header displays "0 Incoming", "0 Outgoing", "0 Forecasted". - Warehouse A forecast incorrectly shows "10 Incoming" in the header, even though no finished product is going there. Cause: ------- - When we create MO for finished Product move is created if there no `location_final_id` then it set mo.warehouse_id.lot_stock_id` as the `location_final_id`. https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/mrp/models/stock_move.py#L466-L467 which is introduce in this [commit](https://github.com/odoo-dev/odoo/commit/95ce0ed97a160e3465c313ed6b9bef938d61586b) - The problem is that `mo.warehouse_id` is a related field computed from `mo.location_src_id.warehouse_id` https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/mrp/models/mrp_production.py#L110 - this warehouse that supplies the **raw materials** (Warehouse A). When the user sets `location_dest_id` to Warehouse B's stock, `mo.warehouse_id` is still Warehouse A, so `location_final_id` is stamped with Warehouse A's stock location. - `product.incoming_qty` (used by the forecast header) evaluates non-done moves using `location_final_id` first (if set), falling back to `location_dest_id` only when `location_final_id` is False: https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/stock/models/product.py#L331-L335 - Because `location_final_id` is set (to WH-A) and non-False, the second clause (which would pick up `location_dest_id` = WH-B) is never evaluated. The result: the move is counted as incoming in Warehouse A and ignored in Warehouse B. - The forecast detail *lines* use only `location_dest_id` to classify moves, so they correctly show the MO as incoming for Warehouse B — producing the inconsistency the user observes. https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/stock/report/stock_forecasted.py#L42-L46 Fix: ---- - Replace `mo.warehouse_id.lot_stock_id.id` with `mo.location_dest_id.id`: - `location_final_id` is meant to track where the product ultimately ends up when the immediate destination is intermediate. The correct "final" location for a finished-product move is exactly what the user chose as `location_dest_id` on the MO — not the stock location of the warehouse that happens to supply the raw materials. - For the standard single-warehouse case, `mo.location_dest_id` equals `mo.warehouse_id.lot_stock_id`, so the behaviour is unchanged. For cross-warehouse MOs (destination = WH-B), `location_final_id` is now stamped with WH-B's stock, making `product.incoming_qty` and the forecast header consistent with the detail lines. ---- opw-6294479 Forward-Port-Of: odoo/odoo#270089
This update resolves a rare technical problem within the Odoo web interface that could occasionally cause a test to fail. The fix ensures that popovers are properly closed, preventing errors that occur when components are destroyed during the testing process. This improves the stability of the web application.
Original PR description
Add an extra step to close the popover and prevent the `Component is destroyed` error[1], which can happen during hoots cleanup, similar to the issue we see when some dialogs perform RPCs as they are being destroyed. [1]: https://runbot.odoo.com/runbot/build/115972540 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273826 Forward-Port-Of: odoo/odoo#273085
2 changes
Resolved issues and error corrections
A recent test within the account module was failing due to an outdated approach to clearing demo data. This update correctly reuses a proven test method and includes a necessary step to ensure data is properly processed, resolving the error and improving test reliability. This ensures accurate reporting and stability.
Original PR description
The test introduced by d60564a42b7c7b16d1d975146291835b65a19461 was using the field `deferred_move_ids` which is defined by account_accountant. As it is used to clear the pre-existing moves (typically demo data), we are re-using the same conditional as test_tour.py to check whether this field is available. By the way, we also add a missing flush_recordset that caused errors in test_kpi_summary_reports_unreconciled_bank_statements. Runbot-error: [939986](https://runbot.odoo.com/odoo/error/939986) Forward-Port-Of: odoo/odoo#271218
This update corrects a discrepancy in the manufacturing order forecast report. Previously, the forecast incorrectly showed incoming quantities for finished products destined for a different warehouse. The fix ensures that the forecast accurately reflects the actual movement of materials, resolving inconsistencies between the forecast header and detail lines.
Original PR description
Version: ---------- - 18.0+ Steps to reproduce: ---------------------- 1. Install `mrp`, create two warehouses A and B. 2. Create a storable product with Track Inventory True. 3. Create a…
Version: ---------- - 18.0+ Steps to reproduce: ---------------------- 1. Install `mrp`, create two warehouses A and B. 2. Create a storable product with Track Inventory True. 3. Create a Manufacturing Order for 10 qty with(Miscellaneous tab): - Components location = Warehouse A (raw materials) - Finished product Location = Warehouse B 4. Confirm the MO. 5. Open the Forecast report for the product. Issue: ------- - Warehouse B forecast shows the MO under the replenishment detail lines (correctly, via `location_dest_id`) but the header displays "0 Incoming", "0 Outgoing", "0 Forecasted". - Warehouse A forecast incorrectly shows "10 Incoming" in the header, even though no finished product is going there. Cause: ------- - When we create MO for finished Product move is created if there no `location_final_id` then it set mo.warehouse_id.lot_stock_id` as the `location_final_id`. https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/mrp/models/stock_move.py#L466-L467 which is introduce in this [commit](https://github.com/odoo-dev/odoo/commit/95ce0ed97a160e3465c313ed6b9bef938d61586b) - The problem is that `mo.warehouse_id` is a related field computed from `mo.location_src_id.warehouse_id` https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/mrp/models/mrp_production.py#L110 - this warehouse that supplies the **raw materials** (Warehouse A). When the user sets `location_dest_id` to Warehouse B's stock, `mo.warehouse_id` is still Warehouse A, so `location_final_id` is stamped with Warehouse A's stock location. - `product.incoming_qty` (used by the forecast header) evaluates non-done moves using `location_final_id` first (if set), falling back to `location_dest_id` only when `location_final_id` is False: https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/stock/models/product.py#L331-L335 - Because `location_final_id` is set (to WH-A) and non-False, the second clause (which would pick up `location_dest_id` = WH-B) is never evaluated. The result: the move is counted as incoming in Warehouse A and ignored in Warehouse B. - The forecast detail *lines* use only `location_dest_id` to classify moves, so they correctly show the MO as incoming for Warehouse B — producing the inconsistency the user observes. https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/stock/report/stock_forecasted.py#L42-L46 Fix: ---- - Replace `mo.warehouse_id.lot_stock_id.id` with `mo.location_dest_id.id`: - `location_final_id` is meant to track where the product ultimately ends up when the immediate destination is intermediate. The correct "final" location for a finished-product move is exactly what the user chose as `location_dest_id` on the MO — not the stock location of the warehouse that happens to supply the raw materials. - For the standard single-warehouse case, `mo.location_dest_id` equals `mo.warehouse_id.lot_stock_id`, so the behaviour is unchanged. For cross-warehouse MOs (destination = WH-B), `location_final_id` is now stamped with WH-B's stock, making `product.incoming_qty` and the forecast header consistent with the detail lines. ---- opw-6294479 Forward-Port-Of: odoo/odoo#270089
1 change
Resolved issues and error corrections
This update corrects a discrepancy in the manufacturing order forecast report. Previously, the forecast incorrectly showed incoming quantities for finished products destined for a different warehouse. The fix ensures the forecast accurately reflects the actual movement of materials across warehouses, resolving a reporting inconsistency.
Original PR description
Version: ---------- - 18.0+ Steps to reproduce: ---------------------- 1. Install `mrp`, create two warehouses A and B. 2. Create a storable product with Track Inventory True. 3. Create a…
Version: ---------- - 18.0+ Steps to reproduce: ---------------------- 1. Install `mrp`, create two warehouses A and B. 2. Create a storable product with Track Inventory True. 3. Create a Manufacturing Order for 10 qty with(Miscellaneous tab): - Components location = Warehouse A (raw materials) - Finished product Location = Warehouse B 4. Confirm the MO. 5. Open the Forecast report for the product. Issue: ------- - Warehouse B forecast shows the MO under the replenishment detail lines (correctly, via `location_dest_id`) but the header displays "0 Incoming", "0 Outgoing", "0 Forecasted". - Warehouse A forecast incorrectly shows "10 Incoming" in the header, even though no finished product is going there. Cause: ------- - When we create MO for finished Product move is created if there no `location_final_id` then it set mo.warehouse_id.lot_stock_id` as the `location_final_id`. https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/mrp/models/stock_move.py#L466-L467 which is introduce in this [commit](https://github.com/odoo-dev/odoo/commit/95ce0ed97a160e3465c313ed6b9bef938d61586b) - The problem is that `mo.warehouse_id` is a related field computed from `mo.location_src_id.warehouse_id` https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/mrp/models/mrp_production.py#L110 - this warehouse that supplies the **raw materials** (Warehouse A). When the user sets `location_dest_id` to Warehouse B's stock, `mo.warehouse_id` is still Warehouse A, so `location_final_id` is stamped with Warehouse A's stock location. - `product.incoming_qty` (used by the forecast header) evaluates non-done moves using `location_final_id` first (if set), falling back to `location_dest_id` only when `location_final_id` is False: https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/stock/models/product.py#L331-L335 - Because `location_final_id` is set (to WH-A) and non-False, the second clause (which would pick up `location_dest_id` = WH-B) is never evaluated. The result: the move is counted as incoming in Warehouse A and ignored in Warehouse B. - The forecast detail *lines* use only `location_dest_id` to classify moves, so they correctly show the MO as incoming for Warehouse B — producing the inconsistency the user observes. https://github.com/odoo/odoo/blob/f958a323fd652af9251215b1b5a2fadc3bccba42/addons/stock/report/stock_forecasted.py#L42-L46 Fix: ---- - Replace `mo.warehouse_id.lot_stock_id.id` with `mo.location_dest_id.id`: - `location_final_id` is meant to track where the product ultimately ends up when the immediate destination is intermediate. The correct "final" location for a finished-product move is exactly what the user chose as `location_dest_id` on the MO — not the stock location of the warehouse that happens to supply the raw materials. - For the standard single-warehouse case, `mo.location_dest_id` equals `mo.warehouse_id.lot_stock_id`, so the behaviour is unchanged. For cross-warehouse MOs (destination = WH-B), `location_final_id` is now stamped with WH-B's stock, making `product.incoming_qty` and the forecast header consistent with the detail lines. ---- opw-6294479 Forward-Port-Of: odoo/odoo#270089
1 change
Resolved issues and error corrections
This fixes an issue where AI-generated fields in Studio could fail when using existing form fields in a prompt. Users can now populate AI fields in appraisal forms without encountering this error.
Original PR description
**STEPS TO REPRODUCE** 1. Add an AI Studio field in the employee appraisal form view (can be a regular text field or other) 2. Add `employee_feedback` to the prompt using '/' 3. Click the AI button to populate the field 4. Error occurs: `TypeError: unsupported operand type(s) for +: 'OrderedSet' and 'list'` **CAUSE** In any model, the read function expects the argument `fields` to be a list. When using AI fields in Studio, the fields argument is stored as an OrderedSet instead of a list, causing errors when performing operations. opw-5954203 Forward-Port-Of: odoo/enterprise#121981 Forward-Port-Of: odoo/enterprise#120799