문제

I know in previous older versions (still 2.0) that I could cancel an order in processing with an invoice but recently that seems to have stopped working for a few of my clients. ie: /V1/orders/{id}/cancel

So I have to change the order cancelation process somehow. Leaving the order closed may also work.

What is the process for cancelling an order that has been invoiced through the API?

What endpoints do I use?

What information do I need?

도움이 되었습니까?

해결책

I think this works as expected. If previously you could have canceled an order that was fully invoiced then the problem was in the past.
Here is how canceling an order (via api or not) works.
The cancel order goes through the Magento\Sales\Api\OrderManagementInterface::cancel() method.
The concrete implementation for this method is Magento\Sales\Model\Service\OrderService::cancel().
and this method looks like this:

public function cancel($id)
{
    $order = $this->orderRepository->get($id);
    if ($order->canCancel()) {
        $order->cancel();
        $this->orderRepository->save($order);
        return true;
    }

    return false;
}

If you are getting the response false it means that $order->canCancel() returns false.
Let's go to that method in the Magento\Sales\Model\Order class.

public function canCancel()
{
    if (!$this->_canVoidOrder()) {
        return false;
    }
    if ($this->canUnhold()) {
        return false;
    }
    if (!$this->canReviewPayment() && $this->canFetchPaymentReviewUpdate()) {
        return false;
    }

    $allInvoiced = true;
    foreach ($this->getAllItems() as $item) {
        if ($item->getQtyToInvoice()) {
            $allInvoiced = false;
            break;
        }
    }

    if ($allInvoiced) {
        return false;
    }

    $state = $this->getState();
    if ($this->isCanceled() || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED) {
        return false;
    }

    if ($this->getActionFlag(self::ACTION_FLAG_CANCEL) === false) {
        return false;
    }

    return true;
}

As you can see, there are a few branches that return false.
The one that handles the invoiced items is this:

    $allInvoiced = true;
    foreach ($this->getAllItems() as $item) {
        if ($item->getQtyToInvoice()) {
            $allInvoiced = false;
            break;
        }
    }

    if ($allInvoiced) {
        return false;
    }

This means that if all the order items are invoiced, the order cannot be canceled.
but if there is at least one item that is not invoiced, the order can be canceled. If you really need this to happen, you can rewrite or plugin the canCancel method and exclude the check for all invoiced items.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 magento.stackexchange
scroll top