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 0036b3b2ab54a5a2f4ff104dbe7b8a3da4526d28..4375092591d194962b108e2ba0351b1a03fa7e5c 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/FlatTableBuilder.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/FlatTableBuilder.php
@@ -221,7 +221,11 @@ class FlatTableBuilder
 
         unset($tables[$entityTableName]);
 
-        $allColumns = array_merge(['entity_id', 'type_id', 'attribute_set_id'], $columnsList);
+        $allColumns = array_values(
+            array_unique(
+                array_merge(['entity_id', $linkField, 'type_id', 'attribute_set_id'], $columnsList)
+            )
+        );
 
         /* @var $status \Magento\Eav\Model\Entity\Attribute */
         $status = $this->_productIndexerHelper->getAttribute('status');
@@ -263,7 +267,7 @@ class FlatTableBuilder
 
             $select->joinLeft(
                 $temporaryTableName,
-                "e.entity_id = " . $temporaryTableName . ".entity_id",
+                sprintf('e.%1$s = %2$s.%1$s', $linkField, $temporaryTableName),
                 $columnsNames
             );
             $allColumns = array_merge($allColumns, $columnsNames);
@@ -277,7 +281,7 @@ class FlatTableBuilder
             if (!empty($columnValueNames)) {
                 $select->joinLeft(
                     $temporaryValueTableName,
-                    "e.${linkField} = " . $temporaryValueTableName . ".entity_id",
+                    sprintf('e.%1$s = %2$s.%1$s', $linkField, $temporaryTableName),
                     $columnValueNames
                 );
                 $allColumns = array_merge($allColumns, $columnValueNames);
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Table/Builder.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Table/Builder.php
new file mode 100644
index 0000000000000000000000000000000000000000..192f411c93b4ea48c1b753d88f586a25aca41838
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Table/Builder.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Model\Indexer\Product\Flat\Table;
+
+/**
+ * Class Builder
+ */
+class Builder implements BuilderInterface
+{
+    /**
+     * @var \Magento\Framework\DB\Ddl\Table
+     */
+    private $tableInstance;
+
+    /**
+     * Builder constructor.
+     *
+     * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
+     * @param string $tableName
+     */
+    public function __construct(\Magento\Framework\DB\Adapter\AdapterInterface $connection, $tableName)
+    {
+        $this->tableInstance = $connection->newTable($tableName);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function addColumn($name, $type, $size = null, $options = [], $comment = null)
+    {
+        $this->tableInstance->addColumn($name, $type, $size, $options, $comment);
+        return $this;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getTable()
+    {
+        return $this->tableInstance;
+    }
+}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Table/BuilderInterface.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Table/BuilderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..b24db9ee74334b743988b4a964004c41a5c610c7
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Table/BuilderInterface.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Model\Indexer\Product\Flat\Table;
+
+/**
+ * Interface BuilderInterface
+ */
+interface BuilderInterface
+{
+    /**
+     * Adds column to table.
+     *
+     * $options contains additional options for columns. Supported values are:
+     * - 'unsigned', for number types only. Default: FALSE.
+     * - 'precision', for numeric and decimal only. Default: taken from $size, if not set there then 0.
+     * - 'scale', for numeric and decimal only. Default: taken from $size, if not set there then 10.
+     * - 'default'. Default: not set.
+     * - 'nullable'. Default: TRUE.
+     * - 'primary', add column to primary index. Default: do not add.
+     * - 'primary_position', only for column in primary index. Default: count of primary columns + 1.
+     * - 'identity' or 'auto_increment'. Default: FALSE.
+     *
+     * @param string $name the column name
+     * @param string $type the column data type
+     * @param string|int|array $size the column length
+     * @param array $options array of additional options
+     * @param string $comment column description
+     * @return $this
+     * @throws \Zend_Db_Exception
+     */
+    public function addColumn($name, $type, $size = null, $options = [], $comment = null);
+
+    /**
+     * @return \Magento\Framework\DB\Ddl\Table
+     */
+    public function getTable();
+}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php
index fdc405b27d3fd8b8b41c69395397c38235c8412e..d00a720a91ddefdad1036c52a0c12d6c5f10d7b3 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Catalog\Model\Indexer\Product\Flat;
 
-use Magento\Framework\App\ResourceConnection;
+use Magento\Catalog\Model\Indexer\Product\Flat\Table\BuilderInterfaceFactory;
 
 /**
  * Class TableBuilder
@@ -32,6 +32,11 @@ class TableBuilder
      */
     protected $resource;
 
+    /**
+     * @var BuilderInterfaceFactory
+     */
+    private $tableBuilderFactory;
+
     /**
      * Check whether builder was executed
      *
@@ -123,17 +128,27 @@ class TableBuilder
         $valueTables = [];
         if (!empty($columns)) {
             $valueTableName = $tableName . $valueFieldSuffix;
-            $temporaryTable = $this->_connection->newTable($tableName);
-            $valueTemporaryTable = $this->_connection->newTable($valueTableName);
+            $temporaryTableBuilder = $this->getTableBuilderFactory()->create(
+                [
+                    'connection' => $this->_connection,
+                    'tableName' => $tableName
+                ]
+            );
+            $valueTemporaryTableBuilder = $this->getTableBuilderFactory()->create(
+                [
+                    'connection' => $this->_connection,
+                    'tableName' => $valueTableName
+                ]
+            );
             $flatColumns = $this->_productIndexerHelper->getFlatColumns();
 
-            $temporaryTable->addColumn('entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER);
+            $temporaryTableBuilder->addColumn('entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER);
 
-            $temporaryTable->addColumn('type_id', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT);
+            $temporaryTableBuilder->addColumn('type_id', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT);
 
-            $temporaryTable->addColumn('attribute_set_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER);
+            $temporaryTableBuilder->addColumn('attribute_set_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER);
 
-            $valueTemporaryTable->addColumn('entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER);
+            $valueTemporaryTableBuilder->addColumn('entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER);
 
             /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
             foreach ($columns as $columnName => $attribute) {
@@ -145,7 +160,7 @@ class TableBuilder
                     $column = $column[$attributeCode];
                 }
 
-                $temporaryTable->addColumn(
+                $temporaryTableBuilder->addColumn(
                     $columnName,
                     $column['type'],
                     isset($column['length']) ? $column['length'] : null
@@ -154,7 +169,7 @@ class TableBuilder
                 $columnValueName = $attributeCode . $valueFieldSuffix;
                 if (isset($flatColumns[$columnValueName])) {
                     $columnValue = $flatColumns[$columnValueName];
-                    $valueTemporaryTable->addColumn(
+                    $valueTemporaryTableBuilder->addColumn(
                         $columnValueName,
                         $columnValue['type'],
                         isset($columnValue['length']) ? $columnValue['length'] : null
@@ -162,11 +177,11 @@ class TableBuilder
                 }
             }
             $this->_connection->dropTemporaryTable($tableName);
-            $this->_connection->createTemporaryTable($temporaryTable);
+            $this->_connection->createTemporaryTable($temporaryTableBuilder->getTable());
 
-            if (count($valueTemporaryTable->getColumns()) > 1) {
+            if (count($valueTemporaryTableBuilder->getTable()->getColumns()) > 1) {
                 $this->_connection->dropTemporaryTable($valueTableName);
-                $this->_connection->createTemporaryTable($valueTemporaryTable);
+                $this->_connection->createTemporaryTable($valueTemporaryTableBuilder->getTable());
                 $valueTables[$valueTableName] = $valueTableName;
             }
         }
@@ -197,7 +212,8 @@ class TableBuilder
         if (!empty($columns)) {
             $select = $this->_connection->select();
             $temporaryEntityTable = $this->_getTemporaryTableName($tableName);
-            $idsColumns = ['entity_id', 'type_id', 'attribute_set_id'];
+            $metadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
+            $idsColumns = array_unique([$metadata->getLinkField(), 'entity_id', 'type_id', 'attribute_set_id']);
 
             $columns = array_merge($idsColumns, array_keys($columns));
 
@@ -261,7 +277,7 @@ class TableBuilder
                 );
                 $temporaryTableName = $this->_getTemporaryTableName($tableName);
                 $temporaryValueTableName = $temporaryTableName . $valueFieldSuffix;
-                $keyColumn = ['entity_id'];
+                $keyColumn = array_unique([$metadata->getLinkField(), 'entity_id']);
                 $columns = array_merge($keyColumn, array_keys($columnsList));
                 $valueColumns = $keyColumn;
                 $flatColumns = $this->_productIndexerHelper->getFlatColumns();
@@ -333,6 +349,19 @@ class TableBuilder
         }
     }
 
+    /**
+     * @return BuilderInterfaceFactory
+     */
+    private function getTableBuilderFactory()
+    {
+        if (null === $this->tableBuilderFactory) {
+            $this->tableBuilderFactory = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(BuilderInterfaceFactory::class);
+        }
+
+        return $this->tableBuilderFactory;
+    }
+
     /**
      * @return \Magento\Framework\EntityManager\MetadataPool
      */
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
new file mode 100644
index 0000000000000000000000000000000000000000..c57dd950dc3e01c038631b52d2eb76657f1c25b1
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/FlatTableBuilderTest.php
@@ -0,0 +1,204 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Model\Indexer\Product\Flat;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+
+/**
+ * Class FlatTableBuilderTest
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class FlatTableBuilderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Catalog\Helper\Product\Flat\Indexer|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $flatIndexerMock;
+
+    /**
+     * @var \Magento\Framework\App\ResourceConnection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resourceMock;
+
+    /**
+     * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $scopeConfigMock;
+
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeManagerMock;
+
+    /**
+     * @var \Magento\Catalog\Model\Indexer\Product\Flat\TableDataInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $tableDataMock;
+
+    /**
+     * @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $connectionMock;
+
+    /**
+     * @var \Magento\Framework\EntityManager\MetadataPool|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $metadataPoolMock;
+
+    /**
+     * @var \Magento\Framework\EntityManager\EntityMetadataInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $metadataMock;
+
+    /**
+     * @var \Magento\Catalog\Model\Indexer\Product\Flat\FlatTableBuilder
+     */
+    private $flatTableBuilder;
+
+    protected function setUp()
+    {
+        $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->flatIndexerMock = $this->getMockBuilder(\Magento\Catalog\Helper\Product\Flat\Indexer::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->resourceMock = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->scopeConfigMock = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->tableDataMock = $this->getMockBuilder(
+            \Magento\Catalog\Model\Indexer\Product\Flat\TableDataInterface::class
+        )->disableOriginalConstructor()->getMockForAbstractClass();
+        $this->connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->metadataPoolMock = $this->getMockBuilder(\Magento\Framework\EntityManager\MetadataPool::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->metadataMock = $this->getMockBuilder(
+            \Magento\Framework\EntityManager\EntityMetadataInterface::class
+        )->disableOriginalConstructor()->getMockForAbstractClass();
+        $this->metadataMock->expects($this->any())->method('getLinkField')->willReturn('entity_id');
+
+        $this->flatTableBuilder = $objectManagerHelper->getObject(
+            \Magento\Catalog\Model\Indexer\Product\Flat\FlatTableBuilder::class,
+            [
+                'productIndexerHelper' => $this->flatIndexerMock,
+                'resource' => $this->resourceMock,
+                'config' => $this->scopeConfigMock,
+                'storeManager' => $this->storeManagerMock,
+                'tableData' => $this->tableDataMock,
+                '_connection' => $this->connectionMock
+            ]
+        );
+        $objectManagerHelper->setBackwardCompatibleProperty(
+            $this->flatTableBuilder,
+            'metadataPool',
+            $this->metadataPoolMock
+        );
+    }
+
+    public function testBuild()
+    {
+        list($storeId, $changedIds, $valueFieldSuffix, $tableDropSuffix, $fillTmpTables) = [1, [], '', '', true];
+        $tableName = 'catalog_product_entity';
+        $attributeTable = 'catalog_product_entity_int';
+        $temporaryTableName = 'catalog_product_entity_int_tmp_indexer';
+        $temporaryValueTableName = 'catalog_product_entity_int_tmp_indexer';
+        $linkField = 'entity_id';
+        $statusId = 22;
+        $this->flatIndexerMock->expects($this->once())->method('getAttributes')->willReturn([]);
+        $this->flatIndexerMock->expects($this->exactly(3))->method('getFlatColumns')
+            ->willReturnOnConsecutiveCalls(
+                [],
+                [$linkField => []],
+                [$linkField => []]
+            );
+        $this->flatIndexerMock->expects($this->once())->method('getFlatIndexes')->willReturn([]);
+        $statusAttributeMock = $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_int' => [
+                        $linkField => $statusAttributeMock
+                    ]
+                ]
+            );
+        $this->flatIndexerMock->expects($this->atLeastOnce())->method('getTable')
+            ->withConsecutive(
+                [$tableName],
+                ['catalog_product_website']
+            )
+            ->willReturn(
+                $tableName,
+                'catalog_product_website'
+            );
+        $this->flatIndexerMock->expects($this->once())->method('getAttribute')
+            ->with('status')
+            ->willReturn($statusAttributeMock);
+        $backendMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $backendMock->expects($this->atLeastOnce())->method('getTable')->willReturn($attributeTable);
+        $statusAttributeMock->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()
+            ->getMock();
+        $this->connectionMock->expects($this->any())->method('newTable')->willReturn($tableMock);
+        $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->connectionMock->expects($this->atLeastOnce())->method('select')->willReturn($selectMock);
+        $selectMock->expects($this->once())->method('from')->with(
+            ['et' => 'catalog_product_entity_tmp_indexer'],
+            [$linkField, 'type_id', 'attribute_set_id']
+        )->willReturnSelf();
+        $selectMock->expects($this->atLeastOnce())->method('joinInner')->willReturnSelf();
+        $selectMock->expects($this->exactly(3))->method('joinLeft')
+            ->withConsecutive(
+                [
+                    ['dstatus' => $attributeTable],
+                    sprintf(
+                        'e.%s = dstatus.%s AND dstatus.store_id = %s AND dstatus.attribute_id = %s',
+                        $linkField,
+                        $linkField,
+                        $storeId,
+                        $statusId
+                    ),
+                    []
+                ],
+                [
+                    $temporaryTableName,
+                    "e.{$linkField} = ${temporaryTableName}.{$linkField}",
+                    [$linkField]
+                ],
+                [
+                    $temporaryValueTableName,
+                    "e.${linkField} = " . $temporaryValueTableName . ".${linkField}",
+                    [$linkField]
+                ]
+            )->willReturnSelf();
+        $this->metadataPoolMock->expects($this->atLeastOnce())->method('getMetadata')->with(ProductInterface::class)
+            ->willReturn($this->metadataMock);
+        $storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->storeManagerMock->expects($this->once())->method('getStore')->with($storeId)->willReturn($storeMock);
+        $this->flatTableBuilder->build($storeId, $changedIds, $valueFieldSuffix, $tableDropSuffix, $fillTmpTables);
+    }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Table/BuilderTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Table/BuilderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0a80250fbdf03153b52b4e509b90bee9bf7dde9c
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Table/BuilderTest.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Model\Indexer\Product\Flat\Table;
+
+/**
+ * Class BuilderTest
+ */
+class BuilderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $connectionMock;
+
+    public function testAddColumn()
+    {
+        $this->connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $table = $this->getMockBuilder(\Magento\Framework\DB\Ddl\Table::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $table->expects($this->once())->method('addColumn')
+            ->with('test', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER)
+            ->willReturnSelf();
+        $tableName = 'test_table';
+        $this->connectionMock->expects($this->once())
+            ->method('newTable')
+            ->with($tableName)
+            ->willReturn($table);
+        $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        /**
+         * @var $builder \Magento\Catalog\Model\Indexer\Product\Flat\Table\Builder
+         */
+        $builder = $objectManagerHelper->getObject(
+            \Magento\Catalog\Model\Indexer\Product\Flat\Table\Builder::class,
+            [
+                'connection' => $this->connectionMock,
+                'tableName' => $tableName
+            ]
+        );
+        $this->assertEquals($builder, $builder->addColumn('test', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER));
+    }
+}
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml
index 49ad7d67d705899077d4beb13f4a26383982dcf5..b355dd2601c3da3a62ad21c0ccf0267e0c2ef809 100644
--- a/app/code/Magento/Catalog/etc/di.xml
+++ b/app/code/Magento/Catalog/etc/di.xml
@@ -47,6 +47,7 @@
     <preference for="Magento\Catalog\Api\CategoryListInterface" type="Magento\Catalog\Model\CategoryList" />
     <preference for="Magento\Catalog\Api\Data\CategorySearchResultsInterface" type="Magento\Framework\Api\SearchResults" />
     <preference for="Magento\Catalog\Model\Config\Source\ProductPriceOptionsInterface" type="Magento\Catalog\Model\Config\Source\Product\Options\Price"/>
+    <preference for="Magento\Catalog\Model\Indexer\Product\Flat\Table\BuilderInterface" type="Magento\Catalog\Model\Indexer\Product\Flat\Table\Builder"/>
     <type name="Magento\Customer\Model\ResourceModel\Visitor">
         <plugin name="catalogLog" type="Magento\Catalog\Model\Plugin\Log" />
     </type>
diff --git a/app/code/Magento/Eav/etc/di.xml b/app/code/Magento/Eav/etc/di.xml
index e273eab770c170c5ab6ff6b27da18ecdf41fc7c6..0fcba9907cc4d46b76cf0b7e86c2e0e1bf61da5a 100644
--- a/app/code/Magento/Eav/etc/di.xml
+++ b/app/code/Magento/Eav/etc/di.xml
@@ -152,9 +152,12 @@
             <argument name="collectionProcessor" xsi:type="object">Magento\Eav\Model\Api\SearchCriteria\AttributeGroupCollectionProcessor</argument>
         </arguments>
     </type>
-    <type name="Magento\Framework\EntityManager\CustomAttributesMapper">
+    <type name="Magento\Framework\EntityManager\CompositeMapper">
         <arguments>
-            <argument name="mapper" xsi:type="object">Magento\Eav\Model\CustomAttributesMapper</argument>
+            <argument name="mappers" xsi:type="array">
+                <item name="mapper" xsi:type="object">Magento\Framework\EntityManager\Mapper</item>
+                <item name="customAttributesMapper" xsi:type="object">Magento\Eav\Model\CustomAttributesMapper</item>
+            </argument>
         </arguments>
     </type>
 </config>
diff --git a/app/code/Magento/Sales/Model/InvoiceOrder.php b/app/code/Magento/Sales/Model/InvoiceOrder.php
index e51b46082d943d8ff609bacb80fae19c861afba4..c503b01a5ab21014683a7eaa5981f65fa16b558f 100644
--- a/app/code/Magento/Sales/Model/InvoiceOrder.php
+++ b/app/code/Magento/Sales/Model/InvoiceOrder.php
@@ -12,15 +12,12 @@ use Magento\Sales\Api\Data\InvoiceCreationArgumentsInterface;
 use Magento\Sales\Api\InvoiceOrderInterface;
 use Magento\Sales\Api\OrderRepositoryInterface;
 use Magento\Sales\Model\Order\Config as OrderConfig;
-use Magento\Sales\Model\Order\Invoice\InvoiceValidatorInterface;
 use Magento\Sales\Model\Order\Invoice\NotifierInterface;
 use Magento\Sales\Model\Order\InvoiceDocumentFactory;
-use Magento\Sales\Model\Order\InvoiceQuantityValidator;
 use Magento\Sales\Model\Order\InvoiceRepository;
 use Magento\Sales\Model\Order\OrderStateResolverInterface;
-use Magento\Sales\Model\Order\OrderValidatorInterface;
 use Magento\Sales\Model\Order\PaymentAdapterInterface;
-use Magento\Sales\Model\Order\Validation\CanInvoice;
+use Magento\Sales\Model\Order\Validation\InvoiceOrderInterface as InvoiceOrderValidator;
 use Psr\Log\LoggerInterface;
 
 /**
@@ -44,11 +41,6 @@ class InvoiceOrder implements InvoiceOrderInterface
      */
     private $invoiceDocumentFactory;
 
-    /**
-     * @var InvoiceValidatorInterface
-     */
-    private $invoiceValidator;
-
     /**
      * @var PaymentAdapterInterface
      */
@@ -69,6 +61,11 @@ class InvoiceOrder implements InvoiceOrderInterface
      */
     private $invoiceRepository;
 
+    /**
+     * @var InvoiceOrderValidator
+     */
+    private $invoiceOrderValidator;
+
     /**
      * @var NotifierInterface
      */
@@ -80,21 +77,15 @@ class InvoiceOrder implements InvoiceOrderInterface
     private $logger;
 
     /**
-     * @var OrderValidatorInterface
-     */
-    private $orderValidator;
-
-    /**
-     * OrderInvoice constructor.
+     * InvoiceOrder constructor.
      * @param ResourceConnection $resourceConnection
      * @param OrderRepositoryInterface $orderRepository
      * @param InvoiceDocumentFactory $invoiceDocumentFactory
-     * @param InvoiceValidatorInterface $invoiceValidator
-     * @param OrderValidatorInterface $orderValidator
      * @param PaymentAdapterInterface $paymentAdapter
      * @param OrderStateResolverInterface $orderStateResolver
      * @param OrderConfig $config
      * @param InvoiceRepository $invoiceRepository
+     * @param InvoiceOrderValidator $invoiceOrderValidator
      * @param NotifierInterface $notifierInterface
      * @param LoggerInterface $logger
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
@@ -103,24 +94,22 @@ class InvoiceOrder implements InvoiceOrderInterface
         ResourceConnection $resourceConnection,
         OrderRepositoryInterface $orderRepository,
         InvoiceDocumentFactory $invoiceDocumentFactory,
-        InvoiceValidatorInterface $invoiceValidator,
-        OrderValidatorInterface $orderValidator,
         PaymentAdapterInterface $paymentAdapter,
         OrderStateResolverInterface $orderStateResolver,
         OrderConfig $config,
         InvoiceRepository $invoiceRepository,
+        InvoiceOrderValidator $invoiceOrderValidator,
         NotifierInterface $notifierInterface,
         LoggerInterface $logger
     ) {
         $this->resourceConnection = $resourceConnection;
         $this->orderRepository = $orderRepository;
         $this->invoiceDocumentFactory = $invoiceDocumentFactory;
-        $this->invoiceValidator = $invoiceValidator;
-        $this->orderValidator = $orderValidator;
         $this->paymentAdapter = $paymentAdapter;
         $this->orderStateResolver = $orderStateResolver;
         $this->config = $config;
         $this->invoiceRepository = $invoiceRepository;
+        $this->invoiceOrderValidator = $invoiceOrderValidator;
         $this->notifierInterface = $notifierInterface;
         $this->logger = $logger;
     }
@@ -158,19 +147,19 @@ class InvoiceOrder implements InvoiceOrderInterface
             ($appendComment && $notify),
             $arguments
         );
-        $errorMessages = array_merge(
-            $this->invoiceValidator->validate(
-                $invoice,
-                [InvoiceQuantityValidator::class]
-            ),
-            $this->orderValidator->validate(
-                $order,
-                [CanInvoice::class]
-            )
+        $errorMessages = $this->invoiceOrderValidator->validate(
+            $order,
+            $invoice,
+            $capture,
+            $items,
+            $notify,
+            $appendComment,
+            $comment,
+            $arguments
         );
-        if (!empty($errorMessages)) {
+        if ($errorMessages->hasMessages()) {
             throw new \Magento\Sales\Exception\DocumentValidationException(
-                __("Invoice Document Validation Error(s):\n" . implode("\n", $errorMessages))
+                __("Invoice Document Validation Error(s):\n" . implode("\n", $errorMessages->getMessages()))
             );
         }
         $connection->beginTransaction();
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidatorInterface.php
index 3889f3b985ff02603009084fa956fab65e505556..030a9a7d128de7d49d989c0e1af61a323786f5a5 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidatorInterface.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidatorInterface.php
@@ -8,6 +8,7 @@ namespace Magento\Sales\Model\Order\Creditmemo;
 use Magento\Sales\Api\Data\CreditmemoInterface;
 use Magento\Sales\Exception\DocumentValidationException;
 use Magento\Sales\Model\ValidatorInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
 
 /**
  * Interface CreditmemoValidatorInterface
@@ -17,7 +18,7 @@ interface CreditmemoValidatorInterface
     /**
      * @param CreditmemoInterface $entity
      * @param ValidatorInterface[] $validators
-     * @return string[]
+     * @return ValidatorResultInterface
      * @throws DocumentValidationException
      */
     public function validate(CreditmemoInterface $entity, array $validators);
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidatorInterface.php
index 9f8bb84ccd16a175ee23de755169281026dc053b..7a758122b8aac13d75dcf5784ef85e71d2298b2d 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidatorInterface.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidatorInterface.php
@@ -7,6 +7,7 @@ namespace Magento\Sales\Model\Order\Creditmemo;
 
 use Magento\Sales\Api\Data\CreditmemoItemCreationInterface;
 use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
 
 /**
  * Interface ItemCreationValidatorInterface
@@ -17,7 +18,7 @@ interface ItemCreationValidatorInterface
      * @param CreditmemoItemCreationInterface $item
      * @param array $validators
      * @param OrderInterface|null $context
-     * @return mixed
+     * @return ValidatorResultInterface
      */
     public function validate(CreditmemoItemCreationInterface $item, array $validators, OrderInterface $context = null);
 }
diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoDocumentFactory.php b/app/code/Magento/Sales/Model/Order/CreditmemoDocumentFactory.php
index 469b226053cdd4e2b0658dcd596d7d740572f0c7..816c3df3fc1f0c6b045f26f2ebb79e769c1be031 100644
--- a/app/code/Magento/Sales/Model/Order/CreditmemoDocumentFactory.php
+++ b/app/code/Magento/Sales/Model/Order/CreditmemoDocumentFactory.php
@@ -7,6 +7,8 @@ namespace Magento\Sales\Model\Order;
 
 /**
  * Class CreditmemoDocumentFactory
+ *
+ * @api
  */
 class CreditmemoDocumentFactory
 {
diff --git a/app/code/Magento/Sales/Model/Order/Invoice/InvoiceValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Invoice/InvoiceValidatorInterface.php
index 568019a40fce5bc69ccab49ca8b3f4fee048505e..44d701b1426e79d3df390b46b7e76ee6743b691c 100644
--- a/app/code/Magento/Sales/Model/Order/Invoice/InvoiceValidatorInterface.php
+++ b/app/code/Magento/Sales/Model/Order/Invoice/InvoiceValidatorInterface.php
@@ -8,6 +8,7 @@ namespace Magento\Sales\Model\Order\Invoice;
 use Magento\Sales\Api\Data\InvoiceInterface;
 use Magento\Sales\Exception\DocumentValidationException;
 use Magento\Sales\Model\ValidatorInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
 
 /**
  * Interface InvoiceValidatorInterface
@@ -17,7 +18,7 @@ interface InvoiceValidatorInterface
     /**
      * @param InvoiceInterface $entity
      * @param ValidatorInterface[] $validators
-     * @return string[]
+     * @return ValidatorResultInterface
      * @throws DocumentValidationException
      */
     public function validate(InvoiceInterface $entity, array $validators);
diff --git a/app/code/Magento/Sales/Model/Order/OrderValidatorInterface.php b/app/code/Magento/Sales/Model/Order/OrderValidatorInterface.php
index c5a9a6c1d32963fcc223099efe1fcb81bb530464..dfc95043cbd33b214b46f26e7fcdc2a039e9272e 100644
--- a/app/code/Magento/Sales/Model/Order/OrderValidatorInterface.php
+++ b/app/code/Magento/Sales/Model/Order/OrderValidatorInterface.php
@@ -8,6 +8,7 @@ namespace Magento\Sales\Model\Order;
 use Magento\Sales\Api\Data\OrderInterface;
 use Magento\Sales\Exception\DocumentValidationException;
 use Magento\Sales\Model\ValidatorInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
 
 /**
  * Interface OrderValidatorInterface
@@ -17,7 +18,7 @@ interface OrderValidatorInterface
     /**
      * @param OrderInterface $entity
      * @param ValidatorInterface[] $validators
-     * @return string[]
+     * @return ValidatorResultInterface
      * @throws DocumentValidationException
      */
     public function validate(OrderInterface $entity, array $validators);
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/ShipmentValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Shipment/ShipmentValidatorInterface.php
index 198a4019bf6b898e0c85fd2e2ff7c7ff77c2a9f6..43501a5b133140390e539a0d81985a4a5437598b 100644
--- a/app/code/Magento/Sales/Model/Order/Shipment/ShipmentValidatorInterface.php
+++ b/app/code/Magento/Sales/Model/Order/Shipment/ShipmentValidatorInterface.php
@@ -8,6 +8,7 @@ namespace Magento\Sales\Model\Order\Shipment;
 use Magento\Sales\Api\Data\ShipmentInterface;
 use Magento\Sales\Exception\DocumentValidationException;
 use Magento\Sales\Model\ValidatorInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
 
 /**
  * Interface ShipmentValidatorInterface
@@ -17,7 +18,7 @@ interface ShipmentValidatorInterface
     /**
      * @param ShipmentInterface $shipment
      * @param ValidatorInterface[] $validators
-     * @return string[]
+     * @return ValidatorResultInterface
      * @throws DocumentValidationException
      */
     public function validate(ShipmentInterface $shipment, array $validators);
diff --git a/app/code/Magento/Sales/Model/Order/Validation/InvoiceOrder.php b/app/code/Magento/Sales/Model/Order/Validation/InvoiceOrder.php
new file mode 100644
index 0000000000000000000000000000000000000000..d912793afa157fbbd997e89ce46c8b84aa5d6f75
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/InvoiceOrder.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Sales\Api\Data\InvoiceCommentCreationInterface;
+use Magento\Sales\Api\Data\InvoiceCreationArgumentsInterface;
+use Magento\Sales\Api\Data\InvoiceInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\Order\Invoice\InvoiceValidatorInterface;
+use Magento\Sales\Model\Order\InvoiceQuantityValidator;
+use Magento\Sales\Model\Order\OrderValidatorInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
+use Magento\Sales\Model\ValidatorResultMerger;
+
+/**
+ * Class InvoiceOrder
+ * Validation for invoice order operation
+ */
+class InvoiceOrder implements InvoiceOrderInterface
+{
+    /**
+     * @var InvoiceValidatorInterface
+     */
+    private $invoiceValidator;
+
+    /**
+     * @var OrderValidatorInterface
+     */
+    private $orderValidator;
+
+    /**
+     * @var ValidatorResultMerger
+     */
+    private $validatorResultMerger;
+
+    /**
+     * InvoiceOrder constructor.
+     * @param InvoiceValidatorInterface $invoiceValidator
+     * @param OrderValidatorInterface $orderValidator
+     * @param ValidatorResultMerger $validatorResultMerger
+     */
+    public function __construct(
+        InvoiceValidatorInterface $invoiceValidator,
+        OrderValidatorInterface $orderValidator,
+        ValidatorResultMerger $validatorResultMerger
+    ) {
+        $this->invoiceValidator = $invoiceValidator;
+        $this->orderValidator = $orderValidator;
+        $this->validatorResultMerger = $validatorResultMerger;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate(
+        OrderInterface $order,
+        InvoiceInterface $invoice,
+        $capture = false,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        InvoiceCommentCreationInterface $comment = null,
+        InvoiceCreationArgumentsInterface $arguments = null
+    ) {
+        return $this->validatorResultMerger->merge(
+            $this->invoiceValidator->validate(
+                $invoice,
+                [InvoiceQuantityValidator::class]
+            ),
+            $this->orderValidator->validate(
+                $order,
+                [CanInvoice::class]
+            )
+        );
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Validation/InvoiceOrderInterface.php b/app/code/Magento/Sales/Model/Order/Validation/InvoiceOrderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..5c27741a1985582ee547a21faf9747d68d2c35c4
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/InvoiceOrderInterface.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Sales\Api\Data\InvoiceCommentCreationInterface;
+use Magento\Sales\Api\Data\InvoiceCreationArgumentsInterface;
+use Magento\Sales\Api\Data\InvoiceInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
+
+/**
+ * Interface InvoiceOrderInterface
+ *
+ * @api
+ */
+interface InvoiceOrderInterface
+{
+    /**
+     * @param OrderInterface $order
+     * @param InvoiceInterface $invoice
+     * @param bool $capture
+     * @param array $items
+     * @param bool $notify
+     * @param bool $appendComment
+     * @param InvoiceCommentCreationInterface|null $comment
+     * @param InvoiceCreationArgumentsInterface|null $arguments
+     * @return ValidatorResultInterface
+     */
+    public function validate(
+        OrderInterface $order,
+        InvoiceInterface $invoice,
+        $capture = false,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        InvoiceCommentCreationInterface $comment = null,
+        InvoiceCreationArgumentsInterface $arguments = null
+    );
+}
diff --git a/app/code/Magento/Sales/Model/Order/Validation/RefundInvoice.php b/app/code/Magento/Sales/Model/Order/Validation/RefundInvoice.php
new file mode 100644
index 0000000000000000000000000000000000000000..d6bc86005cf2c906154ca107cc97c4fac4242fd4
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/RefundInvoice.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\InvoiceInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\Order\Invoice\InvoiceValidatorInterface;
+use Magento\Sales\Model\Order\Creditmemo\CreditmemoValidatorInterface;
+use Magento\Sales\Model\Order\Creditmemo\Item\Validation\CreationQuantityValidator;
+use Magento\Sales\Model\Order\Creditmemo\ItemCreationValidatorInterface;
+use Magento\Sales\Model\Order\Creditmemo\Validation\QuantityValidator;
+use Magento\Sales\Model\Order\Creditmemo\Validation\TotalsValidator;
+use Magento\Sales\Model\Order\OrderValidatorInterface;
+use Magento\Sales\Model\ValidatorResultMerger;
+
+/**
+ * Class RefundInvoice
+ */
+class RefundInvoice implements RefundInvoiceInterface
+{
+    /**
+     * @var OrderValidatorInterface
+     */
+    private $orderValidator;
+
+    /**
+     * @var CreditmemoValidatorInterface
+     */
+    private $creditmemoValidator;
+
+    /**
+     * @var ItemCreationValidatorInterface
+     */
+    private $itemCreationValidator;
+
+    /**
+     * @var InvoiceValidatorInterface
+     */
+    private $invoiceValidator;
+
+    /**
+     * @var ValidatorResultMerger
+     */
+    private $validatorResultMerger;
+
+    /**
+     * RefundArguments constructor.
+     * @param OrderValidatorInterface $orderValidator
+     * @param CreditmemoValidatorInterface $creditmemoValidator
+     * @param ItemCreationValidatorInterface $itemCreationValidator
+     * @param InvoiceValidatorInterface $invoiceValidator
+     * @param ValidatorResultMerger $validatorResultMerger
+     */
+    public function __construct(
+        OrderValidatorInterface $orderValidator,
+        CreditmemoValidatorInterface $creditmemoValidator,
+        ItemCreationValidatorInterface $itemCreationValidator,
+        InvoiceValidatorInterface $invoiceValidator,
+        ValidatorResultMerger $validatorResultMerger
+    ) {
+        $this->orderValidator = $orderValidator;
+        $this->creditmemoValidator = $creditmemoValidator;
+        $this->itemCreationValidator = $itemCreationValidator;
+        $this->invoiceValidator = $invoiceValidator;
+        $this->validatorResultMerger = $validatorResultMerger;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate(
+        InvoiceInterface $invoice,
+        OrderInterface $order,
+        CreditmemoInterface $creditmemo,
+        array $items = [],
+        $isOnline = false,
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        $orderValidationResult = $this->orderValidator->validate(
+            $order,
+            [
+                CanRefund::class
+            ]
+        );
+        $creditmemoValidationResult = $this->creditmemoValidator->validate(
+            $creditmemo,
+            [
+                QuantityValidator::class,
+                TotalsValidator::class
+            ]
+        );
+
+        $itemsValidation = [];
+        foreach ($items as $item) {
+            $itemsValidation[] = $this->itemCreationValidator->validate(
+                $item,
+                [CreationQuantityValidator::class],
+                $order
+            )->getMessages();
+        }
+
+        $invoiceValidationResult = $this->invoiceValidator->validate(
+            $invoice,
+            [
+                \Magento\Sales\Model\Order\Invoice\Validation\CanRefund::class
+            ]
+        );
+
+        return $this->validatorResultMerger->merge(
+            $orderValidationResult,
+            $creditmemoValidationResult,
+            $invoiceValidationResult->getMessages(),
+            ...$itemsValidation
+        );
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Validation/RefundInvoiceInterface.php b/app/code/Magento/Sales/Model/Order/Validation/RefundInvoiceInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..83acc9811bb89f5ed8cff566274eb54a39668ad9
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/RefundInvoiceInterface.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\InvoiceInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
+
+/**
+ * Interface RefundInvoiceInterface
+ *
+ * @api
+ */
+interface RefundInvoiceInterface
+{
+    /**
+     * @param InvoiceInterface $invoice
+     * @param OrderInterface $order
+     * @param CreditmemoInterface $creditmemo
+     * @param array $items
+     * @param bool $isOnline
+     * @param bool $notify
+     * @param bool $appendComment
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment
+     * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments
+     * @return ValidatorResultInterface
+     */
+    public function validate(
+        InvoiceInterface $invoice,
+        OrderInterface $order,
+        CreditmemoInterface $creditmemo,
+        array $items = [],
+        $isOnline = false,
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    );
+}
diff --git a/app/code/Magento/Sales/Model/Order/Validation/RefundOrder.php b/app/code/Magento/Sales/Model/Order/Validation/RefundOrder.php
new file mode 100644
index 0000000000000000000000000000000000000000..c2664fda6b9836df6c91a35aabd6c84ed54e5827
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/RefundOrder.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\Order\Creditmemo\CreditmemoValidatorInterface;
+use Magento\Sales\Model\Order\Creditmemo\Item\Validation\CreationQuantityValidator;
+use Magento\Sales\Model\Order\Creditmemo\ItemCreationValidatorInterface;
+use Magento\Sales\Model\Order\Creditmemo\Validation\QuantityValidator;
+use Magento\Sales\Model\Order\Creditmemo\Validation\TotalsValidator;
+use Magento\Sales\Model\Order\OrderValidatorInterface;
+use Magento\Sales\Model\ValidatorResultMerger;
+
+/**
+ * Class RefundOrder
+ */
+class RefundOrder implements RefundOrderInterface
+{
+    /**
+     * @var OrderValidatorInterface
+     */
+    private $orderValidator;
+
+    /**
+     * @var CreditmemoValidatorInterface
+     */
+    private $creditmemoValidator;
+
+    /**
+     * @var ItemCreationValidatorInterface
+     */
+    private $itemCreationValidator;
+
+    /**
+     * @var ValidatorResultMerger
+     */
+    private $validatorResultMerger;
+
+    /**
+     * RefundArguments constructor.
+     *
+     * @param OrderValidatorInterface $orderValidator
+     * @param CreditmemoValidatorInterface $creditmemoValidator
+     * @param ItemCreationValidatorInterface $itemCreationValidator
+     * @param ValidatorResultMerger $validatorResultMerger
+     */
+    public function __construct(
+        OrderValidatorInterface $orderValidator,
+        CreditmemoValidatorInterface $creditmemoValidator,
+        ItemCreationValidatorInterface $itemCreationValidator,
+        ValidatorResultMerger $validatorResultMerger
+    ) {
+        $this->orderValidator = $orderValidator;
+        $this->creditmemoValidator = $creditmemoValidator;
+        $this->itemCreationValidator = $itemCreationValidator;
+        $this->validatorResultMerger = $validatorResultMerger;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate(
+        OrderInterface $order,
+        CreditmemoInterface $creditmemo,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        $orderValidationResult = $this->orderValidator->validate(
+            $order,
+            [
+                CanRefund::class
+            ]
+        );
+        $creditmemoValidationResult = $this->creditmemoValidator->validate(
+            $creditmemo,
+            [
+                QuantityValidator::class,
+                TotalsValidator::class
+            ]
+        );
+
+        $itemsValidation = [];
+        foreach ($items as $item) {
+            $itemsValidation[] = $this->itemCreationValidator->validate(
+                $item,
+                [CreationQuantityValidator::class],
+                $order
+            )->getMessages();
+        }
+
+        return $this->validatorResultMerger->merge(
+            $orderValidationResult,
+            $creditmemoValidationResult,
+            ...$itemsValidation
+        );
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Validation/RefundOrderInterface.php b/app/code/Magento/Sales/Model/Order/Validation/RefundOrderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..2f770d20b513425dd67303490d67bb3d05fbc515
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/RefundOrderInterface.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
+
+/**
+ * Interface RefundOrderInterface
+ *
+ * @api
+ */
+interface RefundOrderInterface
+{
+    /**
+     * @param OrderInterface $order
+     * @param CreditmemoInterface $creditmemo
+     * @param array $items
+     * @param bool $notify
+     * @param bool $appendComment
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment
+     * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments
+     * @return ValidatorResultInterface
+     */
+    public function validate(
+        OrderInterface $order,
+        CreditmemoInterface $creditmemo,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    );
+}
diff --git a/app/code/Magento/Sales/Model/Order/Validation/ShipOrder.php b/app/code/Magento/Sales/Model/Order/Validation/ShipOrder.php
new file mode 100644
index 0000000000000000000000000000000000000000..984c5f26fa7dbe50234b6f2b075397fb40f62ca1
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/ShipOrder.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\Data\ShipmentInterface;
+use Magento\Sales\Model\Order\Shipment\Validation\QuantityValidator;
+use Magento\Sales\Model\Order\OrderValidatorInterface;
+use Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface;
+use Magento\Sales\Model\Order\Shipment\Validation\TrackValidator;
+use Magento\Sales\Model\ValidatorResultMerger;
+
+/**
+ * Class ShipOrder
+ */
+class ShipOrder implements ShipOrderInterface
+{
+    /**
+     * @var OrderValidatorInterface
+     */
+    private $orderValidator;
+
+    /**
+     * @var ShipmentValidatorInterface
+     */
+    private $shipmentValidator;
+
+    /**
+     * @var ValidatorResultMerger
+     */
+    private $validatorResultMerger;
+
+    /**
+     * ShipOrder constructor.
+     *
+     * @param OrderValidatorInterface $orderValidator
+     * @param ShipmentValidatorInterface $shipmentValidator
+     * @param ValidatorResultMerger $validatorResultMerger
+     */
+    public function __construct(
+        OrderValidatorInterface $orderValidator,
+        ShipmentValidatorInterface $shipmentValidator,
+        ValidatorResultMerger $validatorResultMerger
+    ) {
+        $this->orderValidator = $orderValidator;
+        $this->shipmentValidator = $shipmentValidator;
+        $this->validatorResultMerger = $validatorResultMerger;
+    }
+
+    /**
+     * @param OrderInterface $order
+     * @param ShipmentInterface $shipment
+     * @param array $items
+     * @param bool $notify
+     * @param bool $appendComment
+     * @param \Magento\Sales\Api\Data\ShipmentCommentCreationInterface|null $comment
+     * @param array $tracks
+     * @param array $packages
+     * @param \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface|null $arguments
+     * @return \Magento\Sales\Model\ValidatorResultInterface
+     */
+    public function validate(
+        $order,
+        $shipment,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null,
+        array $tracks = [],
+        array $packages = [],
+        \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface $arguments = null
+    ) {
+        $orderValidationResult = $this->orderValidator->validate(
+            $order,
+            [
+                CanShip::class
+            ]
+        );
+        $shipmentValidationResult = $this->shipmentValidator->validate(
+            $shipment,
+            [
+                QuantityValidator::class,
+                TrackValidator::class
+            ]
+        );
+
+        return $this->validatorResultMerger->merge($orderValidationResult, $shipmentValidationResult);
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Validation/ShipOrderInterface.php b/app/code/Magento/Sales/Model/Order/Validation/ShipOrderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..43f12df445b799621d220182bc009ff02f74c1bb
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/ShipOrderInterface.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\Data\ShipmentInterface;
+
+/**
+ * Interface ShipOrderInterface
+ *
+ * @api
+ */
+interface ShipOrderInterface
+{
+    /**
+     * @param OrderInterface $order
+     * @param ShipmentInterface $shipment
+     * @param array $items
+     * @param bool $notify
+     * @param bool $appendComment
+     * @param \Magento\Sales\Api\Data\ShipmentCommentCreationInterface|null $comment
+     * @param array $tracks
+     * @param array $packages
+     * @param \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface|null $arguments
+     * @return \Magento\Sales\Model\ValidatorResultInterface
+     */
+    public function validate(
+        $order,
+        $shipment,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null,
+        array $tracks = [],
+        array $packages = [],
+        \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface $arguments = null
+    );
+}
diff --git a/app/code/Magento/Sales/Model/RefundInvoice.php b/app/code/Magento/Sales/Model/RefundInvoice.php
index ad9f89b29bff8e18b579ac17c79da4286dc7aa84..60c3a2ac121254591cdc171433770d6c2d539e80 100644
--- a/app/code/Magento/Sales/Model/RefundInvoice.php
+++ b/app/code/Magento/Sales/Model/RefundInvoice.php
@@ -11,18 +11,11 @@ use Magento\Sales\Api\InvoiceRepositoryInterface;
 use Magento\Sales\Api\OrderRepositoryInterface;
 use Magento\Sales\Api\RefundInvoiceInterface;
 use Magento\Sales\Model\Order\Config as OrderConfig;
-use Magento\Sales\Model\Order\Creditmemo\CreditmemoValidatorInterface;
-use Magento\Sales\Model\Order\Creditmemo\ItemCreationValidatorInterface;
 use Magento\Sales\Model\Order\Creditmemo\NotifierInterface;
-use Magento\Sales\Model\Order\Creditmemo\Item\Validation\CreationQuantityValidator;
-use Magento\Sales\Model\Order\Creditmemo\Validation\QuantityValidator;
-use Magento\Sales\Model\Order\Creditmemo\Validation\TotalsValidator;
 use Magento\Sales\Model\Order\CreditmemoDocumentFactory;
-use Magento\Sales\Model\Order\Invoice\InvoiceValidatorInterface;
+use Magento\Sales\Model\Order\Validation\RefundInvoiceInterface as RefundInvoiceValidator;
 use Magento\Sales\Model\Order\OrderStateResolverInterface;
-use Magento\Sales\Model\Order\OrderValidatorInterface;
 use Magento\Sales\Model\Order\PaymentAdapterInterface;
-use Magento\Sales\Model\Order\Validation\CanRefund;
 use Psr\Log\LoggerInterface;
 
 /**
@@ -51,33 +44,13 @@ class RefundInvoice implements RefundInvoiceInterface
      */
     private $invoiceRepository;
 
-    /**
-     * @var OrderValidatorInterface
-     */
-    private $orderValidator;
-
-    /**
-     * @var InvoiceValidatorInterface
-     */
-    private $invoiceValidator;
-
-    /**
-     * @var CreditmemoValidatorInterface
-     */
-    private $creditmemoValidator;
-
-    /**
-     * @var ItemCreationValidatorInterface
-     */
-    private $itemCreationValidator;
-
     /**
      * @var CreditmemoRepositoryInterface
      */
     private $creditmemoRepository;
 
     /**
-     * @var Order\PaymentAdapterInterface
+     * @var PaymentAdapterInterface
      */
     private $paymentAdapter;
 
@@ -87,7 +60,7 @@ class RefundInvoice implements RefundInvoiceInterface
     private $creditmemoDocumentFactory;
 
     /**
-     * @var Order\Creditmemo\NotifierInterface
+     * @var NotifierInterface
      */
     private $notifier;
 
@@ -101,6 +74,11 @@ class RefundInvoice implements RefundInvoiceInterface
      */
     private $logger;
 
+    /**
+     * @var RefundInvoiceValidator
+     */
+    private $validator;
+
     /**
      * RefundInvoice constructor.
      *
@@ -108,10 +86,7 @@ class RefundInvoice implements RefundInvoiceInterface
      * @param OrderStateResolverInterface $orderStateResolver
      * @param OrderRepositoryInterface $orderRepository
      * @param InvoiceRepositoryInterface $invoiceRepository
-     * @param OrderValidatorInterface $orderValidator
-     * @param InvoiceValidatorInterface $invoiceValidator
-     * @param CreditmemoValidatorInterface $creditmemoValidator
-     * @param Order\Creditmemo\ItemCreationValidatorInterface $itemCreationValidator
+     * @param RefundInvoiceValidator $validator
      * @param CreditmemoRepositoryInterface $creditmemoRepository
      * @param PaymentAdapterInterface $paymentAdapter
      * @param CreditmemoDocumentFactory $creditmemoDocumentFactory
@@ -125,10 +100,7 @@ class RefundInvoice implements RefundInvoiceInterface
         OrderStateResolverInterface $orderStateResolver,
         OrderRepositoryInterface $orderRepository,
         InvoiceRepositoryInterface $invoiceRepository,
-        OrderValidatorInterface $orderValidator,
-        InvoiceValidatorInterface $invoiceValidator,
-        CreditmemoValidatorInterface $creditmemoValidator,
-        ItemCreationValidatorInterface $itemCreationValidator,
+        RefundInvoiceValidator $validator,
         CreditmemoRepositoryInterface $creditmemoRepository,
         PaymentAdapterInterface $paymentAdapter,
         CreditmemoDocumentFactory $creditmemoDocumentFactory,
@@ -140,16 +112,13 @@ class RefundInvoice implements RefundInvoiceInterface
         $this->orderStateResolver = $orderStateResolver;
         $this->orderRepository = $orderRepository;
         $this->invoiceRepository = $invoiceRepository;
-        $this->orderValidator = $orderValidator;
-        $this->creditmemoValidator = $creditmemoValidator;
-        $this->itemCreationValidator = $itemCreationValidator;
+        $this->validator = $validator;
         $this->creditmemoRepository = $creditmemoRepository;
         $this->paymentAdapter = $paymentAdapter;
         $this->creditmemoDocumentFactory = $creditmemoDocumentFactory;
         $this->notifier = $notifier;
         $this->config = $config;
         $this->logger = $logger;
-        $this->invoiceValidator = $invoiceValidator;
     }
 
     /**
@@ -174,45 +143,21 @@ class RefundInvoice implements RefundInvoiceInterface
             ($appendComment && $notify),
             $arguments
         );
-        $orderValidationResult = $this->orderValidator->validate(
-            $order,
-            [
-                CanRefund::class
-            ]
-        );
-        $invoiceValidationResult = $this->invoiceValidator->validate(
+
+        $validationMessages = $this->validator->validate(
             $invoice,
-            [
-                \Magento\Sales\Model\Order\Invoice\Validation\CanRefund::class
-            ]
-        );
-        $creditmemoValidationResult = $this->creditmemoValidator->validate(
+            $order,
             $creditmemo,
-            [
-                QuantityValidator::class,
-                TotalsValidator::class
-            ]
-        );
-        $itemsValidation = [];
-        foreach ($items as $item) {
-            $itemsValidation = array_merge(
-                $itemsValidation,
-                $this->itemCreationValidator->validate(
-                    $item,
-                    [CreationQuantityValidator::class],
-                    $order
-                )
-            );
-        }
-        $validationMessages = array_merge(
-            $orderValidationResult,
-            $invoiceValidationResult,
-            $creditmemoValidationResult,
-            $itemsValidation
+            $items,
+            $isOnline,
+            $notify,
+            $appendComment,
+            $comment,
+            $arguments
         );
-        if (!empty($validationMessages )) {
+        if ($validationMessages->hasMessages()) {
             throw new \Magento\Sales\Exception\DocumentValidationException(
-                __("Creditmemo Document Validation Error(s):\n" . implode("\n", $validationMessages))
+                __("Creditmemo Document Validation Error(s):\n" . implode("\n", $validationMessages->getMessages()))
             );
         }
         $connection->beginTransaction();
diff --git a/app/code/Magento/Sales/Model/RefundOrder.php b/app/code/Magento/Sales/Model/RefundOrder.php
index 4cfbe063ea81f29e7a6608c0c04fec269326c44c..abd6e25416729b3b995ba92425cbc3c3c7de8943 100644
--- a/app/code/Magento/Sales/Model/RefundOrder.php
+++ b/app/code/Magento/Sales/Model/RefundOrder.php
@@ -10,17 +10,11 @@ use Magento\Sales\Api\CreditmemoRepositoryInterface;
 use Magento\Sales\Api\OrderRepositoryInterface;
 use Magento\Sales\Api\RefundOrderInterface;
 use Magento\Sales\Model\Order\Config as OrderConfig;
-use Magento\Sales\Model\Order\Creditmemo\CreditmemoValidatorInterface;
-use Magento\Sales\Model\Order\Creditmemo\ItemCreationValidatorInterface;
 use Magento\Sales\Model\Order\Creditmemo\NotifierInterface;
-use Magento\Sales\Model\Order\Creditmemo\Item\Validation\CreationQuantityValidator;
-use Magento\Sales\Model\Order\Creditmemo\Validation\QuantityValidator;
-use Magento\Sales\Model\Order\Creditmemo\Validation\TotalsValidator;
 use Magento\Sales\Model\Order\CreditmemoDocumentFactory;
 use Magento\Sales\Model\Order\OrderStateResolverInterface;
-use Magento\Sales\Model\Order\OrderValidatorInterface;
 use Magento\Sales\Model\Order\PaymentAdapterInterface;
-use Magento\Sales\Model\Order\Validation\CanRefund;
+use Magento\Sales\Model\Order\Validation\RefundOrderInterface as RefundOrderValidator;
 use Psr\Log\LoggerInterface;
 
 /**
@@ -44,28 +38,13 @@ class RefundOrder implements RefundOrderInterface
      */
     private $orderRepository;
 
-    /**
-     * @var OrderValidatorInterface
-     */
-    private $orderValidator;
-
-    /**
-     * @var CreditmemoValidatorInterface
-     */
-    private $creditmemoValidator;
-
-    /**
-     * @var Order\Creditmemo\ItemCreationValidatorInterface
-     */
-    private $itemCreationValidator;
-
     /**
      * @var CreditmemoRepositoryInterface
      */
     private $creditmemoRepository;
 
     /**
-     * @var Order\PaymentAdapterInterface
+     * @var PaymentAdapterInterface
      */
     private $paymentAdapter;
 
@@ -75,7 +54,12 @@ class RefundOrder implements RefundOrderInterface
     private $creditmemoDocumentFactory;
 
     /**
-     * @var Order\Creditmemo\NotifierInterface
+     * @var RefundOrderValidator
+     */
+    private $validator;
+
+    /**
+     * @var NotifierInterface
      */
     private $notifier;
 
@@ -91,15 +75,14 @@ class RefundOrder implements RefundOrderInterface
 
     /**
      * RefundOrder constructor.
+     *
      * @param ResourceConnection $resourceConnection
      * @param OrderStateResolverInterface $orderStateResolver
      * @param OrderRepositoryInterface $orderRepository
-     * @param OrderValidatorInterface $orderValidator
-     * @param CreditmemoValidatorInterface $creditmemoValidator
-     * @param ItemCreationValidatorInterface $itemCreationValidator
      * @param CreditmemoRepositoryInterface $creditmemoRepository
      * @param PaymentAdapterInterface $paymentAdapter
      * @param CreditmemoDocumentFactory $creditmemoDocumentFactory
+     * @param RefundOrderValidator $validator
      * @param NotifierInterface $notifier
      * @param OrderConfig $config
      * @param LoggerInterface $logger
@@ -109,12 +92,10 @@ class RefundOrder implements RefundOrderInterface
         ResourceConnection $resourceConnection,
         OrderStateResolverInterface $orderStateResolver,
         OrderRepositoryInterface $orderRepository,
-        OrderValidatorInterface $orderValidator,
-        CreditmemoValidatorInterface $creditmemoValidator,
-        ItemCreationValidatorInterface $itemCreationValidator,
         CreditmemoRepositoryInterface $creditmemoRepository,
         PaymentAdapterInterface $paymentAdapter,
         CreditmemoDocumentFactory $creditmemoDocumentFactory,
+        RefundOrderValidator $validator,
         NotifierInterface $notifier,
         OrderConfig $config,
         LoggerInterface $logger
@@ -122,12 +103,10 @@ class RefundOrder implements RefundOrderInterface
         $this->resourceConnection = $resourceConnection;
         $this->orderStateResolver = $orderStateResolver;
         $this->orderRepository = $orderRepository;
-        $this->orderValidator = $orderValidator;
-        $this->creditmemoValidator = $creditmemoValidator;
-        $this->itemCreationValidator = $itemCreationValidator;
         $this->creditmemoRepository = $creditmemoRepository;
         $this->paymentAdapter = $paymentAdapter;
         $this->creditmemoDocumentFactory = $creditmemoDocumentFactory;
+        $this->validator = $validator;
         $this->notifier = $notifier;
         $this->config = $config;
         $this->logger = $logger;
@@ -153,34 +132,18 @@ class RefundOrder implements RefundOrderInterface
             ($appendComment && $notify),
             $arguments
         );
-        $orderValidationResult = $this->orderValidator->validate(
+        $validationMessages = $this->validator->validate(
             $order,
-            [
-                CanRefund::class
-            ]
-        );
-        $creditmemoValidationResult = $this->creditmemoValidator->validate(
             $creditmemo,
-            [
-                QuantityValidator::class,
-                TotalsValidator::class
-            ]
+            $items,
+            $notify,
+            $appendComment,
+            $comment,
+            $arguments
         );
-        $itemsValidation = [];
-        foreach ($items as $item) {
-            $itemsValidation = array_merge(
-                $itemsValidation,
-                $this->itemCreationValidator->validate(
-                    $item,
-                    [CreationQuantityValidator::class],
-                    $order
-                )
-            );
-        }
-        $validationMessages = array_merge($orderValidationResult, $creditmemoValidationResult, $itemsValidation);
-        if (!empty($validationMessages)) {
+        if ($validationMessages->hasMessages()) {
             throw new \Magento\Sales\Exception\DocumentValidationException(
-                __("Creditmemo Document Validation Error(s):\n" . implode("\n", $validationMessages))
+                __("Creditmemo Document Validation Error(s):\n" . implode("\n", $validationMessages->getMessages()))
             );
         }
         $connection->beginTransaction();
diff --git a/app/code/Magento/Sales/Model/ShipOrder.php b/app/code/Magento/Sales/Model/ShipOrder.php
index d051144cf73ca166c30ebd6eb9f626306b1720a6..034442a19c1f7e297e364e894ef53275574c4706 100644
--- a/app/code/Magento/Sales/Model/ShipOrder.php
+++ b/app/code/Magento/Sales/Model/ShipOrder.php
@@ -11,14 +11,10 @@ use Magento\Sales\Api\ShipmentRepositoryInterface;
 use Magento\Sales\Api\ShipOrderInterface;
 use Magento\Sales\Model\Order\Config as OrderConfig;
 use Magento\Sales\Model\Order\OrderStateResolverInterface;
-use Magento\Sales\Model\Order\OrderValidatorInterface;
 use Magento\Sales\Model\Order\ShipmentDocumentFactory;
 use Magento\Sales\Model\Order\Shipment\NotifierInterface;
-use Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface;
-use Magento\Sales\Model\Order\Shipment\Validation\QuantityValidator;
-use Magento\Sales\Model\Order\Shipment\Validation\TrackValidator;
-use Magento\Sales\Model\Order\Validation\CanShip;
 use Magento\Sales\Model\Order\Shipment\OrderRegistrarInterface;
+use Magento\Sales\Model\Order\Validation\ShipOrderInterface as ShipOrderValidator;
 use Psr\Log\LoggerInterface;
 
 /**
@@ -42,11 +38,6 @@ class ShipOrder implements ShipOrderInterface
      */
     private $shipmentDocumentFactory;
 
-    /**
-     * @var ShipmentValidatorInterface
-     */
-    private $shipmentValidator;
-
     /**
      * @var OrderStateResolverInterface
      */
@@ -62,6 +53,11 @@ class ShipOrder implements ShipOrderInterface
      */
     private $shipmentRepository;
 
+    /**
+     * @var ShipOrderValidator
+     */
+    private $shipOrderValidator;
+
     /**
      * @var NotifierInterface
      */
@@ -72,11 +68,6 @@ class ShipOrder implements ShipOrderInterface
      */
     private $logger;
 
-    /**
-     * @var OrderValidatorInterface
-     */
-    private $orderValidator;
-
     /**
      * @var OrderRegistrarInterface
      */
@@ -86,11 +77,10 @@ class ShipOrder implements ShipOrderInterface
      * @param ResourceConnection $resourceConnection
      * @param OrderRepositoryInterface $orderRepository
      * @param ShipmentDocumentFactory $shipmentDocumentFactory
-     * @param ShipmentValidatorInterface $shipmentValidator
-     * @param OrderValidatorInterface $orderValidator
      * @param OrderStateResolverInterface $orderStateResolver
      * @param OrderConfig $config
      * @param ShipmentRepositoryInterface $shipmentRepository
+     * @param ShipOrderValidator $shipOrderValidator
      * @param NotifierInterface $notifierInterface
      * @param OrderRegistrarInterface $orderRegistrar
      * @param LoggerInterface $logger
@@ -100,11 +90,10 @@ class ShipOrder implements ShipOrderInterface
         ResourceConnection $resourceConnection,
         OrderRepositoryInterface $orderRepository,
         ShipmentDocumentFactory $shipmentDocumentFactory,
-        ShipmentValidatorInterface $shipmentValidator,
-        OrderValidatorInterface $orderValidator,
         OrderStateResolverInterface $orderStateResolver,
         OrderConfig $config,
         ShipmentRepositoryInterface $shipmentRepository,
+        ShipOrderValidator $shipOrderValidator,
         NotifierInterface $notifierInterface,
         OrderRegistrarInterface $orderRegistrar,
         LoggerInterface $logger
@@ -112,11 +101,10 @@ class ShipOrder implements ShipOrderInterface
         $this->resourceConnection = $resourceConnection;
         $this->orderRepository = $orderRepository;
         $this->shipmentDocumentFactory = $shipmentDocumentFactory;
-        $this->shipmentValidator = $shipmentValidator;
-        $this->orderValidator = $orderValidator;
         $this->orderStateResolver = $orderStateResolver;
         $this->config = $config;
         $this->shipmentRepository = $shipmentRepository;
+        $this->shipOrderValidator = $shipOrderValidator;
         $this->notifierInterface = $notifierInterface;
         $this->logger = $logger;
         $this->orderRegistrar = $orderRegistrar;
@@ -159,23 +147,19 @@ class ShipOrder implements ShipOrderInterface
             $packages,
             $arguments
         );
-        $orderValidationResult = $this->orderValidator->validate(
+        $validationMessages = $this->shipOrderValidator->validate(
             $order,
-            [
-                CanShip::class
-            ]
-        );
-        $shipmentValidationResult = $this->shipmentValidator->validate(
             $shipment,
-            [
-                QuantityValidator::class,
-                TrackValidator::class
-            ]
+            $items,
+            $notify,
+            $appendComment,
+            $comment,
+            $tracks,
+            $packages
         );
-        $validationMessages = array_merge($orderValidationResult, $shipmentValidationResult);
-        if (!empty($validationMessages)) {
+        if ($validationMessages->hasMessages()) {
             throw new \Magento\Sales\Exception\DocumentValidationException(
-                __("Shipment Document Validation Error(s):\n" . implode("\n", $validationMessages))
+                __("Shipment Document Validation Error(s):\n" . implode("\n", $validationMessages->getMessages()))
             );
         }
         $connection->beginTransaction();
diff --git a/app/code/Magento/Sales/Model/Validator.php b/app/code/Magento/Sales/Model/Validator.php
index 10aa0735b952e99e0d889b27ff378411d0d1d6d1..9239223fe3b4a84ee1e319e6f067ca9ba6cfb3e8 100644
--- a/app/code/Magento/Sales/Model/Validator.php
+++ b/app/code/Magento/Sales/Model/Validator.php
@@ -20,21 +20,30 @@ class Validator
      */
     private $objectManager;
 
+    /**
+     * @var ValidatorResultInterfaceFactory
+     */
+    private $validatorResultFactory;
+
     /**
      * Validator constructor.
      *
      * @param ObjectManagerInterface $objectManager
+     * @param ValidatorResultInterfaceFactory $validatorResult
      */
-    public function __construct(ObjectManagerInterface $objectManager)
-    {
+    public function __construct(
+        ObjectManagerInterface $objectManager,
+        ValidatorResultInterfaceFactory $validatorResult
+    ) {
         $this->objectManager = $objectManager;
+        $this->validatorResultFactory = $validatorResult;
     }
 
     /**
      * @param object $entity
      * @param ValidatorInterface[] $validators
      * @param object|null $context
-     * @return \string[]
+     * @return ValidatorResultInterface
      * @throws ConfigurationMismatchException
      */
     public function validate($entity, array $validators, $context = null)
@@ -56,7 +65,11 @@ class Validator
             }
             $messages = array_merge($messages, $validator->validate($entity));
         }
+        $validationResult = $this->validatorResultFactory->create();
+        foreach ($messages as $message) {
+            $validationResult->addMessage($message);
+        }
 
-        return $messages;
+        return $validationResult;
     }
 }
diff --git a/app/code/Magento/Sales/Model/ValidatorResult.php b/app/code/Magento/Sales/Model/ValidatorResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..6dc2933ac42a7c2974d397aebf3e3c599831b5bf
--- /dev/null
+++ b/app/code/Magento/Sales/Model/ValidatorResult.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model;
+
+/**
+ * Class ValidatorResult
+ */
+class ValidatorResult implements ValidatorResultInterface
+{
+    /**
+     * @var \string[]
+     */
+    private $messages = [];
+
+    /**
+     * @inheritdoc
+     */
+    public function addMessage($message)
+    {
+        $this->messages[] = (string)$message;
+    }
+
+    /**
+     * @return bool
+     */
+    public function hasMessages()
+    {
+        return count($this->messages) > 0;
+    }
+
+    /**
+     * @return \string[]
+     */
+    public function getMessages()
+    {
+        return $this->messages;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/ValidatorResultInterface.php b/app/code/Magento/Sales/Model/ValidatorResultInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..c4e284657bdd1f1261094f05337577ebf3656ad7
--- /dev/null
+++ b/app/code/Magento/Sales/Model/ValidatorResultInterface.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model;
+
+/**
+ * Interface ValidatorResultInterface
+ * @api
+ */
+interface ValidatorResultInterface
+{
+    /**
+     * @param string $message
+     * @return void
+     */
+    public function addMessage($message);
+
+    /**
+     * @return bool
+     */
+    public function hasMessages();
+
+    /**
+     * @return \string[]
+     */
+    public function getMessages();
+}
diff --git a/app/code/Magento/Sales/Model/ValidatorResultMerger.php b/app/code/Magento/Sales/Model/ValidatorResultMerger.php
new file mode 100644
index 0000000000000000000000000000000000000000..41f38e8eef078b221c70cdb9520f6043ccfe4daf
--- /dev/null
+++ b/app/code/Magento/Sales/Model/ValidatorResultMerger.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model;
+
+/**
+ * Class ValidatorResultMerger
+ */
+class ValidatorResultMerger
+{
+    /**
+     * @var ValidatorResultInterfaceFactory
+     */
+    private $validatorResultInterfaceFactory;
+
+    /**
+     * ValidatorResultMerger constructor.
+     *
+     * @param ValidatorResultInterfaceFactory $validatorResultInterfaceFactory
+     */
+    public function __construct(ValidatorResultInterfaceFactory $validatorResultInterfaceFactory)
+    {
+        $this->validatorResultInterfaceFactory = $validatorResultInterfaceFactory;
+    }
+
+    /**
+     * Merge two validator results and additional messages
+     *
+     * @param ValidatorResultInterface $first
+     * @param ValidatorResultInterface $second
+     * @param \string[] $validatorMessages
+     * @return ValidatorResultInterface
+     */
+    public function merge(ValidatorResultInterface $first, ValidatorResultInterface $second, ... $validatorMessages)
+    {
+        $messages = array_merge($first->getMessages(), $second->getMessages(), ...$validatorMessages);
+
+        $result = $this->validatorResultInterfaceFactory->create();
+        foreach ($messages as $message) {
+            $result->addMessage($message);
+        }
+
+        return $result;
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/InvoiceOrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/InvoiceOrderTest.php
index 6dfa929acb6290e0e95bf2011b76ec9811691ecc..1169e230e75421d150a2719edfb14c09fddf1120 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/InvoiceOrderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/InvoiceOrderTest.php
@@ -14,19 +14,19 @@ use Magento\Sales\Api\Data\OrderInterface;
 use Magento\Sales\Api\OrderRepositoryInterface;
 use Magento\Sales\Model\Order;
 use Magento\Sales\Model\Order\Config as OrderConfig;
-use Magento\Sales\Model\Order\Invoice\InvoiceValidatorInterface;
 use Magento\Sales\Model\Order\Invoice\NotifierInterface;
 use Magento\Sales\Model\Order\InvoiceDocumentFactory;
 use Magento\Sales\Model\Order\InvoiceRepository;
 use Magento\Sales\Model\Order\OrderStateResolverInterface;
-use Magento\Sales\Model\Order\OrderValidatorInterface;
+use Magento\Sales\Model\Order\Validation\InvoiceOrderInterface;
 use Magento\Sales\Model\Order\PaymentAdapterInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
 use Magento\Sales\Model\InvoiceOrder;
 use Psr\Log\LoggerInterface;
 
 /**
  * Class InvoiceOrderTest
- * 
+ *
  * @SuppressWarnings(PHPMD.TooManyFields)
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
@@ -48,14 +48,9 @@ class InvoiceOrderTest extends \PHPUnit_Framework_TestCase
     private $invoiceDocumentFactoryMock;
 
     /**
-     * @var InvoiceValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var InvoiceOrderInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    private $invoiceValidatorMock;
-
-    /**
-     * @var OrderValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $orderValidatorMock;
+    private $invoiceOrderValidatorMock;
 
     /**
      * @var PaymentAdapterInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -117,6 +112,11 @@ class InvoiceOrderTest extends \PHPUnit_Framework_TestCase
      */
     private $loggerMock;
 
+    /**
+     * @var ValidatorResultInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $errorMessagesMock;
+
     protected function setUp()
     {
         $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class)
@@ -131,14 +131,6 @@ class InvoiceOrderTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $this->invoiceValidatorMock = $this->getMockBuilder(InvoiceValidatorInterface::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $this->orderValidatorMock = $this->getMockBuilder(OrderValidatorInterface::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-
         $this->paymentAdapterMock = $this->getMockBuilder(PaymentAdapterInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
@@ -183,22 +175,37 @@ class InvoiceOrderTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
+        $this->invoiceOrderValidatorMock = $this->getMockBuilder(InvoiceOrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->errorMessagesMock = $this->getMockBuilder(ValidatorResultInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['hasMessages', 'getMessages', 'addMessage'])
+            ->getMock();
+
         $this->invoiceOrder = new InvoiceOrder(
             $this->resourceConnectionMock,
             $this->orderRepositoryMock,
             $this->invoiceDocumentFactoryMock,
-            $this->invoiceValidatorMock,
-            $this->orderValidatorMock,
             $this->paymentAdapterMock,
             $this->orderStateResolverMock,
             $this->configMock,
             $this->invoiceRepositoryMock,
+            $this->invoiceOrderValidatorMock,
             $this->notifierInterfaceMock,
             $this->loggerMock
         );
     }
 
     /**
+     * @param int $orderId
+     * @param bool $capture
+     * @param array $items
+     * @param bool $notify
+     * @param bool $appendComment
+     * @throws \Magento\Sales\Exception\CouldNotInvoiceException
+     * @throws \Magento\Sales\Exception\DocumentValidationException
      * @dataProvider dataProvider
      */
     public function testOrderInvoice($orderId, $capture, $items, $notify, $appendComment)
@@ -207,11 +214,9 @@ class InvoiceOrderTest extends \PHPUnit_Framework_TestCase
             ->method('getConnection')
             ->with('sales')
             ->willReturn($this->adapterInterface);
-
         $this->orderRepositoryMock->expects($this->once())
             ->method('get')
             ->willReturn($this->orderMock);
-
         $this->invoiceDocumentFactoryMock->expects($this->once())
             ->method('create')
             ->with(
@@ -221,66 +226,62 @@ class InvoiceOrderTest extends \PHPUnit_Framework_TestCase
                 ($appendComment && $notify),
                 $this->invoiceCreationArgumentsMock
             )->willReturn($this->invoiceMock);
-
-        $this->invoiceValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->invoiceMock)
-            ->willReturn([]);
-        $this->orderValidatorMock->expects($this->once())
+        $this->invoiceOrderValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
-
+            ->with(
+                $this->orderMock,
+                $this->invoiceMock,
+                $capture,
+                $items,
+                $notify,
+                $appendComment,
+                $this->invoiceCommentCreationMock,
+                $this->invoiceCreationArgumentsMock
+            )
+            ->willReturn($this->errorMessagesMock);
+        $hasMessages = false;
+        $this->errorMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
         $this->paymentAdapterMock->expects($this->once())
             ->method('pay')
             ->with($this->orderMock, $this->invoiceMock, $capture)
             ->willReturn($this->orderMock);
-
         $this->orderStateResolverMock->expects($this->once())
             ->method('getStateForOrder')
             ->with($this->orderMock, [OrderStateResolverInterface::IN_PROGRESS])
             ->willReturn(Order::STATE_PROCESSING);
-
         $this->orderMock->expects($this->once())
             ->method('setState')
             ->with(Order::STATE_PROCESSING)
             ->willReturnSelf();
-
         $this->orderMock->expects($this->once())
             ->method('getState')
             ->willReturn(Order::STATE_PROCESSING);
-
         $this->configMock->expects($this->once())
             ->method('getStateDefaultStatus')
             ->with(Order::STATE_PROCESSING)
             ->willReturn('Processing');
-
         $this->orderMock->expects($this->once())
             ->method('setStatus')
             ->with('Processing')
             ->willReturnSelf();
-
         $this->invoiceMock->expects($this->once())
             ->method('setState')
             ->with(\Magento\Sales\Model\Order\Invoice::STATE_PAID)
             ->willReturnSelf();
-
         $this->invoiceRepositoryMock->expects($this->once())
             ->method('save')
             ->with($this->invoiceMock)
             ->willReturn($this->invoiceMock);
-
         $this->orderRepositoryMock->expects($this->once())
             ->method('save')
             ->with($this->orderMock)
             ->willReturn($this->orderMock);
-
         if ($notify) {
             $this->notifierInterfaceMock->expects($this->once())
                 ->method('notify')
                 ->with($this->orderMock, $this->invoiceMock, $this->invoiceCommentCreationMock);
         }
-
         $this->invoiceMock->expects($this->once())
             ->method('getEntityId')
             ->willReturn(2);
@@ -325,14 +326,25 @@ class InvoiceOrderTest extends \PHPUnit_Framework_TestCase
                 $this->invoiceCreationArgumentsMock
             )->willReturn($this->invoiceMock);
 
-        $this->invoiceValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->invoiceMock)
-            ->willReturn($errorMessages);
-        $this->orderValidatorMock->expects($this->once())
+        $this->invoiceOrderValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
+            ->with(
+                $this->orderMock,
+                $this->invoiceMock,
+                $capture,
+                $items,
+                $notify,
+                $appendComment,
+                $this->invoiceCommentCreationMock,
+                $this->invoiceCreationArgumentsMock
+            )
+            ->willReturn($this->errorMessagesMock);
+        $hasMessages = true;
+
+        $this->errorMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
+        $this->errorMessagesMock->expects($this->once())
+            ->method('getMessages')->willReturn($errorMessages);
 
         $this->invoiceOrder->execute(
             $orderId,
@@ -374,16 +386,25 @@ class InvoiceOrderTest extends \PHPUnit_Framework_TestCase
                 $this->invoiceCreationArgumentsMock
             )->willReturn($this->invoiceMock);
 
-        $this->invoiceValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->invoiceMock)
-            ->willReturn([]);
-        $this->orderValidatorMock->expects($this->once())
+        $this->invoiceOrderValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
-        $e = new \Exception();
+            ->with(
+                $this->orderMock,
+                $this->invoiceMock,
+                $capture,
+                $items,
+                $notify,
+                $appendComment,
+                $this->invoiceCommentCreationMock,
+                $this->invoiceCreationArgumentsMock
+            )
+            ->willReturn($this->errorMessagesMock);
 
+        $hasMessages = false;
+        $this->errorMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
+
+        $e = new \Exception();
         $this->paymentAdapterMock->expects($this->once())
             ->method('pay')
             ->with($this->orderMock, $this->invoiceMock, $capture)
diff --git a/app/code/Magento/Sales/Test/Unit/Model/RefundInvoiceTest.php b/app/code/Magento/Sales/Test/Unit/Model/RefundInvoiceTest.php
index d400c7e1c0d4ed4bd38e6ff7a4eb9a5cb460f833..d249f039a140b69e0aeebf444aff1f3961f0c0b2 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/RefundInvoiceTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/RefundInvoiceTest.php
@@ -17,15 +17,13 @@ use Magento\Sales\Api\InvoiceRepositoryInterface;
 use Magento\Sales\Api\OrderRepositoryInterface;
 use Magento\Sales\Model\Order;
 use Magento\Sales\Model\Order\Config as OrderConfig;
-use Magento\Sales\Model\Order\Creditmemo\CreditmemoValidatorInterface;
-use Magento\Sales\Model\Order\Creditmemo\ItemCreationValidatorInterface;
 use Magento\Sales\Api\Data\CreditmemoItemCreationInterface;
 use Magento\Sales\Model\Order\CreditmemoDocumentFactory;
-use Magento\Sales\Model\Order\Invoice\InvoiceValidatorInterface;
 use Magento\Sales\Model\Order\OrderStateResolverInterface;
-use Magento\Sales\Model\Order\OrderValidatorInterface;
 use Magento\Sales\Model\Order\PaymentAdapterInterface;
 use Magento\Sales\Model\Order\Creditmemo\NotifierInterface;
+use Magento\Sales\Model\Order\Validation\RefundInvoiceInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
 use Magento\Sales\Model\RefundInvoice;
 use Psr\Log\LoggerInterface;
 
@@ -56,21 +54,6 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
      */
     private $creditmemoDocumentFactoryMock;
 
-    /**
-     * @var CreditmemoValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $creditmemoValidatorMock;
-
-    /**
-     * @var OrderValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $orderValidatorMock;
-
-    /**
-     * @var InvoiceValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $invoiceValidatorMock;
-
     /**
      * @var PaymentAdapterInterface|\PHPUnit_Framework_MockObject_MockObject
      */
@@ -137,9 +120,14 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
     private $creditmemoItemCreationMock;
 
     /**
-     * @var ItemCreationValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var RefundInvoiceInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    private $itemCreationValidatorMock;
+    private $refundInvoiceValidatorMock;
+
+    /**
+     * @var ValidatorResultInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $validationMessagesMock;
 
     /**
      * @var LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -160,24 +148,15 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
         $this->creditmemoDocumentFactoryMock = $this->getMockBuilder(CreditmemoDocumentFactory::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->creditmemoValidatorMock = $this->getMockBuilder(CreditmemoValidatorInterface::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $this->orderValidatorMock = $this->getMockBuilder(OrderValidatorInterface::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $this->invoiceValidatorMock = $this->getMockBuilder(InvoiceValidatorInterface::class)
+        $this->paymentAdapterMock = $this->getMockBuilder(PaymentAdapterInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
-        
-        $this->paymentAdapterMock = $this->getMockBuilder(PaymentAdapterInterface::class)
+        $this->refundInvoiceValidatorMock = $this->getMockBuilder(RefundInvoiceInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
-
         $this->orderStateResolverMock = $this->getMockBuilder(OrderStateResolverInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->configMock = $this->getMockBuilder(OrderConfig::class)
             ->disableOriginalConstructor()
             ->getMock();
@@ -221,20 +200,17 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
         $this->creditmemoItemCreationMock = $this->getMockBuilder(CreditmemoItemCreationInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
-        $this->itemCreationValidatorMock = $this->getMockBuilder(ItemCreationValidatorInterface::class)
+        $this->validationMessagesMock = $this->getMockBuilder(ValidatorResultInterface::class)
             ->disableOriginalConstructor()
-            ->getMockForAbstractClass();
+            ->setMethods(['hasMessages', 'getMessages', 'addMessage'])
+            ->getMock();
 
         $this->refundInvoice = new RefundInvoice(
             $this->resourceConnectionMock,
             $this->orderStateResolverMock,
             $this->orderRepositoryMock,
             $this->invoiceRepositoryMock,
-            $this->orderValidatorMock,
-            $this->invoiceValidatorMock,
-            $this->creditmemoValidatorMock,
-            $this->itemCreationValidatorMock,
+            $this->refundInvoiceValidatorMock,
             $this->creditmemoRepositoryMock,
             $this->paymentAdapterMock,
             $this->creditmemoDocumentFactoryMock,
@@ -245,22 +221,27 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
+     * @param int $invoiceId
+     * @param bool $isOnline
+     * @param array $items
+     * @param bool $notify
+     * @param bool $appendComment
+     * @throws \Magento\Sales\Exception\CouldNotRefundException
+     * @throws \Magento\Sales\Exception\DocumentValidationException
      * @dataProvider dataProvider
      */
-    public function testOrderCreditmemo($invoiceId, $items, $notify, $appendComment)
+    public function testOrderCreditmemo($invoiceId, $isOnline, $items, $notify, $appendComment)
     {
         $this->resourceConnectionMock->expects($this->once())
             ->method('getConnection')
             ->with('sales')
             ->willReturn($this->adapterInterface);
-
         $this->invoiceRepositoryMock->expects($this->once())
             ->method('get')
             ->willReturn($this->invoiceMock);
         $this->orderRepositoryMock->expects($this->once())
             ->method('get')
             ->willReturn($this->orderMock);
-
         $this->creditmemoDocumentFactoryMock->expects($this->once())
             ->method('createFromInvoice')
             ->with(
@@ -270,24 +251,23 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
                 ($appendComment && $notify),
                 $this->creditmemoCreationArgumentsMock
             )->willReturn($this->creditmemoMock);
-
-        $this->creditmemoValidatorMock->expects($this->once())
+        $this->refundInvoiceValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->creditmemoMock)
-            ->willReturn([]);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
-        $this->invoiceValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->invoiceMock)
-            ->willReturn([]);
-        $this->itemCreationValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->creditmemoItemCreationMock)
-            ->willReturn([]);
-        $this->orderMock->expects($this->once())->method('setCustomerNoteNotify')->with($notify);
+            ->with(
+                $this->invoiceMock,
+                $this->orderMock,
+                $this->creditmemoMock,
+                $items,
+                $isOnline,
+                $notify,
+                $appendComment,
+                $this->creditmemoCommentCreationMock,
+                $this->creditmemoCreationArgumentsMock
+            )
+            ->willReturn($this->validationMessagesMock);
+        $hasMessages = false;
+        $this->validationMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
         $this->paymentAdapterMock->expects($this->once())
             ->method('refund')
             ->with($this->creditmemoMock, $this->orderMock)
@@ -315,7 +295,6 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
             ->method('setState')
             ->with(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED)
             ->willReturnSelf();
-
         $this->creditmemoRepositoryMock->expects($this->once())
             ->method('save')
             ->with($this->creditmemoMock)
@@ -338,7 +317,7 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
             $this->refundInvoice->execute(
                 $invoiceId,
                 $items,
-                false,
+                true,
                 $notify,
                 $appendComment,
                 $this->creditmemoCommentCreationMock,
@@ -356,6 +335,7 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
         $items = [1 => $this->creditmemoItemCreationMock];
         $notify = true;
         $appendComment = true;
+        $isOnline = false;
         $errorMessages = ['error1', 'error2'];
 
         $this->invoiceRepositoryMock->expects($this->once())
@@ -375,22 +355,25 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
                 $this->creditmemoCreationArgumentsMock
             )->willReturn($this->creditmemoMock);
 
-        $this->creditmemoValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->creditmemoMock)
-            ->willReturn($errorMessages);
-        $this->orderValidatorMock->expects($this->once())
+        $this->refundInvoiceValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
-        $this->invoiceValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->invoiceMock)
-            ->willReturn([]);
-        $this->itemCreationValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->creditmemoItemCreationMock)
-            ->willReturn([]);
+            ->with(
+                $this->invoiceMock,
+                $this->orderMock,
+                $this->creditmemoMock,
+                $items,
+                $isOnline,
+                $notify,
+                $appendComment,
+                $this->creditmemoCommentCreationMock,
+                $this->creditmemoCreationArgumentsMock
+            )
+            ->willReturn($this->validationMessagesMock);
+        $hasMessages = true;
+        $this->validationMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
+        $this->validationMessagesMock->expects($this->once())
+            ->method('getMessages')->willReturn($errorMessages);
 
         $this->assertEquals(
             $errorMessages,
@@ -415,6 +398,7 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
         $items = [1 => $this->creditmemoItemCreationMock];
         $notify = true;
         $appendComment = true;
+        $isOnline = false;
         $this->resourceConnectionMock->expects($this->once())
             ->method('getConnection')
             ->with('sales')
@@ -437,22 +421,23 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
                 $this->creditmemoCreationArgumentsMock
             )->willReturn($this->creditmemoMock);
 
-        $this->creditmemoValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->creditmemoMock)
-            ->willReturn([]);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
-        $this->invoiceValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->invoiceMock)
-            ->willReturn([]);
-        $this->itemCreationValidatorMock->expects($this->once())
+        $this->refundInvoiceValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->creditmemoItemCreationMock)
-            ->willReturn([]);
+            ->with(
+                $this->invoiceMock,
+                $this->orderMock,
+                $this->creditmemoMock,
+                $items,
+                $isOnline,
+                $notify,
+                $appendComment,
+                $this->creditmemoCommentCreationMock,
+                $this->creditmemoCreationArgumentsMock
+            )
+            ->willReturn($this->validationMessagesMock);
+        $hasMessages = false;
+        $this->validationMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
         $e = new \Exception();
 
         $this->paymentAdapterMock->expects($this->once())
@@ -485,8 +470,8 @@ class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
             ->getMockForAbstractClass();
 
         return [
-            'TestWithNotifyTrue' => [1, [1 => $creditmemoItemCreationMock], true, true],
-            'TestWithNotifyFalse' => [1, [1 => $creditmemoItemCreationMock], false, true],
+            'TestWithNotifyTrue' => [1, true,  [1 => $creditmemoItemCreationMock], true, true],
+            'TestWithNotifyFalse' => [1, true,  [1 => $creditmemoItemCreationMock], false, true],
         ];
     }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php
index 7cc2673981c03d9fe858b38f10f7de16cd64287a..4b61453e3c6a2a9cc996dce60a52714fe0113cc2 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php
@@ -15,14 +15,13 @@ use Magento\Sales\Api\Data\OrderInterface;
 use Magento\Sales\Api\OrderRepositoryInterface;
 use Magento\Sales\Model\Order;
 use Magento\Sales\Model\Order\Config as OrderConfig;
-use Magento\Sales\Model\Order\Creditmemo\CreditmemoValidatorInterface;
-use Magento\Sales\Model\Order\Creditmemo\Item\Validation\CreationQuantityValidator;
 use Magento\Sales\Model\Order\CreditmemoDocumentFactory;
 use Magento\Sales\Model\Order\OrderStateResolverInterface;
-use Magento\Sales\Model\Order\OrderValidatorInterface;
+use Magento\Sales\Model\Order\Validation\RefundOrderInterface;
 use Magento\Sales\Model\Order\PaymentAdapterInterface;
 use Magento\Sales\Model\Order\Creditmemo\NotifierInterface;
 use Magento\Sales\Model\RefundOrder;
+use Magento\Sales\Model\ValidatorResultInterface;
 use Psr\Log\LoggerInterface;
 use Magento\Sales\Api\Data\CreditmemoItemCreationInterface;
 
@@ -48,16 +47,6 @@ class RefundOrderTest extends \PHPUnit_Framework_TestCase
      */
     private $creditmemoDocumentFactoryMock;
 
-    /**
-     * @var CreditmemoValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $creditmemoValidatorMock;
-
-    /**
-     * @var OrderValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $orderValidatorMock;
-
     /**
      * @var PaymentAdapterInterface|\PHPUnit_Framework_MockObject_MockObject
      */
@@ -119,15 +108,20 @@ class RefundOrderTest extends \PHPUnit_Framework_TestCase
     private $loggerMock;
 
     /**
-     * @var Order\Creditmemo\ItemCreationValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var RefundOrderInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    private $itemCreationValidatorMock;
+    private $refundOrderValidatorMock;
 
     /**
      * @var CreditmemoItemCreationInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $creditmemoItemCreationMock;
 
+    /**
+     * @var ValidatorResultInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $validationMessagesMock;
+
     protected function setUp()
     {
         $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class)
@@ -139,10 +133,7 @@ class RefundOrderTest extends \PHPUnit_Framework_TestCase
         $this->creditmemoDocumentFactoryMock = $this->getMockBuilder(CreditmemoDocumentFactory::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->creditmemoValidatorMock = $this->getMockBuilder(CreditmemoValidatorInterface::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $this->orderValidatorMock = $this->getMockBuilder(OrderValidatorInterface::class)
+        $this->refundOrderValidatorMock = $this->getMockBuilder(RefundOrderInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->paymentAdapterMock = $this->getMockBuilder(PaymentAdapterInterface::class)
@@ -178,23 +169,22 @@ class RefundOrderTest extends \PHPUnit_Framework_TestCase
         $this->adapterInterface = $this->getMockBuilder(AdapterInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-        $this->itemCreationValidatorMock = $this->getMockBuilder(Order\Creditmemo\ItemCreationValidatorInterface::class)
-            ->disableOriginalConstructor()
-            ->getMockForAbstractClass();
         $this->creditmemoItemCreationMock = $this->getMockBuilder(CreditmemoItemCreationInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
+        $this->validationMessagesMock = $this->getMockBuilder(ValidatorResultInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['hasMessages', 'getMessages', 'addMessage'])
+            ->getMock();
 
         $this->refundOrder = new RefundOrder(
             $this->resourceConnectionMock,
             $this->orderStateResolverMock,
             $this->orderRepositoryMock,
-            $this->orderValidatorMock,
-            $this->creditmemoValidatorMock,
-            $this->itemCreationValidatorMock,
             $this->creditmemoRepositoryMock,
             $this->paymentAdapterMock,
             $this->creditmemoDocumentFactoryMock,
+            $this->refundOrderValidatorMock,
             $this->notifierMock,
             $this->configMock,
             $this->loggerMock
@@ -202,6 +192,11 @@ class RefundOrderTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
+     * @param int $orderId
+     * @param bool $notify
+     * @param bool $appendComment
+     * @throws \Magento\Sales\Exception\CouldNotRefundException
+     * @throws \Magento\Sales\Exception\DocumentValidationException
      * @dataProvider dataProvider
      */
     public function testOrderCreditmemo($orderId, $notify, $appendComment)
@@ -223,22 +218,21 @@ class RefundOrderTest extends \PHPUnit_Framework_TestCase
                 ($appendComment && $notify),
                 $this->creditmemoCreationArgumentsMock
             )->willReturn($this->creditmemoMock);
-        $this->creditmemoValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->creditmemoMock)
-            ->willReturn([]);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
-        $this->itemCreationValidatorMock->expects($this->once())
+        $this->refundOrderValidatorMock->expects($this->once())
             ->method('validate')
             ->with(
-                reset($items),
-                [CreationQuantityValidator::class],
-                $this->orderMock
-            )->willReturn([]);
-        $this->orderMock->expects($this->once())->method('setCustomerNoteNotify')->with($notify);
+                $this->orderMock,
+                $this->creditmemoMock,
+                $items,
+                $notify,
+                $appendComment,
+                $this->creditmemoCommentCreationMock,
+                $this->creditmemoCreationArgumentsMock
+            )
+            ->willReturn($this->validationMessagesMock);
+        $hasMessages = false;
+        $this->validationMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
         $this->paymentAdapterMock->expects($this->once())
             ->method('refund')
             ->with($this->creditmemoMock, $this->orderMock)
