diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/FlatTableBuilder.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/FlatTableBuilder.php
index 4375092591d194962b108e2ba0351b1a03fa7e5c..40516e55e930c4021699dad26b43a4e83fe26a80 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/FlatTableBuilder.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/FlatTableBuilder.php
@@ -281,7 +281,7 @@ class FlatTableBuilder
             if (!empty($columnValueNames)) {
                 $select->joinLeft(
                     $temporaryValueTableName,
-                    sprintf('e.%1$s = %2$s.%1$s', $linkField, $temporaryTableName),
+                    sprintf('e.%1$s = %2$s.%1$s', $linkField, $temporaryValueTableName),
                     $columnValueNames
                 );
                 $allColumns = array_merge($allColumns, $columnValueNames);
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/FlatTableBuilderTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/FlatTableBuilderTest.php
index 7e5a8305467e8e979a9ccc79d39d7ffdb70bb339..d90261f068f5023d8987bab6d64585032385c8ee 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/FlatTableBuilderTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/FlatTableBuilderTest.php
@@ -107,44 +107,42 @@ class FlatTableBuilderTest extends \PHPUnit_Framework_TestCase
 
     public function testBuild()
     {
-        list($storeId, $changedIds, $valueFieldSuffix, $tableDropSuffix, $fillTmpTables) = [1, [], '', '', true];
+        $storeId = 1;
+        $changedIds = [];
+        $valueFieldSuffix = '_value';
+        $tableDropSuffix = '';
+        $fillTmpTables = true;
         $tableName = 'catalog_product_entity';
         $attributeTable = 'catalog_product_entity_int';
         $temporaryTableName = 'catalog_product_entity_int_tmp_indexer';
-        $temporaryValueTableName = 'catalog_product_entity_int_tmp_indexer';
+        $temporaryValueTableName = 'catalog_product_entity_int_tmp_indexer_value';
         $linkField = 'entity_id';
         $statusId = 22;
+        $eavCustomField = 'space_weight';
+        $eavCustomValueField = $eavCustomField . $valueFieldSuffix;
         $this->flatIndexerMock->expects($this->once())->method('getAttributes')->willReturn([]);
         $this->flatIndexerMock->expects($this->exactly(3))->method('getFlatColumns')
-            ->willReturnOnConsecutiveCalls(
-                [],
-                [$linkField => []],
-                [$linkField => []]
-            );
+            ->willReturnOnConsecutiveCalls([], [$eavCustomValueField => []], [$eavCustomValueField => []]);
         $this->flatIndexerMock->expects($this->once())->method('getFlatIndexes')->willReturn([]);
         $statusAttributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute::class)
             ->disableOriginalConstructor()
             ->getMock();
+        $eavCustomAttributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute::class)
+            ->disableOriginalConstructor()
+            ->getMock();
         $this->flatIndexerMock->expects($this->once())->method('getTablesStructure')
             ->willReturn(
                 [
-                    'catalog_product_entity' => [
-                        $linkField => $statusAttributeMock
-                    ],
+                    'catalog_product_entity' => [$linkField => $statusAttributeMock],
                     'catalog_product_entity_int' => [
-                        $linkField => $statusAttributeMock
+                        $linkField => $statusAttributeMock,
+                        $eavCustomField => $eavCustomAttributeMock
                     ]
                 ]
             );
         $this->flatIndexerMock->expects($this->atLeastOnce())->method('getTable')
-            ->withConsecutive(
-                [$tableName],
-                ['catalog_product_website']
-            )
-            ->willReturnOnConsecutiveCalls(
-                $tableName,
-                'catalog_product_website'
-            );
+            ->withConsecutive([$tableName], ['catalog_product_website'])
+            ->willReturnOnConsecutiveCalls($tableName, 'catalog_product_website');
         $this->flatIndexerMock->expects($this->once())->method('getAttribute')
             ->with('status')
             ->willReturn($statusAttributeMock);
@@ -155,6 +153,9 @@ class FlatTableBuilderTest extends \PHPUnit_Framework_TestCase
         $statusAttributeMock->expects($this->atLeastOnce())->method('getBackend')->willReturn(
             $backendMock
         );
+        $eavCustomAttributeMock->expects($this->atLeastOnce())->method('getBackend')->willReturn(
+            $backendMock
+        );
         $statusAttributeMock->expects($this->atLeastOnce())->method('getId')->willReturn($statusId);
         $tableMock = $this->getMockBuilder(\Magento\Framework\DB\Ddl\Table::class)
             ->disableOriginalConstructor()
@@ -185,12 +186,12 @@ class FlatTableBuilderTest extends \PHPUnit_Framework_TestCase
                 [
                     $temporaryTableName,
                     "e.{$linkField} = {$temporaryTableName}.{$linkField}",
-                    [$linkField]
+                    [$linkField, $eavCustomField]
                 ],
                 [
                     $temporaryValueTableName,
-                    "e.{$linkField} = " . $temporaryValueTableName . ".{$linkField}",
-                    [$linkField]
+                    "e.{$linkField} = {$temporaryValueTableName}.{$linkField}",
+                    [$eavCustomValueField]
                 ]
             )->willReturnSelf();
         $this->metadataPoolMock->expects($this->atLeastOnce())->method('getMetadata')->with(ProductInterface::class)
