Daily updates from Odoo
Monday, October 6, 2025
21 changes · 19.0
Enhancements to existing features
Email handling now avoids loading large unnecessary message content into memory during common operations. This reduces the risk of out-of-memory failures and improves processing speed for mail-heavy databases, while keeping the same user-facing behavior.
Original PR description
Modifications are made around read, filtered, list comprehension. The read function usually does not prefetech fields other than stated. But in this case, since the fields are related fields from…
Modifications are made around read, filtered, list comprehension. The read function usually does not prefetech fields other than stated. But in this case, since the fields are related fields from another model, The fields of the other model are prefeteched. This includes the body which can be very big in size and cause an out of memory error. Filtered does not need other fields and keeps them unnecessarily in cache. List comprehension where it has a reference to specific field inside the model also triggers the prefetecher. Benchmark: | |Number of queries| SQL time| Python time|| |-------|----------------------------|----------------|---------------|-| |with prefetch| 82| 1.887 | 7.898| Out of memory| |Without prefetch| 120| 0.385 | 5.973| | The benchmark with the prefetch was done locally with increasing the memory limit. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#211075 Forward-Port-Of: odoo/odoo#183893
Changing a folder to not be discoverable no longer automatically makes the files inside require a direct link. This keeps folder visibility settings from unexpectedly restricting access to existing documents, making document sharing behavior more predictable for users.
Original PR description
Changing the discoverability to not propagate to its children. Previously setting a folder to Discoverable to 'No' would result in all the files also requiring a link to access them, which is unwanted behaviour. Task-4996667
IoT connections now reuse saved IoT box information so devices can continue receiving requests when the internet connection is unavailable. This reduces unnecessary server calls and improves reliability for connected hardware and self-ordering flows during network interruptions.
Original PR description
In order to make the `iot_http` service work offline, we cache the iot box records until there is a full action failure. This avoids useless orm calls and in the meantime, allow making requests to the iot box without internet connection. Community PR: odoo/odoo#226839 Forward-Port-Of: odoo/enterprise#93895
VoIP call recordings are now saved in a single audio channel instead of stereo. This reduces storage usage while keeping recordings suitable for typical business review and compliance needs.
Original PR description
Task-5082457
Resolved issues and error corrections
This fixes a crash that could occur when validating Register Production/Serial from the shop floor after duplicate quality checks were created. Manufacturing users can now complete production validation without being blocked by an unexpected error.
Original PR description
When user tries to validate Register Production/Serial in shop floor, A traceback will appear. Steps to reproduce the error: - Install ``mrp_workorder`` and ``quality_control`` modules with demo data…
When user tries to validate Register Production/Serial in shop floor, A traceback will appear. Steps to reproduce the error: - Install ``mrp_workorder`` and ``quality_control`` modules with demo data - Go to Quality > Create a new Control point > Product: Table Top > Operations: Manufacturing > Save - Create a new MO > Product: Table Top > Confirm > Shop Floor > Click on Assembly 1 > Click on 3 dots > Update Instructions > Improvement Suggestion > Add a step > Propose Change > Validate - Click on 3 dots > Register Production/Serial > Validate - Go back to MO > Quality Checks > Duplicate the newly created quality check > Shop Floor > Click on Assembly 1 > Click on 3 dots > Register Production/Serial > Validate Traceback: ``ValueError: Expected singleton: quality.check(1, 5)`` https://github.com/odoo/enterprise/blob/5103383df3ddf23503e2c7817c5129a742a7800f/mrp_workorder/models/mrp_workorder.py#L846-L848 When User clicks on the validate, ``current_check`` may include several quality checks without a ``previous_check_id``. The code expects only one record, which causes a traceback. sentry-6839419788 Forward-Port-Of: odoo/enterprise#93624
This fix ensures scheduled background jobs refresh their system information before running after an app is installed or removed. It prevents worker crashes caused by jobs using outdated data, improving reliability for databases running with multiple workers.
Original PR description
**step to reproduce:** - start a database with worker, use `--max-cron-thread=1 --workers=2` - Add a sample cron, which runs every minute(just so that we can see the status) - install helpdesk -…
**step to reproduce:**
- start a database with worker, use `--max-cron-thread=1 --workers=2`
- Add a sample cron, which runs every minute(just so that we can see the status)
- install helpdesk
- uninstall helpdesk
**Observation**
- traceback in console
```
2025-09-25 06:07:26,389 18450 ERROR ? odoo.service.server: Worker WorkerCron (18450) Exception occurred, exiting...
Traceback (most recent call last):
File "/home/odoo/odoo/codebase/odoo/17.0/odoo/service/server.py", line 1171, in _runloop
self.process_work()
File "/home/odoo/odoo/codebase/odoo/17.0/odoo/service/server.py", line 1270, in process_work
base.models.ir_cron.ir_cron._process_jobs(db_name)
File "/home/odoo/odoo/codebase/odoo/17.0/odoo/addons/base/models/ir_cron.py", line 139, in _process_jobs
registry[cls._name]._process_job(db, cron_cr, job)
File "/home/odoo/odoo/codebase/odoo/17.0/odoo/addons/base/models/ir_cron.py", line 331, in _process_job
now = fields.Datetime.context_timestamp(ir_cron, datetime.utcnow())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
....
....
File "/home/odoo/odoo/codebase/odoo/17.0/odoo/models.py", line 3873, in fetch
fetched = self._fetch_query(query, fields_to_fetch)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo/codebase/odoo/17.0/odoo/addons/base/models/res_users.py", line 546, in _fetch_query
records = super()._fetch_query(query, fields)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo/codebase/odoo/17.0/odoo/models.py", line 3965, in _fetch_query
self.env.cr.execute(query.select(*sql_terms))
File "/home/odoo/odoo/codebase/odoo/17.0/odoo/sql_db.py", line 335, in execute
res = self._obj.execute(query, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
psycopg2.errors.UndefinedColumn: column res_users.helpdesk_target_closed does not exist
LINE 1: ...s"."odoobot_state", "res_users"."odoobot_failed", "res_users...
```
Issue:
- traceback occurred, as the system is try to fetch fields related to helpdesk module
which do not exists now after uninstalling it.
- cron in case of workers, use daemon threads [1]
- the uninstalled happened with main thread and registry is updated.
- the daemon thread is unaware of this change.
- the `_process_jobs` uses the registry, without checking if it needs reload
[1]: https://github.com/odoo/odoo/blob/e82fdfaf621f45515b92c891334595250accbfbd/odoo/service/server.py#L582-L587
FIx:
- when assigning the registry, we check if needs a reload or not.
opw-5062313
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#229556
Forward-Port-Of: odoo/odoo#228515Breadcrumb labels now refresh correctly when users switch the Odoo interface language. This prevents navigation labels from staying in the previous language, reducing confusion for multilingual users.
Original PR description
[FIX] web: update breadcrumb display name on language switch Versions -------- - 19.0+ Steps ----- 1. Switch the user interface language in Odoo 2. Navigate through the application using breadcrumbs…
[FIX] web: update breadcrumb display name on language switch Versions -------- - 19.0+ Steps ----- 1. Switch the user interface language in Odoo 2. Navigate through the application using breadcrumbs 3. Observe the breadcrumb display names Issue ----- When switching languages, the breadcrumb display names remain in the previous language and do not update to reflect the new language. Cause ----- The action data cached in sessionStorage retains the display names in the original language. When language is switched, the cached action data is not invalidated, causing breadcrumbs to show outdated translated text. Solution -------- Detect language changes by comparing the current user context language with the cached action's language context. When a language mismatch is detected, clear the cached action data from sessionStorage to force a fresh load with properly translated display names. Signed-off-by: PA Sitthipong <sitthipong114@gmail.com> <img width="466" height="198" alt="OdooBugLanguageSwitch" src="https://github.com/user-attachments/assets/83302c7f-bc66-40e4-a310-e7087da1e747" />
Fixes an issue where a manually adjusted delivery date on an invoice could be overwritten after changing product quantities and confirming the invoice. This preserves user-entered delivery information and helps keep invoicing and delivery records accurate.
Original PR description
Versions -------- - 17.0+ Steps ----- 1. Have a sale order with deliverable products & no payment terms; 2. confirm order & validate delivery; 3. create an invoice; 4. modify the delivery date; 5.…
Versions -------- - 17.0+ Steps ----- 1. Have a sale order with deliverable products & no payment terms; 2. confirm order & validate delivery; 3. create an invoice; 4. modify the delivery date; 5. save changes; 6. change product quantity of a line & confirm invoice. Issue ----- The delivery date got reset. Cause ----- The `_compute_show_delivery_date` method gets called, which triggers the recomputation of the `_compute_delivery_date` due it the latter having `line_ids.sale_line_ids.order_id` as its `depends`. Due to the way how `depends` works, if any of the fields in the record chain gets modified, the compute gets triggered. In this case, because we modified a `line_ids` record by changing the quantity, it will therefore recompute the delivery date, overwriting the custom value. Solution -------- As we only want the delivery date to be recomputed when the `effective_date` on the order changes, we should add it to the `depends` to trigger the compute in that scenario. In other scenarios, e.g. modifying the move or one of its lines, we don't want to trigger a recompute, which we can achieve by always including `delivery_date` via `_get_protected_vals` on create/write. opw-4996654 Forward-Port-Of: odoo/odoo#229932 Forward-Port-Of: odoo/odoo#223946
Bank reconciliation now links exchange difference entries to the correct selected line instead of always using the first line. This prevents incorrect accounting references when reconciling multiple bank lines at once, improving accuracy for multi-currency transactions.
Original PR description
When selecting multiple lines in the bank rec widget (reconcile button), it could happen that one of those lines have a exchange diff move linked to it. In this case, the exchange move id was placed on the first line all the time which could be wrong. This commit will change the use of indexes to use the reconciled line of the exchange diff move. no task id --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#226034
This fix lets Spanish TicketBAI credit notes be sent even when the original invoice was issued through a previous invoicing system before TicketBAI was adopted. It prevents valid refunds from being blocked while keeping checks for newer invoices that should already be in TicketBAI.
Original PR description
…re starting to use Tbai 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#225938
Manufacturing orders for products that include variant-specific kit components now correctly include the matching kit operations, such as the right color-related work step. This prevents missing shop floor instructions when a final product uses a specific kit variant.
Original PR description
### Steps to reproduct: - Create 2 products: Final Product (FP), Kit Product (KP) - On KP add a Color attribute with 2 values: Blue, Red - Create a KIT bom for KP wtih 2 operations: - OP: paint it…
### Steps to reproduct:
- Create 2 products: Final Product (FP), Kit Product (KP)
- On KP add a Color attribute with 2 values: Blue, Red
- Create a KIT bom for KP wtih 2 operations:
- OP: paint it Blue, apply on Color: Blue
- OP: paint it Red, apply on Color: Red
- Create a bom for FP with only one component line:
- 1 x Red Kit Product
- Create a MO for 1 unit of FP
#### > The operation was not created using the kit bom
### Cause of the issue:
Even if the bom exploded to find the operations to add on the MO: https://github.com/odoo/odoo/blob/2dfcbe53c80d2d8fe5b6d9828eea90a1d214c2e4/addons/mrp/models/mrp_production.py#L579-L599 The `_skip_operation_line`:
https://github.com/odoo/odoo/blob/2dfcbe53c80d2d8fe5b6d9828eea90a1d214c2e4/addons/mrp/models/mrp_routing.py#L164-L174 is checking if the product of the main bom has the attributes of the operation rather than the kit product used as component.
opw-5080856
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#229810
Forward-Port-Of: odoo/odoo#228032The payroll document generation process now skips payslips when the related employee contact is missing. This prevents scheduled payroll PDF generation from failing and helps keep automated payroll document handling running smoothly.
Original PR description
Currently an error occurs when the **'Payroll: Generate pdfs'** scheduled action runs and tries to create a document for a payslip belonging to an employee who does not have a related partner.…
Currently an error occurs when the **'Payroll: Generate pdfs'** scheduled action runs and tries to create a document for a payslip belonging to an employee who does not have a related partner. **Prerequisites:** - Ensure HR is enabled in `settings>Documents` **Steps to Reproduce:** 1) Install `documents_hr_payroll` module.(with Demo) 2) Navigate to the Employees App. 3) Select any Employee(e.g Abigail Peterson) and open form view. >- click on **contacts** smart button. >- Delete that Record 4) Create a confirmed Payslip for the selected Employee(e.g Abigail Peterson). 5) Activate Developer mode and navigate to schedule Actions. >- Search for 'Payroll: Generate pdfs'. >- Run Manually. Error: `NotNullViolation: null value in column 'partner_id' of relation 'documents_access' violates not-null constraint` Root Cause: When the partner is deleted, the value received from `_get_document_partner` at [1] is `False`, which later on tries to create the `documents.access` record for the new document, it fails because no partner is available to assign access rights, resulting in the error. Solution: This commit prevent Error by ensuring `_check_create_documents` method doesn't allow document creation without valid partner. [1]: https://github.com/odoo/enterprise/blob/99a8d83edb42f172d0dd35c91743fa0c9653dcbb/documents_hr_payroll/models/hr_payslip.py#L20C1-L21 sentry-6814524392 Forward-Port-Of: odoo/enterprise#96191 Forward-Port-Of: odoo/enterprise#92865
Chilean electronic delivery guide XML now shows the quantity actually delivered instead of the quantity originally requested. This prevents overstated quantities when partial deliveries are validated without a backorder, improving document accuracy and compliance.
Original PR description
**Issue** When the delivered quantity of a product is less than the originally demanded quantity, the generated Delivery Guide XML shows the demand (product_uom_qty) instead of the actual delivered…
**Issue** When the delivered quantity of a product is less than the originally demanded quantity, the generated Delivery Guide XML shows the demand (product_uom_qty) instead of the actual delivered quantity (quantity). This results in an incorrect quantity being displayed in the DTE. **Steps to Reproduce** 1. Install the Accounting module, Chilean localization, Sales module, and l10n_cl_edi_stock. 2. Create and confirm a new Sale Order. 3. Click on the Delivery smart button. 4. Adjust the delivered quantity to a value lower than the demand, save, and validate with no backorder. 5. Generate the Delivery Guide. 6. Open the generated DTE XML and observe that the quantity is incorrect. **Root Cause** The quantity displayed in the DTE is taken from product_uom_qty, which represents the planned quantity to be moved, not the actual delivered quantity. The correct field to use is quantity, which reflects the real delivered amount. **Fix** Change the XML output to use quantity instead of product_uom_qty to accurately reflect the actual delivered quantity in the DTE. Opw-4892276 Forward-Port-Of: odoo/enterprise#93260 Forward-Port-Of: odoo/enterprise#89633
When a subcontracted purchase receipt quantity is reduced, Odoo now keeps one manufacturing order open as long as the receipt process is still active. This prevents the workflow from getting stuck and allows later receipt quantity updates to continue correctly.
Original PR description
Steps to reproduce: - Unarchive subcontracting operation type - Create a storable product P1 with a BoM: - BoM type: Subcontracting - Subcontractor: Azure Interior - Component C1 (route: Resupply…
Steps to reproduce:
- Unarchive subcontracting operation type
- Create a storable product P1 with a BoM:
- BoM type: Subcontracting
- Subcontractor: Azure Interior
- Component C1 (route: Resupply Subcontractor on Order)
- Create a purchase order:
- Vendor: Azure Interior
- 10 units of P1
- Confirm the PO → 2 pickings are created:
- Resupply of 10 units of C1
- Receipt of 10 units of P1
- Confirm and validate the resupply of C1
- Components are reserved in the subcontracting MO
- Validate the consumption of 10 units in the receipt
- The MO is updated to 10
- Update the quantity of P1 to 0 in the receipt
Issue:
The manufacturing order is cancelled. As a result, subsequent updates on the receipt cannot recreate MOs.
Fix:
When reducing the receipt quantity, cancel only the extra MOs, but always keep at least one open MO if a subcontracting move is still ongoing.
opw-4792379
Forward-Port-Of: odoo/odoo#225236
Forward-Port-Of: odoo/odoo#223858Customers who quickly use the browser back button after starting an express checkout payment can now try paying again without hitting an error. This prevents a failed checkout flow when the cart has already been converted into an order, improving reliability during payment retries.
Original PR description
This error occurs when trying to make a payment again from the cart. Steps to reproduce: --- - Install the **website_sale** module (with demo) - Activate **Demo** payment provider - Go to Website > Shop > Add a **Warranty** product to Cart > View cart - Pay with Demo > Pay - Click the back button(chrome navbar)(Instantly) - Now again Pay with Demo > Pay Traceback: --- `ValueError: Expected singleton: sale.order()` At [1], this error occurs because **order_sudo** is empty. This happens when there is no product in the cart — typically because, upon clicking **Pay**, a sale order is created for the product, and when the user navigates back, the cart is empty. [1]- https://github.com/odoo/odoo/blob/125fc3028debb311e9f6ad25d8c46699b77525f0/addons/website_sale/controllers/main.py#L1307-L1312 sentry-5682671428 Forward-Port-Of: odoo/odoo#229858
Partner ledger initial balances now include reconciled accounting lines that do not have a partner assigned. This prevents mismatches between opening balances and totals when reviewing reports across different financial periods.
Original PR description
### Issue: The partner ledger does consider lines without partners when calculating the initial balance. ### Steps to reproduce: - Create an invoice in 2025 - Create an entry in 2025 without partner…
### Issue: The partner ledger does consider lines without partners when calculating the initial balance. ### Steps to reproduce: - Create an invoice in 2025 - Create an entry in 2025 without partner for the same amount - Reconcile the two - Open the partner ledger for 2025, everything is correct - Change the dates to 2026, the amount of the initial balance ignores the entry but not the totals ### Cause: The method `_get_sums_without_partner` is called for the totals, but not for the initial balance. Its purpose is to add the amounts of the lines without partners that were reconciled with lines with a partner. ### Solution: Call `_get_sums_without_partner()` in `_get_initial_balance_values()` add the results before returning the initial balances. As this is the same logic as `_query_partners()` we create a new method. This method needs to be called with the dates of the initial balance in the options. So we create a duplicate of the options and input the new dates options. opw-5068790 Forward-Port-Of: odoo/enterprise#96125 Forward-Port-Of: odoo/enterprise#95881
Fixes an issue where exporting the Belgian EC Sales List XML from the VAT Return page could omit the month or quarter when no period was manually selected. The export now uses the company’s tax period settings, helping ensure Belgian tax reporting files are complete and consistent.
Original PR description
**Issue** When accessing the EC Sales List report via the smart button from the VAT Return page, downloading the XML without explicitly selecting a period omits the <Month> element—even though a…
**Issue** When accessing the EC Sales List report via the smart button from the VAT Return page, downloading the XML without explicitly selecting a period omits the <Month> element—even though a month is visibly preselected. **Steps to Reproduce** 1. Install the Accounting module and Belgium localization. 2. Go to the Accounting dashboard. 3. Open the VAT Return via the "Miscellaneous Operations" section. 4. Click the smart button to access the EC Sales List report. 5. Use the gear icon to export the XML. 6. Observe that the XML <Period> section only includes the <Year>—the <Month> is missing. **Root Cause** If no period is explicitly selected, the report uses a period_type of "tax_period". However, this value was not handled when generating the XML, so the logic to include the \<Month> or \<Quarter> elements skipped it. As a result, only the \<Year>, which is always included, was rendered. **Fix** Extend the handling of tax_period to derive the period from the company’s tax periodicity settings and adjust the filter accordingly. This ensures that the generated XML always includes the \<Month> or \<Quarter> element, in addition to \<Year>, whenever the report is based on a tax period. Opw-4702613 Forward-Port-Of: odoo/enterprise#93647 Forward-Port-Of: odoo/enterprise#89290
The AI live chat website block now behaves more consistently with website themes and during page editing. The update improves readability, accessibility, layout, and fullscreen behavior, creating a smoother experience for visitors and website editors.
Original PR description
Resolve theme options compatibility, editing behavior, accessibility and design problems affecting UX and standards compliance. Adherence to theme options: - Apply border-radius correctly to target…
Resolve theme options compatibility, editing behavior, accessibility and design problems affecting UX and standards compliance. Adherence to theme options: - Apply border-radius correctly to target elements - Fix bg-color applying to text-area instead of intended container Edition: - Remove resize/style options on the column since these are not retained on save - Fix the preview that mismatch with actual rendered result - Resolve title/form misalignment in edit mode - Ensure "OR" text readability across different background colors - Preserve container size when the "fullscreen" feature is activated Accessibility: - Add missing focus state for form fields - Add role="presentation" to icons - Add role="button" to anchor tags functioning as buttons Design: - Reduce oversized title font size - Adjust container width on xl and xxl breakpoints - Smooth fullscreen transition to prevent abrupt activation | 19.0 | this PR | |--------|--------| | <img width="1092" height="424" alt="image" src="https://github.com/user-attachments/assets/5cd85204-b9af-4810-9458-c4c96dad562d" /> | <img width="1083" height="409" alt="image" src="https://github.com/user-attachments/assets/b83f2d18-0135-4f5d-b420-11f58070c8a3" /> | task-5089787
SEPA Direct Debit payments are now found correctly during processing after an earlier system change affected how transactions are searched. This helps prevent payment processing failures for customers using SEPA Direct Debit.
Original PR description
After commit 772d8a6f2e66b13f352b56621912e33e7edcccc2,transaction search was changed to rely only on `provider_code`, instead of `custom_mode`. However, the `sepa_direct_debit` logic was not updated accordingly, resulting in transactions no longer being found. This commit adapts the code to the new search logic by using `provider_code` for transaction lookup.
Cancelled manufacturing work orders in backorder flows no longer receive an expected duration as if work had been performed. This prevents inflated or inconsistent manufacturing cost calculations when production is split into backorders.
Original PR description
### Issue: In this bug, the workorder duration being set to duration_expected is causing issues in backorder. To reproduce: 1- Create a Bill of Materials with at least two operations at two work…
### Issue: In this bug, the workorder duration being set to duration_expected is causing issues in backorder. To reproduce: 1- Create a Bill of Materials with at least two operations at two work centers 2- Create a manufacturing order and confirm it. 3- Complete the first operation and edit the quantity on the second operation so there is a backorder for the remaining quantity. 4- In the second work order, the first operation is cancelled, Finish the 2nd operation 5- As you can see, the cancelled operation duration is set to expected duration which is wrong. ### Cause: This issue is caused because of: https://github.com/odoo/odoo/blob/8f0e40286da7b144bfa17880a257406dd8585e57/addons/mrp/models/mrp_production.py#L1774-L1779 Which if work.order.state is `cancel`, the duration will set to `duration_expected`. This will eventually cause issue here: https://github.com/odoo/odoo/pull/222075/commits/8f0e40286da7b144bfa17880a257406dd8585e57#diff-fac872ffb03b811c4976eb2e52991ec544265332df814d92cfda658a5b917423L348 which is fixed by not making the state into `progres` if the state is `cancel`. But that doesn't fix the fact that the cancelled workorder has duration set and it might cause inconsistencies in manufacturing costs. related: #222075 opw-4931653 Forward-Port-Of: odoo/odoo#229975 Forward-Port-Of: odoo/odoo#229742
The reception report now keeps existing warehouse stock reservations intact when users unassign and reassign incoming items to an order. This prevents sales deliveries from showing missing availability even when stock is actually present.
Original PR description
### Issue: #### Steps to reproduce: 1- Activate routes & locations and enable Reception Report 2- Enable Show reception report at validation from operation type: receipts 3- Create a product with…
### Issue: #### Steps to reproduce: 1- Activate routes & locations and enable Reception Report 2- Enable Show reception report at validation from operation type: receipts 3- Create a product with vendor. Put 2 unit on `WH/Stock/Shelf1` 4- Create a Sales Order for 3 units. 5- Create a PO for 1 unit and validate/receive. 6- On the Reception Report, click Assign to link incoming to sales pick 7- Open the sales pick in a new tab, observe there are 2 moves which first one is 1 and 2nd one is 2 8- On the reception report, click Unassign, then Assign again Back on the Pick, only 1 move (the one with quantity of 2) is reserved; checking availability reserves nothing although stock exists. #### Cause: When unassigning from the Reception Report, the system incorrectly unreserves stock that was already in `Shelf1` instead of unreserving the incoming move which the location_id is `WH/Stock`: User clicks Unassign on the Reception Report. `report_stock_reception.action_unassign()` is invoked. That calls `stock_move._do_unreserve()`. `_do_unreserve()` unpicks quants referenced by the `move.move_line_ids`. At this moment one of the `move_line_ids` points to `WH/Stock/Shelf1`, so `_do_unreserve()` removes the reservation from that `shelf1` quant. Consequence: `shelf1` stock(which should have remained reserved) becomes free. The receipt quant at `WH/Stock` remains reserved/ unavailable. When the user clicks Assign again, the system cannot reserve because it is alreade reserved by another move and therefore it is unavailable. #### Root cause: Now we look earlier in the flow to see why the move had a move_line pointing to `WH/Stock/Shelf1` in the first place. Earlier, in `report_stock_reception.action_assign` in the first assign: We create a new move from current outgoing move: https://github.com/odoo/odoo/blob/35ea3dcb2eeb379c8b1127f0c7b42191853c0bd2/addons/stock/report/report_stock_reception.py#L224-L231 And we link current move_lines to the new move: https://github.com/odoo/odoo/blob/35ea3dcb2eeb379c8b1127f0c7b42191853c0bd2/addons/stock/report/report_stock_reception.py#L245-L259 new_out.move_line_ids now contains move lines for multiple source locations, here in our case `[WH/Stock/Shelf1, WH/Stock]` The loop in above code does not check `move_line_id.location_id` when selecting lines. The first matching line in the iteration can be the `shelf1` one, so the code links the `shelf1` move_line to out instead of the `WH/Stock` move_line, which is a mismatch and causes the out move having different location with its move_line, which later will going to cause problem is unassign as explained. ### Fix: We can sort move_line_ids in a way that which line have the same location as potential ins' dest locations come first as better candidates: ```diff - for move_line_id in new_out.move_line_ids: + matching_locations = potential_ins.location_dest_id + for move_line_id in new_out.move_line_ids.sorted(lambda ml: ml.location_id not in matching_locations): ``` opw-4944047 Forward-Port-Of: odoo/odoo#229954 Forward-Port-Of: odoo/odoo#226120