@@ -279,7 +273,6 @@ class RefundOrderTest extends \PHPUnit_Framework_TestCase
                 ->method('notify')
                 ->with($this->orderMock, $this->creditmemoMock, $this->creditmemoCommentCreationMock);
         }
-
         $this->creditmemoMock->expects($this->once())
             ->method('getEntityId')
             ->willReturn(2);
@@ -322,18 +315,23 @@ class RefundOrderTest extends \PHPUnit_Framework_TestCase
                 $this->creditmemoCreationArgumentsMock
             )->willReturn($this->creditmemoMock);
 
-        $this->creditmemoValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->creditmemoMock)
-            ->willReturn($errorMessages);
-        $this->orderValidatorMock->expects($this->once())
+        $this->refundOrderValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
-        $this->itemCreationValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with(reset($items), [CreationQuantityValidator::class], $this->orderMock)
-            ->willReturn([]);
+            ->with(
+                $this->orderMock,
+                $this->creditmemoMock,
+                $items,
+                $notify,
+                $appendComment,
+                $this->creditmemoCommentCreationMock,
+                $this->creditmemoCreationArgumentsMock
+            )
+            ->willReturn($this->validationMessagesMock);
+        $hasMessages = true;
+        $this->validationMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
+        $this->validationMessagesMock->expects($this->once())
+            ->method('getMessages')->willReturn($errorMessages);
 
         $this->assertEquals(
             $errorMessages,
@@ -373,18 +371,21 @@ class RefundOrderTest extends \PHPUnit_Framework_TestCase
                 ($appendComment && $notify),
                 $this->creditmemoCreationArgumentsMock
             )->willReturn($this->creditmemoMock);
-        $this->itemCreationValidatorMock->expects($this->once())
+        $this->refundOrderValidatorMock->expects($this->once())
             ->method('validate')
-            ->with(reset($items), [CreationQuantityValidator::class], $this->orderMock)
-            ->willReturn([]);
-        $this->creditmemoValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->creditmemoMock)
-            ->willReturn([]);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
+            ->with(
+                $this->orderMock,
+                $this->creditmemoMock,
+                $items,
+                $notify,
+                $appendComment,
+                $this->creditmemoCommentCreationMock,
+                $this->creditmemoCreationArgumentsMock
+            )
+            ->willReturn($this->validationMessagesMock);
+        $hasMessages = false;
+        $this->validationMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
         $e = new \Exception();
         $this->paymentAdapterMock->expects($this->once())
             ->method('refund')
diff --git a/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php
index b719babf209f0ceb98c4d019f1e5929b23e7e11f..1daf7a64263b817654bf73ee2155506ea9a5f42d 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php
@@ -18,11 +18,11 @@ use Magento\Sales\Api\ShipmentRepositoryInterface;
 use Magento\Sales\Model\Order;
 use Magento\Sales\Model\Order\Config as OrderConfig;
 use Magento\Sales\Model\Order\OrderStateResolverInterface;
-use Magento\Sales\Model\Order\OrderValidatorInterface;
 use Magento\Sales\Model\Order\ShipmentDocumentFactory;
 use Magento\Sales\Model\Order\Shipment\NotifierInterface;
 use Magento\Sales\Model\Order\Shipment\OrderRegistrarInterface;
-use Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface;
+use Magento\Sales\Model\Order\Validation\ShipOrderInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
 use Magento\Sales\Model\ShipOrder;
 use Psr\Log\LoggerInterface;
 
@@ -49,14 +49,9 @@ class ShipOrderTest extends \PHPUnit_Framework_TestCase
     private $shipmentDocumentFactoryMock;
 
     /**
-     * @var ShipmentValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var ShipOrderInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    private $shipmentValidatorMock;
-
-    /**
-     * @var OrderValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $orderValidatorMock;
+    private $shipOrderValidatorMock;
 
     /**
      * @var OrderRegistrarInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -109,20 +104,25 @@ class ShipOrderTest extends \PHPUnit_Framework_TestCase
     private $shipmentMock;
 
     /**
-     * @var AdapterInterface
+     * @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $adapterMock;
 
     /**
-     * @var ShipmentTrackCreationInterface
+     * @var ShipmentTrackCreationInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $trackMock;
 
     /**
-     * @var ShipmentPackageInterface
+     * @var ShipmentPackageInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $packageMock;
 
+    /**
+     * @var ValidatorResultInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $validationMessagesMock;
+
     /**
      * @var LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
@@ -133,75 +133,58 @@ class ShipOrderTest extends \PHPUnit_Framework_TestCase
         $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class)
             ->disableOriginalConstructor()
             ->getMock();
-
         $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->shipmentDocumentFactoryMock = $this->getMockBuilder(ShipmentDocumentFactory::class)
             ->disableOriginalConstructor()
             ->getMock();
-
-        $this->shipmentValidatorMock = $this->getMockBuilder(ShipmentValidatorInterface::class)
-            ->disableOriginalConstructor()
-            ->getMockForAbstractClass();
-
-        $this->orderValidatorMock = $this->getMockBuilder(OrderValidatorInterface::class)
-            ->disableOriginalConstructor()
-            ->getMockForAbstractClass();
-
         $this->orderRegistrarMock = $this->getMockBuilder(OrderRegistrarInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->orderStateResolverMock = $this->getMockBuilder(OrderStateResolverInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->configMock = $this->getMockBuilder(OrderConfig::class)
             ->disableOriginalConstructor()
             ->getMock();
-
         $this->shipmentRepositoryMock = $this->getMockBuilder(ShipmentRepositoryInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->notifierInterfaceMock = $this->getMockBuilder(NotifierInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->loggerMock = $this->getMockBuilder(LoggerInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->shipmentCommentCreationMock = $this->getMockBuilder(ShipmentCommentCreationInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->shipmentCreationArgumentsMock = $this->getMockBuilder(ShipmentCreationArgumentsInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->orderMock = $this->getMockBuilder(OrderInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->shipmentMock = $this->getMockBuilder(ShipmentInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->packageMock = $this->getMockBuilder(ShipmentPackageInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->trackMock = $this->getMockBuilder(ShipmentTrackCreationInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
         $this->adapterMock = $this->getMockBuilder(AdapterInterface::class)
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-
+        $this->shipOrderValidatorMock = $this->getMockBuilder(ShipOrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->validationMessagesMock = $this->getMockBuilder(ValidatorResultInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['hasMessages', 'getMessages', 'addMessage'])
+            ->getMock();
         $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
 
         $this->model = $helper->getObject(
@@ -209,20 +192,25 @@ class ShipOrderTest extends \PHPUnit_Framework_TestCase
             [
                 'resourceConnection' => $this->resourceConnectionMock,
                 'orderRepository' => $this->orderRepositoryMock,
-                'shipmentRepository' => $this->shipmentRepositoryMock,
                 'shipmentDocumentFactory' => $this->shipmentDocumentFactoryMock,
-                'shipmentValidator' => $this->shipmentValidatorMock,
-                'orderValidator' => $this->orderValidatorMock,
                 'orderStateResolver' => $this->orderStateResolverMock,
-                'orderRegistrar' => $this->orderRegistrarMock,
-                'notifierInterface' => $this->notifierInterfaceMock,
                 'config' => $this->configMock,
-                'logger' => $this->loggerMock
+                'shipmentRepository' => $this->shipmentRepositoryMock,
+                'shipOrderValidator' => $this->shipOrderValidatorMock,
+                'notifierInterface' => $this->notifierInterfaceMock,
+                'logger' => $this->loggerMock,
+                'orderRegistrar' => $this->orderRegistrarMock
             ]
         );
     }
 
     /**
+     * @param int $orderId
+     * @param array $items
+     * @param bool $notify
+     * @param bool $appendComment
+     * @throws \Magento\Sales\Exception\CouldNotShipException
+     * @throws \Magento\Sales\Exception\DocumentValidationException
      * @dataProvider dataProvider
      */
     public function testExecute($orderId, $items, $notify, $appendComment)
@@ -231,11 +219,9 @@ class ShipOrderTest extends \PHPUnit_Framework_TestCase
             ->method('getConnection')
             ->with('sales')
             ->willReturn($this->adapterMock);
-
         $this->orderRepositoryMock->expects($this->once())
             ->method('get')
             ->willReturn($this->orderMock);
-
         $this->shipmentDocumentFactoryMock->expects($this->once())
             ->method('create')
             ->with(
@@ -247,65 +233,61 @@ class ShipOrderTest extends \PHPUnit_Framework_TestCase
                 [$this->packageMock],
                 $this->shipmentCreationArgumentsMock
             )->willReturn($this->shipmentMock);
-
-        $this->shipmentValidatorMock->expects($this->once())
+        $this->shipOrderValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->shipmentMock)
-            ->willReturn([]);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
-
+            ->with(
+                $this->orderMock,
+                $this->shipmentMock,
+                $items,
+                $notify,
+                $appendComment,
+                $this->shipmentCommentCreationMock,
+                [$this->trackMock],
+                [$this->packageMock]
+            )
+            ->willReturn($this->validationMessagesMock);
+        $hasMessages = false;
+        $this->validationMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
         $this->orderRegistrarMock->expects($this->once())
             ->method('register')
             ->with($this->orderMock, $this->shipmentMock)
             ->willReturn($this->orderMock);
-
         $this->orderStateResolverMock->expects($this->once())
             ->method('getStateForOrder')
             ->with($this->orderMock, [OrderStateResolverInterface::IN_PROGRESS])
             ->willReturn(Order::STATE_PROCESSING);
-
         $this->orderMock->expects($this->once())
             ->method('setState')
             ->with(Order::STATE_PROCESSING)
             ->willReturnSelf();
-
         $this->orderMock->expects($this->once())
             ->method('getState')
             ->willReturn(Order::STATE_PROCESSING);
-
         $this->configMock->expects($this->once())
             ->method('getStateDefaultStatus')
             ->with(Order::STATE_PROCESSING)
             ->willReturn('Processing');
-
         $this->orderMock->expects($this->once())
             ->method('setStatus')
             ->with('Processing')
             ->willReturnSelf();
-
         $this->shipmentRepositoryMock->expects($this->once())
             ->method('save')
             ->with($this->shipmentMock)
             ->willReturn($this->shipmentMock);
-
         $this->orderRepositoryMock->expects($this->once())
             ->method('save')
             ->with($this->orderMock)
             ->willReturn($this->orderMock);
-
         if ($notify) {
             $this->notifierInterfaceMock->expects($this->once())
                 ->method('notify')
                 ->with($this->orderMock, $this->shipmentMock, $this->shipmentCommentCreationMock);
         }
-
         $this->shipmentMock->expects($this->once())
             ->method('getEntityId')
             ->willReturn(2);
-
         $this->assertEquals(
             2,
             $this->model->execute(
@@ -348,14 +330,24 @@ class ShipOrderTest extends \PHPUnit_Framework_TestCase
                 $this->shipmentCreationArgumentsMock
             )->willReturn($this->shipmentMock);
 
-        $this->shipmentValidatorMock->expects($this->once())
+        $this->shipOrderValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->shipmentMock)
-            ->willReturn($errorMessages);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
+            ->with(
+                $this->orderMock,
+                $this->shipmentMock,
+                $items,
+                $notify,
+                $appendComment,
+                $this->shipmentCommentCreationMock,
+                [$this->trackMock],
+                [$this->packageMock]
+            )
+            ->willReturn($this->validationMessagesMock);
+        $hasMessages = true;
+        $this->validationMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
+        $this->validationMessagesMock->expects($this->once())
+            ->method('getMessages')->willReturn($errorMessages);
 
         $this->model->execute(
             $orderId,
@@ -372,9 +364,12 @@ class ShipOrderTest extends \PHPUnit_Framework_TestCase
     /**
      * @expectedException \Magento\Sales\Api\Exception\CouldNotShipExceptionInterface
      */
-    public function testCouldNotInvoiceException()
+    public function testCouldNotShipException()
     {
         $orderId = 1;
+        $items = [1 => 2];
+        $notify = true;
+        $appendComment = true;
         $this->resourceConnectionMock->expects($this->once())
             ->method('getConnection')
             ->with('sales')
@@ -387,33 +382,53 @@ class ShipOrderTest extends \PHPUnit_Framework_TestCase
         $this->shipmentDocumentFactoryMock->expects($this->once())
             ->method('create')
             ->with(
-                $this->orderMock
+                $this->orderMock,
+                $items,
+                [$this->trackMock],
+                $this->shipmentCommentCreationMock,
+                ($appendComment && $notify),
+                [$this->packageMock],
+                $this->shipmentCreationArgumentsMock
             )->willReturn($this->shipmentMock);
-
-        $this->shipmentValidatorMock->expects($this->once())
+        $this->shipOrderValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->shipmentMock)
-            ->willReturn([]);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('validate')
-            ->with($this->orderMock)
-            ->willReturn([]);
-        $e = new \Exception();
+            ->with(
+                $this->orderMock,
+                $this->shipmentMock,
+                $items,
+                $notify,
+                $appendComment,
+                $this->shipmentCommentCreationMock,
+                [$this->trackMock],
+                [$this->packageMock]
+            )
+            ->willReturn($this->validationMessagesMock);
+        $hasMessages = false;
+        $this->validationMessagesMock->expects($this->once())
+            ->method('hasMessages')->willReturn($hasMessages);
+        $exception = new \Exception();
 
         $this->orderRegistrarMock->expects($this->once())
             ->method('register')
             ->with($this->orderMock, $this->shipmentMock)
-            ->willThrowException($e);
+            ->willThrowException($exception);
 
         $this->loggerMock->expects($this->once())
             ->method('critical')
-            ->with($e);
+            ->with($exception);
 
         $this->adapterMock->expects($this->once())
             ->method('rollBack');
 
         $this->model->execute(
-            $orderId
+            $orderId,
+            $items,
+            $notify,
+            $appendComment,
+            $this->shipmentCommentCreationMock,
+            [$this->trackMock],
+            [$this->packageMock],
+            $this->shipmentCreationArgumentsMock
         );
     }
 
diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml
index 4b921587c292b54bdd49a40cb174a7de373917f5..4e2487d9dcada2eaf224f8cc30f65fc8fa4a4fc8 100644
--- a/app/code/Magento/Sales/etc/di.xml
+++ b/app/code/Magento/Sales/etc/di.xml
@@ -105,6 +105,11 @@
     <preference for="Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface" type="Magento\Sales\Model\Order\Shipment\ShipmentValidator"/>
     <preference for="Magento\Sales\Model\Order\Creditmemo\CreditmemoValidatorInterface" type="Magento\Sales\Model\Order\Creditmemo\CreditmemoValidator"/>
     <preference for="Magento\Sales\Model\Order\Creditmemo\ItemCreationValidatorInterface" type="Magento\Sales\Model\Order\Creditmemo\ItemCreationValidator"/>
+    <preference for="Magento\Sales\Model\ValidatorResultInterface" type="Magento\Sales\Model\ValidatorResult"/>
+    <preference for="Magento\Sales\Model\Order\Validation\InvoiceOrderInterface" type="Magento\Sales\Model\Order\Validation\InvoiceOrder"/>
+    <preference for="Magento\Sales\Model\Order\Validation\RefundInvoiceInterface" type="Magento\Sales\Model\Order\Validation\RefundInvoice"/>
+    <preference for="Magento\Sales\Model\Order\Validation\RefundOrderInterface" type="Magento\Sales\Model\Order\Validation\RefundOrder"/>
+    <preference for="Magento\Sales\Model\Order\Validation\ShipOrderInterface" type="Magento\Sales\Model\Order\Validation\ShipOrder"/>
     <preference for="Magento\Sales\Model\Order\Creditmemo\NotifierInterface" type="Magento\Sales\Model\Order\Creditmemo\Notifier"/>
     <preference for="Magento\Sales\Api\RefundOrderInterface" type="Magento\Sales\Model\RefundOrder"/>
     <preference for="Magento\Sales\Api\RefundInvoiceInterface" type="Magento\Sales\Model\RefundInvoice"/>
diff --git a/app/code/Magento/SalesInventory/LICENSE.txt b/app/code/Magento/SalesInventory/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..49525fd99da9c51e6d85420266d41cb3d6b7a648
--- /dev/null
+++ b/app/code/Magento/SalesInventory/LICENSE.txt
@@ -0,0 +1,48 @@
+
+Open Software License ("OSL") v. 3.0
+
+This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work:
+
+Licensed under the Open Software License version 3.0
+
+   1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following:
+
+         1. to reproduce the Original Work in copies, either alone or as part of a collective work;
+
+         2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work;
+
+         3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License;
+
+         4. to perform the Original Work publicly; and
+
+         5. to display the Original Work publicly. 
+
+   2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works.
+
+   3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work.
+
+   4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license.
+
+   5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c).
+
+   6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
+
+   7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer.
+
+   8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation.
+
+   9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c).
+
+  10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
+
+  11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License.
+
+  12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
+
+  13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
+
+  14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+  15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
+
+  16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process.
\ No newline at end of file
diff --git a/app/code/Magento/SalesInventory/LICENSE_AFL.txt b/app/code/Magento/SalesInventory/LICENSE_AFL.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f39d641b18a19e56df6c8a3e4038c940fb886b32
--- /dev/null
+++ b/app/code/Magento/SalesInventory/LICENSE_AFL.txt
@@ -0,0 +1,48 @@
+
+Academic Free License ("AFL") v. 3.0
+
+This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work:
+
+Licensed under the Academic Free License version 3.0
+
+   1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following:
+
+         1. to reproduce the Original Work in copies, either alone or as part of a collective work;
+
+         2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work;
+
+         3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License;
+
+         4. to perform the Original Work publicly; and
+
+         5. to display the Original Work publicly.
+
+   2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works.
+
+   3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work.
+
+   4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license.
+
+   5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c).
+
+   6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
+
+   7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer.
+
+   8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation.
+
+   9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c).
+
+  10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
+
+  11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License.
+
+  12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
+
+  13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
+
+  14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+  15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
+
+  16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process.
diff --git a/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php b/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php
new file mode 100644
index 0000000000000000000000000000000000000000..7752d7131031cf0daa63f4c8b8bf49609e3090ed
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Model/Order/ReturnProcessor.php
@@ -0,0 +1,156 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Model\Order;
+
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\CreditmemoItemInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+
+/**
+ * Class ReturnProcessor
+ */
+class ReturnProcessor
+{
+    /**
+     * @var \Magento\CatalogInventory\Api\StockManagementInterface
+     */
+    private $stockManagement;
+
+    /**
+     * @var \Magento\CatalogInventory\Model\Indexer\Stock\Processor
+     */
+    private $stockIndexerProcessor;
+
+    /**
+     * @var \Magento\Catalog\Model\Indexer\Product\Price\Processor
+     */
+    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
+     * @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;
+    }
+
+    /**
+     * @param CreditmemoInterface $creditmemo
+     * @param OrderInterface $order
+     * @param array $returnToStockItems
+     * @return void
+     */
+    public function execute(
+        CreditmemoInterface $creditmemo,
+        OrderInterface $order,
+        array $returnToStockItems = []
+    ) {
+        $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;
+                if (isset($itemsToUpdate[$productId])) {
+                    $itemsToUpdate[$productId] += $qty;
+                } else {
+                    $itemsToUpdate[$productId] = $qty;
+                }
+            }
+        }
+
+        if (!empty($itemsToUpdate)) {
+            $store = $this->storeManager->getStore($order->getStoreId());
+            foreach ($itemsToUpdate as $productId => $qty) {
+                $this->stockManagement->backItemQty(
+                    $productId,
+                    $qty,
+                    $store->getWebsiteId()
+                );
+            }
+
+            $updatedItemIds = array_keys($itemsToUpdate);
+            $this->stockIndexerProcessor->reindexList($updatedItemIds);
+            $this->priceIndexer->reindexList($updatedItemIds);
+        }
+    }
+
+    /**
+     * @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
+     * @param int[] $returnToStockItems
+     * @param int $parentItemId
+     * @return bool
+     */
+    private function canReturnItem(
+        \Magento\Sales\Api\Data\CreditmemoItemInterface $item,
+        $qty,
+        $parentItemId = null,
+        array $returnToStockItems = []
+    ) {
+        return (in_array($item->getOrderItemId(), $returnToStockItems) || in_array($parentItemId, $returnToStockItems))
+        && $qty;
+    }
+}
diff --git a/app/code/Magento/SalesInventory/Model/Order/ReturnValidator.php b/app/code/Magento/SalesInventory/Model/Order/ReturnValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..2195883334fcf6dfa21a55a49797f64a4ec0faa4
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Model/Order/ReturnValidator.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Model\Order;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\CreditmemoItemInterface;
+use Magento\Sales\Api\Data\OrderItemInterface;
+use Magento\Sales\Api\OrderItemRepositoryInterface;
+
+/**
+ * Class ReturnProcessor
+ */
+class ReturnValidator
+{
+    /**
+     * @var OrderItemRepositoryInterface
+     */
+    private $orderItemRepository;
+
+    /**
+     * ReturnValidator constructor.
+     * @param OrderItemRepositoryInterface $orderItemRepository
+     */
+    public function __construct(OrderItemRepositoryInterface $orderItemRepository)
+    {
+        $this->orderItemRepository = $orderItemRepository;
+    }
+
+    /**
+     * @param int[] $returnToStockItems
+     * @param CreditmemoInterface $creditmemo
+     * @return \Magento\Framework\Phrase|null
+     */
+    public function validate($returnToStockItems, CreditmemoInterface $creditmemo)
+    {
+        $creditmemoItems = $creditmemo->getItems();
+
+        /** @var int $item */
+        foreach ($returnToStockItems as $item) {
+            try {
+                $orderItem = $this->orderItemRepository->get($item);
+                if (!$this->isOrderItemPartOfCreditmemo($creditmemoItems, $orderItem)) {
+                    return __('The "%1" product is not part of the current creditmemo.', $orderItem->getSku());
+                }
+            } catch (NoSuchEntityException $e) {
+                return __('The return to stock argument contains product item that is not part of the original order.');
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @param CreditmemoItemInterface[] $creditmemoItems
+     * @param OrderItemInterface $orderItem
+     * @return bool
+     */
+    private function isOrderItemPartOfCreditmemo(array $creditmemoItems, OrderItemInterface $orderItem)
+    {
+        foreach ($creditmemoItems as $creditmemoItem) {
+            if ($creditmemoItem->getOrderItemId() == $orderItem->getItemId()) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/app/code/Magento/SalesInventory/Model/Plugin/Order/ReturnToStockInvoice.php b/app/code/Magento/SalesInventory/Model/Plugin/Order/ReturnToStockInvoice.php
new file mode 100644
index 0000000000000000000000000000000000000000..53a393d83353b4922f61641160dcf3c2aa8b6d85
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Model/Plugin/Order/ReturnToStockInvoice.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Model\Plugin\Order;
+
+/**
+ * Class ReturnToStockInvoice
+ */
+class ReturnToStockInvoice
+{
+    /**
+     * @var \Magento\SalesInventory\Model\Order\ReturnProcessor
+     */
+    private $returnProcessor;
+
+    /**
+     * @var \Magento\Sales\Api\CreditmemoRepositoryInterface
+     */
+    private $creditmemoRepository;
+
+    /**
+     * @var \Magento\Sales\Api\OrderRepositoryInterface
+     */
+    private $orderRepository;
+
+    /**
+     * @var \Magento\Sales\Api\InvoiceRepositoryInterface
+     */
+    private $invoiceRepository;
+
+    /**
+     * @var \Magento\CatalogInventory\Api\StockConfigurationInterface
+     */
+    private $stockConfiguration;
+
+    /**
+     * ReturnToStockInvoice constructor.
+     * @param \Magento\SalesInventory\Model\Order\ReturnProcessor $returnProcessor
+     * @param \Magento\Sales\Api\CreditmemoRepositoryInterface $creditmemoRepository
+     * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
+     * @param \Magento\Sales\Api\InvoiceRepositoryInterface $invoiceRepository
+     * @param \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration
+     */
+    public function __construct(
+        \Magento\SalesInventory\Model\Order\ReturnProcessor $returnProcessor,
+        \Magento\Sales\Api\CreditmemoRepositoryInterface $creditmemoRepository,
+        \Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
+        \Magento\Sales\Api\InvoiceRepositoryInterface $invoiceRepository,
+        \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration
+    ) {
+        $this->returnProcessor = $returnProcessor;
+        $this->creditmemoRepository = $creditmemoRepository;
+        $this->orderRepository = $orderRepository;
+        $this->invoiceRepository = $invoiceRepository;
+        $this->stockConfiguration = $stockConfiguration;
+    }
+
+    /**
+     * @param \Magento\Sales\Api\RefundInvoiceInterface $refundService
+     * @param int $resultEntityId
+     * @param int $invoiceId
+     * @param \Magento\Sales\Api\Data\CreditmemoItemCreationInterface[] $items
+     * @param bool|null $isOnline
+     * @param bool|null $notify
+     * @param bool|null $appendComment
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment
+     * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments
+     * @return int
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterExecute(
+        \Magento\Sales\Api\RefundInvoiceInterface $refundService,
+        $resultEntityId,
+        $invoiceId,
+        array $items = [],
+        $isOnline = false,
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        if ($this->stockConfiguration->isAutoReturnEnabled()) {
+            return $resultEntityId;
+        }
+
+        $invoice = $this->invoiceRepository->get($invoiceId);
+        $order = $this->orderRepository->get($invoice->getOrderId());
+
+        $returnToStockItems = [];
+        if ($arguments !== null
+            && $arguments->getExtensionAttributes() !== null
+            && $arguments->getExtensionAttributes()->getReturnToStockItems() !== null
+        ) {
+            $returnToStockItems = $arguments->getExtensionAttributes()->getReturnToStockItems();
+        }
+
+        $creditmemo = $this->creditmemoRepository->get($resultEntityId);
+        $this->returnProcessor->execute($creditmemo, $order, $returnToStockItems);
+
+        return $resultEntityId;
+    }
+}
diff --git a/app/code/Magento/SalesInventory/Model/Plugin/Order/ReturnToStockOrder.php b/app/code/Magento/SalesInventory/Model/Plugin/Order/ReturnToStockOrder.php
new file mode 100644
index 0000000000000000000000000000000000000000..b21f9f6b1050636738a67c88151ceb1780f3b820
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Model/Plugin/Order/ReturnToStockOrder.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Model\Plugin\Order;
+
+use Magento\CatalogInventory\Api\StockConfigurationInterface;
+use Magento\SalesInventory\Model\Order\ReturnProcessor;
+use Magento\Sales\Api\CreditmemoRepositoryInterface;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Api\RefundOrderInterface;
+
+/**
+ * Class ReturnToStock
+ */
+class ReturnToStockOrder
+{
+    /**
+     * @var ReturnProcessor
+     */
+    private $returnProcessor;
+
+    /**
+     * @var CreditmemoRepositoryInterface
+     */
+    private $creditmemoRepository;
+
+    /**
+     * @var OrderRepositoryInterface
+     */
+    private $orderRepository;
+
+    /**
+     * @var StockConfigurationInterface
+     */
+    private $stockConfiguration;
+
+    /**
+     * ReturnToStockPlugin constructor.
+     *
+     * @param ReturnProcessor $returnProcessor
+     * @param CreditmemoRepositoryInterface $creditmemoRepository
+     * @param OrderRepositoryInterface $orderRepository
+     * @param StockConfigurationInterface $stockConfiguration
+     */
+    public function __construct(
+        ReturnProcessor $returnProcessor,
+        CreditmemoRepositoryInterface $creditmemoRepository,
+        OrderRepositoryInterface $orderRepository,
+        StockConfigurationInterface $stockConfiguration
+    ) {
+        $this->returnProcessor = $returnProcessor;
+        $this->creditmemoRepository = $creditmemoRepository;
+        $this->orderRepository = $orderRepository;
+        $this->stockConfiguration = $stockConfiguration;
+    }
+
+    /**
+     * @param RefundOrderInterface $refundService
+     * @param int $resultEntityId
+     * @param int $orderId
+     * @param \Magento\Sales\Api\Data\CreditmemoItemCreationInterface[] $items
+     * @param bool|null $notify
+     * @param bool|null $appendComment
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment
+     * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments
+     * @return int
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterExecute(
+        RefundOrderInterface $refundService,
+        $resultEntityId,
+        $orderId,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        if ($this->stockConfiguration->isAutoReturnEnabled()) {
+            return $resultEntityId;
+        }
+
+        $order = $this->orderRepository->get($orderId);
+
+        $returnToStockItems = [];
+        if ($arguments !== null
+            && $arguments->getExtensionAttributes() !== null
+            && $arguments->getExtensionAttributes()->getReturnToStockItems() !== null
+        ) {
+            $returnToStockItems = $arguments->getExtensionAttributes()->getReturnToStockItems();
+        }
+
+        $creditmemo = $this->creditmemoRepository->get($resultEntityId);
+        $this->returnProcessor->execute($creditmemo, $order, $returnToStockItems);
+
+        return $resultEntityId;
+    }
+}
diff --git a/app/code/Magento/SalesInventory/Model/Plugin/Order/Validation/InvoiceRefundCreationArguments.php b/app/code/Magento/SalesInventory/Model/Plugin/Order/Validation/InvoiceRefundCreationArguments.php
new file mode 100644
index 0000000000000000000000000000000000000000..7dfa2893c588f713438ee630e8f7fcc7a670bb32
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Model/Plugin/Order/Validation/InvoiceRefundCreationArguments.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Model\Plugin\Order\Validation;
+
+use Magento\Sales\Api\Data\InvoiceInterface;
+use Magento\Sales\Model\Order\Validation\RefundInvoiceInterface;
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\SalesInventory\Model\Order\ReturnValidator;
+use Magento\Sales\Model\ValidatorResultInterface;
+
+/**
+ * Class CreditmemoCreationArguments
+ */
+class InvoiceRefundCreationArguments
+{
+    /**
+     * @var ReturnValidator
+     */
+    private $returnValidator;
+
+    /**
+     * InvoiceRefundCreationArguments constructor.
+     * @param ReturnValidator $returnValidator
+     */
+    public function __construct(
+        ReturnValidator $returnValidator
+    ) {
+        $this->returnValidator = $returnValidator;
+    }
+
+    /**
+     * @param RefundInvoiceInterface $refundInvoiceValidator
+     * @param ValidatorResultInterface $validationResults
+     * @param InvoiceInterface $invoice
+     * @param OrderInterface $order
+     * @param CreditmemoInterface $creditmemo
+     * @param array $items
+     * @param bool $isOnline
+     * @param bool $notify
+     * @param bool $appendComment
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment
+     * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments
+     * @return ValidatorResultInterface
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+     */
+    public function afterValidate(
+        RefundInvoiceInterface $refundInvoiceValidator,
+        ValidatorResultInterface $validationResults,
+        InvoiceInterface $invoice,
+        OrderInterface $order,
+        CreditmemoInterface $creditmemo,
+        array $items = [],
+        $isOnline = false,
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        if ($this->isReturnToStockItems($arguments)) {
+            return $validationResults;
+        }
+
+        /** @var int[] $returnToStockItems */
+        $returnToStockItems = $arguments->getExtensionAttributes()->getReturnToStockItems();
+        $validationMessage = $this->returnValidator->validate($returnToStockItems, $creditmemo);
+        if ($validationMessage) {
+            $validationResults->addMessage($validationMessage);
+        }
+
+        return $validationResults;
+    }
+
+    /**
+     * @param CreditmemoCreationArgumentsInterface|null $arguments
+     * @return bool
+     */
+    private function isReturnToStockItems($arguments)
+    {
+        return $arguments === null
+        || $arguments->getExtensionAttributes() === null
+        || $arguments->getExtensionAttributes()->getReturnToStockItems() === null;
+    }
+}
diff --git a/app/code/Magento/SalesInventory/Model/Plugin/Order/Validation/OrderRefundCreationArguments.php b/app/code/Magento/SalesInventory/Model/Plugin/Order/Validation/OrderRefundCreationArguments.php
new file mode 100644
index 0000000000000000000000000000000000000000..29411c7c5e8c6b072203267660f8eafef1306ab7
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Model/Plugin/Order/Validation/OrderRefundCreationArguments.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Model\Plugin\Order\Validation;
+
+use Magento\Sales\Api\Data\CreditmemoCommentCreationInterface;
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\Order\Validation\RefundOrderInterface;
+use Magento\SalesInventory\Model\Order\ReturnValidator;
+use Magento\Sales\Model\ValidatorResultInterface;
+
+/**
+ * Class OrderRefundCreationArguments
+ */
+class OrderRefundCreationArguments
+{
+    /**
+     * @var ReturnValidator
+     */
+    private $returnValidator;
+
+    /**
+     * OrderRefundCreationArguments constructor.
+     * @param ReturnValidator $returnValidator
+     */
+    public function __construct(
+        ReturnValidator $returnValidator
+    ) {
+        $this->returnValidator = $returnValidator;
+    }
+
+    /**
+     * @param RefundOrderInterface $refundOrderValidator
+     * @param ValidatorResultInterface $validationResults
+     * @param OrderInterface $order
+     * @param CreditmemoInterface $creditmemo
+     * @param array $items
+     * @param bool $notify
+     * @param bool $appendComment
+     * @param CreditmemoCommentCreationInterface|null $comment
+     * @param CreditmemoCreationArgumentsInterface|null $arguments
+     * @return ValidatorResultInterface
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterValidate(
+        RefundOrderInterface $refundOrderValidator,
+        ValidatorResultInterface $validationResults,
+        OrderInterface $order,
+        CreditmemoInterface $creditmemo,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        CreditmemoCommentCreationInterface $comment = null,
+        CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        if ($this->isReturnToStockItems($arguments)) {
+            return $validationResults;
+        }
+
+        $returnToStockItems = $arguments->getExtensionAttributes()->getReturnToStockItems();
+        $validationMessage = $this->returnValidator->validate($returnToStockItems, $creditmemo);
+        if ($validationMessage) {
+            $validationResults->addMessage($validationMessage);
+        }
+
+        return $validationResults;
+    }
+
+    /**
+     * @param CreditmemoCreationArgumentsInterface|null $arguments
+     * @return bool
+     */
+    private function isReturnToStockItems($arguments)
+    {
+        return $arguments === null
+        || $arguments->getExtensionAttributes() === null
+        || $arguments->getExtensionAttributes()->getReturnToStockItems() === null;
+    }
+}
diff --git a/app/code/Magento/SalesInventory/README.md b/app/code/Magento/SalesInventory/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..915569ddd3ce24a240f5938c4e38e5275e9ada2c
--- /dev/null
+++ b/app/code/Magento/SalesInventory/README.md
@@ -0,0 +1 @@
+Magento_SalesInventory module allows retrieve and update stock attributes related to Magento_Sales, such as status and quantity.
diff --git a/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php b/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..523759d54645a1e2db471db948fa116cf59cd32e
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnProcessorTest.php
@@ -0,0 +1,195 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+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;
+use Magento\Sales\Api\Data\OrderItemInterface;
+use Magento\Sales\Api\OrderItemRepositoryInterface;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Store\Api\Data\StoreInterface;
+use Magento\Store\Model\StoreManagerInterface;
+use Magento\SalesInventory\Model\Order\ReturnProcessor;
+
+/**
+ * Class ReturnProcessorTest
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class ReturnProcessorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|OrderInterface
+     */
+    private $orderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|CreditmemoInterface
+     */
+    private $creditmemoMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|StockManagementInterface
+     */
+    private $stockManagementMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\CatalogInventory\Model\Indexer\Stock\Processor
+     */
+    private $stockIndexerProcessorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\Indexer\Product\Price\Processor
+     */
+    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
+     */
+    private $orderItemRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|CreditmemoItemInterface
+     */
+    private $creditmemoItemMock;
+
+    /** @var  ReturnProcessor */
+    private $returnProcessor;
+
+    /** @var  \PHPUnit_Framework_MockObject_MockObject|OrderItemInterface */
+    private $orderItemMock;
+
+    /** @var  \PHPUnit_Framework_MockObject_MockObject|StoreInterface */
+    private $storeMock;
+
+    public function setUp()
+    {
+        $this->stockManagementMock = $this->getMockBuilder(StockManagementInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->stockIndexerProcessorMock = $this->getMockBuilder(
+            \Magento\CatalogInventory\Model\Indexer\Stock\Processor::class
+        )->disableOriginalConstructor()
+            ->getMock();
+        $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)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderItemRepositoryMock = $this->getMockBuilder(OrderItemRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoItemMock = $this->getMockBuilder(CreditmemoItemInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderItemMock = $this->getMockBuilder(OrderItemInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->storeMock = $this->getMockBuilder(StoreInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->returnProcessor = new ReturnProcessor(
+            $this->stockManagementMock,
+            $this->stockIndexerProcessorMock,
+            $this->priceIndexerMock,
+            $this->creditmemoRepositoryMock,
+            $this->storeManagerMock,
+            $this->orderRepositoryMock,
+            $this->orderItemRepositoryMock
+        );
+    }
+
+    public function testExecute()
+    {
+        $orderItemId = 99;
+        $productId = 50;
+        $returnToStockItems = [$orderItemId];
+        $qty = 1;
+        $storeId = 0;
+        $webSiteId = 10;
+
+        $this->creditmemoMock->expects($this->once())
+            ->method('getItems')
+            ->willReturn([$this->creditmemoItemMock]);
+
+        $this->creditmemoItemMock->expects($this->once())
+            ->method('getQty')
+            ->willReturn($qty);
+
+        $this->creditmemoItemMock->expects($this->exactly(2))
+            ->method('getOrderItemId')
+            ->willReturn($orderItemId);
+
+        $this->creditmemoItemMock->expects($this->once())
+            ->method('getProductId')
+            ->willReturn($productId);
+
+        $this->orderItemRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($orderItemId)
+            ->willReturn($this->orderItemMock);
+
+        $this->orderMock->expects($this->once())
+            ->method('getStoreId')
+            ->willReturn($storeId);
+
+        $this->storeManagerMock->expects($this->once())
+            ->method('getStore')
+            ->with($storeId)
+            ->willReturn($this->storeMock);
+
+        $this->storeMock->expects($this->once())
+            ->method('getWebsiteId')
+            ->willReturn($webSiteId);
+
+        $this->stockManagementMock->expects($this->once())
+            ->method('backItemQty')
+            ->with($productId, $qty, $webSiteId)
+            ->willReturn(true);
+
+        $this->stockIndexerProcessorMock->expects($this->once())
+            ->method('reindexList')
+            ->with([$productId]);
+
+        $this->priceIndexerMock->expects($this->once())
+            ->method('reindexList')
+            ->with([$productId]);
+
+        $this->returnProcessor->execute($this->creditmemoMock, $this->orderMock, $returnToStockItems);
+    }
+}
diff --git a/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnValidatorTest.php b/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..da9d3fd8aefd103965f2d577b303e7e1a522223b
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Test/Unit/Model/Order/ReturnValidatorTest.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Test\Unit\Model\Order;
+
+use Magento\SalesInventory\Model\Order\ReturnValidator;
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\CreditmemoItemInterface;
+use Magento\Sales\Api\Data\OrderItemInterface;
+use Magento\Sales\Api\OrderItemRepositoryInterface;
+
+/**
+ * Class ReturnValidatorTest
+ */
+class ReturnValidatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|OrderItemRepositoryInterface
+     */
+    private $orderItemRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|CreditmemoInterface
+     */
+    private $creditMemoMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|CreditmemoItemInterface
+     */
+    private $creditMemoItemMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|OrderItemInterface
+     */
+    private $orderItemMock;
+
+    /**
+     * @var ReturnValidator
+     */
+    private $returnValidator;
+
+    protected function setUp()
+    {
+        $this->orderItemRepositoryMock = $this->getMockBuilder(OrderItemRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->creditMemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->creditMemoItemMock = $this->getMockBuilder(CreditmemoItemInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderItemMock = $this->getMockBuilder(OrderItemInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->returnValidator = new ReturnValidator(
+            $this->orderItemRepositoryMock
+        );
+    }
+
+    /**
+     * @dataProvider dataProvider
+     */
+    public function testValidate(
+        $expectedResult,
+        $returnToStockItems,
+        $orderItemId,
+        $creditMemoItemId,
+        $productSku = null
+    ) {
+        $this->creditMemoMock->expects($this->once())
+            ->method('getItems')
+            ->willReturn([$this->creditMemoItemMock]);
+
+        $this->orderItemRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($returnToStockItems[0])
+            ->willReturn($this->orderItemMock);
+
+        $this->orderItemMock->expects($this->once())
+            ->method('getItemId')
+            ->willReturn($orderItemId);
+
+        $this->creditMemoItemMock->expects($this->once())
+            ->method('getOrderItemId')
+            ->willReturn($creditMemoItemId);
+
+        if ($productSku) {
+            $this->orderItemMock->expects($this->once())
+                ->method('getSku')
+                ->willReturn($productSku);
+        }
+
+        $this->assertEquals(
+            $this->returnValidator->validate($returnToStockItems, $this->creditMemoMock),
+            $expectedResult
+        );
+    }
+
+    public function testValidationWithWrongOrderItems()
+    {
+        $returnToStockItems = [1];
+        $this->creditMemoMock->expects($this->once())
+            ->method('getItems')
+            ->willReturn([$this->creditMemoItemMock]);
+        $this->orderItemRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($returnToStockItems[0])
+            ->willThrowException(new NoSuchEntityException);
+
+        $this->assertEquals(
+            $this->returnValidator->validate($returnToStockItems, $this->creditMemoMock),
+            __('The return to stock argument contains product item that is not part of the original order.')
+        );
+
+    }
+
+    public function dataProvider()
+    {
+        return [
+            'PostirivValidationTest' => [null, [1], 1, 1],
+            'WithWrongReturnToStockItems' => [
+                __('The "%1" product is not part of the current creditmemo.', 'sku1'), [2], 2, 1, 'sku1',
+            ],
+        ];
+    }
+}
diff --git a/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/ReturnToStockInvoiceTest.php b/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/ReturnToStockInvoiceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..35718a96bd509cc8b021c286ca44c042a8a1d67d
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/ReturnToStockInvoiceTest.php
@@ -0,0 +1,179 @@
+<?php
+/**
+ *
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Test\Unit\Model\Plugin\Order;
+
+/**
+ * Class ReturnToStockInvoiceTest
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class ReturnToStockInvoiceTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var  \Magento\SalesInventory\Model\Plugin\Order\ReturnToStockInvoice */
+    private $returnTOStock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\SalesInventory\Model\Order\ReturnProcessor
+     */
+    private $returnProcessorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Api\CreditmemoRepositoryInterface
+     */
+    private $creditmemoRepositoryMock;
+
+    /**
+     * @var  \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Api\InvoiceRepositoryInterface
+     */
+    private $invoiceRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Api\OrderRepositoryInterface
+     */
+    private $orderRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Api\RefundOrderInterface
+     */
+    private $refundInvoiceMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface
+     */
+    private $creditmemoCreationArgumentsMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Api\Data\OrderInterface
+     */
+    private $orderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Api\Data\CreditmemoInterface
+     */
+    private $creditmemoMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Api\Data\InvoiceInterface
+     */
+    private $invoiceMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface
+     */
+    private $extencionAttributesMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\CatalogInventory\Api\StockConfigurationInterface
+     */
+    private $stockConfigurationMock;
+
+    protected function setUp()
+    {
+        $this->returnProcessorMock = $this->getMockBuilder(\Magento\SalesInventory\Model\Order\ReturnProcessor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoRepositoryMock = $this->getMockBuilder(\Magento\Sales\Api\CreditmemoRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderRepositoryMock = $this->getMockBuilder(\Magento\Sales\Api\OrderRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->invoiceRepositoryMock = $this->getMockBuilder(\Magento\Sales\Api\InvoiceRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->refundInvoiceMock = $this->getMockBuilder(\Magento\Sales\Api\RefundInvoiceInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoCreationArgumentsMock = $this->getMockBuilder(
+            \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface::class
+        )->disableOriginalConstructor()
+            ->getMock();
+        $this->extencionAttributesMock = $this->getMockBuilder(
+            \Magento\Sales\Api\Data\CreditmemoCreationArgumentsExtensionInterface::class
+        )->disableOriginalConstructor()
+            ->setMethods(['getReturnToStockItems'])
+            ->getMock();
+        $this->orderMock = $this->getMockBuilder(\Magento\Sales\Api\Data\OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoMock = $this->getMockBuilder(\Magento\Sales\Api\Data\CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->invoiceMock = $this->getMockBuilder(\Magento\Sales\Api\Data\InvoiceInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->stockConfigurationMock = $this->getMockBuilder(
+            \Magento\CatalogInventory\Api\StockConfigurationInterface::class
+        )->disableOriginalConstructor()
+            ->getMock();
+
+        $this->returnTOStock = new \Magento\SalesInventory\Model\Plugin\Order\ReturnToStockInvoice(
+            $this->returnProcessorMock,
+            $this->creditmemoRepositoryMock,
+            $this->orderRepositoryMock,
+            $this->invoiceRepositoryMock,
+            $this->stockConfigurationMock
+        );
+    }
+
+    public function testAfterExecute()
+    {
+        $orderId = 1;
+        $creditmemoId = 99;
+        $items = [];
+        $returnToStockItems = [1];
+        $invoiceId = 98;
+        $this->creditmemoCreationArgumentsMock->expects($this->exactly(3))
+            ->method('getExtensionAttributes')
+            ->willReturn($this->extencionAttributesMock);
+
+        $this->invoiceRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($invoiceId)
+            ->willReturn($this->invoiceMock);
+
+        $this->extencionAttributesMock->expects($this->exactly(2))
+            ->method('getReturnToStockItems')
+            ->willReturn($returnToStockItems);
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($orderId)
+            ->willReturn($this->orderMock);
+
+        $this->creditmemoRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($creditmemoId)
+            ->willReturn($this->creditmemoMock);
+
+        $this->returnProcessorMock->expects($this->once())
+            ->method('execute')
+            ->with($this->creditmemoMock, $this->orderMock, $returnToStockItems);
+
+        $this->invoiceMock->expects($this->once())
+            ->method('getOrderId')
+            ->willReturn($orderId);
+
+        $this->stockConfigurationMock->expects($this->once())
+            ->method('isAutoReturnEnabled')
+            ->willReturn(false);
+
+        $this->assertEquals(
+            $this->returnTOStock->afterExecute(
+                $this->refundInvoiceMock,
+                $creditmemoId,
+                $invoiceId,
+                $items,
+                false,
+                false,
+                false,
+                null,
+                $this->creditmemoCreationArgumentsMock
+            ),
+            $creditmemoId
+        );
+    }
+}
diff --git a/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/ReturnToStockOrderTest.php b/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/ReturnToStockOrderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b4883dd1a7708a844e9c200162060fcac7cbf87a
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/ReturnToStockOrderTest.php
@@ -0,0 +1,158 @@
+<?php
+/**
+ *
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Test\Unit\Model\Plugin\Order;
+
+use Magento\CatalogInventory\Api\StockConfigurationInterface;
+use Magento\SalesInventory\Model\Order\ReturnProcessor;
+use Magento\SalesInventory\Model\Plugin\Order\ReturnToStockOrder;
+use Magento\Sales\Api\CreditmemoRepositoryInterface;
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface;
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsExtensionInterface;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Api\RefundOrderInterface;
+
+/**
+ * Class ReturnToStockOrderTest
+ */
+class ReturnToStockOrderTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var  ReturnToStockOrder */
+    private $returnTOStock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|ReturnProcessor
+     */
+    private $returnProcessorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|CreditmemoRepositoryInterface
+     */
+    private $creditmemoRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|OrderRepositoryInterface
+     */
+    private $orderRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|RefundOrderInterface
+     */
+    private $refundOrderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|CreditmemoCreationArgumentsInterface
+     */
+    private $creditmemoCreationArgumentsMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|OrderInterface
+     */
+    private $orderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|CreditmemoInterface
+     */
+    private $creditmemoMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|StockConfigurationInterface
+     */
+    private $stockConfigurationMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|CreditmemoCreationArgumentsInterface
+     */
+    private $extencionAttributesMock;
+
+    protected function setUp()
+    {
+        $this->returnProcessorMock = $this->getMockBuilder(ReturnProcessor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoRepositoryMock = $this->getMockBuilder(CreditmemoRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->refundOrderMock = $this->getMockBuilder(RefundOrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoCreationArgumentsMock = $this->getMockBuilder(CreditmemoCreationArgumentsInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->extencionAttributesMock = $this->getMockBuilder(CreditmemoCreationArgumentsExtensionInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getReturnToStockItems'])
+            ->getMock();
+        $this->orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->stockConfigurationMock = $this->getMockBuilder(StockConfigurationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->returnTOStock = new ReturnToStockOrder(
+            $this->returnProcessorMock,
+            $this->creditmemoRepositoryMock,
+            $this->orderRepositoryMock,
+            $this->stockConfigurationMock
+        );
+    }
+
+    public function testAfterExecute()
+    {
+        $orderId = 1;
+        $creditmemoId = 99;
+        $items = [];
+        $returnToStockItems = [1];
+        $this->creditmemoCreationArgumentsMock->expects($this->exactly(3))
+            ->method('getExtensionAttributes')
+            ->willReturn($this->extencionAttributesMock);
+
+        $this->extencionAttributesMock->expects($this->exactly(2))
+            ->method('getReturnToStockItems')
+            ->willReturn($returnToStockItems);
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($orderId)
+            ->willReturn($this->orderMock);
+
+        $this->creditmemoRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($creditmemoId)
+            ->willReturn($this->creditmemoMock);
+
+        $this->returnProcessorMock->expects($this->once())
+            ->method('execute')
+            ->with($this->creditmemoMock, $this->orderMock, $returnToStockItems);
+
+        $this->stockConfigurationMock->expects($this->once())
+            ->method('isAutoReturnEnabled')
+            ->willReturn(false);
+
+        $this->assertEquals(
+            $this->returnTOStock->afterExecute(
+                $this->refundOrderMock,
+                $creditmemoId,
+                $orderId,
+                $items,
+                false,
+                false,
+                null,
+                $this->creditmemoCreationArgumentsMock
+            ),
+            $creditmemoId
+        );
+    }
+}
diff --git a/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/Validation/InvoiceRefundCreationArgumentsTest.php b/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/Validation/InvoiceRefundCreationArgumentsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d59da679d15e21331efcba024f05e0c5b0e05d4a
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/Validation/InvoiceRefundCreationArgumentsTest.php
@@ -0,0 +1,150 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Test\Unit\Model\Plugin\Order\Validation;
+
+use Magento\SalesInventory\Model\Order\ReturnValidator;
+use Magento\SalesInventory\Model\Plugin\Order\Validation\InvoiceRefundCreationArguments;
+use Magento\Sales\Model\ValidatorResultInterface;
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface;
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsExtensionInterface;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\InvoiceInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\Order\Validation\RefundInvoiceInterface;
+
+/**
+ * Class InvoiceRefundCreatetionArgumentsTest
+ */
+class InvoiceRefundCreationArgumentsTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var InvoiceRefundCreationArguments
+     */
+    private $plugin;
+
+    /**
+     * @var ReturnValidator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $returnValidatorMock;
+
+    /**
+     * @var CreditmemoCreationArgumentsExtensionInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $extencionAttributesMock;
+
+    /**
+     * @var CreditmemoCreationArgumentsInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoCreationArgumentsMock;
+
+    /**
+     * @var RefundInvoiceInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $refundInvoiceValidatorMock;
+
+    /**
+     * @var InvoiceInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $invoiceMock;
+
+    /**
+     * @var ValidatorResultInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $validateResultMock;
+
+    /**
+     * @var OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var CreditmemoInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoMock;
+
+    protected function setUp()
+    {
+        $this->returnValidatorMock = $this->getMockBuilder(ReturnValidator::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->creditmemoCreationArgumentsMock = $this->getMockBuilder(CreditmemoCreationArgumentsInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->extencionAttributesMock = $this->getMockBuilder(CreditmemoCreationArgumentsExtensionInterface::class)
+            ->setMethods(['getReturnToStockItems'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->validateResultMock = $this->getMockBuilder(ValidatorResultInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->refundInvoiceValidatorMock = $this->getMockBuilder(RefundInvoiceInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->invoiceMock = $this->getMockBuilder(InvoiceInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->plugin = new InvoiceRefundCreationArguments($this->returnValidatorMock);
+    }
+
+    /**
+     * @dataProvider dataProvider
+     */
+    public function testAfterValidation($erroMessage)
+    {
+        $returnToStockItems = [1];
+        $this->creditmemoCreationArgumentsMock->expects($this->exactly(3))
+            ->method('getExtensionAttributes')
+            ->willReturn($this->extencionAttributesMock);
+
+        $this->extencionAttributesMock->expects($this->exactly(2))
+            ->method('getReturnToStockItems')
+            ->willReturn($returnToStockItems);
+
+        $this->returnValidatorMock->expects($this->once())
+            ->method('validate')
+            ->willReturn($erroMessage);
+
+        $this->validateResultMock->expects($erroMessage ? $this->once() : $this->never())
+            ->method('addMessage')
+            ->with($erroMessage);
+
+        $this->plugin->afterValidate(
+            $this->refundInvoiceValidatorMock,
+            $this->validateResultMock,
+            $this->invoiceMock,
+            $this->orderMock,
+            $this->creditmemoMock,
+            [],
+            false,
+            false,
+            false,
+            null,
+            $this->creditmemoCreationArgumentsMock
+        );
+    }
+
+    public function dataProvider()
+    {
+        return [
+            'withErrors' => ['Error!'],
+            'withoutErrors' => ['null'],
+        ];
+    }
+}
diff --git a/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/Validation/OrderRefundCreationArgumentsTest.php b/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/Validation/OrderRefundCreationArgumentsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6a6b88f3d4580df6cde0479297968e12291e8d5d
--- /dev/null
+++ b/app/code/Magento/SalesInventory/Test/Unit/Model/Plugin/Order/Validation/OrderRefundCreationArgumentsTest.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Test\Unit\Model\Plugin\Order\Validation;
+
+use Magento\SalesInventory\Model\Order\ReturnValidator;
+use Magento\SalesInventory\Model\Plugin\Order\Validation\OrderRefundCreationArguments;
+use Magento\Sales\Model\Order\Validation\RefundOrderInterface;
+use Magento\Sales\Model\ValidatorResultInterface;
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface;
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsExtensionInterface;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+
+/**
+ * Class OrderRefundCreatetionArgumentsTest
+ */
+class OrderRefundCreationArgumentsTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var OrderRefundCreationArguments
+     */
+    private $plugin;
+
+    /**
+     * @var ReturnValidator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $returnValidatorMock;
+
+    /**
+     * @var CreditmemoCreationArgumentsExtensionInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $extencionAttributesMock;
+
+    /**
+     * @var CreditmemoCreationArgumentsInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoCreationArgumentsMock;
+
+    /**
+     * @var RefundOrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $refundOrderValidatorMock;
+
+    /**
+     * @var ValidatorResultInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $validateResultMock;
+
+    /**
+     * @var OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var CreditmemoInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoMock;
+
+    protected function setUp()
+    {
+        $this->returnValidatorMock = $this->getMockBuilder(ReturnValidator::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->creditmemoCreationArgumentsMock = $this->getMockBuilder(CreditmemoCreationArgumentsInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->extencionAttributesMock = $this->getMockBuilder(CreditmemoCreationArgumentsExtensionInterface::class)
+            ->setMethods(['getReturnToStockItems'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->validateResultMock = $this->getMockBuilder(ValidatorResultInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->refundOrderValidatorMock = $this->getMockBuilder(RefundOrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->plugin = new OrderRefundCreationArguments($this->returnValidatorMock);
+    }
+
+    /**
+     * @dataProvider dataProvider
+     */
+    public function testAfterValidation($erroMessage)
+    {
+        $returnToStockItems = [1];
+        $this->creditmemoCreationArgumentsMock->expects($this->exactly(3))
+            ->method('getExtensionAttributes')
+            ->willReturn($this->extencionAttributesMock);
+
+        $this->extencionAttributesMock->expects($this->exactly(2))
+            ->method('getReturnToStockItems')
+            ->willReturn($returnToStockItems);
+
+        $this->returnValidatorMock->expects($this->once())
+            ->method('validate')
+            ->willReturn($erroMessage);
+
+        $this->validateResultMock->expects($erroMessage ? $this->once() : $this->never())
+            ->method('addMessage')
+            ->with($erroMessage);
+
+        $this->plugin->afterValidate(
+            $this->refundOrderValidatorMock,
+            $this->validateResultMock,
+            $this->orderMock,
+            $this->creditmemoMock,
+            [],
+            false,
+            false,
+            null,
+            $this->creditmemoCreationArgumentsMock
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function dataProvider()
+    {
+        return [
+            'withErrors' => ['Error!'],
+            'withoutErrors' => ['null'],
+        ];
+    }
+}
diff --git a/app/code/Magento/SalesInventory/composer.json b/app/code/Magento/SalesInventory/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..ff72ce7f0022690682b356235c506512e65497b9
--- /dev/null
+++ b/app/code/Magento/SalesInventory/composer.json
@@ -0,0 +1,26 @@
+{
+    "name": "magento/module-sales-inventory",
+    "description": "N/A",
+    "require": {
+        "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
+        "magento/module-catalog-inventory": "100.2.*",
+        "magento/module-sales": "100.2.*",
+        "magento/module-store": "100.2.*",
+        "magento/module-catalog": "101.2.*",
+        "magento/framework": "100.2.*"
+    },
+    "type": "magento2-module",
+    "version": "100.0.0-dev",
+    "license": [
+        "OSL-3.0",
+        "AFL-3.0"
+    ],
+    "autoload": {
+        "files": [
+            "registration.php"
+        ],
+        "psr-4": {
+            "Magento\\SalesInventory\\": ""
+        }
+    }
+}
diff --git a/app/code/Magento/SalesInventory/etc/di.xml b/app/code/Magento/SalesInventory/etc/di.xml
new file mode 100644
index 0000000000000000000000000000000000000000..aec39d3c51c29d398e7c52f45bf5cf1443d3bffa
--- /dev/null
+++ b/app/code/Magento/SalesInventory/etc/di.xml
@@ -0,0 +1,21 @@
+<?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:ObjectManager/etc/config.xsd">
+    <type name="Magento\Sales\Model\RefundOrder">
+        <plugin name="refundOrderAfter" type="Magento\SalesInventory\Model\Plugin\Order\ReturnToStockOrder"/>
+    </type>
+    <type name="Magento\Sales\Model\RefundInvoice">
+        <plugin name="refundInvoiceAfter" type="Magento\SalesInventory\Model\Plugin\Order\ReturnToStockInvoice"/>
+    </type>
+    <type name="Magento\Sales\Model\Order\Validation\RefundOrderInterface">
+        <plugin name="refundOrderValidationAfter" type="Magento\SalesInventory\Model\Plugin\Order\Validation\OrderRefundCreationArguments"/>
+    </type>
+    <type name="Magento\Sales\Model\Order\Validation\RefundInvoiceInterface">
+        <plugin name="refundInvoiceValidationAfter" type="Magento\SalesInventory\Model\Plugin\Order\Validation\InvoiceRefundCreationArguments"/>
+    </type>
+</config>
diff --git a/app/code/Magento/SalesInventory/etc/extension_attributes.xml b/app/code/Magento/SalesInventory/etc/extension_attributes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..de5b6d41c52621f6ba1b2bf432b912157431bc30
--- /dev/null
+++ b/app/code/Magento/SalesInventory/etc/extension_attributes.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:Api/etc/extension_attributes.xsd">
+    <extension_attributes for="Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface">
+        <attribute code="return_to_stock_items" type="int[]"/>
+    </extension_attributes>
+</config>
\ No newline at end of file
diff --git a/app/code/Magento/SalesInventory/etc/module.xml b/app/code/Magento/SalesInventory/etc/module.xml
new file mode 100644
index 0000000000000000000000000000000000000000..06c9d0d78554afed0c4ab3e2d81bdeaea03c4df9
--- /dev/null
+++ b/app/code/Magento/SalesInventory/etc/module.xml
@@ -0,0 +1,17 @@
+<?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:Module/etc/module.xsd">
+    <module name="Magento_SalesInventory" setup_version="1.0.0">
+        <sequence>
+            <module name="Magento_Sales"/>
+            <module name="Magento_Catalog"/>
+            <module name="Magento_Store"/>
+            <module name="Magento_CatalogInventory"/>
+        </sequence>
+    </module>
+</config>
diff --git a/app/code/Magento/SalesInventory/registration.php b/app/code/Magento/SalesInventory/registration.php
new file mode 100644
index 0000000000000000000000000000000000000000..edb96135508d2c61e5078ca771409a37a2c1bf30
--- /dev/null
+++ b/app/code/Magento/SalesInventory/registration.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+\Magento\Framework\Component\ComponentRegistrar::register(
+    \Magento\Framework\Component\ComponentRegistrar::MODULE,
+    'Magento_SalesInventory',
+    __DIR__
+);
diff --git a/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save.php b/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save.php
index d265159bc630be220bc4a7a64b706e36786510ef..1c59c4033d377996da9d7b36dc5c9b0b6ba02fe8 100644
--- a/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save.php
+++ b/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save.php
@@ -107,6 +107,8 @@ class Save extends \Magento\Backend\App\Action
             $this->_objectManager->get(\Magento\Backend\Model\Session::class)->setCommentText($data['comment_text']);
         }
 
+        $isNeedCreateLabel = isset($data['create_shipping_label']) && $data['create_shipping_label'];
+
         try {
             $this->shipmentLoader->setOrderId($this->getRequest()->getParam('order_id'));
             $this->shipmentLoader->setShipmentId($this->getRequest()->getParam('shipment_id'));
@@ -128,10 +130,12 @@ class Save extends \Magento\Backend\App\Action
                 $shipment->setCustomerNote($data['comment_text']);
                 $shipment->setCustomerNoteNotify(isset($data['comment_customer_notify']));
             }
-            $errorMessages = $this->getShipmentValidator()->validate($shipment, [QuantityValidator::class]);
-            if (!empty($errorMessages)) {
+            $validationResult = $this->getShipmentValidator()
+                ->validate($shipment, [QuantityValidator::class]);
+
+            if ($validationResult->hasMessages()) {
                 $this->messageManager->addError(
-                    __("Shipment Document Validation Error(s):\n" . implode("\n", $errorMessages))
+                    __("Shipment Document Validation Error(s):\n" . implode("\n", $validationResult->getMessages()))
                 );
                 $this->_redirect('*/*/new', ['order_id' => $this->getRequest()->getParam('order_id')]);
                 return;
@@ -140,7 +144,6 @@ class Save extends \Magento\Backend\App\Action
 
             $shipment->getOrder()->setCustomerNoteNotify(!empty($data['send_email']));
             $responseAjax = new \Magento\Framework\DataObject();
-            $isNeedCreateLabel = isset($data['create_shipping_label']) && $data['create_shipping_label'];
 
             if ($isNeedCreateLabel) {
                 $this->labelGenerator->create($shipment, $this->_request);
diff --git a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/SaveTest.php b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/SaveTest.php
index f8d9c06dc8ec05c07c699c4b22e7b830c796e4dc..b1d2fc0d1d74456593b4cb4e3248e965b2033958 100644
--- a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/SaveTest.php
+++ b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/SaveTest.php
@@ -9,6 +9,7 @@
 namespace Magento\Shipping\Test\Unit\Controller\Adminhtml\Order\Shipment;
 
 use Magento\Backend\App\Action;
+use Magento\Sales\Model\ValidatorResultInterface;
 use Magento\Sales\Model\Order\Email\Sender\ShipmentSender;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
 use Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface;
@@ -18,6 +19,7 @@ use Magento\Sales\Model\Order\Shipment\Validation\QuantityValidator;
  * Class SaveTest
  *
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.TooManyFields)
  */
 class SaveTest extends \PHPUnit_Framework_TestCase
 {
@@ -96,6 +98,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
      */
     private $shipmentValidatorMock;
 
+    /**
+     * @var ValidatorResultInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $validationResult;
+
     /**
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
@@ -107,6 +114,9 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->setMethods([])
             ->getMock();
+        $this->validationResult = $this->getMockBuilder(ValidatorResultInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
         $this->labelGenerator = $this->getMockBuilder(\Magento\Shipping\Model\Shipping\LabelGenerator::class)
             ->disableOriginalConstructor()
             ->setMethods([])
@@ -362,7 +372,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             $this->shipmentValidatorMock->expects($this->once())
                 ->method('validate')
                 ->with($shipment, [QuantityValidator::class])
-                ->willReturn([]);
+                ->willReturn($this->validationResult);
+
+            $this->validationResult->expects($this->once())
+                ->method('hasMessages')
+                ->willReturn(false);
 
             $this->saveAction->execute();
             $this->assertEquals($this->response, $this->saveAction->getResponse());
diff --git a/app/etc/di.xml b/app/etc/di.xml
index 28f0d024c3ae234583e19b31800c10c950a5b42d..643390068a5e3e857ccb0e0d2d07fb5e26b8ea81 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -1205,7 +1205,6 @@
         <arguments>
             <argument name="mappers" xsi:type="array">
                 <item name="mapper" xsi:type="object">Magento\Framework\EntityManager\Mapper</item>
-                <item name="customAttributesMapper" xsi:type="object">Magento\Framework\EntityManager\CustomAttributesMapper</item>
             </argument>
         </arguments>
     </type>
diff --git a/composer.json b/composer.json
index 63d02e7c0a8b47dcadcd7444faa17a2d0435950c..fed4465140724cef3c24cd7facdd2ec5ceeba5b6 100644
--- a/composer.json
+++ b/composer.json
@@ -151,6 +151,7 @@
         "magento/module-rss": "100.2.0-dev",
         "magento/module-rule": "100.2.0-dev",
         "magento/module-sales": "100.2.0-dev",
+        "magento/module-sales-inventory": "100.0.0-dev",
         "magento/module-sales-rule": "100.2.0-dev",
         "magento/module-sales-sequence": "100.2.0-dev",
         "magento/module-sample-data": "100.2.0-dev",
diff --git a/composer.lock b/composer.lock
index 54a2b572c024bda51e7c7c2458fab8c45e2acb37..7feb568d766d012e009c59a50226f3ea8bd7b74a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,8 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "0cd85c424e865c554b2f8db093192cfd",
-    "content-hash": "d74ec028da2018e1a161a2e1b70d3f87",
+    "hash": "c23e80be1cc71ab108ce5ac19b3fe509",
+    "content-hash": "5b9734c1bdbda68cf20507525cafa0f2",
     "packages": [
         {
             "name": "braintree/braintree_php",
@@ -342,16 +342,16 @@
         },
         {
             "name": "composer/spdx-licenses",
-            "version": "1.1.4",
+            "version": "1.1.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/composer/spdx-licenses.git",
-                "reference": "88c26372b1afac36d8db601cdf04ad8716f53d88"
+                "reference": "96c6a07b05b716e89a44529d060bc7f5c263cb13"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/88c26372b1afac36d8db601cdf04ad8716f53d88",
-                "reference": "88c26372b1afac36d8db601cdf04ad8716f53d88",
+                "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/96c6a07b05b716e89a44529d060bc7f5c263cb13",
+                "reference": "96c6a07b05b716e89a44529d060bc7f5c263cb13",
                 "shasum": ""
             },
             "require": {
@@ -399,7 +399,7 @@
                 "spdx",
                 "validator"
             ],
-            "time": "2016-05-04 12:27:30"
+            "time": "2016-09-28 07:17:45"
         },
         {
             "name": "justinrainbow/json-schema",
@@ -3242,16 +3242,16 @@
         },
         {
             "name": "friendsofphp/php-cs-fixer",
-            "version": "v1.12.1",
+            "version": "v1.12.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
-                "reference": "d33ee60f3d3e6152888b7f3a385f49e5c43bf1bf"
+                "reference": "baa7112bef3b86c65fcfaae9a7a50436e3902b41"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/d33ee60f3d3e6152888b7f3a385f49e5c43bf1bf",
-                "reference": "d33ee60f3d3e6152888b7f3a385f49e5c43bf1bf",
+                "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/baa7112bef3b86c65fcfaae9a7a50436e3902b41",
+                "reference": "baa7112bef3b86c65fcfaae9a7a50436e3902b41",
                 "shasum": ""
             },
             "require": {
@@ -3296,7 +3296,7 @@
                 }
             ],
             "description": "A tool to automatically fix PHP code style",
-            "time": "2016-09-07 06:48:24"
+            "time": "2016-09-27 07:57:59"
         },
         {
             "name": "lusitanian/oauth",
diff --git a/dev/tests/api-functional/testsuite/Magento/SalesInventory/Api/Service/V1/ReturnItemsAfterRefundOrderTest.php b/dev/tests/api-functional/testsuite/Magento/SalesInventory/Api/Service/V1/ReturnItemsAfterRefundOrderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..68ecebec27c0b0812d76eb7be8c2ac063aff54ef
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/SalesInventory/Api/Service/V1/ReturnItemsAfterRefundOrderTest.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\SalesInventory\Api\Service\V1;
+
+/**
+ * API test for return items to stock
+ */
+class ReturnItemsAfterRefundOrderTest extends \Magento\TestFramework\TestCase\WebapiAbstract
+{
+    const SERVICE_REFUND_ORDER_NAME = 'salesRefundOrderV1';
+    const SERVICE_STOCK_ITEMS_NAME = 'stockItems';
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManager;
+
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+    }
+
+    /**
+     * @dataProvider dataProvider
+     * @magentoApiDataFixture Magento/Sales/_files/order_with_shipping_and_invoice.php
+     */
+    public function testRefundWithReturnItemsToStock($qtyRefund)
+    {
+        $productSku = 'simple';
+        /** @var \Magento\Sales\Model\Order $existingOrder */
+        $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+            ->loadByIncrementId('100000001');
+        $orderItems = $existingOrder->getItems();
+        $orderItem = array_shift($orderItems);
+        $expectedItems = [['order_item_id' => $orderItem->getItemId(), 'qty' => $qtyRefund]];
+        $qtyBeforeRefund = $this->getQtyInStockBySku($productSku);
+
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => '/V1/order/' . $existingOrder->getEntityId() . '/refund',
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_REFUND_ORDER_NAME,
+                'serviceVersion' => 'V1',
+                'operation' => self::SERVICE_REFUND_ORDER_NAME . 'execute',
+            ]
+        ];
+
+        $this->_webApiCall(
+            $serviceInfo,
+            [
+                'orderId' => $existingOrder->getEntityId(),
+                'items' => $expectedItems,
+                'arguments' => [
+                    'extension_attributes' => [
+                        'return_to_stock_items' => [
+                            (int)$orderItem->getItemId()
+                        ],
+                    ],
+                ],
+            ]
+        );
+
+        $qtyAfterRefund = $this->getQtyInStockBySku($productSku);
+
+        try {
+            $this->assertEquals(
+                $qtyBeforeRefund + $expectedItems[0]['qty'],
+                $qtyAfterRefund,
+                'Failed asserting qty of returned items incorrect.'
+            );
+
+        } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+            $this->fail('Failed asserting that Creditmemo was created');
+        }
+    }
+
+    /**
+     * @return array
+     */
+    public function dataProvider()
+    {
+        return [
+            'refundAllOrderItems' => [2],
+            'refundPartition' => [1],
+        ];
+    }
+
+    /**
+     * @param string $sku
+     * @return int
+     */
+    private function getQtyInStockBySku($sku)
+    {
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => '/V1/' . self::SERVICE_STOCK_ITEMS_NAME . "/$sku",
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
+            ],
+            'soap' => [
+                'service' => 'catalogInventoryStockRegistryV1',
+                'serviceVersion' => 'V1',
+                'operation' => 'catalogInventoryStockRegistryV1GetStockItemBySku',
+            ],
+        ];
+        $arguments = ['productSku' => $sku];
+        $apiResult = $this->_webApiCall($serviceInfo, $arguments);
+        return $apiResult['qty'];
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php
index 65e578c1181db4cc44d463d62bf210d4a26a55ee..525b3161ffcd921b6b0b9ea048b1f8e077c094f8 100644
--- a/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php
+++ b/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Cms\Model;
 
+use Magento\Cms\Api\PageRepositoryInterface;
+
 /**
  * @magentoAppArea adminhtml
  */
@@ -44,6 +46,22 @@ class PageTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($expectedIdentifier, $page->getIdentifier());
     }
 
+    /**
+     * @magentoDbIsolation enabled
+     */
+    public function testUpdateTime()
+    {
+        $updateTime = '2016-09-01 00:00:00';
+        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+        /** @var \Magento\Cms\Model\Page $page */
+        $page = $objectManager->create(\Magento\Cms\Model\Page::class);
+        $page->setData(['title' => 'Test', 'stores' => [1]]);
+        $page->setUpdateTime($updateTime);
+        $page->save();
+        $page = $objectManager->get(PageRepositoryInterface::class)->getById($page->getId());
+        $this->assertEquals($updateTime, $page->getUpdateTime());
+    }
+
     public function generateIdentifierFromTitleDataProvider()
     {
         return [
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice_rollback.php
new file mode 100644
index 0000000000000000000000000000000000000000..48cf991c848b067b7a3f631b13da812ab0de39b5
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice_rollback.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+require 'default_rollback.php';
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
index 78342c886de968a02ceed79c215c5dc26ddd9928..f5ae2f2dfd67b5628326149d6d28f055c9d2485f 100755
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
@@ -785,6 +785,7 @@ return [
     ['Mage_Core_Model_Config_Fieldset', 'Magento\Core\Model\Fieldset\Config'],
     ['Mage_Core_Model_Config_Options', 'Magento\Framework\Filesystem'],
     ['Magento\Framework\App\Dir', 'Magento\Framework\Filesystem'],
+    ['Magento\Framework\EntityManager\CustomAttributesMapper'],
     ['Magento\Framework\Filesystem\Adapter\Local', 'Magento\Framework\Filesystem\Driver\File'],
     ['Magento\Framework\Filesystem\Adapter\Zlib', 'Magento\Framework\Filesystem\Driver\Zlib'],
     ['Magento\Framework\Filesystem\AdapterInterface'],
diff --git a/lib/internal/Magento/Framework/EntityManager/CustomAttributesMapper.php b/lib/internal/Magento/Framework/EntityManager/CustomAttributesMapper.php
deleted file mode 100644
index 70cb79f950f28c7f0cefeb98d5e9a278316cccf2..0000000000000000000000000000000000000000
--- a/lib/internal/Magento/Framework/EntityManager/CustomAttributesMapper.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Framework\EntityManager;
-
-/**
- * Class CustomAttributesMapper
- */
-class CustomAttributesMapper implements MapperInterface
-{
-    /**
-     * @var MapperInterface
-     */
-    private $mapper;
-
-    /**
-     * CustomAttributesMapper constructor.
-     *
-     * @param MapperInterface $mapper
-     */
-    public function __construct(MapperInterface $mapper)
-    {
-        $this->mapper = $mapper;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function entityToDatabase($entityType, $data)
-    {
-        return $this->mapper->entityToDatabase($entityType, $data);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @deprecated
-     */
-    public function databaseToEntity($entityType, $data)
-    {
-        return $this->mapper->databaseToEntity($entityType, $data);
-    }
-}
diff --git a/lib/internal/Magento/Framework/EntityManager/Db/CreateRow.php b/lib/internal/Magento/Framework/EntityManager/Db/CreateRow.php
index f4362e4d4a210defe41a380b30516c93130e6751..5eeb1d948ba39b7e8a1a8e3c942eb8a21009cadf 100644
--- a/lib/internal/Magento/Framework/EntityManager/Db/CreateRow.php
+++ b/lib/internal/Magento/Framework/EntityManager/Db/CreateRow.php
@@ -50,11 +50,12 @@ class CreateRow
     {
         $output = [];
         foreach ($connection->describeTable($metadata->getEntityTable()) as $column) {
-
-            if ($column['DEFAULT'] == 'CURRENT_TIMESTAMP') {
+            $columnName = strtolower($column['COLUMN_NAME']);
+            if ($this->canNotSetTimeStamp($columnName, $column, $data)) {
                 continue;
             }
-            if (isset($data[strtolower($column['COLUMN_NAME'])])) {
+
+            if (isset($data[$columnName])) {
                 $output[strtolower($column['COLUMN_NAME'])] = $data[strtolower($column['COLUMN_NAME'])];
             } elseif ($column['DEFAULT'] === null) {
                 $output[strtolower($column['COLUMN_NAME'])] = null;
@@ -66,6 +67,18 @@ class CreateRow
         return $output;
     }
 
+    /**
+     * @param string $columnName
+     * @param string $column
+     * @param array $data
+     * @return bool
+     */
+    private function canNotSetTimeStamp($columnName, $column, array $data)
+    {
+        return $column['DEFAULT'] == 'CURRENT_TIMESTAMP' && !isset($data[$columnName])
+        && empty($column['NULLABLE']);
+    }
+
     /**
      * @param string $entityType
      * @param array $data
diff --git a/lib/internal/Magento/Framework/EntityManager/Db/UpdateRow.php b/lib/internal/Magento/Framework/EntityManager/Db/UpdateRow.php
index 3f65774cf10a615d7cfd95b30b06b0fb1ccd4a1e..0c9189261bc45e1b427fc2bffcdde71d27fc8571 100644
--- a/lib/internal/Magento/Framework/EntityManager/Db/UpdateRow.php
+++ b/lib/internal/Magento/Framework/EntityManager/Db/UpdateRow.php
@@ -50,11 +50,12 @@ class UpdateRow
     {
         $output = [];
         foreach ($connection->describeTable($metadata->getEntityTable()) as $column) {
-            if ($column['DEFAULT'] == 'CURRENT_TIMESTAMP' || $column['IDENTITY']) {
+            $columnName = strtolower($column['COLUMN_NAME']);
+            if ($this->canNotSetTimeStamp($columnName, $column, $data) || $column['IDENTITY']) {
                 continue;
             }
 
-            if (isset($data[strtolower($column['COLUMN_NAME'])])) {
+            if (isset($data[$columnName])) {
                 $output[strtolower($column['COLUMN_NAME'])] = $data[strtolower($column['COLUMN_NAME'])];
             } elseif (!empty($column['NULLABLE'])) {
                 $output[strtolower($column['COLUMN_NAME'])] = null;
@@ -67,6 +68,18 @@ class UpdateRow
         return $output;
     }
 
+    /**
+     * @param string $columnName
+     * @param string $column
+     * @param array $data
+     * @return bool
+     */
+    private function canNotSetTimeStamp($columnName, $column, array $data)
+    {
+        return $column['DEFAULT'] == 'CURRENT_TIMESTAMP' && !isset($data[$columnName])
+        && empty($column['NULLABLE']);
+    }
+
     /**
      * @param string $entityType
      * @param array $data
diff --git a/lib/internal/Magento/Framework/EntityManager/Test/Unit/Db/UpdateRowTest.php b/lib/internal/Magento/Framework/EntityManager/Test/Unit/Db/UpdateRowTest.php
index b22334f4402b1597a7af220cfc168379cde449be..1379ca072bf91898c25a06a796b40f26f2fc2899 100644
--- a/lib/internal/Magento/Framework/EntityManager/Test/Unit/Db/UpdateRowTest.php
+++ b/lib/internal/Magento/Framework/EntityManager/Test/Unit/Db/UpdateRowTest.php
@@ -63,33 +63,14 @@ class UpdateRowTest extends \PHPUnit_Framework_TestCase
         ]);
     }
 
-    public function testExecute()
+    /**
+     * @dataProvider columnsDataProvider
+     * @param array $data
+     * @param array $columns
+     * @param array $preparedColumns
+     */
+    public function testExecute(array $data, array $columns, array $preparedColumns)
     {
-        $data = [
-            'test_link_field' => 1,
-            'identified_field' => 'test_identified_field',
-            'test_simple' => 'test_value',
-        ];
-        $columns = [
-            'test_nullable' => [
-                'NULLABLE' => true,
-                'DEFAULT' => false,
-                'IDENTITY' => false,
-                'COLUMN_NAME' => 'test_nullable',
-            ],
-            'test_simple' => [
-                'NULLABLE' => true,
-                'DEFAULT' => false,
-                'IDENTITY' => false,
-                'COLUMN_NAME' => 'test_simple',
-            ],
-        ];
-        $preparedColumns = [
-            'test_identified_field' => null,
-            'test_nullable' => null,
-            'test_simple' => 'test_value',
-        ];
-
         $this->metadataPoolMock->expects($this->once())
             ->method('getMetadata')
             ->with('test')
@@ -115,7 +96,78 @@ class UpdateRowTest extends \PHPUnit_Framework_TestCase
         $this->metadataMock->expects($this->exactly(2))
             ->method('getIdentifierField')
             ->willReturn('test_identified_field');
-
+        if (empty($data['updated_at'])) {
+            unset($data['updated_at']);
+        }
         $this->assertSame($data, $this->model->execute('test', $data));
     }
+
+    /**
+     * @return array
+     */
+    public function columnsDataProvider()
+    {
+        $data = [
+            'test_link_field' => 1,
+            'identified_field' => 'test_identified_field',
+            'test_simple' => 'test_value',
+        ];
+        $columns = [
+            'test_nullable' => [
+                'NULLABLE' => true,
+                'DEFAULT' => false,
+                'IDENTITY' => false,
+                'COLUMN_NAME' => 'test_nullable',
+            ],
+            'test_simple' => [
+                'NULLABLE' => true,
+                'DEFAULT' => false,
+                'IDENTITY' => false,
+                'COLUMN_NAME' => 'test_simple',
+            ],
+        ];
+        $preparedColumns = [
+            'test_identified_field' => null,
+            'test_nullable' => null,
+            'test_simple' => 'test_value',
+        ];
+
+        return [
+            'default' => [
+                'data' => $data,
+                'columns' => $columns,
+                'preparedColumns' => $preparedColumns,
+            ],
+            'empty timestamp field' => [
+                'data' => array_merge($data, ['updated_at' => '']),
+                'columns' => array_merge(
+                    $columns,
+                    [
+                        'updated_at' => [
+                            'NULLABLE' => false,
+                            'DEFAULT' => 'CURRENT_TIMESTAMP',
+                            'IDENTITY' => false,
+                            'COLUMN_NAME' => 'updated_at',
+                        ],
+                    ]
+                ),
+                'preparedColumns' => $preparedColumns,
+            ],
+            'filled timestamp field' => [
+                'data' => array_merge($data, ['updated_at' => '2016-01-01 00:00:00']),
+                'columns' => array_merge(
+                    $columns,
+                    [
+                        'updated_at' => [
+                            'NULLABLE' => false,
+                            'DEFAULT' => 'CURRENT_TIMESTAMP',
+                            'IDENTITY' => false,
+                            'COLUMN_NAME' => 'updated_at',
+                        ],
+                    ]
+                ),
+                'preparedColumns' => array_merge($preparedColumns, ['updated_at' => '2016-01-01 00:00:00']),
+            ],
+        ];
+    }
 }
diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js
index a74a9f12fb2dfe1a0ea5e79b445608016c61462c..f224218f4f731511b8ba13f3ded06b5a73393f4d 100644
--- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js
+++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js
@@ -46,7 +46,7 @@ define([
     };
 
     schema.flowContent = schema.blockContent.concat(schema.phrasingContent, ['style']);
-    schema.nonEmpty = ['td', 'th', 'iframe', 'video', 'audio', 'object', 'script'].concat(schema.shortEnded);
+    schema.nonEmpty = ['td', 'th', 'iframe', 'video', 'audio', 'object', 'script', 'i', 'em', 'span'].concat(schema.shortEnded);
 
     _.extend(schema, (function (phrasingContent, flowContent) {
         var validElements   = [],
diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js
index 4964e6bb14e703f3a0a11a84ab1af78c7e9cfe6e..66b72857d003397b8a756dc6aae9c0de70c58eeb 100755
--- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js
+++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js
@@ -101,6 +101,8 @@ define([
                 magentoPluginsOptions: magentoPluginsOptions,
                 doctype: '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
                 setup: function(ed){
+                    ed.onPreInit.add(self.onEditorPreInit.bind(self));
+
                     ed.onInit.add(self.onEditorInit.bind(self));
 
                     ed.onSubmit.add(function(ed, e) {
@@ -285,10 +287,18 @@ define([
             }
         },
 
-        onEditorInit: function (editor) {
+        /**
+         * Editor pre-initialise event handler.
+         */
+        onEditorPreInit: function (editor) {
             this.applySchema(editor);
         },
 
+        /**
+         * @deprecated
+         */
+        onEditorInit: function () {},
+
         onFormValidation: function() {
             if (tinyMCE.get(this.id)) {
                 $(this.id).value = tinyMCE.get(this.id).getContent();