diff --git a/app/code/Magento/CatalogInventory/etc/events.xml b/app/code/Magento/CatalogInventory/etc/events.xml
index a1476c2c3f8b161568a042725d6b04c37aeb1be9..d9db59b7a17663b48b2ba2df7677d4147cba11b5 100644
--- a/app/code/Magento/CatalogInventory/etc/events.xml
+++ b/app/code/Magento/CatalogInventory/etc/events.xml
@@ -33,9 +33,6 @@
     <event name="sales_order_item_cancel">
         <observer name="inventory" instance="Magento\CatalogInventory\Observer\CancelOrderItemObserver"/>
     </event>
-    <event name="sales_order_creditmemo_save_after">
-        <observer name="inventory" instance="Magento\CatalogInventory\Observer\RefundOrderInventoryObserver"/>
-    </event>
     <event name="catalog_product_save_after">
         <observer name="inventory" instance="Magento\CatalogInventory\Observer\SaveInventoryDataObserver"/>
     </event>
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js b/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js
index e06b8922b2252fd497db66a79db35af8c543db09..eba77927be79ea6189884f412be03be7ec7a76be 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/region-updater.js
@@ -7,9 +7,10 @@
 define([
     'jquery',
     'mage/template',
+    'underscore',
     'jquery/ui',
     'mage/validation'
-], function ($, mageTemplate) {
+], function ($, mageTemplate, _) {
     'use strict';
 
     $.widget('mage.regionUpdater', {
@@ -124,6 +125,8 @@ define([
          * @private
          */
         _clearError: function () {
+            var args = ['clearError', this.options.regionListId, this.options.regionInputId, this.options.postcodeId];
+
             if (this.options.clearError && typeof this.options.clearError === 'function') {
                 this.options.clearError.call(this);
             } else {
@@ -133,8 +136,8 @@ define([
 
                 this.options.form = $(this.options.form);
 
-                this.options.form && this.options.form.data('validator') && this.options.form.validation('clearError',
-                    this.options.regionListId, this.options.regionInputId, this.options.postcodeId);
+                this.options.form && this.options.form.data('validator') &&
+                    this.options.form.validation.apply(this.options.form, _.compact(args));
 
                 // Clean up errors on region & zip fix
                 $(this.options.regionInputId).removeClass('mage-error').parent().find('[generated]').remove();
diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php
index 36f1310079ed534d928fa03be511a64265f71dc5..ac3ffdc3d622c956074b3fc174df6c24e4cabff3 100644
--- a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php
+++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php
@@ -217,9 +217,9 @@ class CreditmemoLoader extends DataObject
             foreach ($creditmemo->getAllItems() as $creditmemoItem) {
                 $orderItem = $creditmemoItem->getOrderItem();
                 $parentId = $orderItem->getParentItemId();
-                if (isset($backToStock[$orderItem->getId()])) {
+                if ($parentId && isset($backToStock[$parentId]) && $backToStock[$parentId]) {
                     $creditmemoItem->setBackToStock(true);
-                } elseif ($orderItem->getParentItem() && isset($backToStock[$parentId]) && $backToStock[$parentId]) {
+                } elseif (isset($backToStock[$orderItem->getId()])) {
                     $creditmemoItem->setBackToStock(true);
                 } elseif (empty($savedData)) {
                     $creditmemoItem->setBackToStock(
diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php
index 21104933a51d6d8fda5d225ff4b879a07def3d20..ff687074e4a66cc50c457c685fc1757d1529dcb6 100644
--- a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php
+++ b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php
@@ -3,7 +3,6 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Sales\Model\Order;
 
 /**
@@ -23,6 +22,11 @@ class CreditmemoFactory
      */
     protected $taxConfig;
 
+    /**
+     * @var \Magento\Framework\Unserialize\Unserialize
+     */
+    protected $unserialize;
+
     /**
      * Factory constructor
      *
@@ -57,7 +61,12 @@ class CreditmemoFactory
 
             $item = $this->convertor->itemToCreditmemoItem($orderItem);
             if ($orderItem->isDummy()) {
-                $qty = 1;
+                if (isset($data['qtys'][$orderItem->getParentItemId()])) {
+                    $parentQty = $data['qtys'][$orderItem->getParentItemId()];
+                } else {
+                    $parentQty = $orderItem->getParentItem() ? $orderItem->getParentItem()->getQtyToRefund() : 1;
+                }
+                $qty = $this->calculateProductOptions($orderItem, $parentQty);
                 $orderItem->setLockedDoShip(true);
             } else {
                 if (isset($qtys[$orderItem->getId()])) {
@@ -132,7 +141,12 @@ class CreditmemoFactory
 
             $item = $this->convertor->itemToCreditmemoItem($orderItem);
             if ($orderItem->isDummy()) {
-                $qty = 1;
+                if (isset($data['qtys'][$orderItem->getParentItemId()])) {
+                    $parentQty = $data['qtys'][$orderItem->getParentItemId()];
+                } else {
+                    $parentQty = $orderItem->getParentItem() ? $orderItem->getParentItem()->getQtyToRefund() : 1;
+                }
+                $qty = $this->calculateProductOptions($orderItem, $parentQty);
             } else {
                 if (isset($qtys[$orderItem->getId()])) {
                     $qty = (double)$qtys[$orderItem->getId()];
@@ -245,4 +259,38 @@ class CreditmemoFactory
             $creditmemo->setAdjustmentNegative($data['adjustment_negative']);
         }
     }
+
+    /**
+     * @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem
+     * @param array $qtys
+     * @return int
+     */
+    private function calculateProductOptions(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, $parentQty)
+    {
+        $qty = $parentQty;
+        $productOptions = $orderItem->getProductOptions();
+        if (isset($productOptions['bundle_selection_attributes'])) {
+            $bundleSelectionAttributes = $this->getUnserialize()
+                ->unserialize($productOptions['bundle_selection_attributes']);
+            if ($bundleSelectionAttributes) {
+                $qty = $bundleSelectionAttributes['qty'] * $parentQty;
+            }
+        }
+        return $qty;
+    }
+
+    /**
+     * Get Unserialize
+     *
+     * @return \Magento\Framework\Unserialize\Unserialize
+     * @deprecated
+     */
+    private function getUnserialize()
+    {
+        if (!$this->unserialize) {
+            $this->unserialize = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Framework\Unserialize\Unserialize::class);
+        }
+        return $this->unserialize;
+    }
 }
diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/sidebar/items.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/sidebar/items.phtml
index 59bb31a94fa0cadadf177f695271c1efeaa69aa6..a8ccf82c5fe06030055381d9c13228661308e04e 100644
--- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/sidebar/items.phtml
+++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/sidebar/items.phtml
@@ -66,7 +66,13 @@
                         <?php endif; ?>
 
                         <?php if ($block->canDisplayPrice()): ?>
-                            <td class="col-price"><?php /* @noEscape */ echo $block->getItemPrice($_item) ?></td>
+                            <td class="col-price">
+                                <?php if ($block->getDataId() == 'cart'): ?>
+                                    <?php /* @noEscape */ echo $block->getItemPrice($_item->getProduct()) ?>
+                                <?php else: ?>
+                                    <?php /* @noEscape */ echo $block->getItemPrice($_item) ?>
+                                <?php endif; ?>
+                            </td>
                         <?php endif; ?>
 
                         <?php if ($block->canRemoveItems()): ?>
diff --git a/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php b/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php
index 7752d7131031cf0daa63f4c8b8bf49609e3090ed..3680bbb3a1eaefa3ee822eefd99b7b21b320a3f8 100644
--- a/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php
+++ b/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php
@@ -6,7 +6,6 @@
 namespace Magento\SalesInventory\Model\Order;
 
 use Magento\Sales\Api\Data\CreditmemoInterface;
-use Magento\Sales\Api\Data\CreditmemoItemInterface;
 use Magento\Sales\Api\Data\OrderInterface;
 
 /**
@@ -29,52 +28,35 @@ class ReturnProcessor
      */
     private $priceIndexer;
 
-    /**
-     * @var \Magento\Sales\Api\CreditmemoRepositoryInterface
-     */
-    private $creditmemoRepository;
-
     /**
      * @var \Magento\Store\Model\StoreManagerInterface
      */
     private $storeManager;
 
-    /**
-     * @var \Magento\Sales\Api\OrderRepositoryInterface
-     */
-    private $orderRepository;
-
     /**
      * @var \Magento\Sales\Api\OrderItemRepositoryInterface
      */
     private $orderItemRepository;
 
     /**
-     * ReturnToStockPlugin constructor.
-     * @param \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration
+     * ReturnProcessor constructor.
      * @param \Magento\CatalogInventory\Api\StockManagementInterface $stockManagement
      * @param \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexer
      * @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer
-     * @param \Magento\Sales\Api\CreditmemoRepositoryInterface $creditmemoRepository
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
-     * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
      * @param \Magento\Sales\Api\OrderItemRepositoryInterface $orderItemRepository
      */
     public function __construct(
         \Magento\CatalogInventory\Api\StockManagementInterface $stockManagement,
         \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexer,
         \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer,
-        \Magento\Sales\Api\CreditmemoRepositoryInterface $creditmemoRepository,
         \Magento\Store\Model\StoreManagerInterface $storeManager,
-        \Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
         \Magento\Sales\Api\OrderItemRepositoryInterface $orderItemRepository
     ) {
         $this->stockManagement = $stockManagement;
         $this->stockIndexerProcessor = $stockIndexer;
         $this->priceIndexer = $priceIndexer;
-        $this->creditmemoRepository = $creditmemoRepository;
         $this->storeManager = $storeManager;
-        $this->orderRepository = $orderRepository;
         $this->orderItemRepository = $orderItemRepository;
     }
 
@@ -82,22 +64,22 @@ class ReturnProcessor
      * @param CreditmemoInterface $creditmemo
      * @param OrderInterface $order
      * @param array $returnToStockItems
+     * @param bool $isAutoReturn
      * @return void
      */
     public function execute(
         CreditmemoInterface $creditmemo,
         OrderInterface $order,
-        array $returnToStockItems = []
+        array $returnToStockItems = [],
+        $isAutoReturn = false
     ) {
         $itemsToUpdate = [];
         foreach ($creditmemo->getItems() as $item) {
-            $qty = $item->getQty();
             $productId = $item->getProductId();
             $orderItem = $this->orderItemRepository->get($item->getOrderItemId());
             $parentItemId = $orderItem->getParentItemId();
-            if ($this->canReturnItem($item, $qty, $parentItemId, $returnToStockItems)) {
-                $parentItem = $parentItemId ? $this->getItemByOrderId($creditmemo, $parentItemId) : false;
-                $qty = $parentItem ? $parentItem->getQty() * $qty : $qty;
+            $qty = $item->getQty();
+            if ($isAutoReturn || $this->canReturnItem($item, $qty, $parentItemId, $returnToStockItems)) {
                 if (isset($itemsToUpdate[$productId])) {
                     $itemsToUpdate[$productId] += $qty;
                 } else {
@@ -122,21 +104,6 @@ class ReturnProcessor
         }
     }
 
-    /**
-     * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo
-     * @param int $parentItemId
-     * @return bool|CreditmemoItemInterface
-     */
-    private function getItemByOrderId(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo, $parentItemId)
-    {
-        foreach ($creditmemo->getItems() as $item) {
-            if ($item->getOrderItemId() == $parentItemId) {
-                return $item;
-            }
-        }
-        return false;
-    }
-
     /**
      * @param \Magento\Sales\Api\Data\CreditmemoItemInterface $item
      * @param int $qty
diff --git a/app/code/Magento/CatalogInventory/Observer/RefundOrderInventoryObserver.php b/app/code/Magento/SalesInventory/Observer/RefundOrderInventoryObserver.php
similarity index 57%
rename from app/code/Magento/CatalogInventory/Observer/RefundOrderInventoryObserver.php
rename to app/code/Magento/SalesInventory/Observer/RefundOrderInventoryObserver.php
index 9702bfc7cfe425b2c8987c1aec4e86430e1d62ac..acdebcf976a2eead77eb6074611968a9831cd524 100644
--- a/app/code/Magento/CatalogInventory/Observer/RefundOrderInventoryObserver.php
+++ b/app/code/Magento/SalesInventory/Observer/RefundOrderInventoryObserver.php
@@ -4,54 +4,74 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\CatalogInventory\Observer;
+namespace Magento\SalesInventory\Observer;
 
 use Magento\CatalogInventory\Api\StockConfigurationInterface;
 use Magento\CatalogInventory\Api\StockManagementInterface;
 use Magento\Framework\Event\Observer as EventObserver;
 use Magento\Framework\Event\ObserverInterface;
+use Magento\Sales\Model\OrderRepository;
+use Magento\SalesInventory\Model\Order\ReturnProcessor;
 
 /**
  * Catalog inventory module observer
+ * @deprecated
  */
 class RefundOrderInventoryObserver implements ObserverInterface
 {
     /**
      * @var StockConfigurationInterface
      */
-    protected $stockConfiguration;
+    private $stockConfiguration;
 
     /**
      * @var StockManagementInterface
      */
-    protected $stockManagement;
+    private $stockManagement;
 
     /**
      * @var \Magento\CatalogInventory\Model\Indexer\Stock\Processor
      */
-    protected $stockIndexerProcessor;
+    private $stockIndexerProcessor;
 
     /**
      * @var \Magento\Catalog\Model\Indexer\Product\Price\Processor
      */
-    protected $priceIndexer;
+    private $priceIndexer;
 
     /**
+     * @var \Magento\SalesInventory\Model\Order\ReturnProcessor
+     */
+    private $returnProcessor;
+
+    /**
+     * @var \Magento\Sales\Api\OrderRepositoryInterface
+     */
+    private $orderRepository;
+
+    /**
+     * RefundOrderInventoryObserver constructor.
      * @param StockConfigurationInterface $stockConfiguration
      * @param StockManagementInterface $stockManagement
      * @param \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexerProcessor
      * @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer
+     * @param ReturnProcessor $returnProcessor
+     * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
      */
     public function __construct(
         StockConfigurationInterface $stockConfiguration,
         StockManagementInterface $stockManagement,
         \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexerProcessor,
-        \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer
+        \Magento\Catalog\Model\Indexer\Product\Price\Processor $priceIndexer,
+        \Magento\SalesInventory\Model\Order\ReturnProcessor $returnProcessor,
+        \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
     ) {
         $this->stockConfiguration = $stockConfiguration;
         $this->stockManagement = $stockManagement;
         $this->stockIndexerProcessor = $stockIndexerProcessor;
         $this->priceIndexer = $priceIndexer;
+        $this->returnProcessor = $returnProcessor;
+        $this->orderRepository = $orderRepository;
     }
 
     /**
@@ -64,31 +84,18 @@ class RefundOrderInventoryObserver implements ObserverInterface
     {
         /* @var $creditmemo \Magento\Sales\Model\Order\Creditmemo */
         $creditmemo = $observer->getEvent()->getCreditmemo();
-        $itemsToUpdate = [];
-        foreach ($creditmemo->getAllItems() as $item) {
-            $qty = $item->getQty();
-            if (($item->getBackToStock() && $qty) || $this->stockConfiguration->isAutoReturnEnabled()) {
-                $productId = $item->getProductId();
-                $parentItemId = $item->getOrderItem()->getParentItemId();
-                /* @var $parentItem \Magento\Sales\Model\Order\Creditmemo\Item */
-                $parentItem = $parentItemId ? $creditmemo->getItemByOrderId($parentItemId) : false;
-                $qty = $parentItem ? $parentItem->getQty() * $qty : $qty;
-                if (isset($itemsToUpdate[$productId])) {
-                    $itemsToUpdate[$productId] += $qty;
-                } else {
-                    $itemsToUpdate[$productId] = $qty;
-                }
+        $order = $this->orderRepository->get($creditmemo->getOrderId());
+        $returnToStockItems = [];
+        foreach ($creditmemo->getItems() as $item) {
+            if ($item->getBackToStock()) {
+                $returnToStockItems[] = $item->getOrderItemId();
             }
         }
-        if (!empty($itemsToUpdate)) {
-            $this->stockManagement->revertProductsSale(
-                $itemsToUpdate,
-                $creditmemo->getStore()->getWebsiteId()
-            );
-
-            $updatedItemIds = array_keys($itemsToUpdate);
-            $this->stockIndexerProcessor->reindexList($updatedItemIds);
-            $this->priceIndexer->reindexList($updatedItemIds);
-        }
+        $this->returnProcessor->execute(
+            $creditmemo,
+            $order,
+            $returnToStockItems,
+            $this->stockConfiguration->isAutoReturnEnabled()
+        );
     }
 }
diff --git a/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php b/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php
index 523759d54645a1e2db471db948fa116cf59cd32e..efa3bff32c0fa2b40c3a9a57ec04cb1ec5c9f257 100644
--- a/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php
+++ b/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php
@@ -5,9 +5,7 @@
  */
 namespace Magento\SalesInventory\Test\Unit\Model\Order;
 
-use Magento\CatalogInventory\Api\StockConfigurationInterface;
 use Magento\CatalogInventory\Api\StockManagementInterface;
-use Magento\Sales\Api\CreditmemoRepositoryInterface;
 use Magento\Sales\Api\Data\CreditmemoInterface;
 use Magento\Sales\Api\Data\CreditmemoItemInterface;
 use Magento\Sales\Api\Data\OrderInterface;
@@ -49,21 +47,11 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase
      */
     private $priceIndexerMock;
 
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|CreditmemoRepositoryInterface
-     */
-    private $creditmemoRepositoryMock;
-
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject|StoreManagerInterface
      */
     private $storeManagerMock;
 
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|OrderRepositoryInterface
-     */
-    private $orderRepositoryMock;
-
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject|OrderItemRepositoryInterface
      */
@@ -95,13 +83,10 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase
         $this->priceIndexerMock = $this->getMockBuilder(\Magento\Catalog\Model\Indexer\Product\Price\Processor::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->creditmemoRepositoryMock = $this->getMockBuilder(CreditmemoRepositoryInterface::class)
-            ->disableOriginalConstructor()
-            ->getMock();
         $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class)
+        $this->orderItemRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->orderItemRepositoryMock = $this->getMockBuilder(OrderItemRepositoryInterface::class)
@@ -127,9 +112,7 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase
             $this->stockManagementMock,
             $this->stockIndexerProcessorMock,
             $this->priceIndexerMock,
-            $this->creditmemoRepositoryMock,
             $this->storeManagerMock,
-            $this->orderRepositoryMock,
             $this->orderItemRepositoryMock
         );
     }
@@ -139,6 +122,7 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase
         $orderItemId = 99;
         $productId = 50;
         $returnToStockItems = [$orderItemId];
+        $parentItemId = 52;
         $qty = 1;
         $storeId = 0;
         $webSiteId = 10;
@@ -147,10 +131,6 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase
             ->method('getItems')
             ->willReturn([$this->creditmemoItemMock]);
 
-        $this->creditmemoItemMock->expects($this->once())
-            ->method('getQty')
-            ->willReturn($qty);
-
         $this->creditmemoItemMock->expects($this->exactly(2))
             ->method('getOrderItemId')
             ->willReturn($orderItemId);
@@ -190,6 +170,14 @@ class ReturnProcessorTest extends \PHPUnit_Framework_TestCase
             ->method('reindexList')
             ->with([$productId]);
 
+        $this->orderItemMock->expects($this->once())
+            ->method('getParentItemId')
+            ->willReturn($parentItemId);
+
+        $this->creditmemoItemMock->expects($this->once())
+            ->method('getQty')
+            ->willReturn($qty);
+
         $this->returnProcessor->execute($this->creditmemoMock, $this->orderMock, $returnToStockItems);
     }
 }
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php b/app/code/Magento/SalesInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php
similarity index 65%
rename from app/code/Magento/CatalogInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php
rename to app/code/Magento/SalesInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php
index e440ed3380498a0c8d0deb9fb4edbd68a5d2c295..4e553493d07f63ed9f7d0a2d0d0ec7129d7580e7 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php
+++ b/app/code/Magento/SalesInventory/Test/Unit/Observer/RefundOrderInventoryObserverTest.php
@@ -3,9 +3,12 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\CatalogInventory\Test\Unit\Observer;
+namespace Magento\SalesInventory\Test\Unit\Observer;
 
-use Magento\CatalogInventory\Observer\RefundOrderInventoryObserver;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\OrderRepository;
+use Magento\SalesInventory\Model\Order\ReturnProcessor;
+use Magento\SalesInventory\Observer\RefundOrderInventoryObserver;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -47,6 +50,26 @@ class RefundOrderInventoryObserverTest extends \PHPUnit_Framework_TestCase
      */
     protected $eventObserver;
 
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
+     */
+    protected $objectManagerHelper;
+
+    /**
+     * @var OrderRepository|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $orderRepositoryMock;
+
+    /**
+     * @var ReturnProcessor|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $returnProcessorMock;
+
+    /**
+     * @var OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
     protected function setUp()
     {
         $this->stockIndexerProcessor = $this->getMock(
@@ -93,8 +116,22 @@ class RefundOrderInventoryObserverTest extends \PHPUnit_Framework_TestCase
             ->method('getEvent')
             ->will($this->returnValue($this->event));
 
-        $this->observer = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject(
-            \Magento\CatalogInventory\Observer\RefundOrderInventoryObserver::class,
+        $this->orderRepositoryMock = $this->getMockBuilder(OrderRepository::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->returnProcessorMock = $this->getMockBuilder(ReturnProcessor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->observer = $this->objectManagerHelper->getObject(
+            \Magento\SalesInventory\Observer\RefundOrderInventoryObserver::class,
             [
                 'stockConfiguration' => $this->stockConfiguration,
                 'stockManagement' => $this->stockManagement,
@@ -102,83 +139,67 @@ class RefundOrderInventoryObserverTest extends \PHPUnit_Framework_TestCase
                 'priceIndexer' => $this->priceIndexer,
             ]
         );
+
+        $this->objectManagerHelper->setBackwardCompatibleProperty(
+            $this->observer,
+            'orderRepository',
+            $this->orderRepositoryMock
+        );
+        $this->objectManagerHelper->setBackwardCompatibleProperty(
+            $this->observer,
+            'returnProcessor',
+            $this->returnProcessorMock
+        );
     }
 
     public function testRefundOrderInventory()
     {
-        $websiteId = 0;
         $ids = ['1', '14'];
         $items = [];
         $isAutoReturnEnabled = true;
 
-        $store = $this->getMock(
-            \Magento\Store\Model\Store::class,
-            ['getWebsiteId'],
-            [],
-            '',
-            false
-        );
-        $store->expects($this->once())->method('getWebsiteId')->will($this->returnValue($websiteId));
+        $creditMemo = $this->getMock(\Magento\Sales\Model\Order\Creditmemo::class, [], [], '', false);
 
-        $itemsToUpdate = [];
         foreach ($ids as $id) {
             $item = $this->getCreditMemoItem($id);
             $items[] = $item;
-            $itemsToUpdate[$item->getProductId()] = $item->getQty();
         }
-        $creditMemo = $this->getMock(\Magento\Sales\Model\Order\Creditmemo::class, [], [], '', false);
+
         $creditMemo->expects($this->once())
-            ->method('getAllItems')
+            ->method('getItems')
             ->will($this->returnValue($items));
-        $creditMemo->expects($this->once())->method('getStore')->will($this->returnValue($store));
 
         $this->stockConfiguration->expects($this->any())
             ->method('isAutoReturnEnabled')
             ->will($this->returnValue($isAutoReturnEnabled));
 
-        $this->stockManagement->expects($this->once())
-            ->method('revertProductsSale')
-            ->with($itemsToUpdate, $websiteId);
-
-        $this->stockIndexerProcessor->expects($this->once())
-            ->method('reindexList')
-            ->with($ids);
-
-        $this->priceIndexer->expects($this->once())
-            ->method('reindexList')
-            ->with($ids);
-
         $this->event->expects($this->once())
             ->method('getCreditmemo')
             ->will($this->returnValue($creditMemo));
 
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($this->orderMock);
+
+        $this->returnProcessorMock->expects($this->once())
+            ->method('execute')
+            ->with($creditMemo, $this->orderMock, $ids, $isAutoReturnEnabled);
+
         $this->observer->execute($this->eventObserver);
     }
 
     private function getCreditMemoItem($productId)
     {
-        $parentItemId = false;
         $backToStock = true;
-        $qty = 1;
         $item = $this->getMock(
             \Magento\Sales\Model\Order\Creditmemo\Item::class,
-            ['getProductId', 'getOrderItem', 'getBackToStock', 'getQty', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $orderItem = $this->getMock(
-            \Magento\Sales\Model\Order\Item::class,
-            ['getParentItemId', '__wakeup'],
+            ['getOrderItemId', 'getBackToStock', 'getQty', '__wakeup'],
             [],
             '',
             false
         );
-        $orderItem->expects($this->any())->method('getParentItemId')->willReturn($parentItemId);
-        $item->expects($this->any())->method('getOrderItem')->willReturn($orderItem);
-        $item->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
         $item->expects($this->any())->method('getBackToStock')->willReturn($backToStock);
-        $item->expects($this->any())->method('getQty')->willReturn($qty);
+        $item->expects($this->any())->method('getOrderItemId')->willReturn($productId);
         return $item;
     }
 }
diff --git a/app/code/Magento/SalesInventory/etc/events.xml b/app/code/Magento/SalesInventory/etc/events.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a71ed7f8a28a16a4ded03e507876757ec94f436c
--- /dev/null
+++ b/app/code/Magento/SalesInventory/etc/events.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
+    <event name="sales_order_creditmemo_save_after">
+        <observer name="inventory" instance="Magento\SalesInventory\Observer\RefundOrderInventoryObserver"/>
+    </event>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php
new file mode 100644
index 0000000000000000000000000000000000000000..e5c3ab4dad9ee121c1332649dabd8715c3544449
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableProduct\Test\Constraint;
+
+use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit;
+use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex;
+use Magento\Mtf\Constraint\AbstractConstraint;
+use Magento\Mtf\Fixture\FixtureFactory;
+use Magento\Mtf\Fixture\FixtureInterface;
+use Magento\Mtf\ObjectManager;
+use Magento\Mtf\System\Event\EventManagerInterface;
+use Magento\Sales\Test\Fixture\OrderInjectable;
+
+/**
+ * Class AssertProductQtyDecreasedAfterCreditmemo
+ */
+class AssertProductQtyDecreasedAfterCreditmemo extends AbstractConstraint
+{
+    /**
+     * @var FixtureFactory
+     */
+    protected $fixtureFactory;
+
+    /**
+     * Skip fields for create product fixture.
+     *
+     * @var array
+     */
+    protected $skipFields = [
+        'attribute_set_id',
+        'website_ids',
+        'checkout_data',
+        'type_id',
+        'price',
+    ];
+
+    /**
+     * AssertFirstProductForm constructor.
+     * @param ObjectManager $objectManager
+     */
+    public function __construct(
+        ObjectManager $objectManager,
+        EventManagerInterface $eventManager,
+        FixtureFactory $fixtureFactory
+    ) {
+        $this->fixtureFactory = $fixtureFactory;
+        parent::__construct($objectManager, $eventManager);
+    }
+
+    /**
+     * Assert form data equals fixture data
+     *
+     * @param OrderInjectable $order
+     * @param array $data
+     * @param CatalogProductIndex $productGrid
+     * @param CatalogProductEdit $productPage
+     * @return void
+     */
+    public function processAssert(
+        OrderInjectable $order,
+        array $data,
+        CatalogProductIndex $productGrid,
+        CatalogProductEdit $productPage
+    ) {
+        $product = $this->getProduct($order, $data);
+        $this->objectManager->get(\Magento\Catalog\Test\Constraint\AssertProductForm::class)->processAssert(
+            $product,
+            $productGrid,
+            $productPage
+        );
+    }
+
+    /**
+     * Get product's fixture.
+     *
+     * @param OrderInjectable $order
+     * @param array $data
+     * @param int $index [optional]
+     * @return FixtureInterface
+     */
+    protected function getProduct(OrderInjectable $order, array $data, $index = 0)
+    {
+        if (!isset($data['items_data'][$index]['back_to_stock'])
+            || $data['items_data'][$index]['back_to_stock'] != 'Yes'
+        ) {
+            return $order->getEntityId()['products'][$index];
+        }
+        $product = $order->getEntityId()['products'][$index];
+        $productData = $product->getData();
+        $checkoutDataQty = $productData['checkout_data']['qty'];
+
+        $productKey = '';
+        foreach ($productData['checkout_data']['options']['configurable_options'] as $option) {
+            $productKey .= ' ' . $option['title'] . ':' . $option['value'];
+        }
+        $productKey = trim($productKey);
+        $optionProduct = $productData['configurable_attributes_data']['matrix'][$productKey];
+        $optionProduct['qty'] -= ($checkoutDataQty - $data['items_data'][$index]['qty']);
+        $productData = $optionProduct;
+
+        $productData = array_diff_key($productData, array_flip($this->skipFields));
+
+        return $this->fixtureFactory->create(get_class($product), ['data' => $productData]);
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Product qty was decreased after creditmemo creation.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml
index 4a69a7604bca3d74119b07bdcea3b2115a1f6648..32f1957d4173f87b10069b60c8c428b921e260fb 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml
@@ -71,7 +71,40 @@
         </dataset>
 
         <dataset name="configurable_with_qty_1">
-            <field name="name" xsi:type="string">Test configurable product %isolation%</field>
+            <field name="name" xsi:type="string">sku_test_configurable_product_%isolation%</field>
+            <field name="sku" xsi:type="string">sku_test_configurable_product_%isolation%</field>
+            <field name="price" xsi:type="array">
+                <item name="dataset" xsi:type="string">price_40</item>
+            </field>
+            <field name="product_has_weight" xsi:type="string">This item has weight</field>
+            <field name="weight" xsi:type="string">30</field>
+            <field name="status" xsi:type="string">Yes</field>
+            <field name="visibility" xsi:type="string">Catalog, Search</field>
+            <field name="tax_class_id" xsi:type="array">
+                <item name="dataset" xsi:type="string">taxable_goods</item>
+            </field>
+            <field name="url_key" xsi:type="string">configurable-product-%isolation%</field>
+            <field name="configurable_attributes_data" xsi:type="array">
+                <item name="dataset" xsi:type="string">default</item>
+            </field>
+            <field name="quantity_and_stock_status" xsi:type="array">
+                <item name="is_in_stock" xsi:type="string">In Stock</item>
+            </field>
+            <field name="website_ids" xsi:type="array">
+                <item name="0" xsi:type="array">
+                    <item name="dataset" xsi:type="string">default</item>
+                </item>
+            </field>
+            <field name="attribute_set_id" xsi:type="array">
+                <item name="dataset" xsi:type="string">default</item>
+            </field>
+            <field name="checkout_data" xsi:type="array">
+                <item name="dataset" xsi:type="string">configurable_options_with_qty_1</item>
+            </field>
+        </dataset>
+
+        <dataset name="configurable_with_qty_2">
+            <field name="name" xsi:type="string">sku_test_configurable_product_%isolation%</field>
             <field name="sku" xsi:type="string">sku_test_configurable_product_%isolation%</field>
             <field name="price" xsi:type="array">
                 <item name="dataset" xsi:type="string">price_40</item>
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..dd92edc82b3310ad9610c70138578a220e4358cd
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+ -->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd">
+    <testCase name="Magento\Sales\Test\TestCase\CreateCreditMemoEntityTest" summary="Create Credit Memo for Offline Payment Methods" ticketId="MAGETWO-59074">
+        <variation name="CreateCreditMemoEntityWithConfigurableTestVariation1" ticketId="MAGETWO-12447">
+            <data name="description" xsi:type="string">Assert items return to stock (partial refund)</data>
+            <data name="data/items_data/0/back_to_stock" xsi:type="string">Yes</data>
+            <data name="data/items_data/0/qty" xsi:type="string">1</data>
+            <data name="order/dataset" xsi:type="string">default</data>
+            <data name="order/data/entity_id/products" xsi:type="string">configurableProduct::configurable_with_qty_1</data>
+            <data name="order/data/price/dataset" xsi:type="string">full_refund</data>
+            <constraint name="Magento\Sales\Test\Constraint\AssertRefundSuccessCreateMessage" />
+            <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertProductQtyDecreasedAfterCreditmemo" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php
new file mode 100644
index 0000000000000000000000000000000000000000..f48e9e198210c02a66870674cbc35178b7d91df4
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Constraint;
+
+use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit;
+use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex;
+use Magento\Mtf\Constraint\AbstractConstraint;
+use Magento\Mtf\Fixture\FixtureFactory;
+use Magento\Mtf\Fixture\FixtureInterface;
+use Magento\Mtf\ObjectManager;
+use Magento\Mtf\System\Event\EventManagerInterface;
+use Magento\Sales\Test\Fixture\OrderInjectable;
+
+/**
+ * Class AssertProductQtyDecreasedAfterCreditmemo
+ */
+class AssertProductQtyDecreasedAfterCreditmemo extends AbstractConstraint
+{
+    /**
+     * @var FixtureFactory
+     */
+    protected $fixtureFactory;
+
+    /**
+     * Skip fields for create product fixture.
+     *
+     * @var array
+     */
+    protected $skipFields = [
+        'attribute_set_id',
+        'website_ids',
+        'checkout_data',
+        'type_id',
+        'price',
+    ];
+
+    /**
+     * AssertFirstProductForm constructor.
+     * @param ObjectManager $objectManager
+     */
+    public function __construct(
+        ObjectManager $objectManager,
+        EventManagerInterface $eventManager,
+        FixtureFactory $fixtureFactory
+    ) {
+        $this->fixtureFactory = $fixtureFactory;
+        parent::__construct($objectManager, $eventManager);
+    }
+
+    /**
+     * Assert form data equals fixture data
+     *
+     * @param OrderInjectable $order
+     * @param array $data
+     * @param CatalogProductIndex $productGrid
+     * @param CatalogProductEdit $productPage
+     * @return void
+     */
+    public function processAssert(
+        OrderInjectable $order,
+        array $data,
+        CatalogProductIndex $productGrid,
+        CatalogProductEdit $productPage
+    ) {
+        $product = $this->getProduct($order, $data);
+        $this->objectManager->get(\Magento\Catalog\Test\Constraint\AssertProductForm::class)->processAssert(
+            $product,
+            $productGrid,
+            $productPage
+        );
+    }
+
+    /**
+     * Get product's fixture.
+     *
+     * @param OrderInjectable $order
+     * @param array $data
+     * @param int $index [optional]
+     * @return FixtureInterface
+     */
+    protected function getProduct(OrderInjectable $order, array $data, $index = 0)
+    {
+        if (!isset($data['items_data'][$index]['back_to_stock'])
+            || $data['items_data'][$index]['back_to_stock'] != 'Yes'
+        ) {
+            return $order->getEntityId()['products'][$index];
+        }
+        $product = $order->getEntityId()['products'][$index];
+        $productData = $product->getData();
+        $checkoutDataQty = $productData['checkout_data']['qty'];
+        $productData['quantity_and_stock_status']['qty'] -= ($checkoutDataQty - $data['items_data'][$index]['qty']);
+
+        $productData = array_diff_key($productData, array_flip($this->skipFields));
+
+        return $this->fixtureFactory->create(get_class($product), ['data' => $productData]);
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Product qty was decreased after creditmemo creation.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php
index 9d19d10f4d40c6c3e317a97e7e83cd3c79e6f8ae..92b341bef2675fe635f804da2d9a17c5eea54c49 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php
@@ -90,32 +90,7 @@ class CreateCreditMemoEntityTest extends Injectable
 
         return [
             'ids' => ['creditMemoIds' => $result['creditMemoIds']],
-            'product' => $this->getProduct($order, $data),
             'customer' => $order->getDataFieldConfig('customer_id')['source']->getCustomer()
         ];
     }
-
-    /**
-     * Get product's fixture.
-     *
-     * @param OrderInjectable $order
-     * @param array $data
-     * @param int $index [optional]
-     * @return FixtureInterface
-     */
-    protected function getProduct(OrderInjectable $order, array $data, $index = 0)
-    {
-        if (!isset($data['items_data'][$index]['back_to_stock'])
-            || $data['items_data'][$index]['back_to_stock'] != 'Yes'
-        ) {
-            return $order->getEntityId()['products'][$index];
-        }
-        $product = $order->getEntityId()['products'][$index];
-        $productData = $product->getData();
-        $checkoutDataQty = $productData['checkout_data']['qty'];
-        $productData['quantity_and_stock_status']['qty'] -= ($checkoutDataQty - $data['items_data'][$index]['qty']);
-        $productData = array_diff_key($productData, array_flip($this->skipFields));
-
-        return $this->fixtureFactory->create(get_class($product), ['data' => $productData]);
-    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml
index 02b9640acbea4159c0560e8a4727a13cc36e1199..b2cf9843598f48af778edda5a4240409fd9d0365 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml
@@ -22,7 +22,7 @@
             <constraint name="Magento\Sales\Test\Constraint\AssertRefundOrderStatusInCommentsHistory" />
             <constraint name="Magento\Sales\Test\Constraint\AssertOrderCommentsHistoryNotifyStatus" />
             <constraint name="Magento\Sales\Test\Constraint\AssertRefundedGrandTotalOnFrontend" />
-            <constraint name="Magento\Catalog\Test\Constraint\AssertProductForm" />
+            <constraint name="Magento\Sales\Test\Constraint\AssertProductQtyDecreasedAfterCreditmemo" />
             <constraint name="Magento\Sales\Test\Constraint\AssertCreditMemoItems" />
         </variation>
         <variation name="CreateCreditMemoEntityTestVariation2" summary="Assert 0 shipping refund">