diff --git a/vendor/magento/module-sales/Model/ResourceModel/Order/Handler/State.php b/vendor/magento/module-sales/Model/ResourceModel/Order/Handler/State.php
index 47395b17afe..51c45ed5e5a 100644
--- a/vendor/magento/module-sales/Model/ResourceModel/Order/Handler/State.php
+++ b/vendor/magento/module-sales/Model/ResourceModel/Order/Handler/State.php
@@ -38,11 +38,64 @@ class State
             ) {
                 $order->setState(Order::STATE_CLOSED)
                     ->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_CLOSED));
-            } elseif ($currentState === Order::STATE_PROCESSING && !$order->canShip()) {
+            } elseif ($currentState === Order::STATE_PROCESSING
+                && (!$order->canShip() || $this->isPartiallyRefundedOrderShipped($order))
+            ) {
                 $order->setState(Order::STATE_COMPLETE)
                     ->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_COMPLETE));
+            } elseif ($order->getIsVirtual() && $order->getStatus() === Order::STATE_CLOSED) {
+                $order->setState(Order::STATE_CLOSED);
             }
         }
         return $this;
     }
+
+    /**
+     * Check if all items are remaining items after partially refunded are shipped
+     *
+     * @param Order $order
+     * @return bool
+     */
+    public function isPartiallyRefundedOrderShipped(Order $order): bool
+    {
+        $isPartiallyRefundedOrderShipped = false;
+        if ($this->getShippedItems($order) > 0
+            && $order->getTotalQtyOrdered() <= $this->getRefundedItems($order) + $this->getShippedItems($order)) {
+            $isPartiallyRefundedOrderShipped = true;
+        }
+
+        return $isPartiallyRefundedOrderShipped;
+    }
+
+    /**
+     * Get all refunded items number
+     *
+     * @param Order $order
+     * @return int
+     */
+    private function getRefundedItems(Order $order): int
+    {
+        $numOfRefundedItems = 0;
+        foreach ($order->getAllItems() as $item) {
+            if ($item->getProductType() == 'simple') {
+                $numOfRefundedItems += (int)$item->getQtyRefunded();
+            }
+        }
+        return $numOfRefundedItems;
+    }
+
+    /**
+     * Get all shipped items number
+     *
+     * @param Order $order
+     * @return int
+     */
+    private function getShippedItems(Order $order): int
+    {
+        $numOfShippedItems = 0;
+        foreach ($order->getAllItems() as $item) {
+            $numOfShippedItems += (int)$item->getQtyShipped();
+        }
+        return $numOfShippedItems;
+    }
 }
