Skip to content

[FIX] purchase_stock_ux: cancel remaining must not leave a pending vendor receipt nor a counter-delivery - #365

Open
fw-bot-adhoc wants to merge 1 commit into
ingadhoc:19.0from
adhoc-dev:19.0-18.0-t-124773-jc-2-7849-fw
Open

[FIX] purchase_stock_ux: cancel remaining must not leave a pending vendor receipt nor a counter-delivery#365
fw-bot-adhoc wants to merge 1 commit into
ingadhoc:19.0from
adhoc-dev:19.0-18.0-t-124773-jc-2-7849-fw

Conversation

@fw-bot-adhoc

Copy link
Copy Markdown

Problem

When cancelling the remaining qty on a purchase order line (button_cancel_remaining), lowering product_qty does not always cancel the pending receipt:

  • Refund return (ticket 124773): after receiving and returning to the vendor with to refund, a live pending IN move survives. The forecast keeps showing units "to receive" that will never arrive.
  • Negative move that does not net (ticket 124957): when the negative move can't merge against the pending one (different price / final location), a counter-delivery (OUT) to the vendor is generated instead of cancelling the remainder.

Fix

After setting product_qty, explicitly cancel the line's open remaining move, scoped to genuine forward vendor receipts:

rec.move_ids.filtered(
    lambda m: m.state not in ("done", "cancel")
    and not m._is_exchange_move_helper()       # exchange-return replacement: legit expected receipt
    and not m.origin_returned_move_id          # open vendor return: not part of the remainder
).with_context(cancel_from_order=True)._action_cancel()

In 1/2/3-step receptions the pending qty always lives in the first-step move (vendor→input), which hangs off move_ids and has no downstream; core _action_cancel propagates to later moves if needed (and never to done ones), so there's no need to walk the chain. product_qty is not touched, so invoicing (qty_to_invoice) stays intact.

The two exclusions matter because returns and exchange replacements also carry purchase_line_id and thus land in move_ids; without the guards, an open (not-yet-validated) vendor return would be cancelled along with the remainder.

Also replaced the expensive fields_get() probe in _is_exchange_move_helper with a plain 'is_exchange_move' in self._fields check (O(1), no full field-descriptor build).

Tests

test_cancel_remaining.py, parametrized over one/two/three steps:

  • partial receipt → cancel remaining closes the line
  • refund return then cancel remaining (124773) → no pending/inflated IN
  • goods already received in transit are preserved
  • open vendor return must survive cancel remaining (RED without the origin_returned_move_id guard; reproduces the over-cancel reported on the client base)

All green on a v18 test DB (0 failed, 0 error of 4 tests).

Forward-Port-Of: #358

…ndor receipt nor a counter-delivery

When cancelling the remaining qty, lowering product_qty does not always cancel the
pending receipt: with a refund return (ticket 124773) a live pending IN remains and
inflates the forecast of units to receive, and when the negative move does not net
against the pending one (different price/final location) a counter-delivery to the
vendor is generated (ticket 124957).

We now explicitly cancel the line's open remaining move. In 1, 2 or 3 step receptions
the pending qty to receive always lives in the first-step move (vendor->input), which
hangs off move_ids and has no downstream; core (_action_cancel) propagates to later
moves if needed, so there is no need to walk the chain. The cancel is scoped to genuine
forward vendor receipts: exchange-return replacements (a legitimate expected receipt)
and open, not-yet-validated vendor returns (origin_returned_move_id, which also hang off
move_ids and are not part of the remainder) are excluded. product_qty is not touched, so
invoicing (qty_to_invoice) stays intact.

Also replace the expensive fields_get() probe in _is_exchange_move_helper with a plain
'is_exchange_move' in self._fields check (O(1), no full field-descriptor build).

Tests (test_cancel_remaining.py, over 1/2/3 steps): partial receipt, refund return
(124773), preservation of goods in transit, and an open vendor return that must survive
cancel remaining (RED without the origin_returned_move_id guard).

X-original-commit: 44a1146
@roboadhoc

Copy link
Copy Markdown
Contributor

Pull request status dashboard

@fw-bot-adhoc

Copy link
Copy Markdown
Author

@jcadhoc @les-adhoc cherrypicking of pull request #358 failed.

stdout:

Auto-merging purchase_stock_ux/__manifest__.py
CONFLICT (content): Merge conflict in purchase_stock_ux/__manifest__.py
Auto-merging purchase_stock_ux/models/purchase_order_line.py
Auto-merging purchase_stock_ux/models/stock_move.py
CONFLICT (content): Merge conflict in purchase_stock_ux/models/stock_move.py

Either perform the forward-port manually (and push to this branch, proceeding as usual) or close this PR (maybe?).

:shipit: you can use git-fw to re-do the forward-port for you locally.

⚠️ after resolving this conflict, you will need to merge it via @roboadhoc.

More info at https://github.com/odoo/odoo/wiki/Mergebot#forward-port

@fw-bot-adhoc

Copy link
Copy Markdown
Author

@jcadhoc @les-adhoc this forward port of #358 is awaiting action (not merged or closed).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants