diff --git a/app/code/Magento/Braintree/etc/adminhtml/system.xml b/app/code/Magento/Braintree/etc/adminhtml/system.xml
index 5f62a9d7cf1920ebdfc8020befa0f78f00c396bc..e4f4e11983892f98cfc8945ee2a541c428b441dd 100644
--- a/app/code/Magento/Braintree/etc/adminhtml/system.xml
+++ b/app/code/Magento/Braintree/etc/adminhtml/system.xml
@@ -33,7 +33,7 @@
                         </requires>
                     </field>
                     <field id="braintree_cc_vault_active" translate="label" type="select" sortOrder="12" showInDefault="1" showInWebsite="1" showInStore="0">
-                        <label>Vault enabled</label>
+                        <label>Vault Enabled</label>
                         <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                         <config_path>payment/braintree_cc_vault/active</config_path>
                         <requires>
@@ -155,7 +155,7 @@
                             <comment>It is recommended to set this value to "PayPal" per store views.</comment>
                         </field>
                         <field id="braintree_paypal_vault_active" translate="label" type="select" sortOrder="21" showInDefault="1" showInWebsite="1" showInStore="0">
-                            <label>Vault enabled</label>
+                            <label>Vault Enabled</label>
                             <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                             <config_path>payment/braintree_paypal_vault/active</config_path>
                             <requires>
diff --git a/app/code/Magento/Braintree/view/adminhtml/web/styles.css b/app/code/Magento/Braintree/view/adminhtml/web/styles.css
index 31f48cd0b28df1d8235b9ccc9d6b46b13b410bd4..81378f636eb61362ad2840bc859161c91ee8add1 100644
--- a/app/code/Magento/Braintree/view/adminhtml/web/styles.css
+++ b/app/code/Magento/Braintree/view/adminhtml/web/styles.css
@@ -3,6 +3,6 @@
  * See COPYING.txt for license details.
  */
 
-.braintree-section .heading {display: inline-block; background: url("images/braintree_logo.png") no-repeat 0 50% / 18rem auto; padding-left: 20rem;}
-.braintree-section .button-container {display: inline-block; float: right;}
+.braintree-section .heading {background: url("images/braintree_logo.png") no-repeat 0 50% / 18rem auto; padding-left: 20rem;}
+.braintree-section .button-container {float: right;}
 .braintree-section .config-alt {background: url("images/braintree_allinone.png") no-repeat scroll 0 0 / 100% auto; height: 28px; margin: 0.5rem 0 0; width: 230px;}
\ No newline at end of file
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
index 21c12bf0a8b1a64b34db70eaeedd4a78a9682976..75ec58ff908762ff82f3c93e6fa218abde6ba42a 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
@@ -1317,7 +1317,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
 
             $select = $this->_connection->select()->from(
                 $entityTable,
-                $this->getNewSkuFieldsForSelect()
+                array_merge($this->getNewSkuFieldsForSelect(), $this->getOldSkuFieldsForSelect())
             )->where(
                 'sku IN (?)',
                 array_keys($entityRowsIn)
@@ -1330,10 +1330,45 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
                     $this->skuProcessor->setNewSkuData($sku, $key, $value);
                 }
             }
+
+            $this->updateOldSku($newProducts);
         }
+
         return $this;
     }
 
+    /**
+     * Return additional data, needed to select.
+     * @return array
+     */
+    private function getOldSkuFieldsForSelect()
+    {
+        return ['type_id', 'attribute_set_id'];
+    }
+
+    /**
+     * Adds newly created products to _oldSku
+     * @param array $newProducts
+     * @return void
+     */
+    private function updateOldSku(array $newProducts)
+    {
+        $oldSkus = [];
+        foreach ($newProducts as $info) {
+            $typeId = $info['type_id'];
+            $sku = $info['sku'];
+            $oldSkus[$sku] = [
+                'type_id' => $typeId,
+                'attr_set_id' => $info['attribute_set_id'],
+                $this->getProductIdentifierField() => $info[$this->getProductIdentifierField()],
+                'supported_type' => isset($this->_productTypeModels[$typeId]),
+                $this->getProductEntityLinkField() => $info[$this->getProductEntityLinkField()],
+            ];
+        }
+
+        $this->_oldSku = array_replace($this->_oldSku, $oldSkus);
+    }
+
     /**
      * Get new SKU fields for select
      *
@@ -1718,6 +1753,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
                 ['adapter' => $this, 'bunch' => $bunch]
             );
         }
+
         return $this;
     }
 
@@ -2452,6 +2488,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
     {
         $source = $this->_getSource();
         $source->rewind();
+
         while ($source->valid()) {
             try {
                 $rowData = $source->current();
@@ -2465,6 +2502,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
             $rowData = $this->_customFieldsMapping($rowData);
 
             $this->validateRow($rowData, $source->key());
+            
             $source->next();
         }
         $this->checkUrlKeyDuplicates();
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php
index a28f65aef1ece1feda826ae9a1a37635af59aae9..8461e617431d64fe3529162d54841d7da4740cdf 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php
@@ -567,4 +567,13 @@ abstract class AbstractType
         }
         return $this->productEntityLinkField;
     }
+
+    /**
+     * Clean cached values
+     */
+    public function __destruct()
+    {
+        self::$attributeCodeToId = [];
+        self::$commonAttributesCache = [];
+    }
 }
diff --git a/app/code/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox.php b/app/code/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox.php
new file mode 100644
index 0000000000000000000000000000000000000000..16a296a3554548d31f1692f397cd0124e272a1af
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Pricing/Render/FinalPriceBox.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableProduct\Pricing\Render;
+
+use Magento\Catalog\Pricing\Price\FinalPrice;
+use Magento\Catalog\Pricing\Price\RegularPrice;
+use Magento\ConfigurableProduct\Pricing\Price\ConfigurableOptionsProviderInterface;
+use Magento\Framework\Pricing\Price\PriceInterface;
+use Magento\Framework\Pricing\Render\RendererPool;
+use Magento\Framework\Pricing\SaleableInterface;
+use Magento\Framework\View\Element\Template\Context;
+
+class FinalPriceBox extends \Magento\Catalog\Pricing\Render\FinalPriceBox
+{
+    /**
+     * @var ConfigurableOptionsProviderInterface
+     */
+    private $configurableOptionsProvider;
+
+    /**
+     * @param Context $context
+     * @param SaleableInterface $saleableItem
+     * @param PriceInterface $price
+     * @param RendererPool $rendererPool
+     * @param ConfigurableOptionsProviderInterface $configurableOptionsProvider
+     * @param array $data
+     */
+    public function __construct(
+        Context $context,
+        SaleableInterface $saleableItem,
+        PriceInterface $price,
+        RendererPool $rendererPool,
+        ConfigurableOptionsProviderInterface $configurableOptionsProvider,
+        array $data = []
+    ) {
+        $this->configurableOptionsProvider = $configurableOptionsProvider;
+        parent::__construct($context, $saleableItem, $price, $rendererPool, $data);
+    }
+
+    /**
+     * Define if the special price should be shown
+     *
+     * @return bool
+     */
+    public function hasSpecialPrice()
+    {
+        $product = $this->getSaleableItem();
+        foreach ($this->configurableOptionsProvider->getProducts($product) as $subProduct) {
+            $regularPrice = $subProduct->getPriceInfo()->getPrice(RegularPrice::PRICE_CODE)->getValue();
+            $finalPrice = $subProduct->getPriceInfo()->getPrice(FinalPrice::PRICE_CODE)->getValue();
+            if ($finalPrice < $regularPrice) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4dbcfed5315252c62494b6ede30d4d14f9a598b2
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Pricing/Render/FinalPriceBoxTest.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\ConfigurableProduct\Test\Unit\Pricing\Render;
+
+use Magento\Catalog\Pricing\Price\FinalPrice;
+use Magento\Catalog\Pricing\Price\RegularPrice;
+use Magento\ConfigurableProduct\Pricing\Price\ConfigurableOptionsProviderInterface;
+use Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox;
+
+class FinalPriceBoxTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\View\Element\Template\Context|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $context;
+
+    /**
+     * @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $saleableItem;
+
+    /**
+     * @var \Magento\Framework\Pricing\Price\PriceInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $price;
+
+    /**
+     * @var \Magento\Framework\Pricing\Render\RendererPool|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $rendererPool;
+
+    /**
+     * @var ConfigurableOptionsProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $configurableOptionsProvider;
+
+    /**
+     * @var FinalPriceBox
+     */
+    private $model;
+
+    protected function setUp()
+    {
+        $this->context = $this->getMockBuilder(\Magento\Framework\View\Element\Template\Context::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->saleableItem = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->price = $this->getMockBuilder(\Magento\Framework\Pricing\Price\PriceInterface::class)
+            ->getMockForAbstractClass();
+
+        $this->rendererPool = $this->getMockBuilder(\Magento\Framework\Pricing\Render\RendererPool::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->configurableOptionsProvider = $this->getMockBuilder(ConfigurableOptionsProviderInterface::class)
+            ->getMockForAbstractClass();
+
+        $this->model = new FinalPriceBox(
+            $this->context,
+            $this->saleableItem,
+            $this->price,
+            $this->rendererPool,
+            $this->configurableOptionsProvider
+        );
+    }
+
+    /**
+     * @param float $regularPrice
+     * @param float $finalPrice
+     * @param bool $expected
+     * @dataProvider hasSpecialPriceDataProvider
+     */
+    public function testHasSpecialPrice(
+        $regularPrice,
+        $finalPrice,
+        $expected
+    ) {
+        $priceMockOne = $this->getMockBuilder(\Magento\Framework\Pricing\Price\PriceInterface::class)
+            ->getMockForAbstractClass();
+
+        $priceMockOne->expects($this->once())
+            ->method('getValue')
+            ->willReturn($regularPrice);
+
+        $priceMockTwo = $this->getMockBuilder(\Magento\Framework\Pricing\Price\PriceInterface::class)
+            ->getMockForAbstractClass();
+
+        $priceMockTwo->expects($this->once())
+            ->method('getValue')
+            ->willReturn($finalPrice);
+
+        $priceInfoMock = $this->getMockBuilder(\Magento\Framework\Pricing\PriceInfo\Base::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $priceInfoMock->expects($this->exactly(2))
+            ->method('getPrice')
+            ->willReturnMap([
+                [RegularPrice::PRICE_CODE, $priceMockOne],
+                [FinalPrice::PRICE_CODE, $priceMockTwo],
+            ]);
+
+        $productMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class)
+            ->setMethods(['getPriceInfo'])
+            ->getMockForAbstractClass();
+
+        $productMock->expects($this->exactly(2))
+            ->method('getPriceInfo')
+            ->willReturn($priceInfoMock);
+
+        $this->configurableOptionsProvider->expects($this->once())
+            ->method('getProducts')
+            ->with($this->saleableItem)
+            ->willReturn([$productMock]);
+
+        $this->assertEquals($expected, $this->model->hasSpecialPrice());
+    }
+
+    /**
+     * @return array
+     */
+    public function hasSpecialPriceDataProvider()
+    {
+        return [
+            [10., 20., false],
+            [10., 10., false],
+            [20., 10., true],
+        ];
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml b/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml
new file mode 100644
index 0000000000000000000000000000000000000000..47fe31681b5bf0d96ba4cf4935283d415de23ce7
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
+    <referenceBlock name="render.product.prices">
+        <arguments>
+            <argument name="configurable" xsi:type="array">
+                <item name="prices" xsi:type="array">
+                    <item name="final_price" xsi:type="array">
+                        <item name="render_class" xsi:type="string">Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox</item>
+                        <item name="render_template" xsi:type="string">Magento_ConfigurableProduct::product/price/final_price.phtml</item>
+                    </item>
+                </item>
+            </argument>
+        </arguments>
+    </referenceBlock>
+</layout>
diff --git a/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..5943b1ea2af5b5c4a9095a81b3a22dc1019f1da9
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+?>
+
+<?php
+/** @var \Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox$block */
+
+/** @var \Magento\Framework\Pricing\Price\PriceInterface $priceModel */
+$priceModel = $block->getPriceType('regular_price');
+
+/** @var \Magento\Framework\Pricing\Price\PriceInterface $finalPriceModel */
+$finalPriceModel = $block->getPriceType('final_price');
+$idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : '';
+$schema = ($block->getZone() == 'item_view') ? true : false;
+?>
+<?php if ($block->hasSpecialPrice()): ?>
+    <span class="special-price">
+        <?php /* @escapeNotVerified */ echo $block->renderAmount($finalPriceModel->getAmount(), [
+            'display_label'     => __('Special Price'),
+            'price_id'          => $block->getPriceId('product-price-' . $idSuffix),
+            'price_type'        => 'finalPrice',
+            'include_container' => true,
+            'schema' => $schema
+        ]); ?>
+    </span>
+    <span class="old-price sly-old-price no-display">
+        <?php /* @escapeNotVerified */ echo $block->renderAmount($priceModel->getAmount(), [
+            'display_label'     => __('Regular Price'),
+            'price_id'          => $block->getPriceId('old-price-' . $idSuffix),
+            'price_type'        => 'oldPrice',
+            'include_container' => true,
+            'skip_adjustments'  => true
+        ]); ?>
+    </span>
+<?php else: ?>
+    <?php /* @escapeNotVerified */ echo $block->renderAmount($finalPriceModel->getAmount(), [
+        'price_id'          => $block->getPriceId('product-price-' . $idSuffix),
+        'price_type'        => 'finalPrice',
+        'include_container' => true,
+        'schema' => $schema
+    ]); ?>
+<?php endif; ?>
+
+<?php if ($block->showMinimalPrice()): ?>
+    <?php if ($block->getUseLinkForAsLowAs()):?>
+        <a href="<?php /* @escapeNotVerified */ echo $block->getSaleableItem()->getProductUrl(); ?>" class="minimal-price-link">
+            <?php /* @escapeNotVerified */ echo $block->renderAmountMinimal(); ?>
+        </a>
+    <?php else:?>
+        <span class="minimal-price-link">
+            <?php /* @escapeNotVerified */ echo $block->renderAmountMinimal(); ?>
+        </span>
+    <?php endif?>
+<?php endif; ?>
diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js
index bd0314aacf71106c11fa3759a48a9fde13967826..7bea20e78620134fff06d4cd259fee029f4fe637 100644
--- a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js
+++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js
@@ -28,6 +28,7 @@ define([
             '<% } %>',
             mediaGallerySelector: '[data-gallery-role=gallery-placeholder]',
             mediaGalleryInitial: null,
+            slyOldPriceSelector: '.sly-old-price',
             onlyMainImg: false
         },
 
@@ -248,6 +249,7 @@ define([
                 this._resetChildren(element);
             }
             this._reloadPrice();
+            this._displayRegularPriceBlock(this.simpleProduct);
             this._changeProductImage();
         },
 
@@ -444,7 +446,7 @@ define([
         },
 
         /**
-         * Returns pracies for configured products
+         * Returns prices for configured products
          *
          * @param {*} config - Products configuration
          * @returns {*}
@@ -487,6 +489,23 @@ define([
                 undefined :
                 _.first(config.allowedProducts);
 
+        },
+
+        /**
+         * Show or hide regular price block
+         *
+         * @param {*} optionId
+         * @private
+         */
+        _displayRegularPriceBlock: function (optionId) {
+            if (typeof optionId != 'undefined'
+                && this.options.spConfig.optionPrices[optionId].oldPrice.amount
+                != this.options.spConfig.optionPrices[optionId].finalPrice.amount
+            ) {
+                $(this.options.slyOldPriceSelector).show();
+            } else {
+                $(this.options.slyOldPriceSelector).hide();
+            }
         }
 
     });
diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml
index 41ffb74184badc80bfa823e294b2ebde1899952b..fdb9c3f317a4cb04fa1b9908ccde4ca98874ceb3 100644
--- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml
+++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml
@@ -256,6 +256,10 @@
                     <item name="label" xsi:type="string" translate="true">Send Welcome Email From</item>
                     <item name="dataType" xsi:type="string">number</item>
                     <item name="formElement" xsi:type="string">select</item>
+                    <item name="source" xsi:type="string">customer</item>
+                    <item name="imports" xsi:type="array">
+                        <item name="value" xsi:type="string">${ $.provider }:data.customer.store_id</item>
+                    </item>
                 </item>
             </argument>
         </field>
diff --git a/app/code/Magento/Email/Model/Template/Css/Processor.php b/app/code/Magento/Email/Model/Template/Css/Processor.php
new file mode 100644
index 0000000000000000000000000000000000000000..ae7d083750863d2d7dbd5869341bbee772544421
--- /dev/null
+++ b/app/code/Magento/Email/Model/Template/Css/Processor.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Email\Model\Template\Css;
+
+use Magento\Framework\View\Asset\NotationResolver\Variable;
+use Magento\Framework\View\Asset\Repository;
+
+class Processor
+{
+    /**
+     * @var Repository
+     */
+    private $assetRepository;
+
+    /**
+     * @param Repository $assetRepository
+     */
+    public function __construct(Repository $assetRepository)
+    {
+        $this->assetRepository = $assetRepository;
+    }
+
+    /**
+     * Process css placeholders
+     *
+     * @param string $css
+     * @return string
+     */
+    public function process($css)
+    {
+        $matches = [];
+        if (preg_match_all(Variable::VAR_REGEX, $css, $matches, PREG_SET_ORDER)) {
+            $replacements = [];
+            foreach ($matches as $match) {
+                if (!isset($replacements[$match[0]])) {
+                    $replacements[$match[0]] = $this->getPlaceholderValue($match[1]);
+                }
+            }
+            $css = str_replace(array_keys($replacements), $replacements, $css);
+        }
+        return $css;
+    }
+
+    /**
+     * Retrieve placeholder value
+     *
+     * @param string $placeholder
+     * @return string
+     */
+    private function getPlaceholderValue($placeholder)
+    {
+        /** @var \Magento\Framework\View\Asset\File\FallbackContext $context */
+        $context = $this->assetRepository->getStaticViewFileContext();
+
+        switch ($placeholder) {
+            case 'base_url_path':
+                return $context->getBaseUrl();
+            case 'locale':
+                return $context->getLocale();
+            default:
+                return '';
+        }
+    }
+}
diff --git a/app/code/Magento/Email/Model/Template/Filter.php b/app/code/Magento/Email/Model/Template/Filter.php
index 2bb9fc742f258090d1cda46b538053e00fb896e8..d9409d62f159cfd7c2ab1e6c32aae6d07a33b8fc 100644
--- a/app/code/Magento/Email/Model/Template/Filter.php
+++ b/app/code/Magento/Email/Model/Template/Filter.php
@@ -5,6 +5,9 @@
  */
 namespace Magento\Email\Model\Template;
 
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Filesystem;
+use Magento\Framework\Filesystem\Directory\ReadInterface;
 use Magento\Framework\View\Asset\ContentProcessorException;
 use Magento\Framework\View\Asset\ContentProcessorInterface;
 
@@ -153,6 +156,16 @@ class Filter extends \Magento\Framework\Filter\Template
      */
     protected $configVariables;
 
+    /**
+     * @var \Magento\Email\Model\Template\Css\Processor
+     */
+    private $cssProcessor;
+
+    /**
+     * @var ReadInterface
+     */
+    private $pubDirectory;
+
     /**
      * @param \Magento\Framework\Stdlib\StringUtils $string
      * @param \Psr\Log\LoggerInterface $logger
@@ -203,6 +216,31 @@ class Filter extends \Magento\Framework\Filter\Template
         parent::__construct($string, $variables);
     }
 
+    /**
+     * @deprecated
+     * @return Css\Processor
+     */
+    private function getCssProcessor()
+    {
+        if (!$this->cssProcessor) {
+            $this->cssProcessor = ObjectManager::getInstance()->get(Css\Processor::class);
+        }
+        return $this->cssProcessor;
+    }
+
+    /**
+     * @deprecated
+     * @param string $dirType
+     * @return ReadInterface
+     */
+    private function getPubDirectory($dirType)
+    {
+        if (!$this->pubDirectory) {
+            $this->pubDirectory = ObjectManager::getInstance()->get(Filesystem::class)->getDirectoryRead($dirType);
+        }
+        return $this->pubDirectory;
+    }
+
     /**
      * Set use absolute links flag
      *
@@ -788,7 +826,9 @@ class Filter extends \Magento\Framework\Filter\Template
             return '/* ' . __('"file" parameter must be specified') . ' */';
         }
 
-        $css = $this->getCssFilesContent([$params['file']]);
+        $css = $this->getCssProcessor()->process(
+            $this->getCssFilesContent([$params['file']])
+        );
 
         if (strpos($css, ContentProcessorInterface::ERROR_MESSAGE_PREFIX) !== false) {
             // Return compilation error wrapped in CSS comment
@@ -889,7 +929,12 @@ class Filter extends \Magento\Framework\Filter\Template
         try {
             foreach ($files as $file) {
                 $asset = $this->_assetRepo->createAsset($file, $designParams);
-                $css .= $asset->getContent();
+                $pubDirectory = $this->getPubDirectory($asset->getContext()->getBaseDirType());
+                if ($pubDirectory->isExist($asset->getPath())) {
+                    $css .= $pubDirectory->readFile($asset->getPath());
+                } else {
+                    $css .= $asset->getContent();
+                }
             }
         } catch (ContentProcessorException $exception) {
             $css = $exception->getMessage();
@@ -914,6 +959,8 @@ class Filter extends \Magento\Framework\Filter\Template
         $cssToInline = $this->getCssFilesContent(
             $this->getInlineCssFiles()
         );
+        $cssToInline = $this->getCssProcessor()->process($cssToInline);
+
         // Only run Emogrify if HTML and CSS contain content
         if ($html && $cssToInline) {
             try {
diff --git a/app/code/Magento/Email/Test/Unit/Model/Template/Css/ProcessorTest.php b/app/code/Magento/Email/Test/Unit/Model/Template/Css/ProcessorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..fac9ba0f1b5aa902a22f08141e5f0c824a1a1382
--- /dev/null
+++ b/app/code/Magento/Email/Test/Unit/Model/Template/Css/ProcessorTest.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Email\Test\Unit\Model\Template\Css;
+
+use Magento\Email\Model\Template\Css\Processor;
+use Magento\Framework\View\Asset\File\FallbackContext;
+use Magento\Framework\View\Asset\Repository;
+
+class ProcessorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Processor
+     */
+    protected $processor;
+
+    /**
+     * @var Repository|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $assetRepository;
+
+    /**
+     * @var FallbackContext|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $fallbackContext;
+
+    public function setUp()
+    {
+        $this->assetRepository = $this->getMockBuilder(Repository::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->fallbackContext = $this->getMockBuilder(FallbackContext::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->processor = new Processor($this->assetRepository);
+    }
+
+    public function testProcess()
+    {
+        $url = 'http://magento.local/pub/static/';
+        $locale = 'en_US';
+        $css = '@import url("{{base_url_path}}frontend/_view/{{locale}}/css/email.css");';
+        $expectedCss = '@import url("' . $url . 'frontend/_view/' . $locale . '/css/email.css");';
+
+        $this->assetRepository->expects($this->exactly(2))
+            ->method('getStaticViewFileContext')
+            ->willReturn($this->fallbackContext);
+        $this->fallbackContext->expects($this->once())
+            ->method('getBaseUrl')
+            ->willReturn($url);
+        $this->fallbackContext->expects($this->once())
+            ->method('getLocale')
+            ->willReturn($locale);
+        $this->assertEquals($expectedCss, $this->processor->process($css));
+    }
+}
diff --git a/app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php b/app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php
index 84e87e9e8154156b7323e1cbfd5d6d11ebdaab39..bcfd95d897d298faf58543b08ad3385e71f66476 100644
--- a/app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php
+++ b/app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php
@@ -5,6 +5,13 @@
  */
 namespace Magento\Email\Test\Unit\Model\Template;
 
+use Magento\Email\Model\Template\Css\Processor;
+use Magento\Email\Model\Template\Filter;
+use Magento\Framework\App\Area;
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Filesystem\Directory\ReadInterface;
+use Magento\Framework\View\Asset\File\FallbackContext;
+
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
@@ -94,7 +101,6 @@ class FilterTest extends \PHPUnit_Framework_TestCase
 
         $this->escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class)
             ->disableOriginalConstructor()
-            ->enableProxyingToOriginalMethods()
             ->getMock();
 
         $this->assetRepo = $this->getMockBuilder(\Magento\Framework\View\Asset\Repository::class)
@@ -138,7 +144,7 @@ class FilterTest extends \PHPUnit_Framework_TestCase
 
     /**
      * @param array|null $mockedMethods Methods to mock
-     * @return \Magento\Email\Model\Template\Filter|\PHPUnit_Framework_MockObject_MockObject
+     * @return Filter|\PHPUnit_Framework_MockObject_MockObject
      */
     protected function getModel($mockedMethods = null)
     {
@@ -252,13 +258,23 @@ class FilterTest extends \PHPUnit_Framework_TestCase
     public function testApplyInlineCss($html, $css, $expectedResults)
     {
         $filter = $this->getModel(['getCssFilesContent']);
+        $cssProcessor = $this->getMockBuilder(Processor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $reflectionClass = new \ReflectionClass(Filter::class);
+        $reflectionProperty = $reflectionClass->getProperty('cssProcessor');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($filter, $cssProcessor);
+        $cssProcessor->expects($this->any())
+            ->method('process')
+            ->willReturnArgument(0);
 
         $filter->expects($this->exactly(count($expectedResults)))
             ->method('getCssFilesContent')
             ->will($this->returnValue($css));
 
         $designParams = [
-            'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
+            'area' => Area::AREA_FRONTEND,
             'theme' => 'themeId',
             'locale' => 'localeId',
         ];
@@ -269,6 +285,60 @@ class FilterTest extends \PHPUnit_Framework_TestCase
         }
     }
 
+    public function testGetCssFilesContent()
+    {
+        $file = 'css/email.css';
+        $path = Area::AREA_FRONTEND . '/themeId/localeId';
+        $css = 'p{color:black}';
+        $designParams = [
+            'area' => Area::AREA_FRONTEND,
+            'theme' => 'themeId',
+            'locale' => 'localeId',
+        ];
+        $filter = $this->getModel();
+
+        $asset = $this->getMockBuilder(\Magento\Framework\View\Asset\File::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $fallbackContext = $this->getMockBuilder(FallbackContext::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $fallbackContext->expects($this->once())
+            ->method('getBaseDirType')
+            ->willReturn(DirectoryList::STATIC_VIEW);
+        $asset->expects($this->atLeastOnce())
+            ->method('getContext')
+            ->willReturn($fallbackContext);
+
+        $asset->expects($this->atLeastOnce())
+            ->method('getPath')
+            ->willReturn($path . DIRECTORY_SEPARATOR . $file);
+        $this->assetRepo->expects($this->once())
+            ->method('createAsset')
+            ->with($file, $designParams)
+            ->willReturn($asset);
+
+        $pubDirectory = $this->getMockBuilder(ReadInterface::class)
+            ->getMockForAbstractClass();
+        $reflectionClass = new \ReflectionClass(Filter::class);
+        $reflectionProperty = $reflectionClass->getProperty('pubDirectory');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($filter, $pubDirectory);
+        $pubDirectory->expects($this->once())
+            ->method('isExist')
+            ->with($path . DIRECTORY_SEPARATOR . $file)
+            ->willReturn(true);
+        $pubDirectory->expects($this->once())
+            ->method('readFile')
+            ->with($path . DIRECTORY_SEPARATOR . $file)
+            ->willReturn($css);
+
+        $filter->setDesignParams($designParams);
+
+        $this->assertEquals($css, $filter->getCssFilesContent([$file]));
+    }
+
     /**
      * @return array
      */
@@ -301,7 +371,19 @@ class FilterTest extends \PHPUnit_Framework_TestCase
      */
     public function testApplyInlineCssThrowsExceptionWhenDesignParamsNotSet()
     {
-        $this->getModel()->applyInlineCss('test');
+        $filter = $this->getModel();
+        $cssProcessor = $this->getMockBuilder(Processor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $reflectionClass = new \ReflectionClass(Filter::class);
+        $reflectionProperty = $reflectionClass->getProperty('cssProcessor');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($filter, $cssProcessor);
+        $cssProcessor->expects($this->any())
+            ->method('process')
+            ->willReturnArgument(0);
+
+        $filter->applyInlineCss('test');
     }
 
     /**
@@ -348,7 +430,10 @@ class FilterTest extends \PHPUnit_Framework_TestCase
         $construction = ["{{config path={$path}}}", 'config', " path={$path}"];
         $scopeConfigValue = 'value';
 
-        $storeMock = $this->getMock(\Magento\Store\Api\Data\StoreInterface::class, [], [], '', false);
+        $storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->storeManager->expects($this->once())->method('getStore')->willReturn($storeMock);
         $storeMock->expects($this->once())->method('getId')->willReturn(1);
 
@@ -369,7 +454,9 @@ class FilterTest extends \PHPUnit_Framework_TestCase
         $construction = ["{{config path={$path}}}", 'config', " path={$path}"];
         $scopeConfigValue = '';
 
-        $storeMock = $this->getMock(\Magento\Store\Api\Data\StoreInterface::class, [], [], '', false);
+        $storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
         $this->storeManager->expects($this->once())->method('getStore')->willReturn($storeMock);
         $storeMock->expects($this->once())->method('getId')->willReturn(1);
 
diff --git a/app/code/Magento/Multishipping/Block/Checkout/Billing.php b/app/code/Magento/Multishipping/Block/Checkout/Billing.php
index f34ed5fb2671a649f7f8abc2d201b9ffc19dc0b0..34570e12a29efc0071cad327af15f50d64686f35 100644
--- a/app/code/Magento/Multishipping/Block/Checkout/Billing.php
+++ b/app/code/Magento/Multishipping/Block/Checkout/Billing.php
@@ -35,6 +35,7 @@ class Billing extends \Magento\Payment\Block\Form\Container
      * @param \Magento\Checkout\Model\Session $checkoutSession
      * @param \Magento\Payment\Model\Method\SpecificationInterface $paymentSpecification
      * @param array $data
+     * @param array $additionalChecks
      */
     public function __construct(
         \Magento\Framework\View\Element\Template\Context $context,
@@ -43,12 +44,13 @@ class Billing extends \Magento\Payment\Block\Form\Container
         \Magento\Multishipping\Model\Checkout\Type\Multishipping $multishipping,
         \Magento\Checkout\Model\Session $checkoutSession,
         \Magento\Payment\Model\Method\SpecificationInterface $paymentSpecification,
-        array $data = []
+        array $data = [],
+        array $additionalChecks = []
     ) {
         $this->_multishipping = $multishipping;
         $this->_checkoutSession = $checkoutSession;
         $this->paymentSpecification = $paymentSpecification;
-        parent::__construct($context, $paymentHelper, $methodSpecificationFactory, $data);
+        parent::__construct($context, $paymentHelper, $methodSpecificationFactory, $data, $additionalChecks);
         $this->_isScopePrivate = true;
     }
 
diff --git a/app/code/Magento/Payment/Api/Data/PaymentMethodInterface.php b/app/code/Magento/Payment/Api/Data/PaymentMethodInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..881595f60e5415fdeacf3968ccfd8f01b8539ec1
--- /dev/null
+++ b/app/code/Magento/Payment/Api/Data/PaymentMethodInterface.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Api\Data;
+
+/**
+ * Payment method interface.
+ *
+ * @api
+ */
+interface PaymentMethodInterface
+{
+    /**
+     * Get code.
+     *
+     * @return string
+     */
+    public function getCode();
+
+    /**
+     * Get title.
+     *
+     * @return string
+     */
+    public function getTitle();
+
+    /**
+     * Get store id.
+     *
+     * @return int
+     */
+    public function getStoreId();
+
+    /**
+     * Get is active.
+     *
+     * @return bool
+     * @SuppressWarnings(PHPMD.BooleanGetMethodName)
+     */
+    public function getIsActive();
+}
diff --git a/app/code/Magento/Payment/Api/PaymentMethodListInterface.php b/app/code/Magento/Payment/Api/PaymentMethodListInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..faf231562d9ed202073161a5dd7ac927e353a0ae
--- /dev/null
+++ b/app/code/Magento/Payment/Api/PaymentMethodListInterface.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Api;
+
+/**
+ * Payment method list interface.
+ *
+ * @api
+ */
+interface PaymentMethodListInterface
+{
+    /**
+     * Get list of payment methods.
+     *
+     * @param int $storeId
+     * @return \Magento\Payment\Api\Data\PaymentMethodInterface[]
+     */
+    public function getList($storeId);
+
+    /**
+     * Get list of active payment methods.
+     *
+     * @param int $storeId
+     * @return \Magento\Payment\Api\Data\PaymentMethodInterface[]
+     */
+    public function getActiveList($storeId);
+}
diff --git a/app/code/Magento/Payment/Block/Form/Container.php b/app/code/Magento/Payment/Block/Form/Container.php
index cdcd4137159a1994face7ed1ca5cd89e3c0ad3c2..d91c0e3dc39a454d39d6882da41374f4da71383f 100644
--- a/app/code/Magento/Payment/Block/Form/Container.php
+++ b/app/code/Magento/Payment/Block/Form/Container.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Payment\Block\Form;
 
+use Magento\Framework\App\ObjectManager;
 use Magento\Payment\Model\Method\AbstractMethod;
 
 /**
@@ -24,20 +25,38 @@ class Container extends \Magento\Framework\View\Element\Template
     /** @var  \Magento\Payment\Model\Checks\SpecificationFactory */
     protected $methodSpecificationFactory;
 
+    /**
+     * @var \Magento\Payment\Api\PaymentMethodListInterface
+     */
+    private $paymentMethodList;
+
+    /**
+     * @var \Magento\Payment\Model\Method\InstanceFactory
+     */
+    private $paymentMethodInstanceFactory;
+
+    /**
+     * @var array
+     */
+    protected $additionalChecks;
+
     /**
      * @param \Magento\Framework\View\Element\Template\Context $context
      * @param \Magento\Payment\Helper\Data $paymentHelper
      * @param \Magento\Payment\Model\Checks\SpecificationFactory $methodSpecificationFactory
      * @param array $data
+     * @param array $additionalChecks
      */
     public function __construct(
         \Magento\Framework\View\Element\Template\Context $context,
         \Magento\Payment\Helper\Data $paymentHelper,
         \Magento\Payment\Model\Checks\SpecificationFactory $methodSpecificationFactory,
-        array $data = []
+        array $data = [],
+        array $additionalChecks = []
     ) {
         $this->_paymentHelper = $paymentHelper;
         $this->methodSpecificationFactory = $methodSpecificationFactory;
+        $this->additionalChecks = $additionalChecks;
         parent::__construct($context, $data);
     }
 
@@ -69,13 +88,17 @@ class Container extends \Magento\Framework\View\Element\Template
      */
     protected function _canUseMethod($method)
     {
-        return $this->methodSpecificationFactory->create(
+        $checks = array_merge(
             [
                 AbstractMethod::CHECK_USE_FOR_COUNTRY,
                 AbstractMethod::CHECK_USE_FOR_CURRENCY,
                 AbstractMethod::CHECK_ORDER_TOTAL_MIN_MAX,
-            ]
-        )->isApplicable(
+                AbstractMethod::CHECK_ZERO_TOTAL
+            ],
+            $this->additionalChecks
+        );
+
+        return $this->methodSpecificationFactory->create($checks)->isApplicable(
             $method,
             $this->getQuote()
         );
@@ -124,11 +147,11 @@ class Container extends \Magento\Framework\View\Element\Template
             $quote = $this->getQuote();
             $store = $quote ? $quote->getStoreId() : null;
             $methods = [];
-            $specification = $this->methodSpecificationFactory->create([AbstractMethod::CHECK_ZERO_TOTAL]);
-            foreach ($this->_paymentHelper->getStoreMethods($store, $quote) as $method) {
-                if ($this->_canUseMethod($method) && $specification->isApplicable($method, $this->getQuote())) {
-                    $this->_assignMethod($method);
-                    $methods[] = $method;
+            foreach ($this->getPaymentMethodList()->getActiveList($store) as $method) {
+                $methodInstance = $this->getPaymentMethodInstanceFactory()->create($method);
+                if ($methodInstance->isAvailable($quote) && $this->_canUseMethod($methodInstance)) {
+                    $this->_assignMethod($methodInstance);
+                    $methods[] = $methodInstance;
                 }
             }
             $this->setData('methods', $methods);
@@ -150,4 +173,36 @@ class Container extends \Magento\Framework\View\Element\Template
         }
         return false;
     }
+
+    /**
+     * Get payment method list.
+     *
+     * @return \Magento\Payment\Api\PaymentMethodListInterface
+     * @deprecated
+     */
+    private function getPaymentMethodList()
+    {
+        if ($this->paymentMethodList === null) {
+            $this->paymentMethodList = ObjectManager::getInstance()->get(
+                \Magento\Payment\Api\PaymentMethodListInterface::class
+            );
+        }
+        return $this->paymentMethodList;
+    }
+
+    /**
+     * Get payment method instance factory.
+     *
+     * @return \Magento\Payment\Model\Method\InstanceFactory
+     * @deprecated
+     */
+    private function getPaymentMethodInstanceFactory()
+    {
+        if ($this->paymentMethodInstanceFactory === null) {
+            $this->paymentMethodInstanceFactory = ObjectManager::getInstance()->get(
+                \Magento\Payment\Model\Method\InstanceFactory::class
+            );
+        }
+        return $this->paymentMethodInstanceFactory;
+    }
 }
diff --git a/app/code/Magento/Payment/Helper/Data.php b/app/code/Magento/Payment/Helper/Data.php
index 78cde93ba6717a85a04feb6a2bec21090d551695..0c5518a5c4c9f98e0e9f615b8df78bc85163abc9 100644
--- a/app/code/Magento/Payment/Helper/Data.php
+++ b/app/code/Magento/Payment/Helper/Data.php
@@ -118,6 +118,7 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
      * @param null|string|bool|int $store
      * @param Quote|null $quote
      * @return AbstractMethod[]
+     * @deprecated
      */
     public function getStoreMethods($store = null, $quote = null)
     {
diff --git a/app/code/Magento/Payment/Model/Method/InstanceFactory.php b/app/code/Magento/Payment/Model/Method/InstanceFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..c273c71e78330df854eabfb4b564675af028cb23
--- /dev/null
+++ b/app/code/Magento/Payment/Model/Method/InstanceFactory.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Model\Method;
+
+use Magento\Payment\Api\Data\PaymentMethodInterface;
+
+/**
+ * Payment method instance factory.
+ */
+class InstanceFactory
+{
+    /**
+     * @var \Magento\Payment\Helper\Data
+     */
+    private $helper;
+
+    /**
+     * @param \Magento\Payment\Helper\Data $helper
+     */
+    public function __construct(
+        \Magento\Payment\Helper\Data $helper
+    ) {
+        $this->helper = $helper;
+    }
+
+    /**
+     * Create payment method instance.
+     *
+     * @param PaymentMethodInterface $paymentMethod
+     * @return \Magento\Payment\Model\MethodInterface
+     */
+    public function create(PaymentMethodInterface $paymentMethod)
+    {
+        $methodInstance = $this->helper->getMethodInstance($paymentMethod->getCode());
+        $methodInstance->setStore($paymentMethod->getStoreId());
+
+        return $methodInstance;
+    }
+}
diff --git a/app/code/Magento/Payment/Model/MethodList.php b/app/code/Magento/Payment/Model/MethodList.php
index d547fe42f332ca4c49f0ff51ac16c0b59e538556..ff1f786c77f6175ab8d78feac5ee7d270a64fc45 100644
--- a/app/code/Magento/Payment/Model/MethodList.php
+++ b/app/code/Magento/Payment/Model/MethodList.php
@@ -6,12 +6,14 @@
 
 namespace Magento\Payment\Model;
 
+use Magento\Framework\App\ObjectManager;
 use Magento\Payment\Model\Method\AbstractMethod;
 
 class MethodList
 {
     /**
      * @var \Magento\Payment\Helper\Data
+     * @deprecated
      */
     protected $paymentHelper;
 
@@ -20,6 +22,16 @@ class MethodList
      */
     protected $methodSpecificationFactory;
 
+    /**
+     * @var \Magento\Payment\Api\PaymentMethodListInterface
+     */
+    private $paymentMethodList;
+
+    /**
+     * @var \Magento\Payment\Model\Method\InstanceFactory
+     */
+    private $paymentMethodInstanceFactory;
+
     /**
      * @param \Magento\Payment\Helper\Data $paymentHelper
      * @param Checks\SpecificationFactory $specificationFactory
@@ -40,14 +52,16 @@ class MethodList
     public function getAvailableMethods(\Magento\Quote\Api\Data\CartInterface $quote = null)
     {
         $store = $quote ? $quote->getStoreId() : null;
-        $methods = [];
-        foreach ($this->paymentHelper->getStoreMethods($store, $quote) as $method) {
-            if ($this->_canUseMethod($method, $quote)) {
-                $method->setInfoInstance($quote->getPayment());
-                $methods[] = $method;
+        $availableMethods = [];
+
+        foreach ($this->getPaymentMethodList()->getActiveList($store) as $method) {
+            $methodInstance = $this->getPaymentMethodInstanceFactory()->create($method);
+            if ($methodInstance->isAvailable($quote) && $this->_canUseMethod($methodInstance, $quote)) {
+                $methodInstance->setInfoInstance($quote->getPayment());
+                $availableMethods[] = $methodInstance;
             }
         }
-        return $methods;
+        return $availableMethods;
     }
 
     /**
@@ -71,4 +85,36 @@ class MethodList
             $quote
         );
     }
+
+    /**
+     * Get payment method list.
+     *
+     * @return \Magento\Payment\Api\PaymentMethodListInterface
+     * @deprecated
+     */
+    private function getPaymentMethodList()
+    {
+        if ($this->paymentMethodList === null) {
+            $this->paymentMethodList = ObjectManager::getInstance()->get(
+                \Magento\Payment\Api\PaymentMethodListInterface::class
+            );
+        }
+        return $this->paymentMethodList;
+    }
+
+    /**
+     * Get payment method instance factory.
+     *
+     * @return \Magento\Payment\Model\Method\InstanceFactory
+     * @deprecated
+     */
+    private function getPaymentMethodInstanceFactory()
+    {
+        if ($this->paymentMethodInstanceFactory === null) {
+            $this->paymentMethodInstanceFactory = ObjectManager::getInstance()->get(
+                \Magento\Payment\Model\Method\InstanceFactory::class
+            );
+        }
+        return $this->paymentMethodInstanceFactory;
+    }
 }
diff --git a/app/code/Magento/Payment/Model/PaymentMethod.php b/app/code/Magento/Payment/Model/PaymentMethod.php
new file mode 100644
index 0000000000000000000000000000000000000000..581c4703f777e1a853dfd15f9afb8c8c7bcc67a6
--- /dev/null
+++ b/app/code/Magento/Payment/Model/PaymentMethod.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Model;
+
+/**
+ * Payment method class.
+ */
+class PaymentMethod implements \Magento\Payment\Api\Data\PaymentMethodInterface
+{
+    /**
+     * @var string
+     */
+    private $code;
+
+    /**
+     * @var string
+     */
+    private $title;
+
+    /**
+     * @var int
+     */
+    private $storeId;
+
+    /**
+     * @var bool
+     */
+    private $isActive;
+
+    /**
+     * @param string $code
+     * @param string $title
+     * @param int $storeId
+     * @param bool $isActive
+     */
+    public function __construct($code, $title, $storeId, $isActive)
+    {
+        $this->code = $code;
+        $this->title = $title;
+        $this->storeId = $storeId;
+        $this->isActive = $isActive;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getCode()
+    {
+        return $this->code;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getStoreId()
+    {
+        return $this->storeId;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getIsActive()
+    {
+        return $this->isActive;
+    }
+}
diff --git a/app/code/Magento/Payment/Model/PaymentMethodList.php b/app/code/Magento/Payment/Model/PaymentMethodList.php
new file mode 100644
index 0000000000000000000000000000000000000000..5968d201ca6869ab9d38327dc422b7f0b935956d
--- /dev/null
+++ b/app/code/Magento/Payment/Model/PaymentMethodList.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Model;
+
+use Magento\Payment\Api\Data\PaymentMethodInterface;
+
+/**
+ * Payment method list class.
+ */
+class PaymentMethodList implements \Magento\Payment\Api\PaymentMethodListInterface
+{
+    /**
+     * @var \Magento\Payment\Api\Data\PaymentMethodInterfaceFactory
+     */
+    private $methodFactory;
+
+    /**
+     * @var \Magento\Payment\Helper\Data
+     */
+    private $helper;
+
+    /**
+     * @param \Magento\Payment\Api\Data\PaymentMethodInterfaceFactory $methodFactory
+     * @param \Magento\Payment\Helper\Data $helper
+     */
+    public function __construct(
+        \Magento\Payment\Api\Data\PaymentMethodInterfaceFactory $methodFactory,
+        \Magento\Payment\Helper\Data $helper
+    ) {
+        $this->methodFactory = $methodFactory;
+        $this->helper = $helper;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getList($storeId)
+    {
+        $methodsCodes = array_keys($this->helper->getPaymentMethods());
+
+        $methodsInstances = array_map(
+            function ($code) {
+                return $this->helper->getMethodInstance($code);
+            },
+            $methodsCodes
+        );
+
+        $methodsInstances = array_filter($methodsInstances, function (MethodInterface $method) {
+            return !($method instanceof \Magento\Payment\Model\Method\Substitution);
+        });
+
+        @uasort(
+            $methodsInstances,
+            function (MethodInterface $a, MethodInterface $b) use ($storeId) {
+                return (int)$a->getConfigData('sort_order', $storeId) - (int)$b->getConfigData('sort_order', $storeId);
+            }
+        );
+
+        $methodList = array_map(
+            function (MethodInterface $methodInstance) use ($storeId) {
+
+                return $this->methodFactory->create([
+                    'code' => (string)$methodInstance->getCode(),
+                    'title' => (string)$methodInstance->getTitle(),
+                    'storeId' => (int)$storeId,
+                    'isActive' => (bool)$methodInstance->isActive($storeId)
+                ]);
+            },
+            $methodsInstances
+        );
+
+        return array_values($methodList);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getActiveList($storeId)
+    {
+        $methodList = array_filter(
+            $this->getList($storeId),
+            function (PaymentMethodInterface $method) {
+                return $method->getIsActive();
+            }
+        );
+
+        return array_values($methodList);
+    }
+}
diff --git a/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/SoapTest.php b/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/SoapTest.php
index b8e1b0dcdf973dd9311c67dceccccbe3ad2f203b..2a3ae9c3063730aa8743b33c44aa831b6664f19c 100644
--- a/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/SoapTest.php
+++ b/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/SoapTest.php
@@ -48,6 +48,7 @@ class SoapTest extends \PHPUnit_Framework_TestCase
             \Magento\Payment\Gateway\Http\ConverterInterface::class
         )->getMockForAbstractClass();
         $this->client = $this->getMockBuilder(\SoapClient::class)
+            ->setMethods(['__setSoapHeaders', '__soapCall', '__getLastRequest'])
             ->disableOriginalConstructor()
             ->getMock();
 
diff --git a/app/code/Magento/Payment/Test/Unit/Model/MethodListTest.php b/app/code/Magento/Payment/Test/Unit/Model/MethodListTest.php
index 915ccddc05c89ac7b3bbbf836aaa80dc7f0f1c4e..872782407c12994e43aa4a026f4a340450b26b88 100644
--- a/app/code/Magento/Payment/Test/Unit/Model/MethodListTest.php
+++ b/app/code/Magento/Payment/Test/Unit/Model/MethodListTest.php
@@ -24,9 +24,14 @@ class MethodListTest extends \PHPUnit_Framework_TestCase
     protected $objectManager;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Payment\Api\PaymentMethodListInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $paymentMethodList;
+
+    /**
+     * @var \Magento\Payment\Model\Method\InstanceFactory|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $paymentHelperMock;
+    private $paymentMethodInstanceFactory;
 
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
@@ -36,17 +41,35 @@ class MethodListTest extends \PHPUnit_Framework_TestCase
     protected function setUp()
     {
         $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->paymentHelperMock = $this->getMock(\Magento\Payment\Helper\Data::class, [], [], '', false);
-        $this->specificationFactoryMock = $this->getMock(
+
+        $this->paymentMethodList = $this->getMockBuilder(\Magento\Payment\Api\PaymentMethodListInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->paymentMethodInstanceFactory = $this->getMockBuilder(
+            \Magento\Payment\Model\Method\InstanceFactory::class
+        )->disableOriginalConstructor()->getMock();
+
+        $this->specificationFactoryMock = $this->getMock(
             \Magento\Payment\Model\Checks\SpecificationFactory::class, [], [], '', false
         );
-        $this->methodList = $this->objectManager->getObject(
+        $this->methodList = $this->objectManager->getObject(
             \Magento\Payment\Model\MethodList::class,
             [
-                'paymentHelper' => $this->paymentHelperMock,
                 'specificationFactory' => $this->specificationFactoryMock
             ]
         );
+
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->methodList,
+            'paymentMethodList',
+            $this->paymentMethodList
+        );
+        $this->objectManager->setBackwardCompatibleProperty(
+            $this->methodList,
+            'paymentMethodInstanceFactory',
+            $this->paymentMethodInstanceFactory
+        );
     }
 
     public function testGetAvailableMethods()
@@ -58,12 +81,15 @@ class MethodListTest extends \PHPUnit_Framework_TestCase
             ->method('getPayment')
             ->will($this->returnValue($this->getMock(\Magento\Quote\Model\Quote\Payment::class, [], [], '', false)));
 
-        $methodMock = $this->getMock(\Magento\Payment\Model\Method\AbstractMethod::class, [], [], '', false);
+        $methodInstanceMock = $this->getMock(\Magento\Payment\Model\Method\AbstractMethod::class, [], [], '', false);
+        $methodInstanceMock->expects($this->once())
+            ->method('isAvailable')
+            ->willReturn(true);
 
         $compositeMock = $this->getMock(\Magento\Payment\Model\Checks\Composite::class, [], [], '', false);
         $compositeMock->expects($this->atLeastOnce())
             ->method('isApplicable')
-            ->with($methodMock, $quoteMock)
+            ->with($methodInstanceMock, $quoteMock)
             ->will($this->returnValue(true));
 
         $this->specificationFactoryMock->expects($this->atLeastOnce())
@@ -76,18 +102,19 @@ class MethodListTest extends \PHPUnit_Framework_TestCase
             ])
             ->will($this->returnValue($compositeMock));
 
-        $storeMethods = [$methodMock];
-
-        $this->paymentHelperMock->expects($this->once())
-            ->method('getStoreMethods')
-            ->with($storeId, $quoteMock)
-            ->will($this->returnValue($storeMethods));
+        $methodMock = $this->getMockForAbstractClass(\Magento\Payment\Api\Data\PaymentMethodInterface::class);
+        $this->paymentMethodList->expects($this->once())
+            ->method('getActiveList')
+            ->willReturn([$methodMock]);
+        $this->paymentMethodInstanceFactory->expects($this->once())
+            ->method('create')
+            ->willReturn($methodInstanceMock);
 
-        $methodMock->expects($this->atLeastOnce())
+        $methodInstanceMock->expects($this->atLeastOnce())
             ->method('setInfoInstance')
             ->with($this->getMock(\Magento\Quote\Model\Quote\Payment::class, [], [], '', false))
             ->will($this->returnSelf());
 
-        $this->assertEquals([$methodMock], $this->methodList->getAvailableMethods($quoteMock));
+        $this->assertEquals([$methodInstanceMock], $this->methodList->getAvailableMethods($quoteMock));
     }
 }
diff --git a/app/code/Magento/Payment/Test/Unit/Model/PaymentMethodListTest.php b/app/code/Magento/Payment/Test/Unit/Model/PaymentMethodListTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c41e5ac2a1aac326970c6a7a2d39eab30b8a8bcc
--- /dev/null
+++ b/app/code/Magento/Payment/Test/Unit/Model/PaymentMethodListTest.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Test\Unit\Model;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+
+/**
+ * Class PaymentMethodListTest.
+ */
+class PaymentMethodListTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManagerHelper
+     */
+    private $objectManagerHelper;
+
+    /**
+     * @var \Magento\Payment\Model\PaymentMethodList|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $paymentMethodList;
+
+    /**
+     * @var \Magento\Payment\Api\Data\PaymentMethodInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $methodFactoryMock;
+
+    /**
+     * @var \Magento\Payment\Helper\Data|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $helperMock;
+
+    /**
+     * Setup.
+     *
+     * @return void
+     */
+    public function setUp()
+    {
+        $this->methodFactoryMock = $this->getMockBuilder(\Magento\Payment\Api\Data\PaymentMethodInterfaceFactory::class)
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->helperMock = $this->getMockBuilder(\Magento\Payment\Helper\Data::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->paymentMethodList = $this->objectManagerHelper->getObject(
+            \Magento\Payment\Model\PaymentMethodList::class,
+            [
+                'methodFactory' => $this->methodFactoryMock,
+                'helper' => $this->helperMock
+            ]
+        );
+    }
+
+    /**
+     * Setup getList method.
+     *
+     * @param array $paymentMethodConfig
+     * @param array $methodInstancesMap
+     * @return void
+     */
+    private function setUpGetList($paymentMethodConfig, $methodInstancesMap)
+    {
+        $this->helperMock->expects($this->once())
+            ->method('getPaymentMethods')
+            ->willReturn($paymentMethodConfig);
+        $this->helperMock->expects($this->any())
+            ->method('getMethodInstance')
+            ->willReturnMap($methodInstancesMap);
+
+        $this->methodFactoryMock->expects($this->any())
+            ->method('create')
+            ->willReturnCallback(function ($data) {
+                $paymentMethod = $this->getMockBuilder(\Magento\Payment\Api\Data\PaymentMethodInterface::class)
+                    ->getMockForAbstractClass();
+                $paymentMethod->expects($this->any())
+                    ->method('getCode')
+                    ->willReturn($data['code']);
+                $paymentMethod->expects($this->any())
+                    ->method('getIsActive')
+                    ->willReturn($data['isActive']);
+
+                return $paymentMethod;
+            });
+    }
+
+    /**
+     * Test getList.
+     *
+     * @param int $storeId
+     * @param array $paymentMethodConfig
+     * @param array $methodInstancesMap
+     * @param array $expected
+     * @return void
+     *
+     * @dataProvider getListDataProvider
+     */
+    public function testGetList($storeId, $paymentMethodConfig, $methodInstancesMap, $expected)
+    {
+        $this->setUpGetList($paymentMethodConfig, $methodInstancesMap);
+
+        $codes = array_map(
+            function ($method) {
+                return $method->getCode();
+            },
+            $this->paymentMethodList->getList($storeId)
+        );
+
+        $this->assertEquals($expected, $codes);
+    }
+
+    /**
+     * Data provider for getList.
+     *
+     * @return array
+     */
+    public function getListDataProvider()
+    {
+        return [
+            [
+                1,
+                ['method_code_1' => [], 'method_code_2' => []],
+                [
+                    ['method_code_1', $this->mockPaymentMethodInstance(1, 10, 'method_code_1', 'title', true)],
+                    ['method_code_2', $this->mockPaymentMethodInstance(1, 5, 'method_code_2', 'title', true)]
+                ],
+                ['method_code_2', 'method_code_1']
+            ]
+        ];
+    }
+
+    /**
+     * Test getActiveList.
+     *
+     * @param int $storeId
+     * @param array $paymentMethodConfig
+     * @param array $methodInstancesMap
+     * @param array $expected
+     * @return void
+     *
+     * @dataProvider getActiveListDataProvider
+     */
+    public function testGetActiveList($storeId, $paymentMethodConfig, $methodInstancesMap, $expected)
+    {
+        $this->setUpGetList($paymentMethodConfig, $methodInstancesMap);
+
+        $codes = array_map(
+            function ($method) {
+                return $method->getCode();
+            },
+            $this->paymentMethodList->getActiveList($storeId)
+        );
+
+        $this->assertEquals($expected, $codes);
+    }
+
+    /**
+     * Data provider for getActiveList.
+     *
+     * @return array
+     */
+    public function getActiveListDataProvider()
+    {
+        return [
+            [
+                1,
+                ['method_code_1' => [], 'method_code_2' => []],
+                [
+                    ['method_code_1', $this->mockPaymentMethodInstance(1, 10, 'method_code_1', 'title', false)],
+                    ['method_code_2', $this->mockPaymentMethodInstance(1, 5, 'method_code_2', 'title', true)]
+                ],
+                ['method_code_2']
+            ]
+        ];
+    }
+
+    /**
+     * Mock payment method instance.
+     *
+     * @param int $storeId
+     * @param int $sortOrder
+     * @param string $code
+     * @param string $title
+     * @param bool $isActive
+     * @return \PHPUnit_Framework_MockObject_MockObject
+     */
+    private function mockPaymentMethodInstance($storeId, $sortOrder, $code, $title, $isActive)
+    {
+        $paymentMethodInstance = $this->getMockBuilder(\Magento\Payment\Model\Method\AbstractMethod::class)
+            ->setMethods(['getCode', 'getTitle', 'isActive', 'getConfigData'])
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $paymentMethodInstance->expects($this->any())
+            ->method('getConfigData')
+            ->willReturnMap([
+                ['sort_order', $storeId, $sortOrder]
+            ]);
+        $paymentMethodInstance->expects($this->any())
+            ->method('getCode')
+            ->willReturn($code);
+        $paymentMethodInstance->expects($this->any())
+            ->method('getTitle')
+            ->willReturn($title);
+        $paymentMethodInstance->expects($this->any())
+            ->method('isActive')
+            ->willReturn($isActive);
+
+        return $paymentMethodInstance;
+    }
+}
diff --git a/app/code/Magento/Payment/etc/di.xml b/app/code/Magento/Payment/etc/di.xml
index 73f8e2a76334be8c0bde6f1a2c69a063818ca928..c12c2d2cfd51c2be7688aacef7b023e618f2f77a 100644
--- a/app/code/Magento/Payment/etc/di.xml
+++ b/app/code/Magento/Payment/etc/di.xml
@@ -6,6 +6,8 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
+    <preference for="Magento\Payment\Api\Data\PaymentMethodInterface" type="Magento\Payment\Model\PaymentMethod"/>
+    <preference for="Magento\Payment\Api\PaymentMethodListInterface" type="Magento\Payment\Model\PaymentMethodList"/>
     <preference for="Magento\Payment\Gateway\Validator\ResultInterface" type="Magento\Payment\Gateway\Validator\Result"/>
     <preference for="Magento\Payment\Gateway\ConfigFactoryInterface" type="Magento\Payment\Gateway\Config\ConfigFactory" />
     <preference for="Magento\Payment\Gateway\Command\CommandManagerPoolInterface" type="Magento\Payment\Gateway\Command\CommandManagerPool" />
diff --git a/app/code/Magento/Payment/view/frontend/web/js/view/payment/iframe.js b/app/code/Magento/Payment/view/frontend/web/js/view/payment/iframe.js
index c8a6fef58d31ea24dcb930b5e63c6912f8738eff..7d01c195791e482618ae2073a82564cb14aaf339 100644
--- a/app/code/Magento/Payment/view/frontend/web/js/view/payment/iframe.js
+++ b/app/code/Magento/Payment/view/frontend/web/js/view/payment/iframe.js
@@ -154,6 +154,7 @@ define(
              */
             clearTimeout: function () {
                 clearTimeout(this.timeoutId);
+                this.fail();
 
                 return this;
             },
diff --git a/app/code/Magento/Paypal/Block/Adminhtml/System/Config/Fieldset/Payment.php b/app/code/Magento/Paypal/Block/Adminhtml/System/Config/Fieldset/Payment.php
index 4abe12cbc3715d5192a6b1a4f0a2ae44685a368d..725ebb2282418e9e6747c3fc28c72ff600f31e07 100644
--- a/app/code/Magento/Paypal/Block/Adminhtml/System/Config/Fieldset/Payment.php
+++ b/app/code/Magento/Paypal/Block/Adminhtml/System/Config/Fieldset/Payment.php
@@ -78,18 +78,10 @@ class Payment extends \Magento\Config\Block\System\Config\Form\Fieldset
      */
     protected function _getHeaderTitleHtml($element)
     {
-        $html = '<div class="config-heading" ><div class="heading"><strong>' . $element->getLegend();
+        $html = '<div class="config-heading" >';
 
         $groupConfig = $element->getGroup();
 
-        $html .= '</strong>';
-
-        if ($element->getComment()) {
-            $html .= '<span class="heading-intro">' . $element->getComment() . '</span>';
-        }
-        $html .= '<div class="config-alt"></div>';
-        $html .= '</div>';
-
         $disabledAttributeString = $this->_isPaymentEnabled($element) ? '' : ' disabled="disabled"';
         $disabledClassString = $this->_isPaymentEnabled($element) ? '' : ' disabled';
         $htmlId = $element->getHtmlId();
@@ -122,6 +114,13 @@ class Payment extends \Magento\Config\Block\System\Config\Form\Fieldset
             ) . '</a>';
         }
 
+        $html .= '</div>';
+        $html .= '<div class="heading"><strong>' . $element->getLegend() . '</strong>';
+
+        if ($element->getComment()) {
+            $html .= '<span class="heading-intro">' . $element->getComment() . '</span>';
+        }
+        $html .= '<div class="config-alt"></div>';
         $html .= '</div></div>';
 
         return $html;
diff --git a/app/code/Magento/Paypal/Helper/Data.php b/app/code/Magento/Paypal/Helper/Data.php
index 0ecde3bdc5697488e33e3c027a6d0c9a2439d03d..ea69d2ffcf0794f09497d66444d35600a3d8e077 100644
--- a/app/code/Magento/Paypal/Helper/Data.php
+++ b/app/code/Magento/Paypal/Helper/Data.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Paypal\Helper;
 
+use Magento\Framework\App\ObjectManager;
+use Magento\Payment\Model\Method\AbstractMethod;
 use Magento\Paypal\Model\Billing\Agreement\MethodInterface;
 
 /**
@@ -42,6 +44,16 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
      */
     private $configFactory;
 
+    /**
+     * @var \Magento\Payment\Api\PaymentMethodListInterface
+     */
+    private $paymentMethodList;
+
+    /**
+     * @var \Magento\Payment\Model\Method\InstanceFactory
+     */
+    private $paymentMethodInstanceFactory;
+
     /**
      * @param \Magento\Framework\App\Helper\Context $context
      * @param \Magento\Payment\Helper\Data $paymentData
@@ -92,12 +104,20 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
      */
     public function getBillingAgreementMethods($store = null, $quote = null)
     {
-        $result = [];
-        foreach ($this->_paymentData->getStoreMethods($store, $quote) as $method) {
-            if ($method instanceof MethodInterface) {
-                $result[] = $method;
+        $activeMethods = array_map(
+            function (\Magento\Payment\Api\Data\PaymentMethodInterface $method) {
+                return $this->getPaymentMethodInstanceFactory()->create($method);
+            },
+            $this->getPaymentMethodList()->getActiveList($store)
+        );
+
+        $result = array_filter(
+            $activeMethods,
+            function (AbstractMethod $method) use ($quote) {
+                return $method->isAvailable($quote) && $method instanceof MethodInterface;
             }
-        }
+        );
+
         return $result;
     }
 
@@ -118,4 +138,36 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
         }
         return $txnId;
     }
+
+    /**
+     * Get payment method list.
+     *
+     * @return \Magento\Payment\Api\PaymentMethodListInterface
+     * @deprecated
+     */
+    private function getPaymentMethodList()
+    {
+        if ($this->paymentMethodList === null) {
+            $this->paymentMethodList = ObjectManager::getInstance()->get(
+                \Magento\Payment\Api\PaymentMethodListInterface::class
+            );
+        }
+        return $this->paymentMethodList;
+    }
+
+    /**
+     * Get payment method instance factory.
+     *
+     * @return \Magento\Payment\Model\Method\InstanceFactory
+     * @deprecated
+     */
+    private function getPaymentMethodInstanceFactory()
+    {
+        if ($this->paymentMethodInstanceFactory === null) {
+            $this->paymentMethodInstanceFactory = ObjectManager::getInstance()->get(
+                \Magento\Payment\Model\Method\InstanceFactory::class
+            );
+        }
+        return $this->paymentMethodInstanceFactory;
+    }
 }
diff --git a/app/code/Magento/Paypal/Model/Config.php b/app/code/Magento/Paypal/Model/Config.php
index e02615d24ad3d2fbd4e90a768ce9594531acc602..0af8b18355ec32b045c4e609137cb0eed7944373 100644
--- a/app/code/Magento/Paypal/Model/Config.php
+++ b/app/code/Magento/Paypal/Model/Config.php
@@ -866,7 +866,9 @@ class Config extends AbstractConfig
      */
     public function getExpressCheckoutStartUrl($token)
     {
-        return $this->getPaypalUrl(['cmd' => '_express-checkout', 'token' => $token]);
+        return sprintf('https://www.%spaypal.com/checkoutnow/2%s',
+            $this->getValue('sandboxFlag') ? 'sandbox.' : '',
+            '?token=' . urlencode($token));
     }
 
     /**
diff --git a/app/code/Magento/Paypal/Model/Express.php b/app/code/Magento/Paypal/Model/Express.php
index d377e8ed626e15a65a3772041bb837328a4942f3..db1ecdf6b33799673cd22926f5d9dd1b7999f965 100644
--- a/app/code/Magento/Paypal/Model/Express.php
+++ b/app/code/Magento/Paypal/Model/Express.php
@@ -672,19 +672,13 @@ class Express extends \Magento\Payment\Model\Method\AbstractMethod
         
         $additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
 
-        if (
-            !is_array($additionalData)
-            || !isset($additionalData[ExpressCheckout::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT])
-        ) {
+        if (!is_array($additionalData)) {
             return $this;
         }
 
-        $this->getInfoInstance()
-            ->setAdditionalInformation(
-                ExpressCheckout::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT,
-                $additionalData[ExpressCheckout::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT]
-            );
-        
+        foreach ($additionalData as $key => $value) {
+            $this->getInfoInstance()->setAdditionalInformation($key, $value);
+        }
         return $this;
     }
 
diff --git a/app/code/Magento/Paypal/Model/Payflow/Transparent.php b/app/code/Magento/Paypal/Model/Payflow/Transparent.php
index f0383dffc9b2443f96bf903b1b423306ff09b4ea..b5803c5ace3925b75e81df43992f714a74ed9905 100644
--- a/app/code/Magento/Paypal/Model/Payflow/Transparent.php
+++ b/app/code/Magento/Paypal/Model/Payflow/Transparent.php
@@ -166,6 +166,9 @@ class Transparent extends Payflowpro implements TransparentInterface
         $request->setData('trxtype', self::TRXTYPE_AUTH_ONLY);
         $request->setData('origid', $token);
         $request->setData('amt', $this->formatPrice($amount));
+        $request->setData('currency', $order->getBaseCurrencyCode());
+        $request->setData('taxamt', $this->formatPrice($order->getBaseTaxAmount()));
+        $request->setData('freightamt', $this->formatPrice($order->getBaseShippingAmount()));
 
         $response = $this->postRequest($request, $this->getConfig());
         $this->processErrors($response);
diff --git a/app/code/Magento/Paypal/Test/Unit/Helper/DataTest.php b/app/code/Magento/Paypal/Test/Unit/Helper/DataTest.php
index fa0620a36a681eae6a48413044c6784876aaa889..239c5d6cda746d62fdc438791bb29bfc43f61c19 100644
--- a/app/code/Magento/Paypal/Test/Unit/Helper/DataTest.php
+++ b/app/code/Magento/Paypal/Test/Unit/Helper/DataTest.php
@@ -8,9 +8,14 @@ namespace Magento\Paypal\Test\Unit\Helper;
 class DataTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Payment\Api\PaymentMethodListInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_paymentDataMock;
+    private $paymentMethodList;
+
+    /**
+     * @var \Magento\Payment\Model\Method\InstanceFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $paymentMethodInstanceFactory;
 
     /**
      * @var \Magento\Paypal\Model\Config | \PHPUnit_Framework_MockObject_MockObject
@@ -24,11 +29,13 @@ class DataTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->_paymentDataMock = $this->getMockBuilder(
-            \Magento\Payment\Helper\Data::class
-        )->disableOriginalConstructor()->setMethods(
-            ['getStoreMethods', 'getPaymentMethods']
-        )->getMock();
+        $this->paymentMethodList = $this->getMockBuilder(\Magento\Payment\Api\PaymentMethodListInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->paymentMethodInstanceFactory = $this->getMockBuilder(
+            \Magento\Payment\Model\Method\InstanceFactory::class
+        )->disableOriginalConstructor()->getMock();
 
         $this->configMock = $this->getMock(
             \Magento\Paypal\Model\Config::class,
@@ -48,32 +55,41 @@ class DataTest extends \PHPUnit_Framework_TestCase
         $this->_helper = $objectManager->getObject(
             \Magento\Paypal\Helper\Data::class,
             [
-                'paymentData' => $this->_paymentDataMock,
                 'methodCodes' => ['expressCheckout' => 'paypal_express', 'hostedPro' => 'hosted_pro'],
                 'configFactory' => $configMockFactory
             ]
         );
+
+        $objectManager->setBackwardCompatibleProperty(
+            $this->_helper,
+            'paymentMethodList',
+            $this->paymentMethodList
+        );
+        $objectManager->setBackwardCompatibleProperty(
+            $this->_helper,
+            'paymentMethodInstanceFactory',
+            $this->paymentMethodInstanceFactory
+        );
     }
 
     /**
      * @dataProvider getBillingAgreementMethodsDataProvider
      * @param $store
      * @param $quote
-     * @param $paymentMethods
+     * @param $paymentMethodsMap
      * @param $expectedResult
      */
-    public function testGetBillingAgreementMethods($store, $quote, $paymentMethods, $expectedResult)
+    public function testGetBillingAgreementMethods($store, $quote, $paymentMethodsMap, $expectedResult)
     {
-        $this->_paymentDataMock->expects(
-            $this->any()
-        )->method(
-            'getStoreMethods'
-        )->with(
-            $store,
-            $quote
-        )->will(
-            $this->returnValue($paymentMethods)
-        );
+        $this->paymentMethodList->expects(static::once())
+            ->method('getActiveList')
+            ->with($store)
+            ->willReturn(array_column($paymentMethodsMap, 0));
+
+        $this->paymentMethodInstanceFactory->expects(static::any())
+            ->method('create')
+            ->willReturnMap($paymentMethodsMap);
+
         $this->assertEquals($expectedResult, $this->_helper->getBillingAgreementMethods($store, $quote));
     }
 
@@ -84,16 +100,40 @@ class DataTest extends \PHPUnit_Framework_TestCase
     {
         $quoteMock = $this->getMockBuilder(
             \Magento\Quote\Model\Quote::class
-        )->disableOriginalConstructor()->setMethods(
-            null
-        );
-        $methodInterfaceMock = $this->getMockBuilder(
-            \Magento\Paypal\Model\Billing\Agreement\MethodInterface::class
+        )->disableOriginalConstructor()->getMock();
+
+        $methodMock = $this->getMockBuilder(
+            \Magento\Payment\Api\Data\PaymentMethodInterface::class
         )->getMock();
 
+        $agreementMethodInstanceMock = $this->getMockBuilder(
+            \Magento\Paypal\Model\Method\Agreement::class
+        )->disableOriginalConstructor()->getMock();
+        $agreementMethodInstanceMock->expects($this->any())
+            ->method('isAvailable')
+            ->willReturn(true);
+
+        $methodInstanceMock = $this->getMockBuilder(
+            \Magento\Payment\Model\Method\Cc::class
+        )->disableOriginalConstructor()->getMock();
+
         return [
-            ['1', $quoteMock, [$methodInterfaceMock], [$methodInterfaceMock]],
-            ['1', $quoteMock, [new \StdClass()], []]
+            [
+                '1',
+                $quoteMock,
+                [
+                    [$methodMock, $agreementMethodInstanceMock]
+                ],
+                [$agreementMethodInstanceMock]
+            ],
+            [
+                '1',
+                $quoteMock,
+                [
+                    [$methodMock, $methodInstanceMock]
+                ],
+                []
+            ]
         ];
     }
 
diff --git a/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php b/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php
index 33065cc22713bcb654f8304505717288a9f21e0b..9816c37fa01267fa1e1952af91c76bab1fd4cf5c 100644
--- a/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php
+++ b/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php
@@ -182,7 +182,9 @@ class ExpressTest extends \PHPUnit_Framework_TestCase
         $data = new DataObject(
             [
                 PaymentInterface::KEY_ADDITIONAL_DATA => [
-                    Express\Checkout::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT => $transportValue
+                    Express\Checkout::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT => $transportValue,
+                    Express\Checkout::PAYMENT_INFO_TRANSPORT_PAYER_ID => $transportValue,
+                    Express\Checkout::PAYMENT_INFO_TRANSPORT_TOKEN => $transportValue
                 ]
             ]
         );
@@ -202,11 +204,12 @@ class ExpressTest extends \PHPUnit_Framework_TestCase
 
         $this->parentAssignDataExpectation($data);
 
-        $paymentInfo->expects(static::once())
+        $paymentInfo->expects(static::exactly(3))
             ->method('setAdditionalInformation')
-            ->with(
-                Express\Checkout::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT,
-                $transportValue
+            ->withConsecutive(
+                [Express\Checkout::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT, $transportValue],
+                [Express\Checkout::PAYMENT_INFO_TRANSPORT_PAYER_ID, $transportValue],
+                [Express\Checkout::PAYMENT_INFO_TRANSPORT_TOKEN, $transportValue]
             );
 
         $this->_model->assignData($data);
diff --git a/app/code/Magento/Paypal/Test/Unit/Model/Payflow/TransparentTest.php b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/TransparentTest.php
index a107918d16513b2fdce133e43aef00c5109798c8..2d757147cec6a89dc1b6b6b28f283fd29b98f640 100644
--- a/app/code/Magento/Paypal/Test/Unit/Model/Payflow/TransparentTest.php
+++ b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/TransparentTest.php
@@ -122,7 +122,7 @@ class TransparentTest extends \PHPUnit_Framework_TestCase
         $this->orderMock = $this->getMockBuilder(\Magento\Sales\Model\Order::class)
             ->setMethods([
                 'getCustomerId', 'getBillingAddress', 'getShippingAddress', 'getCustomerEmail',
-                'getId', 'getIncrementId'
+                'getId', 'getIncrementId', 'getBaseCurrencyCode'
             ])
             ->disableOriginalConstructor()
             ->getMock();
@@ -164,6 +164,9 @@ class TransparentTest extends \PHPUnit_Framework_TestCase
         $this->paymentMock->expects($this->once())
             ->method('getOrder')
             ->willReturn($this->orderMock);
+        $this->orderMock->expects($this->once())
+            ->method('getBaseCurrencyCode')
+            ->willReturn('USD');
         $this->orderMock->expects($this->once())
             ->method('getBillingAddress')
             ->willReturn($this->addressBillingMock);
diff --git a/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro.xml b/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro.xml
index b567ac87c4fe253b7b0e6423fb7e25f575521462..98f340f0a271135b241bcdc9a90f2e195f3d76b5 100644
--- a/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro.xml
+++ b/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro.xml
@@ -84,7 +84,7 @@
                 </requires>
             </field>
             <field id="payflowpro_cc_vault_active" translate="label" type="select" sortOrder="22" showInDefault="1" showInWebsite="1" showInStore="0">
-                <label>Vault enabled</label>
+                <label>Vault Enabled</label>
                 <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                 <config_path>payment/payflowpro_cc_vault/active</config_path>
                 <attribute type="shared">1</attribute>
diff --git a/app/code/Magento/Paypal/view/adminhtml/web/styles.css b/app/code/Magento/Paypal/view/adminhtml/web/styles.css
index 9e7cfb2afc18e570c18fdc3fe96920606cbe255a..9119a2e317fb75062e74a9e6543732645fab76d5 100644
--- a/app/code/Magento/Paypal/view/adminhtml/web/styles.css
+++ b/app/code/Magento/Paypal/view/adminhtml/web/styles.css
@@ -14,12 +14,11 @@
 .payflow-settings-notice { border:1px solid #d1d0ce;padding:0 10px;margin: 0;}
 .payflow-settings-notice .important-label {color:#f00;}
 .payflow-settings-notice ul.options-list {list-style:disc;padding:0 2em;}
-.paypal-express-section .heading {display: inline-block; background: url("images/pp-logo-200px.png") no-repeat 0 50% / 18rem auto; padding-left: 20rem;}
-.paypal-express-section .button-container {display: inline-block; float: right;}
-.paypal-express-section .config-alt {background: url("images/pp-alt.png") no-repeat; height: 26px; margin: .5rem 0 0; width: 158px;}
+.paypal-express-section .heading {background: url("images/pp-logo-200px.png") no-repeat 0 50% / 18rem auto; padding-left: 20rem;}
+.paypal-express-section .button-container {float: right;}
+.paypal-express-section .config-alt {background: url("images/pp-alt.png") no-repeat; height: 26px; margin: 0.5rem 0 0; width: 158px;}
 .paypal-express-section .link-more {margin-left: 5px;}
-.paypal-other-section .heading {display: inline-block;}
-.paypal-other-section .button-container {display: inline-block; float: right; margin: 1rem 0 0 !important;}
+.paypal-other-section .button-container {float: right; margin: 1rem 0 0 !important;}
 .paypal-other-section > .entry-edit-head > a::before {left: auto !important; right: 1.3rem !important;}
 .paypal-all-in-one-section > .entry-edit-head {background: url("images/AM_mc_vs_dc_ae.jpg") no-repeat scroll 0 50% / 18rem auto; padding-left: 18rem;}
 .paypal-gateways-section > .entry-edit-head {background: url("images/pp-payflow-mark.png") no-repeat scroll 0 50% / 18rem auto; padding-left: 18rem;}
diff --git a/app/code/Magento/Sales/Api/Data/CommentInterface.php b/app/code/Magento/Sales/Api/Data/CommentInterface.php
index fcab786319340535c1c6309c884a678a91341d90..6e447e72ab1c21330ecd56ed81c1fd7bd5114865 100644
--- a/app/code/Magento/Sales/Api/Data/CommentInterface.php
+++ b/app/code/Magento/Sales/Api/Data/CommentInterface.php
@@ -23,14 +23,14 @@ interface CommentInterface
     const COMMENT = 'comment';
 
     /**
-     * Gets the comment for the invoice.
+     * Gets the comment text.
      *
      * @return string Comment.
      */
     public function getComment();
 
     /**
-     * Sets the comment for the invoice.
+     * Sets the comment text.
      *
      * @param string $comment
      * @return $this
@@ -38,14 +38,14 @@ interface CommentInterface
     public function setComment($comment);
 
     /**
-     * Gets the is-visible-on-storefront flag value for the invoice.
+     * Gets the is-visible-on-storefront flag value for the comment.
      *
      * @return int Is-visible-on-storefront flag value.
      */
     public function getIsVisibleOnFront();
 
     /**
-     * Sets the is-visible-on-storefront flag value for the invoice.
+     * Sets the is-visible-on-storefront flag value for the comment.
      *
      * @param int $isVisibleOnFront
      * @return $this
diff --git a/app/code/Magento/Sales/Api/Data/CreditmemoCommentCreationInterface.php b/app/code/Magento/Sales/Api/Data/CreditmemoCommentCreationInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..283e8600738e731ee498a444309adc36c8123d21
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Data/CreditmemoCommentCreationInterface.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Data;
+
+use Magento\Framework\Api\ExtensibleDataInterface;
+
+/**
+ * Interface CreditmemoCommentCreationInterface
+ *
+ * @api
+ */
+interface CreditmemoCommentCreationInterface extends ExtensibleDataInterface, CommentInterface
+{
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\CreditmemoCommentCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes();
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationExtensionInterface $extensionAttributes
+    );
+}
diff --git a/app/code/Magento/Sales/Api/Data/CreditmemoCreationArgumentsInterface.php b/app/code/Magento/Sales/Api/Data/CreditmemoCreationArgumentsInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..2735a94a777f095ed5f4b2c97e114fe75085ddc8
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Data/CreditmemoCreationArgumentsInterface.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Data;
+
+/**
+ * Interface CreditmemoCreationArgumentsInterface
+ *
+ * @api
+ */
+interface CreditmemoCreationArgumentsInterface
+{
+    /**
+     * Gets the credit memo shipping amount.
+     *
+     * @return float|null Credit memo shipping amount.
+     */
+    public function getShippingAmount();
+
+    /**
+     * Gets the credit memo positive adjustment.
+     *
+     * @return float|null Credit memo positive adjustment.
+     */
+    public function getAdjustmentPositive();
+
+    /**
+     * Gets the credit memo negative adjustment.
+     *
+     * @return float|null Credit memo negative adjustment.
+     */
+    public function getAdjustmentNegative();
+
+    /**
+     * Sets the credit memo shipping amount.
+     *
+     * @param float $amount
+     * @return $this
+     */
+    public function setShippingAmount($amount);
+
+    /**
+     * Sets the credit memo positive adjustment.
+     *
+     * @param float $amount
+     * @return $this
+     */
+    public function setAdjustmentPositive($amount);
+
+    /**
+     * Sets the credit memo negative adjustment.
+     *
+     * @param float $amount
+     * @return $this
+     */
+    public function setAdjustmentNegative($amount);
+
+    /**
+     * Gets existing extension attributes.
+     *
+     * @return \Magento\Sales\Api\Data\CreditmemoCreationArgumentsExtensionInterface|null
+     */
+    public function getExtensionAttributes();
+
+    /**
+     * Sets extension attributes.
+     *
+     * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsExtensionInterface $extensionAttributes
+     *
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsExtensionInterface $extensionAttributes
+    );
+}
diff --git a/app/code/Magento/Sales/Api/Data/CreditmemoItemCreationInterface.php b/app/code/Magento/Sales/Api/Data/CreditmemoItemCreationInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..1cd5f3c43be33aa555780af662013a7dda9838d4
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Data/CreditmemoItemCreationInterface.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Data;
+
+use Magento\Framework\Api\ExtensibleDataInterface;
+
+/**
+ * Interface CreditmemoItemCreationInterface
+ * @api
+ */
+interface CreditmemoItemCreationInterface extends LineItemInterface, ExtensibleDataInterface
+{
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\CreditmemoItemCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes();
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\CreditmemoItemCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\CreditmemoItemCreationExtensionInterface $extensionAttributes
+    );
+}
diff --git a/app/code/Magento/Sales/Api/Exception/CouldNotRefundExceptionInterface.php b/app/code/Magento/Sales/Api/Exception/CouldNotRefundExceptionInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..dee24735af620f08fdedd21f2c95d2d778235959
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Exception/CouldNotRefundExceptionInterface.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Exception;
+
+/**
+ * @api
+ */
+interface CouldNotRefundExceptionInterface
+{
+}
diff --git a/app/code/Magento/Sales/Api/RefundInvoiceInterface.php b/app/code/Magento/Sales/Api/RefundInvoiceInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..dc86ccbb58006b9d8417776ecf731151ea5225da
--- /dev/null
+++ b/app/code/Magento/Sales/Api/RefundInvoiceInterface.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api;
+
+/**
+ * Interface RefundInvoiceInterface
+ *
+ * @api
+ */
+interface RefundInvoiceInterface
+{
+    /**
+     * Create refund for invoice
+     *
+     * @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
+     */
+    public function execute(
+        $invoiceId,
+        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/Api/RefundOrderInterface.php b/app/code/Magento/Sales/Api/RefundOrderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..20a782de421989abfa2c1466c7cd9675a6b20008
--- /dev/null
+++ b/app/code/Magento/Sales/Api/RefundOrderInterface.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api;
+
+/**
+ * Interface RefundOrderInterface
+ *
+ * @api
+ */
+interface RefundOrderInterface
+{
+    /**
+     * Create offline refund for order
+     *
+     * @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
+     */
+    public function execute(
+        $orderId,
+        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/Block/Adminhtml/Order/Create/Billing/Method/Form.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Billing/Method/Form.php
index 9a910e48ec0f2e8344c35795dd544cfe9b1dc506..892faf66140180eb791d4bd8ff25c4b4c48ed930 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Billing/Method/Form.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Billing/Method/Form.php
@@ -25,16 +25,18 @@ class Form extends \Magento\Payment\Block\Form\Container
      * @param \Magento\Payment\Model\Checks\SpecificationFactory $methodSpecificationFactory
      * @param \Magento\Backend\Model\Session\Quote $sessionQuote
      * @param array $data
+     * @param array $additionalChecks
      */
     public function __construct(
         \Magento\Framework\View\Element\Template\Context $context,
         \Magento\Payment\Helper\Data $paymentHelper,
         \Magento\Payment\Model\Checks\SpecificationFactory $methodSpecificationFactory,
         \Magento\Backend\Model\Session\Quote $sessionQuote,
-        array $data = []
+        array $data = [],
+        array $additionalChecks = []
     ) {
         $this->_sessionQuote = $sessionQuote;
-        parent::__construct($context, $paymentHelper, $methodSpecificationFactory, $data);
+        parent::__construct($context, $paymentHelper, $methodSpecificationFactory, $data, $additionalChecks);
     }
 
     /**
diff --git a/app/code/Magento/Sales/Exception/CouldNotRefundException.php b/app/code/Magento/Sales/Exception/CouldNotRefundException.php
new file mode 100644
index 0000000000000000000000000000000000000000..59ef4d18b442eda80a5c72c66282c855ca878bd1
--- /dev/null
+++ b/app/code/Magento/Sales/Exception/CouldNotRefundException.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Exception;
+
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Sales\Api\Exception\CouldNotRefundExceptionInterface;
+
+/**
+ * Class CouldNotRefundException
+ */
+class CouldNotRefundException extends LocalizedException implements CouldNotRefundExceptionInterface
+{
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php
index 02b2826f14f6e4d320e7d5b7ad3a2c9b41ec6710..fa7dd86dbef19568afb2ff84e650518bc629d503 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php
@@ -532,11 +532,24 @@ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInt
      */
     public function isLast()
     {
-        foreach ($this->getAllItems() as $item) {
+        $items = $this->getAllItems();
+        foreach ($items as $item) {
             if (!$item->isLast()) {
                 return false;
             }
         }
+
+        if (empty($items)) {
+            $order = $this->getOrder();
+            if ($order) {
+                foreach ($order->getItems() as $orderItem) {
+                    if ($orderItem->canRefund()) {
+                        return false;
+                    }
+                }
+            }
+        }
+
         return true;
     }
 
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/CommentCreation.php b/app/code/Magento/Sales/Model/Order/Creditmemo/CommentCreation.php
new file mode 100644
index 0000000000000000000000000000000000000000..b110b2dbd3986bae566914eef3e164b2410939f3
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/CommentCreation.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo;
+
+use Magento\Sales\Api\Data\CreditmemoCommentCreationInterface;
+
+/**
+ * Class CommentCreation
+ */
+class CommentCreation implements CreditmemoCommentCreationInterface
+{
+    /**
+     * @var \Magento\Sales\Api\Data\CreditmemoCommentCreationExtensionInterface
+     */
+    private $extensionAttributes;
+
+    /**
+     * @var string
+     */
+    private $comment;
+
+    /**
+     * @var int
+     */
+    private $isVisibleOnFront;
+
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\CreditmemoCommentCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+        return $this;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getComment()
+    {
+        return $this->comment;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function setComment($comment)
+    {
+        $this->comment = $comment;
+        return $this;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getIsVisibleOnFront()
+    {
+        return $this->isVisibleOnFront;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function setIsVisibleOnFront($isVisibleOnFront)
+    {
+        $this->isVisibleOnFront = $isVisibleOnFront;
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/CreationArguments.php b/app/code/Magento/Sales/Model/Order/Creditmemo/CreationArguments.php
new file mode 100644
index 0000000000000000000000000000000000000000..fd082bb1dd474b03704b51aec67eba5ea20b23be
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/CreationArguments.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo;
+
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface;
+
+/**
+ * Class CreationArguments
+ */
+class CreationArguments implements CreditmemoCreationArgumentsInterface
+{
+    /**
+     * @var float|null
+     */
+    private $shippingAmount;
+
+    /**
+     * @var float|null
+     */
+    private $adjustmentPositive;
+
+    /**
+     * @var float|null
+     */
+    private $adjustmentNegative;
+
+    /**
+     * @var \Magento\Sales\Api\Data\CreditmemoCreationArgumentsExtensionInterface
+     */
+    private $extensionAttributes;
+
+    /**
+     * @inheritdoc
+     */
+    public function getShippingAmount()
+    {
+        return $this->shippingAmount;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getAdjustmentPositive()
+    {
+        return $this->adjustmentPositive;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getAdjustmentNegative()
+    {
+        return $this->adjustmentNegative;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function setShippingAmount($amount)
+    {
+        $this->shippingAmount = $amount;
+        return $this;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function setAdjustmentPositive($amount)
+    {
+        $this->adjustmentPositive = $amount;
+        return $this;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function setAdjustmentNegative($amount)
+    {
+        $this->adjustmentNegative = $amount;
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidator.php b/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..e49a08e32d83945f1524fb7edaf2f0b6ca5539df
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidator.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo;
+
+use Magento\Sales\Api\Data\CreditmemoInterface;
+
+/**
+ * Class CreditmemoValidator
+ */
+class CreditmemoValidator implements CreditmemoValidatorInterface
+{
+    /**
+     * @var \Magento\Sales\Model\Validator
+     */
+    private $validator;
+
+    /**
+     * InvoiceValidatorRunner constructor.
+     * @param \Magento\Sales\Model\Validator $validator
+     */
+    public function __construct(\Magento\Sales\Model\Validator $validator)
+    {
+        $this->validator = $validator;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate(CreditmemoInterface $entity, array $validators)
+    {
+        return $this->validator->validate($entity, $validators);
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidatorInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..3889f3b985ff02603009084fa956fab65e505556
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidatorInterface.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo;
+
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Exception\DocumentValidationException;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Interface CreditmemoValidatorInterface
+ */
+interface CreditmemoValidatorInterface
+{
+    /**
+     * @param CreditmemoInterface $entity
+     * @param ValidatorInterface[] $validators
+     * @return string[]
+     * @throws DocumentValidationException
+     */
+    public function validate(CreditmemoInterface $entity, array $validators);
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..edad1a2520632b31a89e355bb99913d0287df748
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Item/Validation/CreationQuantityValidator.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo\Item\Validation;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\Data\OrderInterfaceFactory;
+use Magento\Sales\Api\Data\OrderItemInterface;
+use Magento\Sales\Api\OrderItemRepositoryInterface;
+use Magento\Sales\Model\Order\Item;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Class CreationQuantityValidator
+ */
+class CreationQuantityValidator implements ValidatorInterface
+{
+    /**
+     * @var OrderItemRepositoryInterface
+     */
+    private $orderItemRepository;
+
+    /**
+     * @var OrderInterfaceFactory
+     */
+    private $context;
+
+    /**
+     * ItemCreationQuantityValidator constructor.
+     * @param OrderItemRepositoryInterface $orderItemRepository
+     * @param object $context
+     */
+    public function __construct(OrderItemRepositoryInterface $orderItemRepository, $context = null)
+    {
+        $this->orderItemRepository = $orderItemRepository;
+        $this->context = $context;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate($entity)
+    {
+        try {
+            $orderItem = $this->orderItemRepository->get($entity->getOrderItemId());
+            if (!$this->isItemPartOfContextOrder($orderItem)) {
+                return [__('The creditmemo contains product item that is not part of the original order.')];
+            }
+        } catch (NoSuchEntityException $e) {
+            return [__('The creditmemo contains product item that is not part of the original order.')];
+        }
+
+        if (!$this->isQtyAvailable($orderItem, $entity->getQty())) {
+            return [__('The quantity to refund must not be greater than the unrefunded quantity.')];
+        }
+
+        return [];
+    }
+
+    /**
+     * @param Item $orderItem
+     * @param int $qty
+     * @return bool
+     */
+    private function isQtyAvailable(Item $orderItem, $qty)
+    {
+        return $qty <= $orderItem->getQtyToRefund() || $orderItem->isDummy();
+    }
+
+    /**
+     * @param OrderItemInterface $orderItem
+     * @return bool
+     */
+    private function isItemPartOfContextOrder(OrderItemInterface $orderItem)
+    {
+        return $this->context instanceof OrderInterface && $this->context->getEntityId() === $orderItem->getOrderId();
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreation.php b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreation.php
new file mode 100644
index 0000000000000000000000000000000000000000..10e70402be6e4d4e6848f7f1065d44b22058a3d7
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreation.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo;
+
+use Magento\Sales\Api\Data\CreditmemoItemCreationInterface;
+
+/**
+ * Class LineItem
+ */
+class ItemCreation implements CreditmemoItemCreationInterface
+{
+    /**
+     * @var int
+     */
+    private $orderItemId;
+
+    /**
+     * @var float
+     */
+    private $qty;
+
+    /**
+     * @var \Magento\Sales\Api\Data\CreditmemoItemCreationExtensionInterface
+     */
+    private $extensionAttributes;
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getOrderItemId()
+    {
+        return $this->orderItemId;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setOrderItemId($orderItemId)
+    {
+        $this->orderItemId = $orderItemId;
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getQty()
+    {
+        return $this->qty;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setQty($qty)
+    {
+        $this->qty = $qty;
+        return $this;
+    }
+
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\CreditmemoItemCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\CreditmemoItemCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\CreditmemoItemCreationExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidator.php b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..f1b8e6d9cab9ba4324d8ca01ae1b9267f6e4c496
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidator.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo;
+
+use Magento\Sales\Api\Data\CreditmemoItemCreationInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+
+/**
+ * Class ItemCreationValidator
+ */
+class ItemCreationValidator implements ItemCreationValidatorInterface
+{
+    /**
+     * @var \Magento\Sales\Model\Validator
+     */
+    private $validator;
+
+    /**
+     * InvoiceValidatorRunner constructor.
+     * @param \Magento\Sales\Model\Validator $validator
+     */
+    public function __construct(\Magento\Sales\Model\Validator $validator)
+    {
+        $this->validator = $validator;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate(
+        CreditmemoItemCreationInterface $entity,
+        array $validators,
+        OrderInterface $context = null
+    ) {
+        return $this->validator->validate($entity, $validators, $context);
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidatorInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f8bb84ccd16a175ee23de755169281026dc053b
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidatorInterface.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo;
+
+use Magento\Sales\Api\Data\CreditmemoItemCreationInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+
+/**
+ * Interface ItemCreationValidatorInterface
+ */
+interface ItemCreationValidatorInterface
+{
+    /**
+     * @param CreditmemoItemCreationInterface $item
+     * @param array $validators
+     * @param OrderInterface|null $context
+     * @return mixed
+     */
+    public function validate(CreditmemoItemCreationInterface $item, array $validators, OrderInterface $context = null);
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Notifier.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Notifier.php
new file mode 100644
index 0000000000000000000000000000000000000000..47dbecca6b59bdc727f1b58b18e3c88a73c5993f
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Notifier.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo;
+
+/**
+ * CreditMemo notifier.
+ *
+ * @api
+ */
+class Notifier implements \Magento\Sales\Model\Order\Creditmemo\NotifierInterface
+{
+    /**
+     * @var \Magento\Sales\Model\Order\CreditMemo\SenderInterface[]
+     */
+    private $senders;
+
+    /**
+     * @param \Magento\Sales\Model\Order\CreditMemo\SenderInterface[] $senders
+     */
+    public function __construct(array $senders = [])
+    {
+        $this->senders = $senders;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function notify(
+        \Magento\Sales\Api\Data\OrderInterface $order,
+        \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        $forceSyncMode = false
+    ) {
+        foreach ($this->senders as $sender) {
+            $sender->send($order, $creditmemo, $comment, $forceSyncMode);
+        }
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/NotifierInterface.php b/app/code/Magento/Sales/Model/Order/Creditmemo/NotifierInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..ef42bd18633cfc21f0b92df28dde52438ed22c52
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/NotifierInterface.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo;
+
+/**
+ * Interface for CreditMemo notifier.
+ *
+ * @api
+ */
+interface NotifierInterface
+{
+    /**
+     * Notifies customer.
+     *
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment
+     * @param bool $forceSyncMode
+     *
+     * @return void
+     */
+    public function notify(
+        \Magento\Sales\Api\Data\OrderInterface $order,
+        \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        $forceSyncMode = false
+    );
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/RefundOperation.php b/app/code/Magento/Sales/Model/Order/Creditmemo/RefundOperation.php
index ef60ad2ce51bea1c2610f8ca6289d3cf4686c6c9..f01dd0dc3732e12a287306edd7ed173e604e9dc9 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo/RefundOperation.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/RefundOperation.php
@@ -114,9 +114,8 @@ class RefundOperation
                 $order->getBaseTotalInvoicedCost() - $creditmemo->getBaseCost()
             );
 
-            if ($online) {
-                $order->getPayment()->refund($creditmemo);
-            }
+            $creditmemo->setDoTransaction($online);
+            $order->getPayment()->refund($creditmemo);
 
             $this->eventManager->dispatch('sales_order_creditmemo_refund', ['creditmemo' => $creditmemo]);
         }
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php
new file mode 100644
index 0000000000000000000000000000000000000000..76210505fd4672778cfae0742de64bc990ccac86
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php
@@ -0,0 +1,149 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo\Sender;
+
+use Magento\Sales\Model\Order\Email\Sender;
+use Magento\Sales\Model\Order\Creditmemo\SenderInterface;
+
+/**
+ * Email notification sender for Creditmemo.
+ */
+class EmailSender extends Sender implements SenderInterface
+{
+    /**
+     * @var \Magento\Payment\Helper\Data
+     */
+    private $paymentHelper;
+
+    /**
+     * @var \Magento\Sales\Model\ResourceModel\Order\Creditmemo
+     */
+    private $creditmemoResource;
+
+    /**
+     * @var \Magento\Framework\App\Config\ScopeConfigInterface
+     */
+    private $globalConfig;
+
+    /**
+     * @var \Magento\Framework\Event\ManagerInterface
+     */
+    private $eventManager;
+
+    /**
+     * @param \Magento\Sales\Model\Order\Email\Container\Template $templateContainer
+     * @param \Magento\Sales\Model\Order\Email\Container\CreditmemoIdentity $identityContainer
+     * @param \Magento\Sales\Model\Order\Email\SenderBuilderFactory $senderBuilderFactory
+     * @param \Psr\Log\LoggerInterface $logger
+     * @param \Magento\Sales\Model\Order\Address\Renderer $addressRenderer
+     * @param \Magento\Payment\Helper\Data $paymentHelper
+     * @param \Magento\Sales\Model\ResourceModel\Order\Creditmemo $creditmemoResource
+     * @param \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig
+     * @param \Magento\Framework\Event\ManagerInterface $eventManager
+     */
+    public function __construct(
+        \Magento\Sales\Model\Order\Email\Container\Template $templateContainer,
+        \Magento\Sales\Model\Order\Email\Container\CreditmemoIdentity $identityContainer,
+        \Magento\Sales\Model\Order\Email\SenderBuilderFactory $senderBuilderFactory,
+        \Psr\Log\LoggerInterface $logger,
+        \Magento\Sales\Model\Order\Address\Renderer $addressRenderer,
+        \Magento\Payment\Helper\Data $paymentHelper,
+        \Magento\Sales\Model\ResourceModel\Order\Creditmemo $creditmemoResource,
+        \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig,
+        \Magento\Framework\Event\ManagerInterface $eventManager
+    ) {
+        parent::__construct(
+            $templateContainer,
+            $identityContainer,
+            $senderBuilderFactory,
+            $logger,
+            $addressRenderer
+        );
+
+        $this->paymentHelper = $paymentHelper;
+        $this->creditmemoResource = $creditmemoResource;
+        $this->globalConfig = $globalConfig;
+        $this->eventManager = $eventManager;
+    }
+
+    /**
+     * Sends order creditmemo email to the customer.
+     *
+     * Email will be sent immediately in two cases:
+     *
+     * - if asynchronous email sending is disabled in global settings
+     * - if $forceSyncMode parameter is set to TRUE
+     *
+     * Otherwise, email will be sent later during running of
+     * corresponding cron job.
+     *
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment
+     * @param bool $forceSyncMode
+     *
+     * @return bool
+     */
+    public function send(
+        \Magento\Sales\Api\Data\OrderInterface $order,
+        \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        $forceSyncMode = false
+    ) {
+        $creditmemo->setSendEmail(true);
+
+        if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
+            $transport = [
+                'order' => $order,
+                'creditmemo' => $creditmemo,
+                'comment' => $comment ? $comment->getComment() : '',
+                'billing' => $order->getBillingAddress(),
+                'payment_html' => $this->getPaymentHtml($order),
+                'store' => $order->getStore(),
+                'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
+                'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
+            ];
+
+            $this->eventManager->dispatch(
+                'email_creditmemo_set_template_vars_before',
+                ['sender' => $this, 'transport' => $transport]
+            );
+
+            $this->templateContainer->setTemplateVars($transport);
+
+            if ($this->checkAndSend($order)) {
+                $creditmemo->setEmailSent(true);
+
+                $this->creditmemoResource->saveAttribute($creditmemo, ['send_email', 'email_sent']);
+
+                return true;
+            }
+        } else {
+            $creditmemo->setEmailSent(null);
+
+            $this->creditmemoResource->saveAttribute($creditmemo, 'email_sent');
+        }
+
+        $this->creditmemoResource->saveAttribute($creditmemo, 'send_email');
+
+        return false;
+    }
+
+    /**
+     * Returns payment info block as HTML.
+     *
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     *
+     * @return string
+     */
+    private function getPaymentHtml(\Magento\Sales\Api\Data\OrderInterface $order)
+    {
+        return $this->paymentHelper->getInfoBlockHtml(
+            $order->getPayment(),
+            $this->identityContainer->getStore()->getStoreId()
+        );
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/SenderInterface.php b/app/code/Magento/Sales/Model/Order/Creditmemo/SenderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..00d316a8ec98aa79f3ef991b187e9070f2c15901
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/SenderInterface.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo;
+
+/**
+ * Interface for notification sender for CreditMemo.
+ */
+interface SenderInterface
+{
+    /**
+     * Sends notification to a customer.
+     *
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment
+     * @param bool $forceSyncMode
+     *
+     * @return bool
+     */
+    public function send(
+        \Magento\Sales\Api\Data\OrderInterface $order,
+        \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        $forceSyncMode = false
+    );
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Validation/QuantityValidator.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Validation/QuantityValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..82fd0479166e5257730b9c0ec83079eb5d13b37e
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Validation/QuantityValidator.php
@@ -0,0 +1,253 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo\Validation;
+
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\Data\OrderItemInterface;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\InvoiceRepositoryInterface;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Model\Order;
+use Magento\Sales\Model\Order\Creditmemo;
+use Magento\Sales\Model\Order\Item;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Class QuantityValidator
+ */
+class QuantityValidator implements ValidatorInterface
+{
+    /**
+     * @var OrderRepositoryInterface
+     */
+    private $orderRepository;
+
+    /**
+     * @var InvoiceRepositoryInterface
+     */
+    private $invoiceRepository;
+
+    /**
+     * @var \Magento\Framework\Pricing\PriceCurrencyInterface
+     */
+    private $priceCurrency;
+
+    /**
+     * InvoiceValidator constructor.
+     *
+     * @param OrderRepositoryInterface $orderRepository
+     * @param InvoiceRepositoryInterface $invoiceRepository
+     * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
+     */
+    public function __construct(
+        OrderRepositoryInterface $orderRepository,
+        InvoiceRepositoryInterface $invoiceRepository,
+        \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
+    ) {
+        $this->orderRepository = $orderRepository;
+        $this->invoiceRepository = $invoiceRepository;
+        $this->priceCurrency = $priceCurrency;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate($entity)
+    {
+        /**
+         * @var $entity CreditmemoInterface
+         */
+        if ($entity->getOrderId() === null) {
+            return [__('Order Id is required for creditmemo document')];
+        }
+
+        $messages = [];
+
+        $order = $this->orderRepository->get($entity->getOrderId());
+        $orderItemsById = $this->getOrderItems($order);
+        $invoiceQtysRefundLimits = $this->getInvoiceQtysRefundLimits($entity, $order);
+
+        $totalQuantity = 0;
+        foreach ($entity->getItems() as $item) {
+            if (!isset($orderItemsById[$item->getOrderItemId()])) {
+                $messages[] = __(
+                    'The creditmemo contains product SKU "%1" that is not part of the original order.',
+                    $item->getSku()
+                );
+                continue;
+            }
+            $orderItem = $orderItemsById[$item->getOrderItemId()];
+
+            if (
+                !$this->canRefundItem($orderItem, $item->getQty(), $invoiceQtysRefundLimits) ||
+                !$this->isQtyAvailable($orderItem, $item->getQty())
+            ) {
+                $messages[] =__(
+                    'The quantity to creditmemo must not be greater than the unrefunded quantity'
+                    . ' for product SKU "%1".',
+                    $orderItem->getSku()
+                );
+            } else {
+                $totalQuantity += $item->getQty();
+            }
+        }
+
+        if ($entity->getGrandTotal() <= 0) {
+            $messages[] = __('The credit memo\'s total must be positive.');
+        } elseif ($totalQuantity <= 0 && !$this->canRefundShipping($order)) {
+            $messages[] = __('You can\'t create a creditmemo without products.');
+        }
+
+        return $messages;
+    }
+
+    /**
+     * We can have problem with float in php (on some server $a=762.73;$b=762.73; $a-$b!=0)
+     * for this we have additional diapason for 0
+     * TotalPaid - contains amount, that were not rounded.
+     *
+     * @param OrderInterface $order
+     * @return bool
+     */
+    private function canRefundShipping(OrderInterface $order)
+    {
+        return !abs($this->priceCurrency->round($order->getShippingAmount()) - $order->getShippingRefunded()) < .0001;
+    }
+
+    /**
+     * @param CreditmemoInterface $creditmemo
+     * @param OrderInterface $order
+     * @return array
+     */
+    private function getInvoiceQtysRefundLimits(CreditmemoInterface $creditmemo, OrderInterface $order)
+    {
+        $invoiceQtysRefundLimits = [];
+        if ($creditmemo->getInvoiceId() !== null) {
+            $invoiceQtysRefunded = [];
+            $invoice = $this->invoiceRepository->get($creditmemo->getInvoiceId());
+            foreach ($order->getCreditmemosCollection() as $createdCreditmemo) {
+                if (
+                    $createdCreditmemo->getState() != Creditmemo::STATE_CANCELED &&
+                    $createdCreditmemo->getInvoiceId() == $invoice->getId()
+                ) {
+                    foreach ($createdCreditmemo->getAllItems() as $createdCreditmemoItem) {
+                        $orderItemId = $createdCreditmemoItem->getOrderItem()->getId();
+                        if (isset($invoiceQtysRefunded[$orderItemId])) {
+                            $invoiceQtysRefunded[$orderItemId] += $createdCreditmemoItem->getQty();
+                        } else {
+                            $invoiceQtysRefunded[$orderItemId] = $createdCreditmemoItem->getQty();
+                        }
+                    }
+                }
+            }
+
+            foreach ($invoice->getItems() as $invoiceItem) {
+                $invoiceQtyCanBeRefunded = $invoiceItem->getQty();
+                $orderItemId = $invoiceItem->getOrderItem()->getId();
+                if (isset($invoiceQtysRefunded[$orderItemId])) {
+                    $invoiceQtyCanBeRefunded = $invoiceQtyCanBeRefunded - $invoiceQtysRefunded[$orderItemId];
+                }
+                $invoiceQtysRefundLimits[$orderItemId] = $invoiceQtyCanBeRefunded;
+            }
+        }
+
+        return $invoiceQtysRefundLimits;
+    }
+
+    /**
+     * @param OrderInterface $order
+     * @return OrderItemInterface[]
+     */
+    private function getOrderItems(OrderInterface $order)
+    {
+        $orderItemsById = [];
+        foreach ($order->getItems() as $item) {
+            $orderItemsById[$item->getItemId()] = $item;
+        }
+
+        return $orderItemsById;
+    }
+
+    /**
+     * @param Item $orderItem
+     * @param int $qty
+     * @return bool
+     */
+    private function isQtyAvailable(Item $orderItem, $qty)
+    {
+        return $qty <= $orderItem->getQtyToRefund() || $orderItem->isDummy();
+    }
+
+    /**
+     * Check if order item can be refunded
+     *
+     * @param \Magento\Sales\Model\Order\Item $item
+     * @param double $qty
+     * @param array $invoiceQtysRefundLimits
+     * @return bool
+     */
+    private function canRefundItem(\Magento\Sales\Model\Order\Item $item, $qty, array $invoiceQtysRefundLimits)
+    {
+        if ($item->isDummy()) {
+            return $this->canRefundDummyItem($item, $qty, $invoiceQtysRefundLimits);
+        }
+
+        return $this->canRefundNoDummyItem($item, $invoiceQtysRefundLimits);
+    }
+
+    /**
+     * Check if no dummy order item can be refunded
+     *
+     * @param \Magento\Sales\Model\Order\Item $item
+     * @param array $invoiceQtysRefundLimits
+     * @return bool
+     */
+    private function canRefundNoDummyItem(\Magento\Sales\Model\Order\Item $item, array $invoiceQtysRefundLimits = [])
+    {
+        if ($item->getQtyToRefund() < 0) {
+            return false;
+        }
+        if (isset($invoiceQtysRefundLimits[$item->getId()])) {
+            return $invoiceQtysRefundLimits[$item->getId()] > 0;
+        }
+        return true;
+    }
+
+    /**
+     * @param Item $item
+     * @param int $qty
+     * @param array $invoiceQtysRefundLimits
+     * @return bool
+     */
+    private function canRefundDummyItem(\Magento\Sales\Model\Order\Item $item, $qty, array $invoiceQtysRefundLimits)
+    {
+        if ($item->getHasChildren()) {
+            foreach ($item->getChildrenItems() as $child) {
+                if ($this->canRefundRequestedQty($child, $qty, $invoiceQtysRefundLimits)) {
+                    return true;
+                }
+            }
+        } elseif ($item->getParentItem()) {
+            return $this->canRefundRequestedQty($item->getParentItem(), $qty, $invoiceQtysRefundLimits);
+        }
+
+        return false;
+    }
+
+    /**
+     * @param Item $item
+     * @param int $qty
+     * @param array $invoiceQtysRefundLimits
+     * @return bool
+     */
+    private function canRefundRequestedQty(
+        \Magento\Sales\Model\Order\Item $item,
+        $qty,
+        array $invoiceQtysRefundLimits
+    ) {
+        return $qty === null ? $this->canRefundNoDummyItem($item, $invoiceQtysRefundLimits) : $qty > 0;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Validation/TotalsValidator.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Validation/TotalsValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..2cefc377b0674392b69c57d47d96ee418d57d788
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Validation/TotalsValidator.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Creditmemo\Validation;
+
+use Magento\Framework\Pricing\PriceCurrencyInterface;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Class TotalsValidator
+ */
+class TotalsValidator implements ValidatorInterface
+{
+    /**
+     * @var PriceCurrencyInterface
+     */
+    private $priceCurrency;
+
+    /**
+     * TotalsValidator constructor.
+     *
+     * @param PriceCurrencyInterface $priceCurrency
+     */
+    public function __construct(PriceCurrencyInterface $priceCurrency)
+    {
+        $this->priceCurrency = $priceCurrency;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function validate($entity)
+    {
+        $messages = [];
+        $baseOrderRefund = $this->priceCurrency->round(
+            $entity->getOrder()->getBaseTotalRefunded() + $entity->getBaseGrandTotal()
+        );
+        if ($baseOrderRefund > $this->priceCurrency->round($entity->getOrder()->getBaseTotalPaid())) {
+            $baseAvailableRefund = $entity->getOrder()->getBaseTotalPaid()
+                - $entity->getOrder()->getBaseTotalRefunded();
+
+            $messages[] = __(
+                'The most money available to refund is %1.',
+                $baseAvailableRefund
+            );
+        }
+
+        return $messages;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoDocumentFactory.php b/app/code/Magento/Sales/Model/Order/CreditmemoDocumentFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..469b226053cdd4e2b0658dcd596d7d740572f0c7
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/CreditmemoDocumentFactory.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order;
+
+/**
+ * Class CreditmemoDocumentFactory
+ */
+class CreditmemoDocumentFactory
+{
+    /**
+     * @var \Magento\Sales\Model\Order\CreditmemoFactory
+     */
+    private $creditmemoFactory;
+
+    /**
+     * @var \Magento\Sales\Api\Data\CreditmemoCommentInterfaceFactory
+     */
+    private $commentFactory;
+
+    /**
+     * @var \Magento\Framework\EntityManager\HydratorPool
+     */
+    private $hydratorPool;
+
+    /**
+     * @var \Magento\Sales\Api\OrderRepositoryInterface
+     */
+    private $orderRepository;
+
+    /**
+     * CreditmemoDocumentFactory constructor.
+     *
+     * @param \Magento\Sales\Model\Order\CreditmemoFactory $creditmemoFactory
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentInterfaceFactory $commentFactory
+     * @param \Magento\Framework\EntityManager\HydratorPool $hydratorPool
+     * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
+     */
+    public function __construct(
+        \Magento\Sales\Model\Order\CreditmemoFactory $creditmemoFactory,
+        \Magento\Sales\Api\Data\CreditmemoCommentInterfaceFactory $commentFactory,
+        \Magento\Framework\EntityManager\HydratorPool $hydratorPool,
+        \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
+    ) {
+        $this->creditmemoFactory = $creditmemoFactory;
+        $this->commentFactory = $commentFactory;
+        $this->hydratorPool = $hydratorPool;
+        $this->orderRepository = $orderRepository;
+    }
+
+    /**
+     * Get array with original data for new Creditmemo document
+     *
+     * @param \Magento\Sales\Api\Data\CreditmemoItemCreationInterface[] $items
+     * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments
+     * @return array
+     */
+    private function getCreditmemoCreationData(
+        array $items = [],
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        $data = ['qtys' => []];
+        foreach ($items as $item) {
+            $data['qtys'][$item->getOrderItemId()] = $item->getQty();
+        }
+        if ($arguments) {
+            $hydrator = $this->hydratorPool->getHydrator(
+                \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface::class
+            );
+            $data = array_merge($hydrator->extract($arguments), $data);
+        }
+        return $data;
+    }
+
+    /**
+     *  Attach comment to the Creditmemo document.
+     *
+     * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment
+     * @param bool $appendComment
+     * @return \Magento\Sales\Api\Data\CreditmemoInterface
+     */
+    private function attachComment(
+        \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment,
+        $appendComment = false
+    ) {
+        $commentData = $this->hydratorPool->getHydrator(
+            \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface::class
+        )->extract($comment);
+        $comment = $this->commentFactory->create(['data' => $commentData]);
+        $comment->setParentId($creditmemo->getEntityId())
+            ->setStoreId($creditmemo->getStoreId())
+            ->setCreditmemo($creditmemo)
+            ->setIsCustomerNotified($appendComment);
+        $creditmemo->setComments([$comment]);
+        return $creditmemo;
+
+    }
+
+    /**
+     * Create new Creditmemo
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     * @param \Magento\Sales\Api\Data\CreditmemoItemCreationInterface[] $items
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment
+     * @param bool|null $appendComment
+     * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments
+     * @return \Magento\Sales\Api\Data\CreditmemoInterface
+     */
+    public function createFromOrder(
+        \Magento\Sales\Api\Data\OrderInterface $order,
+        array $items = [],
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        $data = $this->getCreditmemoCreationData($items, $arguments);
+        $creditmemo = $this->creditmemoFactory->createByOrder($order, $data);
+        if ($comment) {
+            $creditmemo = $this->attachComment($creditmemo, $comment, $appendComment);
+        }
+        return $creditmemo;
+    }
+
+    /**
+     * @param \Magento\Sales\Api\Data\InvoiceInterface $invoice
+     * @param \Magento\Sales\Api\Data\CreditmemoItemCreationInterface[] $items
+     * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment
+     * @param bool|null $appendComment
+     * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments
+     * @return \Magento\Sales\Api\Data\CreditmemoInterface
+     */
+    public function createFromInvoice(
+        \Magento\Sales\Api\Data\InvoiceInterface $invoice,
+        array $items = [],
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        $data = $this->getCreditmemoCreationData($items, $arguments);
+        /** @var $invoice \Magento\Sales\Model\Order\Invoice */
+        $invoice->setOrder($this->orderRepository->get($invoice->getOrderId()));
+        $creditmemo = $this->creditmemoFactory->createByInvoice($invoice, $data);
+        if ($comment) {
+            $creditmemo = $this->attachComment($creditmemo, $comment, $appendComment);
+        }
+        return $creditmemo;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Invoice/Validation/CanRefund.php b/app/code/Magento/Sales/Model/Order/Invoice/Validation/CanRefund.php
new file mode 100644
index 0000000000000000000000000000000000000000..8e68cade3caa7e1a83ad1b3522eab2d43d2672cc
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Invoice/Validation/CanRefund.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Invoice\Validation;
+
+use Magento\Payment\Model\InfoInterface;
+use Magento\Payment\Model\MethodInterface;
+use Magento\Sales\Api\Data\InvoiceInterface;
+use Magento\Sales\Api\OrderPaymentRepositoryInterface;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Model\Order\Invoice;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Class CanRefund
+ */
+class CanRefund implements ValidatorInterface
+{
+    /**
+     * @var OrderPaymentRepositoryInterface
+     */
+    private $paymentRepository;
+
+    /**
+     * @var OrderRepositoryInterface
+     */
+    private $orderRepository;
+
+    /**
+     * CanRefund constructor.
+     *
+     * @param OrderPaymentRepositoryInterface $paymentRepository
+     * @param OrderRepositoryInterface $orderRepository
+     */
+    public function __construct(
+        OrderPaymentRepositoryInterface $paymentRepository,
+        OrderRepositoryInterface $orderRepository
+    ) {
+        $this->paymentRepository = $paymentRepository;
+        $this->orderRepository = $orderRepository;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate($entity)
+    {
+        if (
+            $entity->getState() == Invoice::STATE_PAID &&
+            $this->isGrandTotalEnoughToRefund($entity) &&
+            $this->isPaymentAllowRefund($entity)
+        ) {
+            return [];
+        }
+
+        return [__('We can\'t create creditmemo for the invoice.')];
+    }
+
+    /**
+     * @param InvoiceInterface $invoice
+     * @return bool
+     */
+    private function isPaymentAllowRefund(InvoiceInterface $invoice)
+    {
+        $order = $this->orderRepository->get($invoice->getOrderId());
+        $payment = $order->getPayment();
+        if (!$payment instanceof InfoInterface) {
+            return false;
+        }
+        $method = $payment->getMethodInstance();
+        return $this->canPartialRefund($method, $payment) || $this->canFullRefund($invoice, $method);
+    }
+
+    /**
+     * @param InvoiceInterface $entity
+     * @return bool
+     */
+    private function isGrandTotalEnoughToRefund(InvoiceInterface $entity)
+    {
+        return abs($entity->getBaseGrandTotal() - $entity->getBaseTotalRefunded()) >= .0001;
+    }
+
+    /**
+     * @param MethodInterface $method
+     * @param InfoInterface $payment
+     * @return bool
+     */
+    private function canPartialRefund(MethodInterface $method, InfoInterface $payment)
+    {
+        return $method->canRefund() &&
+        $method->canRefundPartialPerInvoice() &&
+        $payment->getAmountPaid() > $payment->getAmountRefunded();
+    }
+
+    /**
+     * @param InvoiceInterface $invoice
+     * @param MethodInterface $method
+     * @return bool
+     */
+    private function canFullRefund(InvoiceInterface $invoice, MethodInterface $method)
+    {
+        return $method->canRefund() && !$invoice->getIsUsedForRefund();
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Validation/CanRefund.php b/app/code/Magento/Sales/Model/Order/Validation/CanRefund.php
new file mode 100644
index 0000000000000000000000000000000000000000..c6fc1a0d705e8d49f49918f7919ec5cfaa3ee199
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/CanRefund.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Framework\Pricing\PriceCurrencyInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\Order;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Class CanRefund
+ */
+class CanRefund implements ValidatorInterface
+{
+    /**
+     * @var PriceCurrencyInterface
+     */
+    private $priceCurrency;
+
+    /**
+     * CanRefund constructor.
+     *
+     * @param PriceCurrencyInterface $priceCurrency
+     */
+    public function __construct(PriceCurrencyInterface $priceCurrency)
+    {
+        $this->priceCurrency = $priceCurrency;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate($entity)
+    {
+        $messages = [];
+        if ($entity->getState() === Order::STATE_PAYMENT_REVIEW ||
+            $entity->getState() === Order::STATE_HOLDED ||
+            $entity->getState() === Order::STATE_CANCELED ||
+            $entity->getState() === Order::STATE_CLOSED
+        ) {
+            $messages[] = __(
+                'A creditmemo can not be created when an order has a status of %1',
+                $entity->getStatus()
+            );
+        } elseif (!$this->isTotalPaidEnoughForRefund($entity)) {
+            $messages[] = __('The order does not allow a creditmemo to be created.');
+        }
+
+        return $messages;
+    }
+
+    /**
+     * We can have problem with float in php (on some server $a=762.73;$b=762.73; $a-$b!=0)
+     * for this we have additional diapason for 0
+     * TotalPaid - contains amount, that were not rounded.
+     *
+     * @param OrderInterface $order
+     * @return bool
+     */
+    private function isTotalPaidEnoughForRefund(OrderInterface $order)
+    {
+        return !abs($this->priceCurrency->round($order->getTotalPaid()) - $order->getTotalRefunded()) < .0001;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/RefundInvoice.php b/app/code/Magento/Sales/Model/RefundInvoice.php
new file mode 100644
index 0000000000000000000000000000000000000000..37bf915aa505c6a757208b40a2c888515c6c8bc0
--- /dev/null
+++ b/app/code/Magento/Sales/Model/RefundInvoice.php
@@ -0,0 +1,252 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model;
+
+use Magento\Framework\App\ResourceConnection;
+use Magento\Sales\Api\CreditmemoRepositoryInterface;
+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\OrderStateResolverInterface;
+use Magento\Sales\Model\Order\OrderValidatorInterface;
+use Magento\Sales\Model\Order\PaymentAdapterInterface;
+use Magento\Sales\Model\Order\Validation\CanRefund;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Class RefundInvoice
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class RefundInvoice implements RefundInvoiceInterface
+{
+    /**
+     * @var ResourceConnection
+     */
+    private $resourceConnection;
+
+    /**
+     * @var OrderStateResolverInterface
+     */
+    private $orderStateResolver;
+
+    /**
+     * @var OrderRepositoryInterface
+     */
+    private $orderRepository;
+
+    /**
+     * @var InvoiceRepositoryInterface
+     */
+    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
+     */
+    private $paymentAdapter;
+
+    /**
+     * @var CreditmemoDocumentFactory
+     */
+    private $creditmemoDocumentFactory;
+
+    /**
+     * @var Order\Creditmemo\NotifierInterface
+     */
+    private $notifier;
+
+    /**
+     * @var OrderConfig
+     */
+    private $config;
+
+    /**
+     * @var LoggerInterface
+     */
+    private $logger;
+
+    /**
+     * RefundInvoice constructor.
+     *
+     * @param ResourceConnection $resourceConnection
+     * @param OrderStateResolverInterface $orderStateResolver
+     * @param OrderRepositoryInterface $orderRepository
+     * @param InvoiceRepositoryInterface $invoiceRepository
+     * @param OrderValidatorInterface $orderValidator
+     * @param InvoiceValidatorInterface $invoiceValidator
+     * @param CreditmemoValidatorInterface $creditmemoValidator
+     * @param Order\Creditmemo\ItemCreationValidatorInterface $itemCreationValidator
+     * @param CreditmemoRepositoryInterface $creditmemoRepository
+     * @param PaymentAdapterInterface $paymentAdapter
+     * @param CreditmemoDocumentFactory $creditmemoDocumentFactory
+     * @param NotifierInterface $notifier
+     * @param OrderConfig $config
+     * @param LoggerInterface $logger
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+     */
+    public function __construct(
+        ResourceConnection $resourceConnection,
+        OrderStateResolverInterface $orderStateResolver,
+        OrderRepositoryInterface $orderRepository,
+        InvoiceRepositoryInterface $invoiceRepository,
+        OrderValidatorInterface $orderValidator,
+        InvoiceValidatorInterface $invoiceValidator,
+        CreditmemoValidatorInterface $creditmemoValidator,
+        ItemCreationValidatorInterface $itemCreationValidator,
+        CreditmemoRepositoryInterface $creditmemoRepository,
+        PaymentAdapterInterface $paymentAdapter,
+        CreditmemoDocumentFactory $creditmemoDocumentFactory,
+        NotifierInterface $notifier,
+        OrderConfig $config,
+        LoggerInterface $logger
+    ) {
+        $this->resourceConnection = $resourceConnection;
+        $this->orderStateResolver = $orderStateResolver;
+        $this->orderRepository = $orderRepository;
+        $this->invoiceRepository = $invoiceRepository;
+        $this->orderValidator = $orderValidator;
+        $this->creditmemoValidator = $creditmemoValidator;
+        $this->itemCreationValidator = $itemCreationValidator;
+        $this->creditmemoRepository = $creditmemoRepository;
+        $this->paymentAdapter = $paymentAdapter;
+        $this->creditmemoDocumentFactory = $creditmemoDocumentFactory;
+        $this->notifier = $notifier;
+        $this->config = $config;
+        $this->logger = $logger;
+        $this->invoiceValidator = $invoiceValidator;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function execute(
+        $invoiceId,
+        array $items = [],
+        $isOnline = false,
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        $connection = $this->resourceConnection->getConnection('sales');
+        $invoice = $this->invoiceRepository->get($invoiceId);
+        $order = $this->orderRepository->get($invoice->getOrderId());
+        $creditmemo = $this->creditmemoDocumentFactory->createFromInvoice(
+            $invoice,
+            $items,
+            $comment,
+            ($appendComment && $notify),
+            $arguments
+        );
+        $orderValidationResult = $this->orderValidator->validate(
+            $order,
+            [
+                CanRefund::class
+            ]
+        );
+        $invoiceValidationResult = $this->invoiceValidator->validate(
+            $invoice,
+            [
+                \Magento\Sales\Model\Order\Invoice\Validation\CanRefund::class
+            ]
+        );
+        $creditmemoValidationResult = $this->creditmemoValidator->validate(
+            $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
+        );
+        if (!empty($validationMessages )) {
+            throw new \Magento\Sales\Exception\DocumentValidationException(
+                __("Creditmemo Document Validation Error(s):\n" . implode("\n", $validationMessages))
+            );
+        }
+        $connection->beginTransaction();
+        try {
+            $creditmemo->setState(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED);
+            $order = $this->paymentAdapter->refund($creditmemo, $order, $isOnline);
+            $order->setState(
+                $this->orderStateResolver->getStateForOrder($order, [])
+            );
+            $order->setStatus($this->config->getStateDefaultStatus($order->getState()));
+            if (!$isOnline) {
+                $invoice->setIsUsedForRefund(true);
+                $invoice->setBaseTotalRefunded(
+                    $invoice->getBaseTotalRefunded() + $creditmemo->getBaseGrandTotal()
+                );
+            }
+            $this->invoiceRepository->save($invoice);
+            $order = $this->orderRepository->save($order);
+            $creditmemo = $this->creditmemoRepository->save($creditmemo);
+            $connection->commit();
+        } catch (\Exception $e) {
+            $this->logger->critical($e);
+            $connection->rollBack();
+            throw new \Magento\Sales\Exception\CouldNotRefundException(
+                __('Could not save a Creditmemo, see error log for details')
+            );
+        }
+        if ($notify) {
+            if (!$appendComment) {
+                $comment = null;
+            }
+            $this->notifier->notify($order, $creditmemo, $comment);
+        }
+
+        return $creditmemo->getEntityId();
+    }
+}
diff --git a/app/code/Magento/Sales/Model/RefundOrder.php b/app/code/Magento/Sales/Model/RefundOrder.php
new file mode 100644
index 0000000000000000000000000000000000000000..65d81df0d1de9fc4d2b2a7803369a0eda440ba12
--- /dev/null
+++ b/app/code/Magento/Sales/Model/RefundOrder.php
@@ -0,0 +1,214 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model;
+
+use Magento\Framework\App\ResourceConnection;
+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 Psr\Log\LoggerInterface;
+
+/**
+ * Class RefundOrder
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class RefundOrder implements RefundOrderInterface
+{
+    /**
+     * @var ResourceConnection
+     */
+    private $resourceConnection;
+
+    /**
+     * @var OrderStateResolverInterface
+     */
+    private $orderStateResolver;
+
+    /**
+     * @var OrderRepositoryInterface
+     */
+    private $orderRepository;
+
+    /**
+     * @var OrderValidatorInterface
+     */
+    private $orderValidator;
+
+    /**
+     * @var CreditmemoValidatorInterface
+     */
+    private $creditmemoValidator;
+
+    /**
+     * @var Order\Creditmemo\ItemCreationValidatorInterface
+     */
+    private $itemCreationValidator;
+
+    /**
+     * @var CreditmemoRepositoryInterface
+     */
+    private $creditmemoRepository;
+
+    /**
+     * @var Order\PaymentAdapterInterface
+     */
+    private $paymentAdapter;
+
+    /**
+     * @var CreditmemoDocumentFactory
+     */
+    private $creditmemoDocumentFactory;
+
+    /**
+     * @var Order\Creditmemo\NotifierInterface
+     */
+    private $notifier;
+
+    /**
+     * @var OrderConfig
+     */
+    private $config;
+
+    /**
+     * @var LoggerInterface
+     */
+    private $logger;
+
+    /**
+     * 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 NotifierInterface $notifier
+     * @param OrderConfig $config
+     * @param LoggerInterface $logger
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+     */
+    public function __construct(
+        ResourceConnection $resourceConnection,
+        OrderStateResolverInterface $orderStateResolver,
+        OrderRepositoryInterface $orderRepository,
+        OrderValidatorInterface $orderValidator,
+        CreditmemoValidatorInterface $creditmemoValidator,
+        ItemCreationValidatorInterface $itemCreationValidator,
+        CreditmemoRepositoryInterface $creditmemoRepository,
+        PaymentAdapterInterface $paymentAdapter,
+        CreditmemoDocumentFactory $creditmemoDocumentFactory,
+        NotifierInterface $notifier,
+        OrderConfig $config,
+        LoggerInterface $logger
+    ) {
+        $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->notifier = $notifier;
+        $this->config = $config;
+        $this->logger = $logger;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function execute(
+        $orderId,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
+        \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null
+    ) {
+        $connection = $this->resourceConnection->getConnection('sales');
+        $order = $this->orderRepository->get($orderId);
+        $creditmemo = $this->creditmemoDocumentFactory->createFromOrder(
+            $order,
+            $items,
+            $comment,
+            ($appendComment && $notify),
+            $arguments
+        );
+        $orderValidationResult = $this->orderValidator->validate(
+            $order,
+            [
+                CanRefund::class
+            ]
+        );
+        $creditmemoValidationResult = $this->creditmemoValidator->validate(
+            $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, $creditmemoValidationResult, $itemsValidation);
+        if (!empty($validationMessages)) {
+            throw new \Magento\Sales\Exception\DocumentValidationException(
+                __("Creditmemo Document Validation Error(s):\n" . implode("\n", $validationMessages))
+            );
+        }
+        $connection->beginTransaction();
+        try {
+            $creditmemo->setState(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED);
+            $order = $this->paymentAdapter->refund($creditmemo, $order);
+            $order->setState(
+                $this->orderStateResolver->getStateForOrder($order, [])
+            );
+            $order->setStatus($this->config->getStateDefaultStatus($order->getState()));
+
+            $order = $this->orderRepository->save($order);
+            $creditmemo = $this->creditmemoRepository->save($creditmemo);
+            $connection->commit();
+        } catch (\Exception $e) {
+            $this->logger->critical($e);
+            $connection->rollBack();
+            throw new \Magento\Sales\Exception\CouldNotRefundException(
+                __('Could not save a Creditmemo, see error log for details')
+            );
+        }
+        if ($notify) {
+            if (!$appendComment) {
+                $comment = null;
+            }
+            $this->notifier->notify($order, $creditmemo, $comment);
+        }
+
+        return $creditmemo->getEntityId();
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Validator.php b/app/code/Magento/Sales/Model/Validator.php
index b8d57ded2970209d5d2184945fbb22f13de47dbd..10aa0735b952e99e0d889b27ff378411d0d1d6d1 100644
--- a/app/code/Magento/Sales/Model/Validator.php
+++ b/app/code/Magento/Sales/Model/Validator.php
@@ -33,14 +33,20 @@ class Validator
     /**
      * @param object $entity
      * @param ValidatorInterface[] $validators
-     * @return string[]
+     * @param object|null $context
+     * @return \string[]
      * @throws ConfigurationMismatchException
      */
-    public function validate($entity, array $validators)
+    public function validate($entity, array $validators, $context = null)
     {
         $messages = [];
+        $validatorArguments = [];
+        if ($context !== null) {
+            $validatorArguments['context'] = $context;
+        }
+
         foreach ($validators as $validatorName) {
-            $validator = $this->objectManager->get($validatorName);
+            $validator = $this->objectManager->create($validatorName, $validatorArguments);
             if (!$validator instanceof ValidatorInterface) {
                 throw new ConfigurationMismatchException(
                     __(
diff --git a/app/code/Magento/Sales/Model/ValidatorInterface.php b/app/code/Magento/Sales/Model/ValidatorInterface.php
index 1882782e314f7b47b507c042697f223eadbf36b7..4489af44f40361f036e92671f776af479e45a4d7 100644
--- a/app/code/Magento/Sales/Model/ValidatorInterface.php
+++ b/app/code/Magento/Sales/Model/ValidatorInterface.php
@@ -15,7 +15,7 @@ interface ValidatorInterface
 {
     /**
      * @param object $entity
-     * @return array
+     * @return \Magento\Framework\Phrase[]
      * @throws DocumentValidationException
      * @throws NoSuchEntityException
      */
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Item/Validation/CreateQuantityValidatorTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Item/Validation/CreateQuantityValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1466a0f4fc9fe8d44841bcf4d31d4a34ab8abe44
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Item/Validation/CreateQuantityValidatorTest.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order\Creditmemo\Item\Validation;
+
+use Magento\Sales\Api\OrderItemRepositoryInterface;
+use Magento\Sales\Model\Order\Creditmemo\Item\Validation\CreationQuantityValidator;
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\Order\Item;
+
+/**
+ * Class CreateQuantityValidatorTest
+ */
+class CreateQuantityValidatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var OrderItemRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderItemRepositoryMock;
+
+    /**
+     * @var Item|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderItemMock;
+
+    /**
+     * @var CreationQuantityValidator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $createQuantityValidator;
+
+    /**
+     * @var OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $contexMock;
+
+    /**
+     * @var \stdClass|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $entity;
+
+    protected function setUp()
+    {
+        $this->orderItemRepositoryMock = $this->getMockBuilder(OrderItemRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['get'])
+            ->getMockForAbstractClass();
+
+        $this->orderItemMock = $this->getMockBuilder(Item::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->entity = $this->getMockBuilder(\stdClass::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getOrderItemId', 'getQty'])
+            ->getMock();
+    }
+
+    /**
+     * @dataProvider dataProvider
+     */
+    public function testValidateCreditMemoProductItems($orderItemId, $expectedResult, $withContext = false)
+    {
+        if ($orderItemId) {
+            $this->entity->expects($this->once())
+                ->method('getOrderItemId')
+                ->willReturn($orderItemId);
+
+            $this->orderItemRepositoryMock->expects($this->once())
+                ->method('get')
+                ->with($orderItemId)
+                ->willReturn($this->orderItemMock);
+        } else {
+            $this->entity->expects($this->once())
+                ->method('getOrderItemId')
+                ->willThrowException(new NoSuchEntityException());
+        }
+
+        $this->contexMock = null;
+        if ($withContext) {
+            $this->contexMock = $this->getMockBuilder(OrderInterface::class)
+                ->disableOriginalConstructor()
+                ->getMockForAbstractClass();
+
+            $this->entity->expects($this->once())
+                ->method('getQty')
+                ->willReturn(11);
+        }
+
+        $this->createQuantityValidator = new CreationQuantityValidator(
+            $this->orderItemRepositoryMock,
+            $this->contexMock
+        );
+
+        $this->assertEquals($expectedResult, $this->createQuantityValidator->validate($this->entity));
+    }
+
+    public function dataProvider()
+    {
+        return [
+            'testValidateCreditMemoProductItems' => [
+                1,
+                [__('The creditmemo contains product item that is not part of the original order.')],
+            ],
+            'testValidateWithException' => [
+                null,
+                [__('The creditmemo contains product item that is not part of the original order.')]
+            ],
+            'testValidateWithContext' => [
+                1,
+                [__('The quantity to refund must not be greater than the unrefunded quantity.')],
+                true
+            ],
+        ];
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/RefundOperationTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/RefundOperationTest.php
index 1b8d40d0427165f5c8587deb422b1ac9e3f4dbd2..2c5173507d997797c8d47cef8d7c70a6ceb56370 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/RefundOperationTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/RefundOperationTest.php
@@ -50,7 +50,7 @@ class RefundOperationTest extends \PHPUnit_Framework_TestCase
 
         $this->creditmemoMock = $this->getMockBuilder(\Magento\Sales\Api\Data\CreditmemoInterface::class)
             ->disableOriginalConstructor()
-            ->setMethods(['getBaseCost'])
+            ->setMethods(['getBaseCost', 'setDoTransaction'])
             ->getMockForAbstractClass();
 
         $this->paymentMock = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class)
@@ -142,6 +142,7 @@ class RefundOperationTest extends \PHPUnit_Framework_TestCase
     public function testExecuteOffline($amounts)
     {
         $orderId = 1;
+        $online = false;
         $this->creditmemoMock->expects($this->once())
             ->method('getState')
             ->willReturn(Creditmemo::STATE_REFUNDED);
@@ -174,8 +175,17 @@ class RefundOperationTest extends \PHPUnit_Framework_TestCase
         $this->orderMock->expects($this->never())
             ->method('setTotalOnlineRefunded');
 
-        $this->orderMock->expects($this->never())
-            ->method('getPayment');
+        $this->orderMock->expects($this->once())
+            ->method('getPayment')
+            ->willReturn($this->paymentMock);
+
+        $this->paymentMock->expects($this->once())
+            ->method('refund')
+            ->with($this->creditmemoMock);
+
+        $this->creditmemoMock->expects($this->once())
+            ->method('setDoTransaction')
+            ->with($online);
 
         $this->eventManagerMock->expects($this->once())
             ->method('dispatch')
@@ -186,7 +196,7 @@ class RefundOperationTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals(
             $this->orderMock,
-            $this->subject->execute($this->creditmemoMock, $this->orderMock, false)
+            $this->subject->execute($this->creditmemoMock, $this->orderMock, $online)
         );
     }
 
@@ -197,6 +207,7 @@ class RefundOperationTest extends \PHPUnit_Framework_TestCase
     public function testExecuteOnline($amounts)
     {
         $orderId = 1;
+        $online = true;
         $this->creditmemoMock->expects($this->once())
             ->method('getState')
             ->willReturn(Creditmemo::STATE_REFUNDED);
@@ -229,6 +240,10 @@ class RefundOperationTest extends \PHPUnit_Framework_TestCase
         $this->orderMock->expects($this->never())
             ->method('setTotalOfflineRefunded');
 
+        $this->creditmemoMock->expects($this->once())
+            ->method('setDoTransaction')
+            ->with($online);
+
         $this->orderMock->expects($this->once())
             ->method('getPayment')
             ->willReturn($this->paymentMock);
@@ -238,7 +253,7 @@ class RefundOperationTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals(
             $this->orderMock,
-            $this->subject->execute($this->creditmemoMock, $this->orderMock, true)
+            $this->subject->execute($this->creditmemoMock, $this->orderMock, $online)
         );
     }
 
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d1fe28b21b59b47558c0e44d0b55eacc0f6b847c
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php
@@ -0,0 +1,361 @@
+<?php
+
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order\Creditmemo\Sender;
+
+/**
+ * Unit test for email notification sender for Creditmemo.
+ * @SuppressWarnings(PHPMD.TooManyFields)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class EmailSenderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Sales\Model\Order\Creditmemo\Sender\EmailSender
+     */
+    private $subject;
+
+    /**
+     * @var \Magento\Sales\Model\Order|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var \Magento\Store\Model\Store|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Email\Sender|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $senderMock;
+
+    /**
+     * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $loggerMock;
+
+    /**
+     * @var \Magento\Sales\Api\Data\CreditmemoInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoMock;
+
+    /**
+     * @var \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $commentMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Address|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $addressMock;
+
+    /**
+     * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $globalConfigMock;
+
+    /**
+     * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $eventManagerMock;
+
+    /**
+     * @var \Magento\Payment\Model\Info|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $paymentInfoMock;
+
+    /**
+     * @var \Magento\Payment\Helper\Data|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $paymentHelperMock;
+
+    /**
+     * @var \Magento\Sales\Model\ResourceModel\Order\Creditmemo|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoResourceMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Address\Renderer|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $addressRendererMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Email\Container\Template|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $templateContainerMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Email\Container\CreditmemoIdentity|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $identityContainerMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Email\SenderBuilderFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $senderBuilderFactoryMock;
+
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    protected function setUp()
+    {
+        $this->orderMock = $this->getMockBuilder(\Magento\Sales\Model\Order::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class)
+            ->setMethods(['getStoreId'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->storeMock->expects($this->any())
+            ->method('getStoreId')
+            ->willReturn(1);
+        $this->orderMock->expects($this->any())
+            ->method('getStore')
+            ->willReturn($this->storeMock);
+
+        $this->senderMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Email\Sender::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['send', 'sendCopyTo'])
+            ->getMock();
+
+        $this->loggerMock = $this->getMockBuilder(\Psr\Log\LoggerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->creditmemoMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Creditmemo::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['setSendEmail', 'setEmailSent'])
+            ->getMock();
+
+        $this->commentMock = $this->getMockBuilder(\Magento\Sales\Api\Data\CreditmemoCommentCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->commentMock->expects($this->any())
+            ->method('getComment')
+            ->willReturn('Comment text');
+
+        $this->addressMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Address::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderMock->expects($this->any())
+            ->method('getBillingAddress')
+            ->willReturn($this->addressMock);
+        $this->orderMock->expects($this->any())
+            ->method('getShippingAddress')
+            ->willReturn($this->addressMock);
+
+        $this->globalConfigMock = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->eventManagerMock = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->paymentInfoMock = $this->getMockBuilder(\Magento\Payment\Model\Info::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderMock->expects($this->any())
+            ->method('getPayment')
+            ->willReturn($this->paymentInfoMock);
+
+        $this->paymentHelperMock = $this->getMockBuilder(\Magento\Payment\Helper\Data::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->paymentHelperMock->expects($this->any())
+            ->method('getInfoBlockHtml')
+            ->with($this->paymentInfoMock, 1)
+            ->willReturn('Payment Info Block');
+
+        $this->creditmemoResourceMock = $this->getMockBuilder(
+            \Magento\Sales\Model\ResourceModel\Order\Creditmemo::class
+        )->disableOriginalConstructor()
+            ->getMock();
+
+        $this->addressRendererMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Address\Renderer::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->addressRendererMock->expects($this->any())
+            ->method('format')
+            ->with($this->addressMock, 'html')
+            ->willReturn('Formatted address');
+
+        $this->templateContainerMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Email\Container\Template::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->identityContainerMock = $this->getMockBuilder(
+            \Magento\Sales\Model\Order\Email\Container\CreditmemoIdentity::class
+        )
+        ->disableOriginalConstructor()
+        ->getMock();
+
+        $this->identityContainerMock->expects($this->any())
+            ->method('getStore')
+            ->willReturn($this->storeMock);
+
+        $this->senderBuilderFactoryMock = $this->getMockBuilder(
+            \Magento\Sales\Model\Order\Email\SenderBuilderFactory::class
+        )
+        ->disableOriginalConstructor()
+        ->setMethods(['create'])
+        ->getMock();
+
+        $this->subject = new \Magento\Sales\Model\Order\Creditmemo\Sender\EmailSender(
+            $this->templateContainerMock,
+            $this->identityContainerMock,
+            $this->senderBuilderFactoryMock,
+            $this->loggerMock,
+            $this->addressRendererMock,
+            $this->paymentHelperMock,
+            $this->creditmemoResourceMock,
+            $this->globalConfigMock,
+            $this->eventManagerMock
+        );
+    }
+
+    /**
+     * @param int $configValue
+     * @param bool $forceSyncMode
+     * @param bool $isComment
+     * @param bool $emailSendingResult
+     *
+     * @dataProvider sendDataProvider
+     *
+     * @return void
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testSend($configValue, $forceSyncMode, $isComment, $emailSendingResult)
+    {
+        $this->globalConfigMock->expects($this->once())
+            ->method('getValue')
+            ->with('sales_email/general/async_sending')
+            ->willReturn($configValue);
+
+        if (!$isComment) {
+            $this->commentMock = null;
+        }
+
+        $this->creditmemoMock->expects($this->once())
+            ->method('setSendEmail')
+            ->with(true);
+
+        if (!$configValue || $forceSyncMode) {
+            $transport = [
+                'order' => $this->orderMock,
+                'creditmemo' => $this->creditmemoMock,
+                'comment' => $isComment ? 'Comment text' : '',
+                'billing' => $this->addressMock,
+                'payment_html' => 'Payment Info Block',
+                'store' => $this->storeMock,
+                'formattedShippingAddress' => 'Formatted address',
+                'formattedBillingAddress' => 'Formatted address',
+            ];
+
+            $this->eventManagerMock->expects($this->once())
+                ->method('dispatch')
+                ->with(
+                    'email_creditmemo_set_template_vars_before',
+                    [
+                        'sender' => $this->subject,
+                        'transport' => $transport,
+                    ]
+                );
+
+            $this->templateContainerMock->expects($this->once())
+                ->method('setTemplateVars')
+                ->with($transport);
+
+            $this->identityContainerMock->expects($this->once())
+                ->method('isEnabled')
+                ->willReturn($emailSendingResult);
+
+            if ($emailSendingResult) {
+                $this->senderBuilderFactoryMock->expects($this->once())
+                    ->method('create')
+                    ->willReturn($this->senderMock);
+
+                $this->senderMock->expects($this->once())
+                    ->method('send');
+
+                $this->senderMock->expects($this->once())
+                    ->method('sendCopyTo');
+
+                $this->creditmemoMock->expects($this->once())
+                    ->method('setEmailSent')
+                    ->with(true);
+
+                $this->creditmemoResourceMock->expects($this->once())
+                    ->method('saveAttribute')
+                    ->with($this->creditmemoMock, ['send_email', 'email_sent']);
+
+                $this->assertTrue(
+                    $this->subject->send(
+                        $this->orderMock,
+                        $this->creditmemoMock,
+                        $this->commentMock,
+                        $forceSyncMode
+                    )
+                );
+            } else {
+                $this->creditmemoResourceMock->expects($this->once())
+                    ->method('saveAttribute')
+                    ->with($this->creditmemoMock, 'send_email');
+
+                $this->assertFalse(
+                    $this->subject->send(
+                        $this->orderMock,
+                        $this->creditmemoMock,
+                        $this->commentMock,
+                        $forceSyncMode
+                    )
+                );
+            }
+        } else {
+            $this->creditmemoMock->expects($this->once())
+                ->method('setEmailSent')
+                ->with(null);
+
+            $this->creditmemoResourceMock->expects($this->at(0))
+                ->method('saveAttribute')
+                ->with($this->creditmemoMock, 'email_sent');
+            $this->creditmemoResourceMock->expects($this->at(1))
+                ->method('saveAttribute')
+                ->with($this->creditmemoMock, 'send_email');
+
+            $this->assertFalse(
+                $this->subject->send(
+                    $this->orderMock,
+                    $this->creditmemoMock,
+                    $this->commentMock,
+                    $forceSyncMode
+                )
+            );
+        }
+    }
+
+    /**
+     * @return array
+     */
+    public function sendDataProvider()
+    {
+        return [
+            'Successful sync sending with comment' => [0, false, true, true],
+            'Successful sync sending without comment' => [0, false, false, true],
+            'Failed sync sending with comment' => [0, false, true, false],
+            'Successful forced sync sending with comment' => [1, true, true, true],
+            'Async sending' => [1, false, false, false],
+        ];
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Validation/QuantityValidatorTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Validation/QuantityValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..838c062956c24ac900835e53e746998f1de1271d
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Validation/QuantityValidatorTest.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order\Creditmemo\Validation;
+
+use Magento\Framework\Pricing\PriceCurrencyInterface;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\InvoiceRepositoryInterface;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Model\Order\Creditmemo\Validation\QuantityValidator;
+
+/**
+ * Class QuantityValidatorTest
+ */
+class QuantityValidatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var OrderRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderRepositoryMock;
+
+    /**
+     * @var InvoiceRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $invoiceRepositoryMock;
+
+    /**
+     * @var QuantityValidator
+     */
+    private $validator;
+
+    /**
+     * @var PriceCurrencyInterface
+     */
+    private $priceCurrencyMock;
+
+    /**
+     * @inheritDoc
+     */
+    protected function setUp()
+    {
+        $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->invoiceRepositoryMock = $this->getMockBuilder(InvoiceRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->priceCurrencyMock = $this->getMockBuilder(PriceCurrencyInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->validator = new QuantityValidator(
+            $this->orderRepositoryMock,
+            $this->invoiceRepositoryMock,
+            $this->priceCurrencyMock
+        );
+    }
+
+    public function testValidateWithoutItems()
+    {
+        $creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $creditmemoMock->expects($this->exactly(2))->method('getOrderId')
+            ->willReturn(1);
+        $creditmemoMock->expects($this->once())->method('getItems')
+            ->willReturn([]);
+        $orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $orderMock->expects($this->once())->method('getItems')
+            ->willReturn([]);
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with(1)
+            ->willReturn($orderMock);
+        $creditmemoMock->expects($this->once())->method('getGrandTotal')
+            ->willReturn(0);
+        $this->assertEquals(
+            [
+                __('The credit memo\'s total must be positive.')
+            ],
+            $this->validator->validate($creditmemoMock)
+        );
+    }
+
+    public function testValidateWithoutOrder()
+    {
+        $creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $creditmemoMock->expects($this->once())->method('getOrderId')
+            ->willReturn(null);
+        $creditmemoMock->expects($this->never())->method('getItems');
+        $this->assertEquals(
+            [__('Order Id is required for creditmemo document')],
+            $this->validator->validate($creditmemoMock)
+        );
+    }
+
+    public function testValidateWithWrongItemId()
+    {
+        $orderId = 1;
+        $orderItemId = 1;
+        $creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $creditmemoMock->expects($this->exactly(2))->method('getOrderId')
+            ->willReturn($orderId);
+        $creditmemoItemMock = $this->getMockBuilder(
+            \Magento\Sales\Api\Data\CreditmemoItemInterface::class
+        )->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $creditmemoItemMock->expects($this->once())->method('getOrderItemId')
+            ->willReturn($orderItemId);
+        $creditmemoItemSku = 'sku';
+        $creditmemoItemMock->expects($this->once())->method('getSku')
+            ->willReturn($creditmemoItemSku);
+        $creditmemoMock->expects($this->exactly(1))->method('getItems')
+            ->willReturn([$creditmemoItemMock]);
+
+        $orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $orderMock->expects($this->once())->method('getItems')
+            ->willReturn([]);
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($orderId)
+            ->willReturn($orderMock);
+        $creditmemoMock->expects($this->once())->method('getGrandTotal')
+            ->willReturn(12);
+
+        $this->assertEquals(
+            [
+                __(
+                    'The creditmemo contains product SKU "%1" that is not part of the original order.',
+                    $creditmemoItemSku
+                ),
+                __('You can\'t create a creditmemo without products.')
+            ],
+            $this->validator->validate($creditmemoMock)
+        );
+    }
+
+    /**
+     * @param int $orderId
+     * @param int $orderItemId
+     * @param int $qtyToRequest
+     * @param int $qtyToRefund
+     * @param string $sku
+     * @param array $expected
+     * @dataProvider dataProviderForValidateQty
+     */
+    public function testValidate($orderId, $orderItemId, $qtyToRequest, $qtyToRefund, $sku, $total, array $expected)
+    {
+        $creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $creditmemoMock->expects($this->exactly(2))->method('getOrderId')
+            ->willReturn($orderId);
+        $creditmemoMock->expects($this->once())->method('getGrandTotal')
+            ->willReturn($total);
+        $creditmemoItemMock = $this->getMockBuilder(
+            \Magento\Sales\Api\Data\CreditmemoItemInterface::class
+        )->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $creditmemoItemMock->expects($this->exactly(2))->method('getOrderItemId')
+            ->willReturn($orderItemId);
+        $creditmemoItemMock->expects($this->never())->method('getSku')
+            ->willReturn($sku);
+        $creditmemoItemMock->expects($this->atLeastOnce())->method('getQty')
+            ->willReturn($qtyToRequest);
+        $creditmemoMock->expects($this->exactly(1))->method('getItems')
+            ->willReturn([$creditmemoItemMock]);
+
+        $orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $orderItemMock->expects($this->exactly(2))->method('getQtyToRefund')
+            ->willReturn($qtyToRefund);
+        $creditmemoItemMock->expects($this->any())->method('getQty')
+            ->willReturn($qtyToRequest);
+        $orderMock->expects($this->once())->method('getItems')
+            ->willReturn([$orderItemMock]);
+        $orderItemMock->expects($this->once())->method('getItemId')
+            ->willReturn($orderItemId);
+        $orderItemMock->expects($this->any())->method('getSku')
+            ->willReturn($sku);
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($orderId)
+            ->willReturn($orderMock);
+
+        $this->assertEquals(
+            $expected,
+            $this->validator->validate($creditmemoMock)
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function dataProviderForValidateQty()
+    {
+        $sku = 'sku';
+
+        return [
+            [
+                'orderId' => 1,
+                'orderItemId' => 1,
+                'qtyToRequest' => 1,
+                'qtyToRefund' => 1,
+                'sku',
+                'total' => 15,
+                'expected' => []
+            ],
+            [
+                'orderId' => 1,
+                'orderItemId' => 1,
+                'qtyToRequest' => 2,
+                'qtyToRefund' => 1,
+                'sku',
+                'total' => 0,
+                'expected' => [
+                    __(
+                        'The quantity to creditmemo must not be greater than the unrefunded quantity'
+                        . ' for product SKU "%1".',
+                        $sku
+                    ),
+                    __('The credit memo\'s total must be positive.')
+                ]
+            ],
+        ];
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoDocumentFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoDocumentFactoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..521167f10aebd0993adebfef05e88f4b28ef1f54
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoDocumentFactoryTest.php
@@ -0,0 +1,265 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Model\Order\CreditmemoDocumentFactory;
+use Magento\Sales\Api\Data\CreditmemoCommentInterface;
+use Magento\Sales\Model\Order;
+use Magento\Sales\Model\Order\Invoice;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\CreditmemoItemCreationInterface;
+use Magento\Sales\Api\Data\CreditmemoCommentCreationInterface;
+use Magento\Framework\EntityManager\HydratorPool;
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface;
+use Magento\Sales\Model\Order\CreditmemoFactory;
+use Magento\Framework\EntityManager\HydratorInterface;
+
+/**
+ * Class CreditmemoDocumentFactoryTest
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class CreditmemoDocumentFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var CreditmemoDocumentFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $factory;
+
+    /**
+     * @var CreditmemoFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoFactoryMock;
+
+    /**
+     * @var \Magento\Sales\Api\Data\CreditmemoCommentInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $commentFactoryMock;
+
+    /**
+     * @var HydratorPool|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $hydratorPoolMock;
+
+    /**
+     * @var HydratorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $hydratorMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Invoice|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $invoiceMock;
+
+    /**
+     * @var CreditmemoItemCreationInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoItemCreationMock;
+
+    /**
+     * @var CreditmemoCommentCreationInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $commentCreationMock;
+
+    /**
+     * @var CreditmemoCreationArgumentsInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $commentCreationArgumentsMock;
+
+    /**
+     * @var CreditmemoInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoMock;
+
+    /**
+     * @var CreditmemoCommentInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $commentMock;
+
+    /**
+     * @var OrderRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderRepositoryMock;
+
+    public function setUp()
+    {
+        $this->objectManager = new ObjectManager($this);
+        $this->creditmemoFactoryMock = $this->getMockBuilder(CreditmemoFactory::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->commentFactoryMock =
+            $this->getMockBuilder('Magento\Sales\Api\Data\CreditmemoCommentInterfaceFactory')
+                ->setMethods(['create'])
+                ->getMock();
+        $this->hydratorPoolMock = $this->getMockBuilder(HydratorPool::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderMock = $this->getMockBuilder(Order::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->invoiceMock = $this->getMockBuilder(Invoice::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoItemCreationMock = $this->getMockBuilder(CreditmemoItemCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->hydratorMock = $this->getMockBuilder(HydratorInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->commentCreationArgumentsMock = $this->getMockBuilder(CreditmemoCreationArgumentsInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->commentCreationMock = $this->getMockBuilder(CreditmemoCommentCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoMock->expects($this->once())
+            ->method('getEntityId')
+            ->willReturn(11);
+
+        $this->commentMock = $this->getMockBuilder(CreditmemoCommentInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(
+                array_merge(
+                    get_class_methods(CreditmemoCommentInterface::class),
+                    ['setStoreId', 'setCreditmemo']
+                )
+            )
+            ->getMock();
+        $this->factory = $this->objectManager->getObject(
+            CreditmemoDocumentFactory::class,
+            [
+                'creditmemoFactory' => $this->creditmemoFactoryMock,
+                'commentFactory' => $this->commentFactoryMock,
+                'hydratorPool' => $this->hydratorPoolMock,
+                'orderRepository' => $this->orderRepositoryMock
+            ]
+        );
+    }
+
+    private function commonFactoryFlow()
+    {
+        $this->creditmemoItemCreationMock->expects($this->once())
+            ->method('getOrderItemId')
+            ->willReturn(7);
+        $this->creditmemoItemCreationMock->expects($this->once())
+            ->method('getQty')
+            ->willReturn(3);
+        $this->hydratorPoolMock->expects($this->exactly(2))
+            ->method('getHydrator')
+            ->willReturnMap(
+                [
+                    [CreditmemoCreationArgumentsInterface::class, $this->hydratorMock],
+                    [CreditmemoCommentCreationInterface::class, $this->hydratorMock],
+                ]
+            );
+        $this->hydratorMock->expects($this->exactly(2))
+            ->method('extract')
+            ->willReturnMap([
+                [$this->commentCreationArgumentsMock, ['shipping_amount' => '20.00']],
+                [$this->commentCreationMock, ['comment' => 'text']]
+            ]);
+        $this->commentFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(
+                [
+                    'data' => [
+                        'comment' => 'text'
+                    ]
+                ]
+            )
+            ->willReturn($this->commentMock);
+        $this->creditmemoMock->expects($this->once())
+            ->method('getEntityId')
+            ->willReturn(11);
+        $this->creditmemoMock->expects($this->once())
+            ->method('getStoreId')
+            ->willReturn(1);
+        $this->commentMock->expects($this->once())
+            ->method('setParentId')
+            ->with(11)
+            ->willReturnSelf();
+        $this->commentMock->expects($this->once())
+            ->method('setStoreId')
+            ->with(1)
+            ->willReturnSelf();
+        $this->commentMock->expects($this->once())
+            ->method('setIsCustomerNotified')
+            ->with(true)
+            ->willReturnSelf();
+        $this->commentMock->expects($this->once())
+            ->method('setCreditmemo')
+            ->with($this->creditmemoMock)
+            ->willReturnSelf();
+    }
+
+    public function testCreateFromOrder()
+    {
+        $this->commonFactoryFlow();
+        $this->creditmemoFactoryMock->expects($this->once())
+            ->method('createByOrder')
+            ->with(
+                $this->orderMock,
+                [
+                    'shipping_amount' => '20.00',
+                    'qtys' => [7 => 3]
+                ]
+            )
+            ->willReturn($this->creditmemoMock);
+        $this->factory->createFromOrder(
+            $this->orderMock,
+            [$this->creditmemoItemCreationMock],
+            $this->commentCreationMock,
+            true,
+            $this->commentCreationArgumentsMock
+        );
+    }
+
+    public function testCreateFromInvoice()
+    {
+        $this->commonFactoryFlow();
+        $this->creditmemoFactoryMock->expects($this->once())
+            ->method('createByInvoice')
+            ->with(
+                $this->invoiceMock,
+                [
+                    'shipping_amount' => '20.00',
+                    'qtys' => [7 => 3]
+                ]
+            )
+            ->willReturn($this->creditmemoMock);
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($this->orderMock);
+        $this->invoiceMock->expects($this->once())
+            ->method('setOrder')
+            ->with($this->orderMock)
+            ->willReturnSelf();
+        $this->factory->createFromInvoice(
+            $this->invoiceMock,
+            [$this->creditmemoItemCreationMock],
+            $this->commentCreationMock,
+            true,
+            $this->commentCreationArgumentsMock
+        );
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Validation/CanRefundTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Validation/CanRefundTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..773f3b75c91f5c4f6aad03576b0cfe9dd4746ab1
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Validation/CanRefundTest.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order\Invoice\Validation;
+
+use Magento\Sales\Api\Data\OrderInterface;
+
+/**
+ * Class CanRefundTest
+ */
+class CanRefundTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Sales\Model\Order\Invoice|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $invoiceMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderPaymentRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $paymentMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Invoice\Validation\CanRefund
+     */
+    private $validator;
+
+    protected function setUp()
+    {
+        $this->invoiceMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Invoice::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderPaymentRepositoryMock = $this->getMockBuilder(
+            \Magento\Sales\Api\OrderPaymentRepositoryInterface::class
+        )
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->orderRepositoryMock = $this->getMockBuilder(\Magento\Sales\Api\OrderRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->paymentMock = $this->getMockBuilder(\Magento\Payment\Model\InfoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->validator = new \Magento\Sales\Model\Order\Invoice\Validation\CanRefund(
+            $this->orderPaymentRepositoryMock,
+            $this->orderRepositoryMock
+        );
+    }
+
+    public function testValidateWrongInvoiceState()
+    {
+        $this->invoiceMock->expects($this->exactly(2))
+            ->method('getState')
+            ->willReturnOnConsecutiveCalls(
+                \Magento\Sales\Model\Order\Invoice::STATE_OPEN,
+                \Magento\Sales\Model\Order\Invoice::STATE_CANCELED
+            );
+        $this->assertEquals(
+            [__('We can\'t create creditmemo for the invoice.')],
+            $this->validator->validate($this->invoiceMock)
+        );
+        $this->assertEquals(
+            [__('We can\'t create creditmemo for the invoice.')],
+            $this->validator->validate($this->invoiceMock)
+        );
+    }
+
+    public function testValidateInvoiceSumWasRefunded()
+    {
+        $this->invoiceMock->expects($this->once())
+            ->method('getState')
+            ->willReturn(\Magento\Sales\Model\Order\Invoice::STATE_PAID);
+        $this->invoiceMock->expects($this->once())
+            ->method('getBaseGrandTotal')
+            ->willReturn(1);
+        $this->invoiceMock->expects($this->once())
+            ->method('getBaseTotalRefunded')
+            ->willReturn(1);
+        $this->assertEquals(
+            [__('We can\'t create creditmemo for the invoice.')],
+            $this->validator->validate($this->invoiceMock)
+        );
+    }
+
+    public function testValidate()
+    {
+        $this->invoiceMock->expects($this->once())
+            ->method('getState')
+            ->willReturn(\Magento\Sales\Model\Order\Invoice::STATE_PAID);
+        $orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($orderMock);
+        $orderMock->expects($this->once())
+            ->method('getPayment')
+            ->willReturn($this->paymentMock);
+        $methodInstanceMock = $this->getMockBuilder(\Magento\Payment\Model\MethodInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->paymentMock->expects($this->once())
+            ->method('getMethodInstance')
+            ->willReturn($methodInstanceMock);
+        $methodInstanceMock->expects($this->atLeastOnce())
+            ->method('canRefund')
+            ->willReturn(true);
+        $this->invoiceMock->expects($this->once())
+            ->method('getBaseGrandTotal')
+            ->willReturn(1);
+        $this->invoiceMock->expects($this->once())
+            ->method('getBaseTotalRefunded')
+            ->willReturn(0);
+        $this->assertEquals(
+            [],
+            $this->validator->validate($this->invoiceMock)
+        );
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanRefundTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanRefundTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0b4246d46944444041d92089ddc19a4d270df86f
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanRefundTest.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order\Validation;
+
+use Magento\Sales\Model\Order;
+
+/**
+ * Class CanRefundTest
+ */
+class CanRefundTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Sales\Model\Order\Validation\CanRefund|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $model;
+
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Sales\Api\Data\OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var \Magento\Framework\Pricing\PriceCurrencyInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $priceCurrencyMock;
+
+    protected function setUp()
+    {
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->orderMock = $this->getMockBuilder(\Magento\Sales\Api\Data\OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getStatus', 'getItems'])
+            ->getMockForAbstractClass();
+
+        $this->priceCurrencyMock = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->priceCurrencyMock->expects($this->any())
+            ->method('round')
+            ->willReturnArgument(0);
+        $this->model = new \Magento\Sales\Model\Order\Validation\CanRefund(
+            $this->priceCurrencyMock
+        );
+    }
+
+    /**
+     * @param string $state
+     *
+     * @dataProvider canCreditmemoWrongStateDataProvider
+     */
+    public function testCanCreditmemoWrongState($state)
+    {
+        $this->orderMock->expects($this->any())
+            ->method('getState')
+            ->willReturn($state);
+        $this->orderMock->expects($this->once())
+            ->method('getStatus')
+            ->willReturn('status');
+        $this->orderMock->expects($this->never())
+            ->method('getTotalPaid')
+            ->willReturn(15);
+        $this->orderMock->expects($this->never())
+            ->method('getTotalRefunded')
+            ->willReturn(14);
+        $this->assertEquals(
+            [__('A creditmemo can not be created when an order has a status of %1', 'status')],
+            $this->model->validate($this->orderMock)
+        );
+    }
+
+    /**
+     * Data provider for testCanCreditmemoWrongState
+     * @return array
+     */
+    public function canCreditmemoWrongStateDataProvider()
+    {
+        return [
+            [Order::STATE_PAYMENT_REVIEW],
+            [Order::STATE_HOLDED],
+            [Order::STATE_CANCELED],
+            [Order::STATE_CLOSED],
+        ];
+    }
+
+    public function testCanCreditmemoNoMoney()
+    {
+        $this->orderMock->expects($this->any())
+            ->method('getState')
+            ->willReturn(Order::STATE_PROCESSING);
+        $this->orderMock->expects($this->once())
+            ->method('getTotalPaid')
+            ->willReturn(15);
+        $this->orderMock->expects($this->once())
+            ->method('getTotalRefunded')
+            ->willReturn(15);
+        $this->assertEquals(
+            [
+                __('The order does not allow a creditmemo to be created.')
+            ],
+            $this->model->validate($this->orderMock)
+        );
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/RefundInvoiceTest.php b/app/code/Magento/Sales/Test/Unit/Model/RefundInvoiceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1c4aab6dd2feb1f2ac4d260bc44245633bc17467
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/RefundInvoiceTest.php
@@ -0,0 +1,491 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model;
+
+use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\DB\Adapter\AdapterInterface;
+use Magento\Sales\Api\CreditmemoRepositoryInterface;
+use Magento\Sales\Api\Data\CreditmemoCommentCreationInterface;
+use Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface;
+use Magento\Sales\Api\Data\CreditmemoInterface;
+use Magento\Sales\Api\Data\InvoiceInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+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\RefundInvoice;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Class RefundInvoiceTest
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.TooManyFields)
+ */
+class RefundInvoiceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resourceConnectionMock;
+
+    /**
+     * @var OrderRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderRepositoryMock;
+
+    /**
+     * @var InvoiceRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $invoiceRepositoryMock;
+
+    /**
+     * @var CreditmemoDocumentFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    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
+     */
+    private $paymentAdapterMock;
+
+    /**
+     * @var OrderStateResolverInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderStateResolverMock;
+
+    /**
+     * @var OrderConfig|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $configMock;
+
+    /**
+     * @var Order\CreditmemoRepository|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoRepositoryMock;
+
+    /**
+     * @var NotifierInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $notifierMock;
+
+    /**
+     * @var RefundInvoice|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $refundInvoice;
+
+    /**
+     * @var CreditmemoCreationArgumentsInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoCommentCreationMock;
+
+    /**
+     * @var CreditmemoCommentCreationInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoCreationArgumentsMock;
+
+    /**
+     * @var OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $invoiceMock;
+
+    /**
+     * @var CreditmemoInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoMock;
+
+    /**
+     * @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $adapterInterface;
+
+    /**
+     * @var CreditmemoItemCreationInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoItemCreationMock;
+
+    /**
+     * @var ItemCreationValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $itemCreationValidatorMock;
+
+    /**
+     * @var LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $loggerMock;
+
+    protected function setUp()
+    {
+        $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->invoiceRepositoryMock = $this->getMockBuilder(InvoiceRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $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)
+            ->disableOriginalConstructor()
+            ->getMock();
+        
+        $this->paymentAdapterMock = $this->getMockBuilder(PaymentAdapterInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderStateResolverMock = $this->getMockBuilder(OrderStateResolverInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->configMock = $this->getMockBuilder(OrderConfig::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->creditmemoRepositoryMock = $this->getMockBuilder(CreditmemoRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->notifierMock = $this->getMockBuilder(NotifierInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->loggerMock = $this->getMockBuilder(LoggerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->creditmemoCommentCreationMock = $this->getMockBuilder(CreditmemoCommentCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->creditmemoCreationArgumentsMock = $this->getMockBuilder(CreditmemoCreationArgumentsInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->invoiceMock = $this->getMockBuilder(InvoiceInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->adapterInterface = $this->getMockBuilder(AdapterInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->creditmemoItemCreationMock = $this->getMockBuilder(CreditmemoItemCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->itemCreationValidatorMock = $this->getMockBuilder(ItemCreationValidatorInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->refundInvoice = new RefundInvoice(
+            $this->resourceConnectionMock,
+            $this->orderStateResolverMock,
+            $this->orderRepositoryMock,
+            $this->invoiceRepositoryMock,
+            $this->orderValidatorMock,
+            $this->invoiceValidatorMock,
+            $this->creditmemoValidatorMock,
+            $this->itemCreationValidatorMock,
+            $this->creditmemoRepositoryMock,
+            $this->paymentAdapterMock,
+            $this->creditmemoDocumentFactoryMock,
+            $this->notifierMock,
+            $this->configMock,
+            $this->loggerMock
+        );
+    }
+
+    /**
+     * @dataProvider dataProvider
+     */
+    public function testOrderCreditmemo($invoiceId, $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(
+                $this->invoiceMock,
+                $items,
+                $this->creditmemoCommentCreationMock,
+                ($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->invoiceValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->invoiceMock)
+            ->willReturn([]);
+        $this->itemCreationValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->creditmemoItemCreationMock)
+            ->willReturn([]);
+        $this->paymentAdapterMock->expects($this->once())
+            ->method('refund')
+            ->with($this->creditmemoMock, $this->orderMock)
+            ->willReturn($this->orderMock);
+        $this->orderStateResolverMock->expects($this->once())
+            ->method('getStateForOrder')
+            ->with($this->orderMock, [])
+            ->willReturn(Order::STATE_CLOSED);
+        $this->orderMock->expects($this->once())
+            ->method('setState')
+            ->with(Order::STATE_CLOSED)
+            ->willReturnSelf();
+        $this->orderMock->expects($this->once())
+            ->method('getState')
+            ->willReturn(Order::STATE_CLOSED);
+        $this->configMock->expects($this->once())
+            ->method('getStateDefaultStatus')
+            ->with(Order::STATE_CLOSED)
+            ->willReturn('Closed');
+        $this->orderMock->expects($this->once())
+            ->method('setStatus')
+            ->with('Closed')
+            ->willReturnSelf();
+        $this->creditmemoMock->expects($this->once())
+            ->method('setState')
+            ->with(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED)
+            ->willReturnSelf();
+
+        $this->creditmemoRepositoryMock->expects($this->once())
+            ->method('save')
+            ->with($this->creditmemoMock)
+            ->willReturn($this->creditmemoMock);
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('save')
+            ->with($this->orderMock)
+            ->willReturn($this->orderMock);
+        if ($notify) {
+            $this->notifierMock->expects($this->once())
+                ->method('notify')
+                ->with($this->orderMock, $this->creditmemoMock, $this->creditmemoCommentCreationMock);
+        }
+        $this->creditmemoMock->expects($this->once())
+            ->method('getEntityId')
+            ->willReturn(2);
+
+        $this->assertEquals(
+            2,
+            $this->refundInvoice->execute(
+                $invoiceId,
+                $items,
+                false,
+                $notify,
+                $appendComment,
+                $this->creditmemoCommentCreationMock,
+                $this->creditmemoCreationArgumentsMock
+            )
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Sales\Api\Exception\DocumentValidationExceptionInterface
+     */
+    public function testDocumentValidationException()
+    {
+        $invoiceId = 1;
+        $items = [1 => $this->creditmemoItemCreationMock];
+        $notify = true;
+        $appendComment = true;
+        $errorMessages = ['error1', 'error2'];
+
+        $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(
+                $this->invoiceMock,
+                $items,
+                $this->creditmemoCommentCreationMock,
+                ($appendComment && $notify),
+                $this->creditmemoCreationArgumentsMock
+            )->willReturn($this->creditmemoMock);
+
+        $this->creditmemoValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->creditmemoMock)
+            ->willReturn($errorMessages);
+        $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->assertEquals(
+            $errorMessages,
+            $this->refundInvoice->execute(
+                $invoiceId,
+                $items,
+                false,
+                $notify,
+                $appendComment,
+                $this->creditmemoCommentCreationMock,
+                $this->creditmemoCreationArgumentsMock
+            )
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Sales\Api\Exception\CouldNotRefundExceptionInterface
+     */
+    public function testCouldNotCreditmemoException()
+    {
+        $invoiceId = 1;
+        $items = [1 => $this->creditmemoItemCreationMock];
+        $notify = true;
+        $appendComment = true;
+        $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(
+                $this->invoiceMock,
+                $items,
+                $this->creditmemoCommentCreationMock,
+                ($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->invoiceValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->invoiceMock)
+            ->willReturn([]);
+        $this->itemCreationValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->creditmemoItemCreationMock)
+            ->willReturn([]);
+        $e = new \Exception();
+
+        $this->paymentAdapterMock->expects($this->once())
+            ->method('refund')
+            ->with($this->creditmemoMock, $this->orderMock)
+            ->willThrowException($e);
+
+        $this->loggerMock->expects($this->once())
+            ->method('critical')
+            ->with($e);
+
+        $this->adapterInterface->expects($this->once())
+            ->method('rollBack');
+
+        $this->refundInvoice->execute(
+            $invoiceId,
+            $items,
+            false,
+            $notify,
+            $appendComment,
+            $this->creditmemoCommentCreationMock,
+            $this->creditmemoCreationArgumentsMock
+        );
+    }
+
+    public function dataProvider()
+    {
+        $creditmemoItemCreationMock = $this->getMockBuilder(CreditmemoItemCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        return [
+            'TestWithNotifyTrue' => [1, [1 => $creditmemoItemCreationMock], true, true],
+            'TestWithNotifyFalse' => [1, [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
new file mode 100644
index 0000000000000000000000000000000000000000..7d684695664ba1d1b63a5b78cf610da019cf39bb
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php
@@ -0,0 +1,423 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model;
+
+use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\DB\Adapter\AdapterInterface;
+use Magento\Sales\Api\CreditmemoRepositoryInterface;
+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\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\PaymentAdapterInterface;
+use Magento\Sales\Model\Order\Creditmemo\NotifierInterface;
+use Magento\Sales\Model\RefundOrder;
+use Psr\Log\LoggerInterface;
+use Magento\Sales\Api\Data\CreditmemoItemCreationInterface;
+
+/**
+ * Class RefundOrderTest
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.TooManyFields)
+ */
+class RefundOrderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resourceConnectionMock;
+
+    /**
+     * @var OrderRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderRepositoryMock;
+
+    /**
+     * @var CreditmemoDocumentFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoDocumentFactoryMock;
+
+    /**
+     * @var CreditmemoValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoValidatorMock;
+
+    /**
+     * @var OrderValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderValidatorMock;
+
+    /**
+     * @var PaymentAdapterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $paymentAdapterMock;
+
+    /**
+     * @var OrderStateResolverInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderStateResolverMock;
+
+    /**
+     * @var OrderConfig|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $configMock;
+
+    /**
+     * @var Order\CreditmemoRepository|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoRepositoryMock;
+
+    /**
+     * @var NotifierInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $notifierMock;
+
+    /**
+     * @var RefundOrder|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $refundOrder;
+
+    /**
+     * @var CreditmemoCreationArgumentsInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoCommentCreationMock;
+
+    /**
+     * @var CreditmemoCommentCreationInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoCreationArgumentsMock;
+
+    /**
+     * @var OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var CreditmemoInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoMock;
+
+    /**
+     * @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $adapterInterface;
+
+    /**
+     * @var LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $loggerMock;
+
+    /**
+     * @var Order\Creditmemo\ItemCreationValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $itemCreationValidatorMock;
+
+    /**
+     * @var CreditmemoItemCreationInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $creditmemoItemCreationMock;
+
+    protected function setUp()
+    {
+        $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $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->paymentAdapterMock = $this->getMockBuilder(PaymentAdapterInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->orderStateResolverMock = $this->getMockBuilder(OrderStateResolverInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->configMock = $this->getMockBuilder(OrderConfig::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->creditmemoRepositoryMock = $this->getMockBuilder(CreditmemoRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->notifierMock = $this->getMockBuilder(NotifierInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->loggerMock = $this->getMockBuilder(LoggerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->creditmemoCommentCreationMock = $this->getMockBuilder(CreditmemoCommentCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->creditmemoCreationArgumentsMock = $this->getMockBuilder(CreditmemoCreationArgumentsInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $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->refundOrder = new RefundOrder(
+            $this->resourceConnectionMock,
+            $this->orderStateResolverMock,
+            $this->orderRepositoryMock,
+            $this->orderValidatorMock,
+            $this->creditmemoValidatorMock,
+            $this->itemCreationValidatorMock,
+            $this->creditmemoRepositoryMock,
+            $this->paymentAdapterMock,
+            $this->creditmemoDocumentFactoryMock,
+            $this->notifierMock,
+            $this->configMock,
+            $this->loggerMock
+        );
+    }
+
+    /**
+     * @dataProvider dataProvider
+     */
+    public function testOrderCreditmemo($orderId, $notify, $appendComment)
+    {
+        $items = [$this->creditmemoItemCreationMock];
+        $this->resourceConnectionMock->expects($this->once())
+            ->method('getConnection')
+            ->with('sales')
+            ->willReturn($this->adapterInterface);
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($this->orderMock);
+        $this->creditmemoDocumentFactoryMock->expects($this->once())
+            ->method('createFromOrder')
+            ->with(
+                $this->orderMock,
+                $items,
+                $this->creditmemoCommentCreationMock,
+                ($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())
+            ->method('validate')
+            ->with(
+                reset($items),
+                [CreationQuantityValidator::class],
+                $this->orderMock
+            )->willReturn([]);
+        $this->paymentAdapterMock->expects($this->once())
+            ->method('refund')
+            ->with($this->creditmemoMock, $this->orderMock)
+            ->willReturn($this->orderMock);
+        $this->orderStateResolverMock->expects($this->once())
+            ->method('getStateForOrder')
+            ->with($this->orderMock, [])
+            ->willReturn(Order::STATE_CLOSED);
+
+        $this->orderMock->expects($this->once())
+            ->method('setState')
+            ->with(Order::STATE_CLOSED)
+            ->willReturnSelf();
+
+        $this->orderMock->expects($this->once())
+            ->method('getState')
+            ->willReturn(Order::STATE_CLOSED);
+
+        $this->configMock->expects($this->once())
+            ->method('getStateDefaultStatus')
+            ->with(Order::STATE_CLOSED)
+            ->willReturn('Closed');
+
+        $this->orderMock->expects($this->once())
+            ->method('setStatus')
+            ->with('Closed')
+            ->willReturnSelf();
+
+        $this->creditmemoMock->expects($this->once())
+            ->method('setState')
+            ->with(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED)
+            ->willReturnSelf();
+
+        $this->creditmemoRepositoryMock->expects($this->once())
+            ->method('save')
+            ->with($this->creditmemoMock)
+            ->willReturn($this->creditmemoMock);
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('save')
+            ->with($this->orderMock)
+            ->willReturn($this->orderMock);
+
+        if ($notify) {
+            $this->notifierMock->expects($this->once())
+                ->method('notify')
+                ->with($this->orderMock, $this->creditmemoMock, $this->creditmemoCommentCreationMock);
+        }
+
+        $this->creditmemoMock->expects($this->once())
+            ->method('getEntityId')
+            ->willReturn(2);
+
+        $this->assertEquals(
+            2,
+            $this->refundOrder->execute(
+                $orderId,
+                $items,
+                $notify,
+                $appendComment,
+                $this->creditmemoCommentCreationMock,
+                $this->creditmemoCreationArgumentsMock
+            )
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Sales\Api\Exception\DocumentValidationExceptionInterface
+     */
+    public function testDocumentValidationException()
+    {
+        $orderId = 1;
+        $items = [$this->creditmemoItemCreationMock];
+        $notify = true;
+        $appendComment = true;
+        $errorMessages = ['error1', 'error2'];
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($this->orderMock);
+
+        $this->creditmemoDocumentFactoryMock->expects($this->once())
+            ->method('createFromOrder')
+            ->with(
+                $this->orderMock,
+                $items,
+                $this->creditmemoCommentCreationMock,
+                ($appendComment && $notify),
+                $this->creditmemoCreationArgumentsMock
+            )->willReturn($this->creditmemoMock);
+
+        $this->creditmemoValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->creditmemoMock)
+            ->willReturn($errorMessages);
+        $this->orderValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->orderMock)
+            ->willReturn([]);
+        $this->itemCreationValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with(reset($items), [CreationQuantityValidator::class], $this->orderMock)
+            ->willReturn([]);
+
+        $this->assertEquals(
+            $errorMessages,
+            $this->refundOrder->execute(
+                $orderId,
+                $items,
+                $notify,
+                $appendComment,
+                $this->creditmemoCommentCreationMock,
+                $this->creditmemoCreationArgumentsMock
+            )
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Sales\Api\Exception\CouldNotRefundExceptionInterface
+     */
+    public function testCouldNotCreditmemoException()
+    {
+        $orderId = 1;
+        $items = [$this->creditmemoItemCreationMock];
+        $notify = true;
+        $appendComment = true;
+        $this->resourceConnectionMock->expects($this->once())
+            ->method('getConnection')
+            ->with('sales')
+            ->willReturn($this->adapterInterface);
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($this->orderMock);
+        $this->creditmemoDocumentFactoryMock->expects($this->once())
+            ->method('createFromOrder')
+            ->with(
+                $this->orderMock,
+                $items,
+                $this->creditmemoCommentCreationMock,
+                ($appendComment && $notify),
+                $this->creditmemoCreationArgumentsMock
+            )->willReturn($this->creditmemoMock);
+        $this->itemCreationValidatorMock->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([]);
+        $e = new \Exception();
+        $this->paymentAdapterMock->expects($this->once())
+            ->method('refund')
+            ->with($this->creditmemoMock, $this->orderMock)
+            ->willThrowException($e);
+        $this->loggerMock->expects($this->once())
+            ->method('critical')
+            ->with($e);
+        $this->adapterInterface->expects($this->once())
+            ->method('rollBack');
+
+        $this->refundOrder->execute(
+            $orderId,
+            $items,
+            $notify,
+            $appendComment,
+            $this->creditmemoCommentCreationMock,
+            $this->creditmemoCreationArgumentsMock
+        );
+    }
+
+    public function dataProvider()
+    {
+        return [
+            'TestWithNotifyTrue' => [1, true, true],
+            'TestWithNotifyFalse' => [1, false, true],
+        ];
+    }
+}
diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml
index 47800b377bb4dd5703a6d3640980982e99bbeaed..4b921587c292b54bdd49a40cb174a7de373917f5 100644
--- a/app/code/Magento/Sales/etc/di.xml
+++ b/app/code/Magento/Sales/etc/di.xml
@@ -47,6 +47,8 @@
     <preference for="Magento\Sales\Api\CreditmemoItemRepositoryInterface" type="Magento\Sales\Api\Data\CreditmemoItem\Repository"/>
     <preference for="Magento\Sales\Api\CreditmemoRepositoryInterface" type="Magento\Sales\Model\Order\CreditmemoRepository"/>
     <preference for="Magento\Sales\Api\CreditmemoManagementInterface" type="Magento\Sales\Model\Service\CreditmemoService"/>
+    <preference for="Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface" type="Magento\Sales\Model\Order\Creditmemo\CreationArguments"/>
+    <preference for="Magento\Sales\Api\Data\CreditmemoItemCreationInterface" type="Magento\Sales\Model\Order\Creditmemo\ItemCreation"/>
     <preference for="Magento\Sales\Api\InvoiceCommentRepositoryInterface" type="Magento\Sales\Api\Data\InvoiceComment\Repository"/>
     <preference for="Magento\Sales\Api\InvoiceItemRepositoryInterface" type="Magento\Sales\Api\Data\InvoiceItem\Repository"/>
     <preference for="Magento\Sales\Api\InvoiceRepositoryInterface" type="Magento\Sales\Model\Order\InvoiceRepository"/>
@@ -55,6 +57,7 @@
     <preference for="Magento\Sales\Api\Data\InvoiceItemCreationInterface" type="Magento\Sales\Model\Order\Invoice\ItemCreation"/>
     <preference for="Magento\Sales\Api\Data\InvoiceCommentCreationInterface" type="Magento\Sales\Model\Order\Invoice\CommentCreation"/>
     <preference for="Magento\Sales\Api\Data\ShipmentCommentCreationInterface" type="Magento\Sales\Model\Order\Shipment\CommentCreation"/>
+    <preference for="Magento\Sales\Api\Data\CreditmemoCommentCreationInterface" type="Magento\Sales\Model\Order\Creditmemo\CommentCreation"/>
     <preference for="Magento\Sales\Api\OrderAddressRepositoryInterface" type="Magento\Sales\Model\Order\AddressRepository"/>
     <preference for="Magento\Sales\Api\OrderCustomerManagementInterface" type="Magento\Sales\Model\Order\CustomerManagement"/>
     <preference for="Magento\Sales\Api\OrderItemRepositoryInterface" type="Magento\Sales\Model\Order\ItemRepository"/>
@@ -100,6 +103,11 @@
     <preference for="Magento\Sales\Model\Order\OrderValidatorInterface" type="Magento\Sales\Model\Order\OrderValidator"/>
     <preference for="Magento\Sales\Model\Order\Invoice\InvoiceValidatorInterface" type="Magento\Sales\Model\Order\Invoice\InvoiceValidator"/>
     <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\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"/>
     <type name="Magento\Sales\Model\ResourceModel\Report" shared="false"/>
     <type name="Magento\Sales\Model\Order\Pdf\Config\Reader">
         <arguments>
@@ -926,6 +934,13 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Sales\Model\Order\Creditmemo\Notifier">
+        <arguments>
+            <argument name="senders" xsi:type="array">
+                <item name="email" xsi:type="object">Magento\Sales\Model\Order\Creditmemo\Sender\EmailSender</item>
+            </argument>
+        </arguments>
+    </type>
     <type name="Magento\Framework\EntityManager\HydratorPool">
         <arguments>
             <argument name="hydrators" xsi:type="array">
diff --git a/app/code/Magento/Sales/etc/webapi.xml b/app/code/Magento/Sales/etc/webapi.xml
index 4c7fe03a201f8b25c2af83219fd0576da4c2cd3e..b2a88b8cad709d1b0726a66d70b9779241840409 100644
--- a/app/code/Magento/Sales/etc/webapi.xml
+++ b/app/code/Magento/Sales/etc/webapi.xml
@@ -133,6 +133,12 @@
             <resource ref="Magento_Sales::sales" />
         </resources>
     </route>
+    <route url="/V1/invoice/:invoiceId/refund" method="POST">
+        <service class="Magento\Sales\Api\RefundInvoiceInterface" method="execute"/>
+        <resources>
+            <resource ref="Magento_Sales::sales" />
+        </resources>
+    </route>
     <route url="/V1/creditmemo/:id/comments" method="GET">
         <service class="Magento\Sales\Api\CreditmemoManagementInterface" method="getCommentsList"/>
         <resources>
@@ -181,6 +187,12 @@
             <resource ref="Magento_Sales::sales" />
         </resources>
     </route>
+    <route url="/V1/order/:orderId/refund" method="POST">
+        <service class="Magento\Sales\Api\RefundOrderInterface" method="execute"/>
+        <resources>
+            <resource ref="Magento_Sales::sales" />
+        </resources>
+    </route>
     <route url="/V1/shipment/:id" method="GET">
         <service class="Magento\Sales\Api\ShipmentRepositoryInterface" method="get"/>
         <resources>
diff --git a/app/code/Magento/Vault/Model/Method/Vault.php b/app/code/Magento/Vault/Model/Method/Vault.php
index 0e6689461e14b6d8647693aa2dc942a240bc2cc2..ce85936607192b81fcdd9da59fb48704fc92d48e 100644
--- a/app/code/Magento/Vault/Model/Method/Vault.php
+++ b/app/code/Magento/Vault/Model/Method/Vault.php
@@ -579,7 +579,7 @@ final class Vault implements VaultPaymentInterface
     public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null)
     {
         return $this->getVaultProvider()->isAvailable($quote)
-            && $this->config->getValue(self::$activeKey, $this->getStore() ?: $quote->getStoreId());
+            && $this->config->getValue(self::$activeKey, $this->getStore() ?: ($quote ? $quote->getStoreId() : null));
     }
 
     /**
diff --git a/app/code/Magento/Vault/Model/Ui/TokensConfigProvider.php b/app/code/Magento/Vault/Model/Ui/TokensConfigProvider.php
index 434a5875b5bb1b4bffb1b77547e64740107b902d..6a86ed694642c31407ba0c08e3ac39f646244cca 100644
--- a/app/code/Magento/Vault/Model/Ui/TokensConfigProvider.php
+++ b/app/code/Magento/Vault/Model/Ui/TokensConfigProvider.php
@@ -7,7 +7,7 @@ namespace Magento\Vault\Model\Ui;
 
 use Magento\Checkout\Model\ConfigProviderInterface;
 use Magento\Framework\App\ObjectManager;
-use Magento\Payment\Helper\Data;
+use Magento\Payment\Api\Data\PaymentMethodInterface;
 use Magento\Store\Model\StoreManagerInterface;
 use Magento\Vault\Model\CustomerTokenManagement;
 use Magento\Vault\Model\VaultPaymentInterface;
@@ -39,9 +39,14 @@ final class TokensConfigProvider implements ConfigProviderInterface
     private $customerTokenManagement;
 
     /**
-     * @var Data
+     * @var \Magento\Payment\Api\PaymentMethodListInterface
      */
-    private $paymentDataHelper;
+    private $paymentMethodList;
+
+    /**
+     * @var \Magento\Payment\Model\Method\InstanceFactory
+     */
+    private $paymentMethodInstanceFactory;
 
     /**
      * Constructor
@@ -98,21 +103,16 @@ final class TokensConfigProvider implements ConfigProviderInterface
     }
 
     /**
-     * Get list of available vault ui token providers
+     * Get list of available vault ui token providers.
+     *
      * @return TokenUiComponentProviderInterface[]
      */
     private function getComponentProviders()
     {
         $providers = [];
-        $storeId = $this->storeManager->getStore()->getId();
-        $paymentMethods = $this->getPaymentDataHelper()->getStoreMethods($storeId);
+        $vaultPaymentMethods = $this->getVaultPaymentMethodList();
 
-        foreach ($paymentMethods as $method) {
-            /** VaultPaymentInterface $method */
-            if (!$method instanceof VaultPaymentInterface || !$method->isActive($storeId)) {
-                continue;
-            }
-            
+        foreach ($vaultPaymentMethods as $method) {
             $providerCode = $method->getProviderCode();
             $componentProvider = $this->getComponentProvider($providerCode);
             if ($componentProvider === null) {
@@ -139,15 +139,60 @@ final class TokensConfigProvider implements ConfigProviderInterface
     }
 
     /**
-     * Get payment data helper instance
-     * @return Data
+     * Get list of active Vault payment methods.
+     *
+     * @return VaultPaymentInterface[]
+     */
+    private function getVaultPaymentMethodList()
+    {
+        $storeId = $this->storeManager->getStore()->getId();
+
+        $paymentMethods = array_map(
+            function (PaymentMethodInterface $paymentMethod) {
+                return $this->getPaymentMethodInstanceFactory()->create($paymentMethod);
+            },
+            $this->getPaymentMethodList()->getActiveList($storeId)
+        );
+
+        $availableMethods = array_filter(
+            $paymentMethods,
+            function (\Magento\Payment\Model\MethodInterface $methodInstance) {
+                return $methodInstance instanceof VaultPaymentInterface;
+            }
+        );
+
+        return $availableMethods;
+    }
+
+    /**
+     * Get payment method list.
+     *
+     * @return \Magento\Payment\Api\PaymentMethodListInterface
+     * @deprecated
+     */
+    private function getPaymentMethodList()
+    {
+        if ($this->paymentMethodList === null) {
+            $this->paymentMethodList = ObjectManager::getInstance()->get(
+                \Magento\Payment\Api\PaymentMethodListInterface::class
+            );
+        }
+        return $this->paymentMethodList;
+    }
+
+    /**
+     * Get payment method instance factory.
+     *
+     * @return \Magento\Payment\Model\Method\InstanceFactory
      * @deprecated
      */
-    private function getPaymentDataHelper()
+    private function getPaymentMethodInstanceFactory()
     {
-        if ($this->paymentDataHelper === null) {
-            $this->paymentDataHelper = ObjectManager::getInstance()->get(Data::class);
+        if ($this->paymentMethodInstanceFactory === null) {
+            $this->paymentMethodInstanceFactory = ObjectManager::getInstance()->get(
+                \Magento\Payment\Model\Method\InstanceFactory::class
+            );
         }
-        return $this->paymentDataHelper;
+        return $this->paymentMethodInstanceFactory;
     }
 }
diff --git a/app/code/Magento/Vault/Model/Ui/VaultConfigProvider.php b/app/code/Magento/Vault/Model/Ui/VaultConfigProvider.php
index 8bf88e7a94f509ddd9d23c239dd59dccb15d4e85..9cd7b97562df98e309b9ddd182a5ced144b2e555 100644
--- a/app/code/Magento/Vault/Model/Ui/VaultConfigProvider.php
+++ b/app/code/Magento/Vault/Model/Ui/VaultConfigProvider.php
@@ -8,7 +8,7 @@ namespace Magento\Vault\Model\Ui;
 use Magento\Checkout\Model\ConfigProviderInterface;
 use Magento\Framework\App\ObjectManager;
 use Magento\Framework\Session\SessionManagerInterface;
-use Magento\Payment\Helper\Data;
+use Magento\Payment\Api\Data\PaymentMethodInterface;
 use Magento\Store\Model\StoreManagerInterface;
 use Magento\Vault\Model\VaultPaymentInterface;
 
@@ -32,9 +32,14 @@ class VaultConfigProvider implements ConfigProviderInterface
     private $session;
 
     /**
-     * @var Data
+     * @var \Magento\Payment\Api\PaymentMethodListInterface
      */
-    private $paymentDataHelper;
+    private $paymentMethodList;
+
+    /**
+     * @var \Magento\Payment\Model\Method\InstanceFactory
+     */
+    private $paymentMethodInstanceFactory;
 
     /**
      * VaultConfigProvider constructor.
@@ -73,36 +78,60 @@ class VaultConfigProvider implements ConfigProviderInterface
     }
 
     /**
-     * Get list of active Vault payment methods
-     * @return array
+     * Get list of active Vault payment methods.
+     *
+     * @return VaultPaymentInterface[]
      */
     private function getVaultPaymentMethodList()
     {
-        $availableMethods = [];
         $storeId = $this->storeManager->getStore()->getId();
 
-        $paymentMethods = $this->getPaymentDataHelper()->getStoreMethods($storeId);
-        foreach ($paymentMethods as $method) {
-            /** VaultPaymentInterface $method */
-            if (!$method instanceof VaultPaymentInterface) {
-                continue;
+        $paymentMethods = array_map(
+            function (PaymentMethodInterface $paymentMethod) {
+                return $this->getPaymentMethodInstanceFactory()->create($paymentMethod);
+            },
+            $this->getPaymentMethodList()->getActiveList($storeId)
+        );
+
+        $availableMethods = array_filter(
+            $paymentMethods,
+            function (\Magento\Payment\Model\MethodInterface $methodInstance) {
+                return $methodInstance instanceof VaultPaymentInterface;
             }
-            $availableMethods[] = $method;
-        }
+        );
 
         return $availableMethods;
     }
 
     /**
-     * Get payment data helper instance
-     * @return Data
+     * Get payment method list.
+     *
+     * @return \Magento\Payment\Api\PaymentMethodListInterface
+     * @deprecated
+     */
+    private function getPaymentMethodList()
+    {
+        if ($this->paymentMethodList === null) {
+            $this->paymentMethodList = ObjectManager::getInstance()->get(
+                \Magento\Payment\Api\PaymentMethodListInterface::class
+            );
+        }
+        return $this->paymentMethodList;
+    }
+
+    /**
+     * Get payment method instance factory.
+     *
+     * @return \Magento\Payment\Model\Method\InstanceFactory
      * @deprecated
      */
-    private function getPaymentDataHelper()
+    private function getPaymentMethodInstanceFactory()
     {
-        if ($this->paymentDataHelper === null) {
-            $this->paymentDataHelper = ObjectManager::getInstance()->get(Data::class);
+        if ($this->paymentMethodInstanceFactory === null) {
+            $this->paymentMethodInstanceFactory = ObjectManager::getInstance()->get(
+                \Magento\Payment\Model\Method\InstanceFactory::class
+            );
         }
-        return $this->paymentDataHelper;
+        return $this->paymentMethodInstanceFactory;
     }
 }
diff --git a/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php b/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php
index fc6f3e4d2390b58303ff9261b86787fa50b1535a..e5c83911025246d10c56687604d343b233db382b 100644
--- a/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php
+++ b/app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php
@@ -274,4 +274,32 @@ class VaultTest extends \PHPUnit_Framework_TestCase
             ['isAvailableProvider' => true, 'isActiveVault' => true, 'expected' => true],
         ];
     }
+
+    /**
+     * @covers \Magento\Vault\Model\Method\Vault::isAvailable
+     */
+    public function testIsAvailableWithoutQuote()
+    {
+        $quote = null;
+
+        $vaultProvider = $this->getMockForAbstractClass(MethodInterface::class);
+        $config = $this->getMockForAbstractClass(ConfigInterface::class);
+
+        $vaultProvider->expects(static::once())
+            ->method('isAvailable')
+            ->with($quote)
+            ->willReturn(true);
+
+        $config->expects(static::once())
+            ->method('getValue')
+            ->with('active', $quote)
+            ->willReturn(false);
+
+        /** @var Vault $model */
+        $model = $this->objectManager->getObject(Vault::class, [
+            'config' => $config,
+            'vaultProvider' => $vaultProvider
+        ]);
+        static::assertFalse($model->isAvailable($quote));
+    }
 }
diff --git a/app/code/Magento/Vault/Test/Unit/Model/Ui/TokensConfigProviderTest.php b/app/code/Magento/Vault/Test/Unit/Model/Ui/TokensConfigProviderTest.php
index e64fff27ff14ca0ad0aa0ffc6d4c0eda539f8be1..3e4b8b145af67da759d6445234d18bd528832810 100644
--- a/app/code/Magento/Vault/Test/Unit/Model/Ui/TokensConfigProviderTest.php
+++ b/app/code/Magento/Vault/Test/Unit/Model/Ui/TokensConfigProviderTest.php
@@ -7,7 +7,6 @@ namespace Magento\Vault\Test\Unit\Model\Ui;
 
 use Magento\Customer\Model\Session;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
-use Magento\Payment\Helper\Data;
 use Magento\Store\Api\Data\StoreInterface;
 use Magento\Store\Model\StoreManagerInterface;
 use Magento\Vault\Api\Data\PaymentTokenInterface;
@@ -33,10 +32,25 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
     private $storeManager;
 
     /**
-     * @var VaultPaymentInterface|MockObject
+     * @var \Magento\Payment\Api\PaymentMethodListInterface|MockObject
+     */
+    private $paymentMethodList;
+
+    /**
+     * @var \Magento\Payment\Model\Method\InstanceFactory|MockObject
+     */
+    private $paymentMethodInstanceFactory;
+
+    /**
+     * @var \Magento\Payment\Api\Data\PaymentMethodInterface|MockObject
      */
     private $vaultPayment;
 
+    /**
+     * @var VaultPaymentInterface|MockObject
+     */
+    private $vaultPaymentInstance;
+
     /**
      * @var StoreInterface|MockObject
      */
@@ -47,11 +61,6 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
      */
     private $customerTokenManagement;
 
-    /**
-     * @var Data|MockObject
-     */
-    private $paymentDataHelper;
-
     /**
      * @var ObjectManager
      */
@@ -59,13 +68,18 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->vaultPayment = $this->getMock(VaultPaymentInterface::class);
+        $this->paymentMethodList = $this->getMockBuilder(\Magento\Payment\Api\PaymentMethodListInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->paymentMethodInstanceFactory = $this->getMockBuilder(
+            \Magento\Payment\Model\Method\InstanceFactory::class
+        )->disableOriginalConstructor()->getMock();
+
+        $this->vaultPayment = $this->getMockForAbstractClass(\Magento\Payment\Api\Data\PaymentMethodInterface::class);
+        $this->vaultPaymentInstance = $this->getMockForAbstractClass(VaultPaymentInterface::class);
         $this->storeManager = $this->getMock(StoreManagerInterface::class);
         $this->store = $this->getMock(StoreInterface::class);
-        $this->paymentDataHelper = $this->getMockBuilder(Data::class)
-            ->disableOriginalConstructor()
-            ->setMethods(['getStoreMethods'])
-            ->getMock();
 
         $this->objectManager = new ObjectManager($this);
         $this->customerTokenManagement = $this->getMockBuilder(CustomerTokenManagement::class)
@@ -99,17 +113,17 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
         $this->store->expects(static::once())
             ->method('getId')
             ->willReturn($storeId);
-        
-        $this->paymentDataHelper->expects(static::once())
-            ->method('getStoreMethods')
+
+        $this->paymentMethodList->expects(static::once())
+            ->method('getActiveList')
             ->with($storeId)
             ->willReturn([$this->vaultPayment]);
+
+        $this->paymentMethodInstanceFactory->expects($this->once())
+            ->method('create')
+            ->willReturn($this->vaultPaymentInstance);
         
-        $this->vaultPayment->expects(static::once())
-            ->method('isActive')
-            ->with($storeId)
-            ->willReturn(true);
-        $this->vaultPayment->expects(static::once())
+        $this->vaultPaymentInstance->expects(static::once())
             ->method('getProviderCode')
             ->willReturn($vaultProviderCode);
 
@@ -142,8 +156,13 @@ class TokensConfigProviderTest extends \PHPUnit_Framework_TestCase
 
         $this->objectManager->setBackwardCompatibleProperty(
             $configProvider,
-            'paymentDataHelper',
-            $this->paymentDataHelper
+            'paymentMethodList',
+            $this->paymentMethodList
+        );
+        $this->objectManager->setBackwardCompatibleProperty(
+            $configProvider,
+            'paymentMethodInstanceFactory',
+            $this->paymentMethodInstanceFactory
         );
 
         static::assertEquals($expectedConfig, $configProvider->getConfig());
diff --git a/app/code/Magento/Vault/Test/Unit/Model/Ui/VaultConfigProviderTest.php b/app/code/Magento/Vault/Test/Unit/Model/Ui/VaultConfigProviderTest.php
index 7d0d8339ab2b1825a77041ff4f2beb0a6d686ea1..d00531637b86d4e509662a31ce2da32752ba4a8b 100644
--- a/app/code/Magento/Vault/Test/Unit/Model/Ui/VaultConfigProviderTest.php
+++ b/app/code/Magento/Vault/Test/Unit/Model/Ui/VaultConfigProviderTest.php
@@ -7,7 +7,6 @@ namespace Magento\Vault\Test\Unit\Model\Ui;
 
 use Magento\Customer\Model\Session;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
-use Magento\Payment\Helper\Data;
 use Magento\Store\Api\Data\StoreInterface;
 use Magento\Store\Model\StoreManagerInterface;
 use Magento\Vault\Model\Ui\VaultConfigProvider;
@@ -21,15 +20,25 @@ use PHPUnit_Framework_MockObject_MockObject as MockObject;
 class VaultConfigProviderTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var Data|MockObject
+     * @var \Magento\Payment\Api\PaymentMethodListInterface|MockObject
      */
-    private $paymentDataHelper;
+    private $paymentMethodList;
 
     /**
-     * @var VaultPaymentInterface|MockObject
+     * @var \Magento\Payment\Model\Method\InstanceFactory|MockObject
+     */
+    private $paymentMethodInstanceFactory;
+
+    /**
+     * @var \Magento\Payment\Api\Data\PaymentMethodInterface|MockObject
      */
     private $vaultPayment;
 
+    /**
+     * @var VaultPaymentInterface|MockObject
+     */
+    private $vaultPaymentInstance;
+
     /**
      * @var Session|MockObject
      */
@@ -52,12 +61,16 @@ class VaultConfigProviderTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->paymentDataHelper = $this->getMockBuilder(Data::class)
+        $this->paymentMethodList = $this->getMockBuilder(\Magento\Payment\Api\PaymentMethodListInterface::class)
             ->disableOriginalConstructor()
-            ->setMethods(['getStoreMethods'])
-            ->getMock();
+            ->getMockForAbstractClass();
 
-        $this->vaultPayment = $this->getMockForAbstractClass(VaultPaymentInterface::class);
+        $this->paymentMethodInstanceFactory = $this->getMockBuilder(
+            \Magento\Payment\Model\Method\InstanceFactory::class
+        )->disableOriginalConstructor()->getMock();
+
+        $this->vaultPayment = $this->getMockForAbstractClass(\Magento\Payment\Api\Data\PaymentMethodInterface::class);
+        $this->vaultPaymentInstance = $this->getMockForAbstractClass(VaultPaymentInterface::class);
         $this->storeManager = $this->getMockForAbstractClass(StoreManagerInterface::class);
         $this->store = $this->getMockForAbstractClass(StoreInterface::class);
         $this->session = $this->getMockBuilder(Session::class)
@@ -68,8 +81,13 @@ class VaultConfigProviderTest extends \PHPUnit_Framework_TestCase
         $this->vaultConfigProvider = new VaultConfigProvider($this->storeManager, $this->session);
         $objectManager->setBackwardCompatibleProperty(
             $this->vaultConfigProvider,
-            'paymentDataHelper',
-            $this->paymentDataHelper
+            'paymentMethodList',
+            $this->paymentMethodList
+        );
+        $objectManager->setBackwardCompatibleProperty(
+            $this->vaultConfigProvider,
+            'paymentMethodInstanceFactory',
+            $this->paymentMethodInstanceFactory
         );
     }
 
@@ -101,15 +119,19 @@ class VaultConfigProviderTest extends \PHPUnit_Framework_TestCase
             ->method('getId')
             ->willReturn($storeId);
 
-        $this->paymentDataHelper->expects(static::once())
-            ->method('getStoreMethods')
+        $this->paymentMethodList->expects(static::once())
+            ->method('getActiveList')
             ->with($storeId)
             ->willReturn([$this->vaultPayment]);
 
-        $this->vaultPayment->expects(static::once())
+        $this->paymentMethodInstanceFactory->expects($this->once())
+            ->method('create')
+            ->willReturn($this->vaultPaymentInstance);
+
+        $this->vaultPaymentInstance->expects(static::once())
             ->method('getCode')
             ->willReturn($vaultPaymentCode);
-        $this->vaultPayment->expects($customerId !== null ? static::once() : static::never())
+        $this->vaultPaymentInstance->expects($customerId !== null ? static::once() : static::never())
             ->method('isActive')
             ->with($storeId)
             ->willReturn($vaultEnabled);
diff --git a/app/code/Magento/Wishlist/Helper/Data.php b/app/code/Magento/Wishlist/Helper/Data.php
index d64d1a185f0a2e7871eadc5973eb2cfe9e9853f6..736786e6e30b391e5c6b85b05f4b5ded99e7e112 100644
--- a/app/code/Magento/Wishlist/Helper/Data.php
+++ b/app/code/Magento/Wishlist/Helper/Data.php
@@ -446,7 +446,13 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
      */
     protected function _getCartUrlParameters($item)
     {
-        return ['item' => is_string($item) ? $item : $item->getWishlistItemId()];
+        $params = [
+            'item' => is_string($item) ? $item : $item->getWishlistItemId(),
+        ];
+        if ($item instanceof \Magento\Wishlist\Model\Item) {
+            $params['qty'] = $item->getQty();
+        }
+        return $params;
     }
 
     /**
diff --git a/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php b/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php
index 46054445620ac2286f40e700e5eca1a62bd2b9f6..ec6e959a3d4cadeee9ca5136fc9f919628ab4022 100644
--- a/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php
+++ b/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php
@@ -124,6 +124,7 @@ class DataTest extends \PHPUnit_Framework_TestCase
             ->setMethods([
                 'getProduct',
                 'getWishlistItemId',
+                'getQty',
             ])
             ->getMock();
 
@@ -217,6 +218,7 @@ class DataTest extends \PHPUnit_Framework_TestCase
         $url = 'result url';
         $storeId = 1;
         $wishlistItemId = 1;
+        $wishlistItemQty = 1;
 
         $this->wishlistItem->expects($this->once())
             ->method('getProduct')
@@ -224,6 +226,9 @@ class DataTest extends \PHPUnit_Framework_TestCase
         $this->wishlistItem->expects($this->once())
             ->method('getWishlistItemId')
             ->willReturn($wishlistItemId);
+        $this->wishlistItem->expects($this->once())
+            ->method('getQty')
+            ->willReturn($wishlistItemQty);
 
         $this->product->expects($this->once())
             ->method('isVisibleInSiteVisibility')
@@ -243,9 +248,13 @@ class DataTest extends \PHPUnit_Framework_TestCase
             ->with('wishlist/index/cart')
             ->willReturn($url);
 
+        $expected = [
+            'item' => $wishlistItemId,
+            'qty' => $wishlistItemQty,
+        ];
         $this->postDataHelper->expects($this->once())
             ->method('getPostData')
-            ->with($url, ['item' => $wishlistItemId])
+            ->with($url, $expected)
             ->willReturn($url);
 
         $this->assertEquals($url, $this->model->getAddToCartParams($this->wishlistItem));
@@ -256,6 +265,7 @@ class DataTest extends \PHPUnit_Framework_TestCase
         $url = 'result url';
         $storeId = 1;
         $wishlistItemId = 1;
+        $wishlistItemQty = 1;
         $referer = 'referer';
         $refererEncoded = 'referer_encoded';
 
@@ -265,6 +275,9 @@ class DataTest extends \PHPUnit_Framework_TestCase
         $this->wishlistItem->expects($this->once())
             ->method('getWishlistItemId')
             ->willReturn($wishlistItemId);
+        $this->wishlistItem->expects($this->once())
+            ->method('getQty')
+            ->willReturn($wishlistItemQty);
 
         $this->product->expects($this->once())
             ->method('isVisibleInSiteVisibility')
@@ -288,9 +301,14 @@ class DataTest extends \PHPUnit_Framework_TestCase
             ->with('wishlist/index/cart')
             ->willReturn($url);
 
+        $expected = [
+            'item' => $wishlistItemId,
+            ActionInterface::PARAM_NAME_URL_ENCODED => $refererEncoded,
+            'qty' => $wishlistItemQty,
+        ];
         $this->postDataHelper->expects($this->once())
             ->method('getPostData')
-            ->with($url, ['item' => $wishlistItemId, ActionInterface::PARAM_NAME_URL_ENCODED => $refererEncoded])
+            ->with($url, $expected)
             ->willReturn($url);
 
         $this->assertEquals($url, $this->model->getAddToCartParams($this->wishlistItem, true));
@@ -363,6 +381,7 @@ class DataTest extends \PHPUnit_Framework_TestCase
         $url = 'result url';
         $storeId = 1;
         $wishlistItemId = 1;
+        $wishlistItemQty = 1;
 
         $this->wishlistItem->expects($this->once())
             ->method('getProduct')
@@ -370,6 +389,9 @@ class DataTest extends \PHPUnit_Framework_TestCase
         $this->wishlistItem->expects($this->once())
             ->method('getWishlistItemId')
             ->willReturn($wishlistItemId);
+        $this->wishlistItem->expects($this->once())
+            ->method('getQty')
+            ->willReturn($wishlistItemQty);
 
         $this->product->expects($this->once())
             ->method('isVisibleInSiteVisibility')
@@ -383,9 +405,13 @@ class DataTest extends \PHPUnit_Framework_TestCase
             ->with('wishlist/shared/cart')
             ->willReturn($url);
 
+        $exptected = [
+            'item' => $wishlistItemId,
+            'qty' => $wishlistItemQty,
+        ];
         $this->postDataHelper->expects($this->once())
             ->method('getPostData')
-            ->with($url, ['item' => $wishlistItemId])
+            ->with($url, $exptected)
             ->willReturn($url);
 
         $this->assertEquals($url, $this->model->getSharedAddToCartUrl($this->wishlistItem));
diff --git a/app/code/Magento/Wishlist/view/frontend/web/wishlist.js b/app/code/Magento/Wishlist/view/frontend/web/wishlist.js
index a4fdc178c704f340e77f109110d63a4b0bde5dc3..0d6e510e5f5e955e54933f1a737f35b0da8fc5b6 100644
--- a/app/code/Magento/Wishlist/view/frontend/web/wishlist.js
+++ b/app/code/Magento/Wishlist/view/frontend/web/wishlist.js
@@ -47,6 +47,7 @@ define([
                         event.preventDefault();
                         $.mage.dataPost().postData($(event.currentTarget).data('post-remove'));
                     }, this))
+                    .on('click', this.options.addToCartSelector, $.proxy(this._beforeAddToCart, this))
                     .on('click', this.options.addAllToCartSelector, $.proxy(this._addAllWItemsToCart, this))
                     .on('focusin focusout', this.options.commentInputType, $.proxy(this._focusComment, this));
             }
@@ -59,6 +60,27 @@ define([
             });
         },
 
+        /**
+         * Process data before add to cart
+         *
+         * - update item's qty value.
+         *
+         * @param {Event} event
+         * @private
+         */
+        _beforeAddToCart: function(event) {
+            var elem = $(event.currentTarget),
+                itemId = elem.data(this.options.dataAttribute),
+                qtyName = $.validator.format(this.options.nameFormat, itemId),
+                qtyValue = elem.parents().find('[name="' + qtyName + '"]').val(),
+                params = elem.data('post');
+
+            if (params) {
+                params.data = $.extend({}, params.data, {'qty': qtyValue});
+                elem.data('post', params);
+            }
+        },
+
         /**
          * Add wish list items to cart.
          * @private
diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2050e01cbfdd70f5b26b40d4728d265b6b50fc77
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php
@@ -0,0 +1,314 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Service\V1;
+
+/**
+ * API test for creation of Creditmemo for certain Order.
+ */
+class RefundOrderTest extends \Magento\TestFramework\TestCase\WebapiAbstract
+{
+    const SERVICE_READ_NAME = 'salesRefundOrderV1';
+    const SERVICE_VERSION = 'V1';
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Sales\Api\CreditmemoRepositoryInterface
+     */
+    private $creditmemoRepository;
+
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+
+        $this->creditmemoRepository = $this->objectManager->get(
+            \Magento\Sales\Api\CreditmemoRepositoryInterface::class
+        );
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/Sales/_files/order_with_shipping_and_invoice.php
+     */
+    public function testShortRequest()
+    {
+        /** @var \Magento\Sales\Model\Order $existingOrder */
+        $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+            ->loadByIncrementId('100000001');
+
+        $result = $this->_webApiCall(
+            $this->getServiceData($existingOrder),
+            ['orderId' => $existingOrder->getEntityId()]
+        );
+
+        $this->assertNotEmpty(
+            $result,
+            'Failed asserting that the received response is correct'
+        );
+
+        /** @var \Magento\Sales\Model\Order $updatedOrder */
+        $updatedOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+            ->loadByIncrementId($existingOrder->getIncrementId());
+
+        try {
+            $creditmemo = $this->creditmemoRepository->get($result);
+
+            $expectedItems = $this->getOrderItems($existingOrder);
+            $actualCreditmemoItems = $this->getCreditmemoItems($creditmemo);
+            $actualRefundedOrderItems = $this->getRefundedOrderItems($updatedOrder);
+
+            $this->assertEquals(
+                $expectedItems,
+                $actualCreditmemoItems,
+                'Failed asserting that the Creditmemo contains all requested items'
+            );
+
+            $this->assertEquals(
+                $expectedItems,
+                $actualRefundedOrderItems,
+                'Failed asserting that all requested order items were refunded'
+            );
+
+            $this->assertEquals(
+                $creditmemo->getShippingAmount(),
+                $existingOrder->getShippingAmount(),
+                'Failed asserting that the Creditmemo contains correct shipping amount'
+            );
+
+            $this->assertEquals(
+                $creditmemo->getShippingAmount(),
+                $updatedOrder->getShippingRefunded(),
+                'Failed asserting that proper shipping amount of the Order was refunded'
+            );
+
+            $this->assertNotEquals(
+                $existingOrder->getStatus(),
+                $updatedOrder->getStatus(),
+                'Failed asserting that order status was changed'
+            );
+        } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+            $this->fail('Failed asserting that Creditmemo was created');
+        }
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/Sales/_files/order_with_shipping_and_invoice.php
+     */
+    public function testFullRequest()
+    {
+        /** @var \Magento\Sales\Model\Order $existingOrder */
+        $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+            ->loadByIncrementId('100000001');
+
+        $expectedItems = $this->getOrderItems($existingOrder);
+        $expectedItems[0]['qty'] = $expectedItems[0]['qty'] - 1;
+
+        $expectedComment = [
+            'comment' => 'Test Comment',
+            'is_visible_on_front' => 1
+        ];
+
+        $expectedShippingAmount = 15;
+        $expectedAdjustmentPositive = 5.53;
+        $expectedAdjustmentNegative = 5.53;
+
+        $result = $this->_webApiCall(
+            $this->getServiceData($existingOrder),
+            [
+                'orderId' => $existingOrder->getEntityId(),
+                'items' => $expectedItems,
+                'comment' => $expectedComment,
+                'arguments' => [
+                    'shipping_amount' => $expectedShippingAmount,
+                    'adjustment_positive' => $expectedAdjustmentPositive,
+                    'adjustment_negative' => $expectedAdjustmentNegative
+                ]
+            ]
+        );
+
+        $this->assertNotEmpty(
+            $result,
+            'Failed asserting that the received response is correct'
+        );
+
+        /** @var \Magento\Sales\Model\Order $updatedOrder */
+        $updatedOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+            ->loadByIncrementId($existingOrder->getIncrementId());
+
+        try {
+            $creditmemo = $this->creditmemoRepository->get($result);
+
+            $actualCreditmemoItems = $this->getCreditmemoItems($creditmemo);
+            $actualCreditmemoComment = $this->getRecentComment($creditmemo);
+            $actualRefundedOrderItems = $this->getRefundedOrderItems($updatedOrder);
+
+            $this->assertEquals(
+                $expectedItems,
+                $actualCreditmemoItems,
+                'Failed asserting that the Creditmemo contains all requested items'
+            );
+
+            $this->assertEquals(
+                $expectedItems,
+                $actualRefundedOrderItems,
+                'Failed asserting that all requested order items were refunded'
+            );
+
+            $this->assertEquals(
+                $expectedComment,
+                $actualCreditmemoComment,
+                'Failed asserting that the Creditmemo contains correct comment'
+            );
+
+            $this->assertEquals(
+                $expectedShippingAmount,
+                $creditmemo->getShippingAmount(),
+                'Failed asserting that the Creditmemo contains correct shipping amount'
+            );
+
+            $this->assertEquals(
+                $expectedShippingAmount,
+                $updatedOrder->getShippingRefunded(),
+                'Failed asserting that proper shipping amount of the Order was refunded'
+            );
+
+            $this->assertEquals(
+                $expectedAdjustmentPositive,
+                $creditmemo->getAdjustmentPositive(),
+                'Failed asserting that the Creditmemo contains correct positive adjustment'
+            );
+
+            $this->assertEquals(
+                $expectedAdjustmentNegative,
+                $creditmemo->getAdjustmentNegative(),
+                'Failed asserting that the Creditmemo contains correct negative adjustment'
+            );
+
+            $this->assertEquals(
+                $existingOrder->getStatus(),
+                $updatedOrder->getStatus(),
+                'Failed asserting that order status was NOT changed'
+            );
+        } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+            $this->fail('Failed asserting that Creditmemo was created');
+        }
+    }
+
+    /**
+     * Prepares and returns info for API service.
+     *
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     *
+     * @return array
+     */
+    private function getServiceData(\Magento\Sales\Api\Data\OrderInterface $order)
+    {
+        return [
+            'rest' => [
+                'resourcePath' => '/V1/order/' . $order->getEntityId() . '/refund',
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_READ_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_READ_NAME . 'execute',
+            ]
+        ];
+    }
+
+    /**
+     * Gets all items of given Order in proper format.
+     *
+     * @param \Magento\Sales\Model\Order $order
+     *
+     * @return array
+     */
+    private function getOrderItems(\Magento\Sales\Model\Order $order)
+    {
+        $items = [];
+
+        /** @var \Magento\Sales\Api\Data\OrderItemInterface $item */
+        foreach ($order->getAllItems() as $item) {
+            $items[] = [
+                'order_item_id' => $item->getItemId(),
+                'qty' => $item->getQtyOrdered(),
+            ];
+        }
+
+        return $items;
+    }
+
+    /**
+     * Gets refunded items of given Order in proper format.
+     *
+     * @param \Magento\Sales\Model\Order $order
+     *
+     * @return array
+     */
+    private function getRefundedOrderItems(\Magento\Sales\Model\Order $order)
+    {
+        $items = [];
+
+        /** @var \Magento\Sales\Api\Data\OrderItemInterface $item */
+        foreach ($order->getAllItems() as $item) {
+            if ($item->getQtyRefunded() > 0) {
+                $items[] = [
+                    'order_item_id' => $item->getItemId(),
+                    'qty' => $item->getQtyRefunded(),
+                ];
+            }
+        }
+
+        return $items;
+    }
+
+    /**
+     * Gets all items of given Creditmemo in proper format.
+     *
+     * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo
+     *
+     * @return array
+     */
+    private function getCreditmemoItems(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo)
+    {
+        $items = [];
+
+        /** @var \Magento\Sales\Api\Data\CreditmemoItemInterface $item */
+        foreach ($creditmemo->getItems() as $item) {
+            $items[] = [
+                'order_item_id' => $item->getOrderItemId(),
+                'qty' => $item->getQty(),
+            ];
+        }
+
+        return $items;
+    }
+
+    /**
+     * Gets the most recent comment of given Creditmemo in proper format.
+     *
+     * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo
+     *
+     * @return array|null
+     */
+    private function getRecentComment(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo)
+    {
+        $comments = $creditmemo->getComments();
+
+        if ($comments) {
+            $comment = reset($comments);
+
+            return [
+                'comment' => $comment->getComment(),
+                'is_visible_on_front' => $comment->getIsVisibleOnFront(),
+            ];
+        }
+
+        return null;
+    }
+}
diff --git a/dev/tests/functional/bootstrap.php b/dev/tests/functional/bootstrap.php
index 72dc6bf208cd0e5dff754f515db9f3a1a5b9a4c7..1ff4fd4e8d22396a71e3413cf9e4247b5225f0b2 100644
--- a/dev/tests/functional/bootstrap.php
+++ b/dev/tests/functional/bootstrap.php
@@ -11,7 +11,15 @@ defined('MTF_STATES_PATH') || define('MTF_STATES_PATH', MTF_BP . '/lib/Magento/M
 
 require_once __DIR__ . '/../../../app/bootstrap.php';
 restore_error_handler();
-require_once __DIR__ . '/vendor/autoload.php';
+$vendorAutoload = __DIR__ . '/vendor/autoload.php';
+
+if (isset($composerAutoloader)) {
+    /** var $mtfComposerAutoload \Composer\Autoload\ClassLoader */
+    $mtfComposerAutoload = include $vendorAutoload;
+    $composerAutoloader->addClassMap($mtfComposerAutoload->getClassMap());
+} else {
+    $composerAutoloader = include $vendorAutoload;
+}
 
 setCustomErrorHandler();
 
diff --git a/dev/tests/functional/composer.json b/dev/tests/functional/composer.json
index 936c4b968af3b88ed9f05fb2d21dfe3c8184181f..512c5bc8d5df666ced655806af0da64952d0f4ef 100644
--- a/dev/tests/functional/composer.json
+++ b/dev/tests/functional/composer.json
@@ -1,8 +1,8 @@
 {
     "require": {
-        "magento/mtf": "1.0.0-rc47",
+        "magento/mtf": "1.0.0-rc48",
         "php": "~5.6.0|7.0.2|~7.0.6",
-        "phpunit/phpunit": "4.1.0",
+        "phpunit/phpunit": "~4.8.0|~5.5.0",
         "phpunit/phpunit-selenium": ">=1.2"
     },
     "suggest": {
diff --git a/dev/tests/functional/credentials.xml.dist b/dev/tests/functional/credentials.xml.dist
index 3c61630fb148df35b67d7430c961bcfc9482cbb1..88794d183e8781d5cea1c9199370c67daae1585c 100644
--- a/dev/tests/functional/credentials.xml.dist
+++ b/dev/tests/functional/credentials.xml.dist
@@ -27,4 +27,36 @@
     <field replace="carriers_dhl_id_eu" value="" />
     <field replace="carriers_dhl_password_eu" value="" />
     <field replace="carriers_dhl_account_eu" value="" />
+
+    <field path="payment/authorizenet_directpost/login" value="" />
+    <field path="payment/authorizenet_directpost/trans_key" value="" />
+    <field path="payment/authorizenet_directpost/trans_md5" value="" />
+
+    <field path="payment/braintree_section/braintree/braintree_advanced/merchant_account_id" value="" />
+    <field path="payment/braintree_section/braintree/braintree_required/merchant_id" value="" />
+    <field path="payment/braintree_section/braintree/braintree_required/public_key" value="" />
+    <field path="payment/braintree_section/braintree/braintree_required/private_key" value="" />
+
+    <field path="payment/paypal_group_all_in_one/wpp_usuk/wpp_required_settings/wpp_and_express_checkout/business_account" value="" />
+    <field path="payment/paypal_group_all_in_one/wpp_usuk/wpp_required_settings/wpp_and_express_checkout/api_username" value="" />
+    <field path="payment/paypal_group_all_in_one/wpp_usuk/wpp_required_settings/wpp_and_express_checkout/api_password" value="" />
+    <field path="payment/paypal_group_all_in_one/wpp_usuk/wpp_required_settings/wpp_and_express_checkout/api_signature" value="" />
+    <field path="payment/paypal_express/merchant_id" value="" />
+
+    <field path="payment/paypal_payment_gateways/paypal_payflowpro_with_express_checkout/paypal_payflow_required/paypal_payflow_api_settings/business_account" value="" />
+    <field path="payment/paypal_payment_gateways/paypal_payflowpro_with_express_checkout/paypal_payflow_required/paypal_payflow_api_settings/partner" value="" />
+    <field path="payment/paypal_payment_gateways/paypal_payflowpro_with_express_checkout/paypal_payflow_required/paypal_payflow_api_settings/user" value="" />
+    <field path="payment/paypal_payment_gateways/paypal_payflowpro_with_express_checkout/paypal_payflow_required/paypal_payflow_api_settings/pwd" value="" />
+    <field path="payment/paypal_payment_gateways/paypal_payflowpro_with_express_checkout/paypal_payflow_required/paypal_payflow_api_settings/vendor" value="" />
+
+    <field path="payment/paypal_alternative_payment_methods/express_checkout_us/express_checkout_required/express_checkout_required_express_checkout/business_account" value="" />
+    <field path="payment/paypal_alternative_payment_methods/express_checkout_us/express_checkout_required/express_checkout_required_express_checkout/api_username" value="" />
+    <field path="payment/paypal_alternative_payment_methods/express_checkout_us/express_checkout_required/express_checkout_required_express_checkout/api_password" value="" />
+    <field path="payment/paypal_alternative_payment_methods/express_checkout_us/express_checkout_required/express_checkout_required_express_checkout/api_signature" value="" />
+
+    <field path="payment/paypal_payment_gateways/payflow_link_us/payflow_link_required/payflow_link_payflow_link/business_account" value="" />
+    <field path="payment/paypal_payment_gateways/payflow_link_us/payflow_link_required/payflow_link_payflow_link/partner" value="" />
+    <field path="payment/paypal_payment_gateways/payflow_link_us/payflow_link_required/payflow_link_payflow_link/user" value="" />
+    <field path="payment/paypal_payment_gateways/payflow_link_us/payflow_link_required/payflow_link_payflow_link/pwd" value="" />
+    <field path="payment/paypal_payment_gateways/payflow_link_us/payflow_link_required/payflow_link_payflow_link/vendor" value="" />
 </replace>
diff --git a/dev/tests/functional/lib/Magento/Mtf/Client/Element/RadiobuttonElement.php b/dev/tests/functional/lib/Magento/Mtf/Client/Element/RadiobuttonElement.php
new file mode 100644
index 0000000000000000000000000000000000000000..cfb7990196598e317d3ec51b41b1524ac62a7fb5
--- /dev/null
+++ b/dev/tests/functional/lib/Magento/Mtf/Client/Element/RadiobuttonElement.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Mtf\Client\Element;
+
+use Magento\Mtf\Client\Locator;
+
+/**
+ * Class provides ability to work with page element radio button.
+ */
+class RadiobuttonElement extends SimpleElement
+{
+    /**
+     * Label for radio button selector.
+     *
+     * @var string
+     */
+    protected $labelSelector = './..//label[contains(., "%s")]';
+
+    /**
+     * Selector for selected label.
+     *
+     * @var string
+     */
+    protected $selectedLabelSelector = 'input[type=radio]:checked + label';
+
+    /**
+     * Get value of the required element.
+     *
+     * @return string
+     */
+    public function getValue()
+    {
+        $this->eventManager->dispatchEvent(['get_value'], [$this->getAbsoluteSelector()]);
+
+        return $this->find($this->selectedLabelSelector)->getText();
+    }
+
+    /**
+     * Select radio button based on label value.
+     *
+     * @param string $value
+     * @return void
+     */
+    public function setValue($value)
+    {
+        $this->eventManager->dispatchEvent(['set_value'], [__METHOD__, $this->getAbsoluteSelector()]);
+
+        $radioButtonLabel = $this->find(sprintf($this->labelSelector, $value), Locator::SELECTOR_XPATH);
+        if (!$this->isSelected()) {
+            $radioButtonLabel->click();
+        }
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/System/Config/Braintree.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/System/Config/Braintree.php
index f46f070216c6e59456281af4ae99762898b3da71..c85c857cbeb5450ae39c29bc6658ef920e984f96 100644
--- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/System/Config/Braintree.php
+++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/System/Config/Braintree.php
@@ -33,7 +33,7 @@ class Braintree extends Block
     private $enablers = [
         'Enable this Solution' => "#payment_us_braintree_section_braintree_active",
         'Enable PayPal through Braintree' => '#payment_us_braintree_section_braintree_active_braintree_paypal',
-        'Vault enabled' => '#payment_us_braintree_section_braintree_braintree_cc_vault_active'
+        'Vault Enabled' => '#payment_us_braintree_section_braintree_braintree_cc_vault_active'
     ];
 
     /**
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductInCart.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductInCart.php
new file mode 100644
index 0000000000000000000000000000000000000000..831d2e88b37cbeabab87108ffab56f63668c6f63
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductInCart.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Bundle\Test\Constraint;
+
+use Magento\Catalog\Test\Constraint\AssertProductInCart;
+use Magento\Checkout\Test\Page\CheckoutCart;
+use Magento\Mtf\Fixture\FixtureInterface;
+
+/**
+ * Assertion that bundle product is correctly displayed in cart.
+ */
+class AssertBundleProductInCart extends AssertProductInCart
+{
+    /**
+     * Count prices.
+     *
+     * @param FixtureInterface $product
+     * @param CheckoutCart $checkoutCart
+     * @return void
+     */
+    protected function countPrices(FixtureInterface $product, CheckoutCart $checkoutCart)
+    {
+        parent::countPrices($product, $checkoutCart);
+        $this->countSubItemPrice($product);
+    }
+
+    /**
+     * Count subItem price.
+     *
+     * @param FixtureInterface $product
+     * @return void
+     */
+    private function countSubItemPrice(FixtureInterface $product)
+    {
+        $checkoutData = $product->getCheckoutData();
+        if (isset($checkoutData['cartItem']['subItemPrice'])) {
+            $this->fixtureActualPrice += $checkoutData["cartItem"]["subItemPrice"];
+        }
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductPage.php
index 704404e665ac1c394d9d28621a0dcb9139dd4047..8e113996bda074b089119339a984ea217b6a6e7a 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductPage.php
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductPage.php
@@ -46,4 +46,39 @@ class AssertBundleProductPage extends AssertProductPage
 
         return empty($errors) ? null : implode("\n", $errors);
     }
+
+    /**
+     * Verify product special price is displayed on product page(front-end).
+     *
+     * @return string|null
+     */
+    protected function verifySpecialPrice()
+    {
+        if (!$this->product->hasData('special_price')) {
+            return null;
+        }
+
+        $priceBlock = $this->productView->getPriceBlock();
+
+        if (!$priceBlock->isVisible()) {
+            return "Price block for '{$this->product->getName()}' product' is not visible.";
+        }
+
+        if (!$priceBlock->isOldPriceVisible()) {
+            return 'Bundle special price is not set.';
+        }
+
+        $regularPrice = $priceBlock->getOldPrice();
+        $priceData = $this->product->getDataFieldConfig('price')['source']->getPriceData();
+
+        if (!isset($priceData['regular_from'])) {
+            return 'Regular from price not set.';
+        }
+
+        if ($priceData['regular_from'] != $regularPrice) {
+            return 'Bundle regular price on product view page is not correct.';
+        }
+
+        return null;
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml
index 0b142044323d197e72a4c1544334d42cd7e16ae5..3e9b055c48ca5a1bfa5df3410ec48ef708a71fa7 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml
@@ -150,7 +150,7 @@
             <field name="products" xsi:type="array">
                 <item name="0" xsi:type="array">
                     <item name="0" xsi:type="string">catalogProductSimple::default</item>
-                    <item name="1" xsi:type="string">catalogProductSimple::product_100_dollar</item>
+                    <item name="1" xsi:type="string">catalogProductSimple::product_10_dollar</item>
                 </item>
             </field>
         </dataset>
@@ -604,5 +604,66 @@
                 </item>
             </field>
         </dataset>
+
+        <dataset name="dynamic_with_two_required_options_assigned_products_with_special_price">
+            <field name="bundle_options" xsi:type="array">
+                <item name="0" xsi:type="array">
+                    <item name="title" xsi:type="string">Drop-down Option</item>
+                    <item name="type" xsi:type="string">Drop-down</item>
+                    <item name="required" xsi:type="string">Yes</item>
+                    <item name="assigned_products" xsi:type="array">
+                        <item name="0" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">1</item>
+                            </item>
+                        </item>
+                        <item name="1" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">1</item>
+                            </item>
+                        </item>
+                    </item>
+                </item>
+                <item name="1" xsi:type="array">
+                    <item name="title" xsi:type="string">Drop-down Option</item>
+                    <item name="type" xsi:type="string">Drop-down</item>
+                    <item name="required" xsi:type="string">Yes</item>
+                    <item name="assigned_products" xsi:type="array">
+                        <item name="0" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">1</item>
+                            </item>
+                        </item>
+                        <item name="1" xsi:type="array">
+                            <item name="search_data" xsi:type="array">
+                                <item name="name" xsi:type="string">%product_name%</item>
+                            </item>
+                            <item name="data" xsi:type="array">
+                                <item name="selection_qty" xsi:type="string">1</item>
+                            </item>
+                        </item>
+                    </item>
+                </item>
+            </field>
+            <field name="products" xsi:type="array">
+                <item name="0" xsi:type="array">
+                    <item name="0" xsi:type="string">catalogProductSimple::product_10_dollar</item>
+                    <item name="1" xsi:type="string">catalogProductSimple::product_with_special_price</item>
+                </item>
+                <item name="1" xsi:type="array">
+                    <item name="0" xsi:type="string">catalogProductSimple::product_10_dollar</item>
+                    <item name="1" xsi:type="string">catalogProductSimple::product_with_special_price</item>
+                </item>
+            </field>
+        </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml
index 3cc61abfd2e89b3bcfdbe61aac6fbc84dbf461de..97c11284d77c88194a5a5271e31ca7b91a4babf3 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml
@@ -206,6 +206,36 @@
             </field>
         </dataset>
 
+        <dataset name="bundle_with_custom_options_3">
+            <field name="options" xsi:type="array">
+                <item name="bundle_options" xsi:type="array">
+                    <item name="0" xsi:type="array">
+                        <item name="title" xsi:type="string">Drop-down Option</item>
+                        <item name="type" xsi:type="string">Drop-down</item>
+                        <item name="value" xsi:type="array">
+                            <item name="name" xsi:type="string">product_10_dollar</item>
+                        </item>
+                    </item>
+                </item>
+                <item name="custom_options" xsi:type="array">
+                    <item name="0" xsi:type="array">
+                        <item name="title" xsi:type="string">attribute_key_0</item>
+                        <item name="value" xsi:type="string">option_key_0</item>
+                    </item>
+                    <item name="1" xsi:type="array">
+                        <item name="title" xsi:type="string">attribute_key_1</item>
+                        <item name="value" xsi:type="string">option_key_0</item>
+                    </item>
+                </item>
+            </field>
+            <field name="cartItem" xsi:type="array">
+                <item name="price" xsi:type="string">100</item>
+                <item name="qty" xsi:type="string">1</item>
+                <item name="subtotal" xsi:type="string">100</item>
+                <item name="subItemPrice" xsi:type="string">10</item>
+            </field>
+        </dataset>
+
         <dataset name="bundle_all_types_bundle_fixed_and_custom_options">
             <field name="options" xsi:type="array">
                 <item name="bundle_options" xsi:type="array">
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/Price.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/Price.xml
index c6b69dd6937d9bba0628b6cd7fca47d988cf12fb..c4431c5d02072766003b123ce269298f275d5be9 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/Price.xml
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/Price.xml
@@ -78,6 +78,18 @@
             <field name="cart_price" xsi:type="string">756.00</field>
         </dataset>
 
+        <dataset name="fixed-51">
+            <field name="price_from" xsi:type="string">51.00</field>
+            <field name="price_to" xsi:type="string">52.00</field>
+            <field name="regular_from" xsi:type="string">135.00</field>
+        </dataset>
+
+        <dataset name="fixed-756-custom-options">
+            <field name="price_from" xsi:type="string">785.00</field>
+            <field name="price_to" xsi:type="string">786.00</field>
+            <field name="cart_price" xsi:type="string">786.00</field>
+        </dataset>
+
         <dataset name="bundle_fixed_with_category">
             <field name="price_from" xsi:type="string">130.00</field>
             <field name="price_to" xsi:type="string">144.00</field>
@@ -94,6 +106,12 @@
             <field name="price_from" xsi:type="string">8.00</field>
             <field name="price_to" xsi:type="string">20.00</field>
             <field name="cart_price" xsi:type="string">80.00</field>
+            <field name="regular_from" xsi:type="string">40.00</field>
+        </dataset>
+
+        <dataset name="dynamic-18">
+            <field name="price_from" xsi:type="string">18.00</field>
+            <field name="price_to" xsi:type="string">20.00</field>
         </dataset>
 
         <dataset name="dynamic-32">
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml
index 6fcef33132603bdcc157dcd683993a5893a2dcfb..678e9306cbadb3bc22dafd9bca089a8b7f304ba7 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.xml
@@ -160,7 +160,7 @@
             <constraint name="Magento\Catalog\Test\Constraint\AssertProductOutOfStock" />
             <constraint name="Magento\Bundle\Test\Constraint\AssertBundlePriceView" />
         </variation>
-        <variation name="CreateBundleProductEntityTestVariation7">
+        <variation name="CreateBundleProductEntityTestVariation7" summary="Check bundle dynamic product with tier price">
             <data name="product/data/url_key" xsi:type="string">bundle-product-%isolation%</data>
             <data name="product/data/name" xsi:type="string">BundleProduct %isolation%</data>
             <data name="product/data/sku_type" xsi:type="string">Yes</data>
@@ -333,5 +333,118 @@
             <constraint name="Magento\Bundle\Test\Constraint\AssertBundleInCategory" />
             <constraint name="Magento\Bundle\Test\Constraint\AssertBundleProductPage" />
         </variation>
+        <variation name="CreateBundleProductEntityTestVariation17" summary="Create fixed bundle product with tier price and custom options with fixed and percent price">
+            <data name="product/data/url_key" xsi:type="string">bundle-product-%isolation%</data>
+            <data name="product/data/name" xsi:type="string">Bundle Fixed %isolation%</data>
+            <data name="product/data/sku_type" xsi:type="string">No</data>
+            <data name="product/data/sku" xsi:type="string">sku_bundle_fixed_%isolation%</data>
+            <data name="product/data/price_type" xsi:type="string">No</data>
+            <data name="product/data/price/value" xsi:type="string">100</data>
+            <data name="product/data/price/dataset" xsi:type="string">fixed-100</data>
+            <data name="product/data/weight_type" xsi:type="string">No</data>
+            <data name="product/data/weight" xsi:type="string">10</data>
+            <data name="product/data/tier_price/dataset" xsi:type="string">default</data>
+            <data name="product/data/price_view" xsi:type="string">As Low as</data>
+            <data name="product/data/stock_data/use_config_manage_stock" xsi:type="string">No</data>
+            <data name="product/data/stock_data/manage_stock" xsi:type="string">No</data>
+            <data name="product/data/shipment_type" xsi:type="string">Together</data>
+            <data name="product/data/bundle_selections/dataset" xsi:type="string">second</data>
+            <data name="product/data/custom_options/dataset" xsi:type="string">percent_and_fixed_drop_down_options</data>
+            <data name="product/data/checkout_data/dataset" xsi:type="string">bundle_with_custom_options_3</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertBundleProductForm" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertBundleItemsOnProductPage" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertTierPriceOnBundleProductPage" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertProductCustomOptionsOnBundleProductPage" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertBundleProductInCart" />
+        </variation>
+        <variation name="CreateBundleProductEntityTestVariation18" summary="Create dynamic bundle product with tier price for sub-item">
+            <data name="product/data/url_key" xsi:type="string">bundle-product-%isolation%</data>
+            <data name="product/data/name" xsi:type="string">BundleProduct %isolation%</data>
+            <data name="product/data/sku_type" xsi:type="string">Yes</data>
+            <data name="product/data/sku" xsi:type="string">bundle_sku_%isolation%</data>
+            <data name="product/data/price_type" xsi:type="string">Yes</data>
+            <data name="product/data/price/dataset" xsi:type="string">dynamic-50</data>
+            <data name="product/data/weight_type" xsi:type="string">No</data>
+            <data name="product/data/weight" xsi:type="string">10</data>
+            <data name="product/data/tier_price/dataset" xsi:type="string">default</data>
+            <data name="product/data/price_view" xsi:type="string">As Low as</data>
+            <data name="product/data/stock_data/use_config_manage_stock" xsi:type="string">No</data>
+            <data name="product/data/stock_data/manage_stock" xsi:type="string">No</data>
+            <data name="product/data/shipment_type" xsi:type="string">Together</data>
+            <data name="product/data/bundle_selections/dataset" xsi:type="string">default_dynamic</data>
+            <data name="product/data/bundle_selections/products" xsi:type="string">catalogProductSimple::simple_with_tier_price,catalogProductVirtual::product_50_dollar</data>
+            <data name="product/data/checkout_data/dataset" xsi:type="string">bundle_default</data>
+            <data name="product/data/visibility" xsi:type="string">Search</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertBundleProductForm" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertBundleItemsOnProductPage" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertTierPriceOnBundleProductPage" />
+        </variation>
+        <variation name="CreateBundleProductEntityTestVariation19" summary="Create bundle with simple out of stock">
+            <data name="product/data/url_key" xsi:type="string">bundle-product-%isolation%</data>
+            <data name="product/data/name" xsi:type="string">BundleProduct %isolation%</data>
+            <data name="product/data/sku" xsi:type="string">bundle_sku_%isolation%</data>
+            <data name="product/data/price_type" xsi:type="string">Yes</data>
+            <data name="product/data/price/dataset" xsi:type="string">dynamic-50</data>
+            <data name="product/data/bundle_selections/dataset" xsi:type="string">default_dynamic</data>
+            <data name="product/data/bundle_selections/products" xsi:type="string">catalogProductSimple::out_of_stock,catalogProductSimple::out_of_stock</data>
+            <data name="product/data/checkout_data/dataset" xsi:type="string">bundle_default</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductOutOfStock" />
+        </variation>
+        <variation name="CreateBundleProductEntityTestVariation21" summary="Create default fixed bundle with custom Website">
+            <data name="product/data/url_key" xsi:type="string">bundle-product-%isolation%</data>
+            <data name="product/data/name" xsi:type="string">Bundle Fixed %isolation%</data>
+            <data name="product/data/sku_type" xsi:type="string">No</data>
+            <data name="product/data/sku" xsi:type="string">sku_bundle_fixed_%isolation%</data>
+            <data name="product/data/price_type" xsi:type="string">No</data>
+            <data name="product/data/price/value" xsi:type="string">10</data>
+            <data name="product/data/bundle_selections/dataset" xsi:type="string">second</data>
+            <data name="product/data/bundle_selections/products" xsi:type="string">catalogProductSimple::product_100_dollar,catalogProductSimple::product_40_dollar</data>
+            <data name="product/data/checkout_data/dataset" xsi:type="string">bundle_default</data>
+            <data name="product/data/website_ids/0/dataset" xsi:type="string">custom_store</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductOnCustomWebsite" />
+        </variation>
+        <variation name="CreateBundleProductEntityTestVariation22" summary="Create Bundle (fixed) Product with special price and Custom options with fixed price">
+            <data name="product/data/url_key" xsi:type="string">bundle-product-%isolation%</data>
+            <data name="product/data/name" xsi:type="string">Bundle Fixed %isolation%</data>
+            <data name="product/data/sku_type" xsi:type="string">No</data>
+            <data name="product/data/sku" xsi:type="string">sku_bundle_fixed_%isolation%</data>
+            <data name="product/data/price_type" xsi:type="string">No</data>
+            <data name="product/data/price/value" xsi:type="string">100</data>
+            <data name="product/data/price/dataset" xsi:type="string">fixed-51</data>
+            <data name="product/data/price_view" xsi:type="string">Price Range</data>
+            <data name="product/data/special_price" xsi:type="string">20</data>
+            <data name="product/data/bundle_selections/dataset" xsi:type="string">second</data>
+            <data name="product/data/custom_options/dataset" xsi:type="string">drop_down_with_one_option_fixed_price</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertBundleProductPage" />
+        </variation>
+        <variation name="CreateBundleProductEntityTestVariation23" summary="Create Bundle (dynamic) Product with special price">
+            <data name="product/data/url_key" xsi:type="string">bundle-product-%isolation%</data>
+            <data name="product/data/name" xsi:type="string">Bundle Dynamic %isolation%</data>
+            <data name="product/data/sku_type" xsi:type="string">Yes</data>
+            <data name="product/data/sku" xsi:type="string">sku_bundle_dynamic_%isolation%</data>
+            <data name="product/data/price_type" xsi:type="string">Yes</data>
+            <data name="product/data/price/dataset" xsi:type="string">dynamic-8</data>
+            <data name="product/data/special_price" xsi:type="string">20</data>
+            <data name="product/data/bundle_selections/dataset" xsi:type="string">default_dynamic</data>
+            <data name="product/data/bundle_selections/products" xsi:type="string">catalogProductSimple::product_100_dollar,catalogProductSimple::product_40_dollar</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertBundleProductPage" />
+        </variation>
+        <variation name="CreateBundleProductEntityTestVariation24" summary="Create Bundle (dynamic) Product with One of the bundle options has special price">
+            <data name="product/data/url_key" xsi:type="string">bundle-product-%isolation%</data>
+            <data name="product/data/name" xsi:type="string">Bundle Dynamic %isolation%</data>
+            <data name="product/data/sku_type" xsi:type="string">Yes</data>
+            <data name="product/data/sku" xsi:type="string">sku_bundle_dynamic_%isolation%</data>
+            <data name="product/data/price_type" xsi:type="string">Yes</data>
+            <data name="product/data/price/dataset" xsi:type="string">dynamic-18</data>
+            <data name="product/data/bundle_selections/dataset" xsi:type="string">dynamic_with_two_required_options_assigned_products_with_special_price</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertBundleProductPage" />
+        </variation>
     </testCase>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.xml
index 1f241c1e321be78e51a04d04c3e2ca2ab4b04ca0..e4f567de39481249ca083398152f237c35b3c2cf 100644
--- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.xml
@@ -73,5 +73,15 @@
             <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
             <constraint name="Magento\Bundle\Test\Constraint\AssertBundleProductPage" />
         </variation>
+        <variation name="UpdateBundleProductEntityTestVariation5" summary="Update Bundle (fixed) Product with custom option">
+            <data name="originalProduct/dataset" xsi:type="string">bundle_fixed_product</data>
+            <data name="product/data/url_key" xsi:type="string">bundle-product-%isolation%</data>
+            <data name="product/data/name" xsi:type="string">bundle_fixed_%isolation%</data>
+            <data name="product/data/sku" xsi:type="string">bundle_sku_%isolation%</data>
+            <data name="product/data/price/dataset" xsi:type="string">fixed-756-custom-options</data>
+            <data name="product/data/custom_options/dataset" xsi:type="string">drop_down_with_one_option_fixed_price</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
+            <constraint name="Magento\Bundle\Test\Constraint\AssertBundleProductPage" />
+        </variation>
     </testCase>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml
index 593ab70e100ff473b6a87c1ea75e6f3af348107d..42f490d76191a524b12c7837ab5958907199fece 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml
@@ -134,11 +134,11 @@
         <strategy>xpath</strategy>
         <fields>
             <schedule_update_from>
-                <input>text</input>
+                <input>datepicker</input>
                 <selector>input[name='custom_design_from']</selector>
             </schedule_update_from>
             <schedule_update_to>
-                <input>text</input>
+                <input>datepicker</input>
                 <selector>input[name='custom_design_to']</selector>
             </schedule_update_to>
         </fields>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/Section/ProductGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/Section/ProductGrid.php
index e05bf4af830b6f03dfa801fbb18eefff5a366132..eb2a9c4a835ceb8e55156f49a7ebb9d04ef1cc86 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/Section/ProductGrid.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/Section/ProductGrid.php
@@ -36,5 +36,5 @@ class ProductGrid extends Grid
      *
      * @var string
      */
-    protected $selectItem = 'tbody tr .col-in_category';
+    protected $selectItem = 'tbody tr .col-in_category input';
 }
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php
index 85514109053b438af1425cf266d11bd8ac596cb3..e698691faa64d41d7f540dac04c5d48658363333 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php
@@ -14,13 +14,33 @@ use Magento\Mtf\Constraint\AbstractConstraint;
 use Magento\Mtf\Fixture\FixtureInterface;
 
 /**
- * Class AssertProductInCart
- * Assertion that the product is correctly displayed in cart
+ * Assertion that the product is correctly displayed in cart.
  */
 class AssertProductInCart extends AbstractConstraint
 {
     /**
-     * Assertion that the product is correctly displayed in cart
+     * Price on form.
+     *
+     * @var string
+     */
+    protected $formPrice;
+
+    /**
+     * Fixture actual price.
+     *
+     * @var string
+     */
+    protected $fixtureActualPrice;
+
+    /**
+     * Fixture price.
+     *
+     * @var string
+     */
+    protected $fixturePrice;
+
+    /**
+     * Assertion that the product is correctly displayed in cart.
      *
      * @param CatalogProductView $catalogProductView
      * @param FixtureInterface $product
@@ -41,58 +61,102 @@ class AssertProductInCart extends AbstractConstraint
         $catalogProductView->getMessagesBlock()->waitSuccessMessage();
 
         // Check price
-        $this->assertOnShoppingCart($product, $checkoutCart);
+        $this->countPrices($product, $checkoutCart);
+        \PHPUnit_Framework_Assert::assertEquals(
+            $this->fixtureActualPrice,
+            $this->formPrice,
+            'Product price in shopping cart is not correct.'
+        );
     }
 
     /**
-     * Assert prices on the shopping cart
+     * Count prices.
      *
      * @param FixtureInterface $product
      * @param CheckoutCart $checkoutCart
      * @return void
+     */
+    protected function countPrices(FixtureInterface $product, CheckoutCart $checkoutCart)
+    {
+        /** @var CatalogProductSimple $product */
+        $this->fixturePrice = $product->getPrice();
+        $this->prepareFormPrice($product, $checkoutCart);
+        $this->countSpecialPrice($product);
+        $this->countCheckoutCartItemPrice($product);
+        $this->countCustomOptionsPrice($product);
+    }
+
+    /**
+     * Count count special price.
      *
-     * @SuppressWarnings(PHPMD.NPathComplexity)
+     * @param FixtureInterface $product
+     * @return void
      */
-    protected function assertOnShoppingCart(FixtureInterface $product, CheckoutCart $checkoutCart)
+    protected function countSpecialPrice(FixtureInterface $product)
     {
-        $checkoutCart->open();
         /** @var CatalogProductSimple $product */
-        $customOptions = $product->getCustomOptions();
-        $checkoutData = $product->getCheckoutData();
-        $checkoutCartItem = isset($checkoutData['cartItem']) ? $checkoutData['cartItem'] : [];
-        $checkoutCustomOptions = isset($checkoutData['options']['custom_options'])
-            ? $checkoutData['options']['custom_options']
-            : [];
-        $fixturePrice = $product->getPrice();
         $specialPrice = $product->getSpecialPrice();
-        $cartItem = $checkoutCart->getCartBlock()->getCartItem($product);
-        $formPrice = $cartItem->getPrice();
-
         if ($specialPrice) {
-            $fixturePrice = $specialPrice;
+            $this->fixturePrice = $product->getSpecialPrice();
         }
+    }
+
+    /**
+     * Prepare form price.
+     *
+     * @param FixtureInterface $product
+     * @param CheckoutCart $checkoutCart
+     * @return void
+     */
+    protected function prepareFormPrice(FixtureInterface $product, CheckoutCart $checkoutCart)
+    {
+        $checkoutCart->open();
+        $cartItem = $checkoutCart->getCartBlock()->getCartItem($product);
+        $this->formPrice = $cartItem->getPrice();
+    }
+
+    /**
+     * Count cart item price.
+     *
+     * @param FixtureInterface $product
+     * @return void
+     */
+    protected function countCheckoutCartItemPrice(FixtureInterface $product)
+    {
+        /** @var CatalogProductSimple $product */
+        $checkoutData = $product->getCheckoutData();
+        $checkoutCartItem = isset($checkoutData['cartItem']) ? $checkoutData['cartItem'] : [];
         if (isset($checkoutCartItem['price'])) {
-            $fixturePrice = $checkoutCartItem['price'];
+            $this->fixturePrice = $checkoutCartItem['price'];
         }
-        $fixtureActualPrice = $fixturePrice;
+        $this->fixtureActualPrice = $this->fixturePrice;
+    }
 
+    /**
+     * Count custom options price.
+     *
+     * @param FixtureInterface $product
+     * @return void
+     */
+    protected function countCustomOptionsPrice(FixtureInterface $product)
+    {
+        /** @var CatalogProductSimple $product */
+        $customOptions = $product->getCustomOptions();
+        $checkoutData = $product->getCheckoutData();
+        $checkoutCustomOptions = isset($checkoutData['options']['custom_options'])
+            ? $checkoutData['options']['custom_options']
+            : [];
         foreach ($checkoutCustomOptions as $checkoutOption) {
             $attributeKey = str_replace('attribute_key_', '', $checkoutOption['title']);
             $optionKey = str_replace('option_key_', '', $checkoutOption['value']);
             $option = $customOptions[$attributeKey]['options'][$optionKey];
 
             if ('Fixed' == $option['price_type']) {
-                $fixtureActualPrice += $option['price'];
+                $this->fixtureActualPrice += $option['price'];
             } else {
-                $fixtureActualPrice += ($fixturePrice / 100) * $option['price'];
+                $this->fixtureActualPrice += ($this->fixturePrice / 100) * $option['price'];
             }
         }
-
-        \PHPUnit_Framework_Assert::assertEquals(
-            $fixtureActualPrice,
-            $formPrice,
-            'Product price in shopping cart is not correct.'
-        );
     }
 
     /**
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php
index e660b0ea05fab3e365f899374a9240e14bdd951c..2ccb804b073f90255f378a6e3ef6e8af5d427332 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Curl.php
@@ -413,12 +413,12 @@ class Curl extends AbstractCurl implements CatalogProductSimpleInterface
     {
         if (!empty($this->fields['product']['website_ids'])) {
             foreach ($this->fixture->getDataFieldConfig('website_ids')['source']->getWebsites() as $key => $website) {
-                $this->fields['product']['website_ids'][$key] = $website->getWebsiteId();
+                $this->fields['product']['extension_attributes']['website_ids'][$key] = $website->getWebsiteId();
             }
         } else {
             $website = \Magento\Mtf\ObjectManagerFactory::getObjectManager()
                 ->create(\Magento\Store\Test\Fixture\Website::class, ['dataset' => 'default']);
-            $this->fields['product']['website_ids'][] = $website->getWebsiteId();
+            $this->fields['product']['extension_attributes']['website_ids'][] = $website->getWebsiteId();
         }
     }
 
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Webapi.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Webapi.php
index 4ec372ab7163bb627bdf1353618f81231bed504d..4c3d344832f85f57d065ccccc01e44e1daf873b1 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Webapi.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Webapi.php
@@ -64,13 +64,6 @@ class Webapi extends AbstractWebApi implements CatalogProductSimpleInterface
         'custom_attributes'
     ];
 
-    /**
-     * Website Ids for current Product.
-     *
-     * @var array
-     */
-    private $websiteIds = [];
-
     /**
      * @constructor
      * @param DataInterface $configuration
@@ -102,8 +95,6 @@ class Webapi extends AbstractWebApi implements CatalogProductSimpleInterface
         $this->prepareData();
         $this->convertData();
 
-        //TODO: Change create and assign product to website flow using 1 request after MAGETWO-52812 delivery.
-
         /** @var CatalogProductSimple $fixture */
         $url = $_ENV['app_frontend_url'] . 'rest/all/V1/products';
         $this->webapiTransport->write($url, $this->fields, CurlInterface::POST);
@@ -116,110 +107,9 @@ class Webapi extends AbstractWebApi implements CatalogProductSimpleInterface
             throw new \Exception("Product creation by webapi handler was not successful! Response: {$encodedResponse}");
         }
 
-        $this->assignToWebsites($response);
-
         return $this->parseResponse($response);
     }
 
-    /**
-     * Assign appropriate Websites to Product and unset all other.
-     *
-     * @param array $product
-     * @return void
-     */
-    private function assignToWebsites($product)
-    {
-        $this->setWebsites($product);
-        $this->unsetWebsites($product);
-    }
-
-    /**
-     * Get all Websites.
-     *
-     * @return array
-     * @throws \Exception
-     */
-    private function getAllWebsites()
-    {
-        $url = $_ENV['app_frontend_url'] . 'rest/V1/store/websites';
-        $this->webapiTransport->write($url, [], CurlInterface::GET);
-        $encodedResponse = $this->webapiTransport->read();
-        $response = json_decode($encodedResponse, true);
-        $this->webapiTransport->close();
-
-        if (!isset($response[0]['id'])) {
-            $this->eventManager->dispatchEvent(['webapi_failed'], [$response]);
-            throw new \Exception(
-                "Attempt to get all Websites by webapi handler was not successful! Response: {$encodedResponse}"
-            );
-        }
-
-        return $response;
-    }
-
-    /**
-     * Set appropriate Websites to Product.
-     *
-     * @param array $product
-     * @return void
-     * @throws \Exception
-     */
-    private function setWebsites($product)
-    {
-        foreach ($this->websiteIds as $id) {
-            $url = $_ENV['app_frontend_url'] . 'rest/V1/products/' . $product['sku'] . '/websites';
-            $productWebsiteLink = ['productWebsiteLink' => ['website_id' => $id, 'sku' => $product['sku']]];
-            $this->webapiTransport->write($url, $productWebsiteLink, CurlInterface::POST);
-            $encodedResponse = $this->webapiTransport->read();
-            $response = json_decode($encodedResponse, true);
-            $this->webapiTransport->close();
-
-            if ($response !== true) {
-                $this->eventManager->dispatchEvent(['webapi_failed'], [$response]);
-                throw new \Exception(
-                    "Product addition to Website by webapi handler was not successful! Response: {$encodedResponse}"
-                );
-            }
-        }
-    }
-
-    /**
-     * Unset all Websites from Product except appropriate.
-     *
-     * @param array $product
-     * @return void
-     * @throws \Exception
-     */
-    private function unsetWebsites($product)
-    {
-        $allWebsites = $this->getAllWebsites();
-        $websiteIds = [];
-
-        foreach ($allWebsites as $website) {
-            if ($website['code'] == 'admin') {
-                continue;
-            }
-            $websiteIds[] = $website['id'];
-        }
-
-        $websiteIds = array_diff($websiteIds, $this->websiteIds);
-
-        foreach ($websiteIds as $id) {
-            $url = $_ENV['app_frontend_url'] . 'rest/V1/products/' . $product['sku'] . '/websites/' . $id;
-            $this->webapiTransport->write($url, [], CurlInterface::DELETE);
-            $encodedResponse = $this->webapiTransport->read();
-            $response = json_decode($encodedResponse, true);
-            $this->webapiTransport->close();
-
-            if ($response !== true) {
-                $this->eventManager->dispatchEvent(['webapi_failed'], [$response]);
-                throw new \Exception(
-                    "Product deduction from Website by webapi handler was not successful! Response: {$encodedResponse}"
-                );
-            }
-        }
-    }
-
     /**
      * Prepare data for creating product request.
      *
@@ -244,7 +134,6 @@ class Webapi extends AbstractWebApi implements CatalogProductSimpleInterface
     protected function convertData()
     {
         $fields = [];
-        $this->websiteIds = $this->fields['product']['website_ids'];
 
         unset($this->fields['product']['website_ids']);
         unset($this->fields['product']['checkout_data']);
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
index 23c13fb1206df158e3f9824651cba9cb6a1ff30e..ecd68593b08cc252e67a144ccd2a9610ac88f22d 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
@@ -1215,7 +1215,9 @@
                 <item name="dataset" xsi:type="string">taxable_goods</item>
             </field>
             <field name="website_ids" xsi:type="array">
-                <item name="0" xsi:type="string">Main Website</item>
+                <item name="0" xsi:type="array">
+                    <item name="dataset" xsi:type="string">default</item>
+                </item>
             </field>
             <field name="visibility" xsi:type="string">Catalog, Search</field>
             <field name="url_key" xsi:type="string">simple-product-%isolation%</field>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml
index 2b826e84b8e134197fac2a1279ba9bed7363c214..3252f0178e24195e724b45a17021d0528990070a 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml
@@ -75,6 +75,37 @@
             </field>
         </dataset>
 
+        <dataset name="percent_and_fixed_drop_down_options">
+            <field name="0" xsi:type="array">
+                <item name="title" xsi:type="string">custom option drop down %isolation%</item>
+                <item name="is_require" xsi:type="string">Yes</item>
+                <item name="type" xsi:type="string">Select/Drop-down</item>
+                <item name="options" xsi:type="array">
+                    <item name="0" xsi:type="array">
+                        <item name="title" xsi:type="string">30 bucks</item>
+                        <item name="price" xsi:type="string">30</item>
+                        <item name="price_type" xsi:type="string">Fixed</item>
+                        <item name="sku" xsi:type="string">sku_drop_down_row_1</item>
+                        <item name="sort_order" xsi:type="string">0</item>
+                    </item>
+                </item>
+            </field>
+            <field name="1" xsi:type="array">
+                <item name="title" xsi:type="string">custom option drop down 2 %isolation%</item>
+                <item name="is_require" xsi:type="string">Yes</item>
+                <item name="type" xsi:type="string">Select/Drop-down</item>
+                <item name="options" xsi:type="array">
+                    <item name="0" xsi:type="array">
+                        <item name="title" xsi:type="string">40 Percent</item>
+                        <item name="price" xsi:type="string">40</item>
+                        <item name="price_type" xsi:type="string">Percent</item>
+                        <item name="sku" xsi:type="string">sku_drop_down_row_1</item>
+                        <item name="sort_order" xsi:type="string">0</item>
+                    </item>
+                </item>
+            </field>
+        </dataset>
+
         <dataset name="drop_down_with_one_option_fixed_price">
             <field name="0" xsi:type="array">
                 <item name="title" xsi:type="string">custom option drop down %isolation%</item>
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml
index 63e232f3dac7215406275df395f8cfd0c5adb667..6a1f225bc9429e47b68ffb85bd06fc0443ebdbf9 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml
@@ -47,7 +47,7 @@
             <constraint name="Magento\Sales\Test\Constraint\AssertOrderButtonsAvailable" />
             <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" />
         </variation>
-        <variation name="OnePageCheckoutTestVariation3" summary="Checkout as UK guest with simple product">
+        <variation name="OnePageCheckoutTestVariation3" summary="Checkout as UK guest with simple product" ticketId="MAGETWO-42603">
             <data name="products/0" xsi:type="string">catalogProductSimple::default</data>
             <data name="customer/dataset" xsi:type="string">default</data>
             <data name="checkoutMethod" xsi:type="string">guest</data>
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Curl.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Curl.php
index 402aa6ba0d3184731d43ea3a858d97b42f127816..bf5d5944aa3da0a7093d5bbe33ea00897f3b5397 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Curl.php
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Curl.php
@@ -61,6 +61,24 @@ class Curl extends ProductCurl implements ConfigurableProductInterface
         return $data;
     }
 
+    /**
+     * Preparation of websites data.
+     *
+     * @return void
+     */
+    protected function prepareWebsites()
+    {
+        if (!empty($this->fields['product']['website_ids'])) {
+            foreach ($this->fixture->getDataFieldConfig('website_ids')['source']->getWebsites() as $key => $website) {
+                $this->fields['product']['website_ids'][$key] = $website->getWebsiteId();
+            }
+        } else {
+            $website = \Magento\Mtf\ObjectManagerFactory::getObjectManager()
+                ->create(\Magento\Store\Test\Fixture\Website::class, ['dataset' => 'default']);
+            $this->fields['product']['website_ids'][] = $website->getWebsiteId();
+        }
+    }
+
     /**
      * Preparation of attribute set data.
      *
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/CustomerForm.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/CustomerForm.xml
index 664f96cd4b42f9de8d7ffa4da458ba2a5ada0fc4..bb56a9edaf9a13d7b7fad3c2253e6cebdf5af59e 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/CustomerForm.xml
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/CustomerForm.xml
@@ -24,6 +24,9 @@
             <gender>
                 <input>select</input>
             </gender>
+            <dob>
+                <input>datepicker</input>
+            </dob>
         </fields>
     </account_information>
     <addresses>
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml
index 6997cca28fac0a1c25d3c75fecb75bd1e1182ed7..248b26561af3a568250a72e6beba60c73c38f50c 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml
@@ -27,7 +27,7 @@
             <data name="customer/data/lastname" xsi:type="string">Doe%isolation%</data>
             <data name="customer/data/suffix" xsi:type="string">S</data>
             <data name="customer/data/email" xsi:type="string">JohnDoe%isolation%@example.com</data>
-            <data name="customer/data/dob" xsi:type="string">Mar 16, 2004</data>
+            <data name="customer/data/dob" xsi:type="string">03/16/2004</data>
             <data name="customer/data/gender" xsi:type="string">Male</data>
             <constraint name="Magento\Customer\Test\Constraint\AssertCustomerSuccessSaveMessage" />
             <constraint name="Magento\Customer\Test\Constraint\AssertCustomerInGrid" />
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml
index ac63dcaf2805eac03fce22b9113e325c890a65b2..c2132672d900a65fe81b3f011266d036cd390e91 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.xml
@@ -16,7 +16,7 @@
             <data name="customer/data/lastname" xsi:type="string">Doe%isolation%</data>
             <data name="customer/data/suffix" xsi:type="string">_Suffix%isolation%</data>
             <data name="customer/data/email" xsi:type="string">JohnDoe%isolation%@example.com</data>
-            <data name="customer/data/dob" xsi:type="string">Aug 1, 1986</data>
+            <data name="customer/data/dob" xsi:type="string">08/01/1986</data>
             <data name="customer/data/taxvat" xsi:type="string">123456789001</data>
             <data name="customer/data/gender" xsi:type="string">Male</data>
             <constraint name="Magento\Customer\Test\Constraint\AssertCustomerSuccessSaveMessage" />
@@ -52,7 +52,7 @@
             <data name="customer/data/lastname" xsi:type="string">Doe%isolation%</data>
             <data name="customer/data/suffix" xsi:type="string">_JaneSuffix%isolation%</data>
             <data name="customer/data/email" xsi:type="string">Jane%isolation%@example.com</data>
-            <data name="customer/data/dob" xsi:type="string">Dec 1, 2000</data>
+            <data name="customer/data/dob" xsi:type="string">01/12/2000</data>
             <data name="customer/data/taxvat" xsi:type="string">987654321</data>
             <data name="customer/data/gender" xsi:type="string">Female</data>
             <data name="address/data/prefix" xsi:type="string">Prefix%isolation%_</data>
diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.xml b/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.xml
index 55c9bd16509c4382b1d4496d361e7d849c5b68e0..2589b105fa8c1ee9cbe6b548b102545bef5b0c7b 100644
--- a/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.xml
+++ b/dev/tests/functional/tests/app/Magento/Install/Test/Block/WebConfiguration.xml
@@ -13,7 +13,7 @@
         <admin />
         <keyOwn>
             <selector>[value="user"]</selector>
-            <input>checkbox</input>
+            <input>radiobutton</input>
         </keyOwn>
         <keyValue>
             <selector>[name="key"]</selector>
@@ -24,12 +24,12 @@
         </apacheRewrites>
         <httpsFront>
             <selector>[ng-model*="front"]</selector>
-            <input>checkbox</input>
+            <input>radiobutton</input>
         </httpsFront>
         <https />
         <httpsAdmin>
             <selector>[type="checkbox"][ng-model*="admin"]</selector>
-            <input>checkbox</input>
+            <input>radiobutton</input>
         </httpsAdmin>
     </fields>
 </mapping>
diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.xml b/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.xml
index b5db164511847745de9cc5aaac96532434a4bbd1..8cdf27b35a472cb8f5cff195c1a43fe6fae2673e 100644
--- a/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.xml
@@ -7,17 +7,15 @@
  -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd">
     <testCase name="Magento\Install\Test\TestCase\InstallTest" summary="[Web Setup][Auto] Install CE Magento via Web Interface" ticketId="MAGETWO-31431">
-        <variation name="InstallTestVariation1">
-            <data name="description" xsi:type="string">Install with custom admin path.</data>
+        <variation name="InstallTestVariation1" summary="Install with custom admin path">
             <data name="user/dataset" xsi:type="string">default</data>
             <data name="install/admin" xsi:type="string">custom</data>
             <constraint name="Magento\Install\Test\Constraint\AssertSuccessInstall" />
             <constraint name="Magento\User\Test\Constraint\AssertUserSuccessLogin" />
         </variation>
-        <variation name="InstallTestVariation2">
-            <data name="description" xsi:type="string">Install with custom encryption key and changed currency and locale.</data>
+        <variation name="InstallTestVariation2" summary="Install with custom encryption key and changed currency and locale">
             <data name="user/dataset" xsi:type="string">default</data>
-            <data name="install/keyOwn" xsi:type="string">Yes</data>
+            <data name="install/keyOwn" xsi:type="string">I want to use my own encryption key</data>
             <data name="install/keyValue" xsi:type="string">123123qa</data>
             <data name="install/storeLanguage" xsi:type="string">German (Germany)</data>
             <data name="install/storeCurrency" xsi:type="string">Euro (EUR)</data>
@@ -28,33 +26,29 @@
             <constraint name="Magento\User\Test\Constraint\AssertUserSuccessLogin" />
             <constraint name="Magento\Install\Test\Constraint\AssertCurrencySelected" />
         </variation>
-        <variation name="InstallTestVariation3">
-            <data name="description" xsi:type="string">Install with table prefix.</data>
+        <variation name="InstallTestVariation3" summary="Install with table prefix">
             <data name="user/dataset" xsi:type="string">default</data>
             <data name="install/dbTablePrefix" xsi:type="string">pref_</data>
             <data name="install/storeLanguage" xsi:type="string">Chinese (China)</data>
             <constraint name="Magento\Install\Test\Constraint\AssertSuccessInstall" />
             <constraint name="Magento\User\Test\Constraint\AssertUserSuccessLogin" />
         </variation>
-        <variation name="InstallTestVariation4">
-            <data name="description" xsi:type="string">Install with enabled url rewrites.</data>
+        <variation name="InstallTestVariation4" summary="Install with enabled url rewrites">
             <data name="user/dataset" xsi:type="string">default</data>
             <data name="install/apacheRewrites" xsi:type="string">Yes</data>
             <constraint name="Magento\Install\Test\Constraint\AssertSuccessInstall" />
             <constraint name="Magento\User\Test\Constraint\AssertUserSuccessLogin" />
             <constraint name="Magento\Install\Test\Constraint\AssertRewritesEnabled" />
         </variation>
-        <variation name="InstallTestVariation5">
-            <data name="description" xsi:type="string">Install with enabled secure urls.</data>
+        <variation name="InstallTestVariation5" summary="Install with enabled secure urls">
             <data name="user/dataset" xsi:type="string">default</data>
-            <data name="install/httpsFront" xsi:type="string">Yes</data>
-            <data name="install/httpsAdmin" xsi:type="string">Yes</data>
+            <data name="install/httpsFront" xsi:type="string">Use HTTPS for Magento Storefront</data>
+            <data name="install/httpsAdmin" xsi:type="string">Use HTTPS for Magento Admin</data>
             <constraint name="Magento\Install\Test\Constraint\AssertSuccessInstall" />
             <constraint name="Magento\User\Test\Constraint\AssertUserSuccessLogin" />
             <constraint name="Magento\Install\Test\Constraint\AssertSecureUrlEnabled" />
         </variation>
-        <variation name="InstallTestVariation6">
-            <data name="description" xsi:type="string">Install with default values.</data>
+        <variation name="InstallTestVariation6" summary="Install with default values">
             <data name="user/dataset" xsi:type="string">default</data>
             <constraint name="Magento\Install\Test\Constraint\AssertSuccessInstall" />
             <constraint name="Magento\User\Test\Constraint\AssertUserSuccessLogin" />
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php
index f05092745c7608ca1a83bdc54fba527d116e95cb..e3b01aa3af9a0dfa4517ad3fe4b527eec9d30ad0 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php
@@ -42,7 +42,7 @@ class PayflowPro extends Block
             '_payflow_required_enable_paypal_payflow',
         'Enable PayPal Credit' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_with_express_checkout_paypal' .
             '_payflow_required_enable_express_checkout_bml_payflow',
-        'Vault enabled' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_with_express_checkout_paypal_' .
+        'Vault Enabled' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_with_express_checkout_paypal_' .
             'payflow_required_payflowpro_cc_vault_active'
     ];
 
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php
index 709dc4b54b53f275b222a1cc2981bce88f7fb605..cd146aa8f809cf5de0cbddcb02be83a19e59928f 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php
@@ -42,7 +42,7 @@ class PaymentsPro extends Block
             '_payflow',
         'Enable PayPal Credit' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_payflow_required_enable_' .
             'express_checkout_bml_payflow',
-        'Vault enabled' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_payflow_required_payflowpro_cc_vault' .
+        'Vault Enabled' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_payflow_required_payflowpro_cc_vault' .
             '_active'
     ];
 
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPayflowProConfigStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPayflowProConfigStep.php
index a468fbde2f4d252997f1f84973063b397ea074b5..7e0c9d934161eb36d8b16454d8b263978cd6c21a 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPayflowProConfigStep.php
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPayflowProConfigStep.php
@@ -130,7 +130,7 @@ class CheckPayflowProConfigStep implements TestStepInterface
         $this->payflowProConfigBlock->enablePayflowPro();
         $this->assertFieldsAreActive->processAssert(
             $this->systemConfigEditSectionPayment,
-            [$enablers['Enable this Solution'], $enablers['Enable PayPal Credit'], $enablers['Vault enabled']]
+            [$enablers['Enable this Solution'], $enablers['Enable PayPal Credit'], $enablers['Vault Enabled']]
         );
         $this->assertFieldsAreEnabled->processAssert(
             $this->systemConfigEditSectionPayment,
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPaymentsProConfigStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPaymentsProConfigStep.php
index 2555eab030720c475f56aa28181607a0be452fac..4c3318d14f9611a7890e8621e29661cafc1ca620 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPaymentsProConfigStep.php
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPaymentsProConfigStep.php
@@ -130,7 +130,7 @@ class CheckPaymentsProConfigStep implements TestStepInterface
         $this->paymentsProConfigBlock->enablePaymentsPro();
         $this->assertFieldsAreActive->processAssert(
             $this->systemConfigEditSectionPayment,
-            [$enablers['Enable this Solution'], $enablers['Enable PayPal Credit'], $enablers['Vault enabled']]
+            [$enablers['Enable this Solution'], $enablers['Enable PayPal Credit'], $enablers['Vault Enabled']]
         );
         $this->assertFieldsAreEnabled->processAssert(
             $this->systemConfigEditSectionPayment,
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/Product/Grid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/Product/Grid.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f7cc54fe88cab5dca510a0682c1c8439040ddaa
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/Product/Grid.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Review\Test\Block\Adminhtml\Edit\Product;
+
+use Magento\Ui\Test\Block\Adminhtml\DataGrid;
+
+/**
+ * Review catalog product grid.
+ */
+class Grid extends DataGrid
+{
+    /**
+     * Grid filter selectors
+     *
+     * @var array
+     */
+    protected $filters = [
+        'title' => [
+            'selector' => 'input[name="title"]',
+        ],
+        'sku' => [
+            'selector' => 'input[name="sku"]',
+        ],
+    ];
+}
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php
index 3ba4369fb0fcc9f8d7d63b846577817579dd11ab..afadc1b0858ae072227cebbc0cd721b501182b22 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php
@@ -34,7 +34,7 @@ class RatingElement extends SimpleElement
      *
      * @var string
      */
-    protected $ratingByNumber = './/*[@id="rating_detail"]//*[contains(@class,"field-rating")][%d]';
+    protected $ratingByNumber = './/*[contains(@class,"field-rating")][%d]';
 
     /**
      * Set rating value
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Edit/Section/Reviews.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Edit/Section/Reviews.php
index 37ea3df90a89ffef811be2e6f885ca15b3e80976..5b45f54600ceb2ec0fec9847127146b3952317fa 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Edit/Section/Reviews.php
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Edit/Section/Reviews.php
@@ -23,12 +23,12 @@ class Reviews extends Section
     /**
      * Returns product reviews grid.
      *
-     * @return \Magento\Review\Test\Block\Adminhtml\Product\Grid
+     * @return \Magento\Review\Test\Block\Adminhtml\Edit\Product\Grid
      */
     public function getReviewsGrid()
     {
         return $this->blockFactory->create(
-            \Magento\Review\Test\Block\Adminhtml\Product\Grid::class,
+            \Magento\Review\Test\Block\Adminhtml\Edit\Product\Grid::class,
             ['element' => $this->_rootElement->find($this->reviews)]
         );
     }
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php
index 55060e7a85db92baba5c832d5c6805c687641907..e1aa3b9d5a9a57c46c05c58fa51c622f263ca899 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php
@@ -6,13 +6,20 @@
 
 namespace Magento\Review\Test\Block\Adminhtml\Product;
 
-use Magento\Ui\Test\Block\Adminhtml\DataGrid;
+use Magento\Backend\Test\Block\Widget\Grid as AbstractGrid;
 
 /**
  * Review catalog product grid.
  */
-class Grid extends DataGrid
+class Grid extends AbstractGrid
 {
+    /**
+     * First row selector
+     *
+     * @var string
+     */
+    protected $firstRowSelector = './/tbody/tr[1]';
+
     /**
      * Grid filter selectors
      *
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/ReviewForm.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/ReviewForm.xml
index 1832618a7da64a6122744586e63554805d2b394d..348cd3429149a73e490cff6c6d3a361d52c2a30d 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/ReviewForm.xml
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/ReviewForm.xml
@@ -20,7 +20,7 @@
             <input>textarea</input>
         </detail>
         <ratings>
-            <selector>#detailed_rating</selector>
+            <selector>#rating_detail</selector>
             <class>Magento\Review\Test\Block\Adminhtml\Edit\RatingElement</class>
         </ratings>
     </fields>
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/ReviewForm.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/ReviewForm.php
index 6bb20785adf91701ee63183764bcefeabef9415b..91ab33e5ca32102ab427dd55a839f11fea2f20ef 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/ReviewForm.php
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/ReviewForm.php
@@ -37,14 +37,14 @@ class ReviewForm extends AbstractForm
      *
      * @var string
      */
-    protected $rating = './/*[@id="%s_rating_label"]/span';
+    protected $rating = './/*[@id="%s_rating_label"]';
 
     /**
      * Selector for label of rating vote.
      *
      * @var string
      */
-    protected $ratingVoteLabel = './div[contains(@class,"vote")]/label[contains(@id,"_%d_label")]';
+    protected $ratingVoteLabel = './following-sibling::div[contains(@class,"vote")]/label[contains(@id,"_%d_label")]';
 
     /**
      * Submit review form.
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php
index aeeff3480e4a623c23f8491f19a180f2acbcab48..9130c5285848e2d04f5978403c23ae0b2278ff16 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php
@@ -109,13 +109,14 @@ class CreateProductReviewBackendEntityTest extends Injectable
     {
         // Precondition:
         $product = $review->getDataFieldConfig('entity_id')['source']->getEntity();
-        $filter = ['id' => $product->getId()];
+        $filter = ['sku' => $product->getSku()];
         $this->review = $review;
 
         // Steps:
         $this->reviewIndex->open();
         $this->reviewIndex->getReviewActions()->addNew();
-        $this->reviewEdit->getProductGrid()->searchAndOpen($filter);
+        $this->reviewEdit->getProductGrid()->search($filter);
+        $this->reviewEdit->getProductGrid()->openFirstRow();
         $this->reviewEdit->getReviewForm()->fill($this->review);
         $this->reviewEdit->getPageActions()->save();
 
diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SelectVersion.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SelectVersion.php
index 0ce9dd2867a13fe09cc24bfb11fe6dcd404a2522..437203e072e9626465f6ba9c2a44dd7e97551695 100644
--- a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SelectVersion.php
+++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SelectVersion.php
@@ -30,6 +30,13 @@ class SelectVersion extends Form
      */
     protected $firstField = '#selectVersion';
 
+    /**
+     * Show all versions checkbox
+     *
+     * @var string
+     */
+    private $showAllVersions = '#showUnstable';
+
     /**
      * Click on 'Next' button.
      *
@@ -50,9 +57,24 @@ class SelectVersion extends Form
     public function fill(FixtureInterface $fixture, SimpleElement $element = null)
     {
         $this->waitForElementVisible($this->firstField);
+        $this->chooseShowAllVersions();
+
         return parent::fill($fixture, $element);
     }
 
+    /**
+     * Show all versions include unstable
+     *
+     * @return void
+     */
+    private function chooseShowAllVersions()
+    {
+        $element = $this->_rootElement->find($this->showAllVersions, Locator::SELECTOR_CSS);
+        if ($element->isVisible()) {
+            $element->click();
+        }
+    }
+
     /**
      * Choose 'yes' for upgrade option called 'Other components'
      *
diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessMessage.php
index 7f7d17f60679c3ef1a04810505eaab0ad7533bf2..dcfb2922d5c787150487ecf95542ed9d24411b64 100644
--- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessMessage.php
+++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessMessage.php
@@ -23,7 +23,7 @@ class AssertSuccessMessage extends AbstractConstraint
      */
     public function processAssert(SetupWizard $setupWizard, $package)
     {
-        $message = "You upgraded:";
+        $message = "You upgraded";
         \PHPUnit_Framework_Assert::assertContains(
             $message,
             $setupWizard->getSuccessMessage()->getUpdaterStatus(),
diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php
index eae09d72a47b9eb635b7415c056616a1abf19576..3fc6f044f88521794f579aa653bacd6d87e44d14 100644
--- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php
+++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php
@@ -135,7 +135,7 @@ class DataGrid extends Grid
      *
      * @var string
      */
-    protected $sortLink = "//th[contains(@class, '%s')]/span[contains(text(), '%s')]";
+    protected $sortLink = './/div[@data-role="grid-wrapper"]//th[contains(@class, "%s")]/span[contains(text(), "%s")]';
 
     /**
      * Current page input.
diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/setup.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/setup.xml
index 6a5c6e5d904ddb2b9de92ab7f851f97ffad7db44..e1f1395bc132c892f884ceb170dd3ade6bdf525b 100644
--- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/setup.xml
+++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/setup.xml
@@ -11,5 +11,8 @@
         <allow>
             <module value="Magento_Setup"/>
         </allow>
+        <deny>
+            <class value="Magento\Setup\Test\TestCase\UpgradeSystemTest"/>
+        </deny>
     </rule>
 </config>
diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/upgrade.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/upgrade.xml
new file mode 100644
index 0000000000000000000000000000000000000000..71f50859db921163bf50a8f85d79e96c58f288a6
--- /dev/null
+++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/upgrade.xml
@@ -0,0 +1,15 @@
+<?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="../../../../../vendor/magento/mtf/Magento/Mtf/TestRunner/etc/testRunner.xsd">
+    <rule scope="testsuite">
+        <allow>
+            <class value="Magento\Setup\Test\TestCase\UpgradeSystemTest"/>
+        </allow>
+    </rule>
+</config>
\ No newline at end of file
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
index a1762a065ba8814b50964ec13be8a2a319e616e3..db5511bf9d8ff32be83947c691d063bd4d143205 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
@@ -14,6 +14,7 @@
  */
 namespace Magento\CatalogImportExport\Model\Import;
 
+use Magento\Catalog\Api\Data\ProductInterface;
 use Magento\Catalog\Api\ProductRepositoryInterface;
 use Magento\Catalog\Model\Category;
 use Magento\Framework\App\Bootstrap;
@@ -557,7 +558,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
     /**
      * @magentoDataIsolation enabled
      * @magentoDataFixture mediaImportImageFixture
-     *
+     * @magentoAppIsolation enabled
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function testSaveMediaImage()
@@ -732,6 +733,7 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
     /**
      * @magentoDataFixture Magento/Catalog/_files/products_with_multiselect_attribute.php
      * @magentoAppIsolation enabled
+     * @magentoDbIsolation enabled
      */
     public function testValidateInvalidMultiselectValues()
     {
@@ -1268,4 +1270,62 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase
             $this->assertEquals($manageStockUseConfig, $stockItem->getUseConfigManageStock());
         }
     }
+
+    /**
+     * @magentoDataFixture Magento/Store/_files/website.php
+     * @magentoDataFixture Magento/Store/_files/core_fixturestore.php
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     */
+    public function testProductWithMultipleStoresInDifferentBunches()
+    {
+        $products = [
+            'simple1',
+            'simple2',
+            'simple3'
+        ];
+
+        $importExportData = $this->getMockBuilder(\Magento\ImportExport\Helper\Data::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $importExportData->expects($this->atLeastOnce())
+            ->method('getBunchSize')
+            ->willReturn(1);
+        $this->_model = $this->objectManager->create(
+            \Magento\CatalogImportExport\Model\Import\Product::class,
+            ['importExportData' => $importExportData]
+        );
+
+        $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class);
+        $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+        $source = $this->objectManager->create(
+            \Magento\ImportExport\Model\Import\Source\Csv::class,
+            [
+                'file' => __DIR__ . '/_files/products_to_import_with_multiple_store.csv',
+                'directory' => $directory
+            ]
+        );
+        $errors = $this->_model->setParameters(
+            ['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, 'entity' => 'catalog_product']
+        )->setSource(
+            $source
+        )->validateData();
+
+        $this->assertTrue($errors->getErrorsCount() == 0);
+
+        $this->_model->importData();
+        $productCollection = $this->objectManager
+            ->create(\Magento\Catalog\Model\ResourceModel\Product\Collection::class);
+        $this->assertCount(3, $productCollection->getItems());
+        $actualProductSkus = array_map(
+            function(ProductInterface $item) {
+                return $item->getSku();
+            },
+            $productCollection->getItems()
+        );
+        $this->assertEquals(
+            $products,
+            array_values($actualProductSkus)
+        );
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_multiple_store.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_multiple_store.csv
new file mode 100644
index 0000000000000000000000000000000000000000..a4ad5adb7b0f4a5de7f0371c1002d0a305d07221
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_multiple_store.csv
@@ -0,0 +1,6 @@
+sku,product_type,store_view_code,name,price,attribute_set_code,categories
+simple1,simple,fixturestore,"simple 1",25,Default,"Default Category/Category 1"
+simple1,simple,,"simple 1",25,Default,"Default Category/Category 1"
+simple2,simple,fixturestore,"simple 2",34,Default,"Default Category/Category 1"
+simple2,simple,,"simple 2",34,Default,"Default Category/Category 1"
+simple3,simple,,"simple 3",58,Default,"Default Category/Category 1"
diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml b/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml
index 40bf9602edb12ad06b710839876d7af438b5a831..f9f8f1ffba91a55536c9d2221b68dc85b702e7f0 100644
--- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml
+++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml
@@ -115,7 +115,7 @@
                         </requires>
                     </field>
                     <field id="payflowpro_cc_vault_active" translate="label" type="select" sortOrder="22" showInDefault="1" showInWebsite="1" showInStore="0">
-                        <label>Vault enabled</label>
+                        <label>Vault Enabled</label>
                         <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                         <config_path>payment/payflowpro_cc_vault/active</config_path>
                         <attribute type="shared">1</attribute>
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice.php
new file mode 100644
index 0000000000000000000000000000000000000000..3dfa428c4aad48ee2bfbd8eadbc10fc516090d67
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+require 'order.php';
+
+$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+
+/** @var \Magento\Sales\Model\Order $order */
+$order = $objectManager->create(\Magento\Sales\Model\Order::class)
+    ->loadByIncrementId('100000001');
+
+/** @var \Magento\Sales\Model\Service\InvoiceService $invoiceService */
+$invoiceService = $objectManager->create(\Magento\Sales\Api\InvoiceManagementInterface::class);
+
+/** @var \Magento\Framework\DB\Transaction $transaction */
+$transaction = $objectManager->create(\Magento\Framework\DB\Transaction::class);
+
+$order->setData(
+    'base_to_global_rate',
+    1
+)->setData(
+    'base_to_order_rate',
+    1
+)->setData(
+    'shipping_amount',
+    20
+)->setData(
+    'base_shipping_amount',
+    20
+);
+
+$invoice = $invoiceService->prepareInvoice($order);
+$invoice->register();
+
+$order->setIsInProcess(true);
+
+$transaction->addObject($invoice)->addObject($order)->save();
diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Config/ValidatorTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/Config/ValidatorTest.php
index 16ca335beea7b1ada8928efd20396bce5225a1e6..bb899fa6af598e7550bca75a8b6203bf26a9dd3d 100644
--- a/dev/tests/integration/testsuite/Magento/Theme/Model/Config/ValidatorTest.php
+++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Config/ValidatorTest.php
@@ -12,7 +12,7 @@ use Magento\Email\Model\Template;
  */
 class ValidatorTest extends \PHPUnit_Framework_TestCase
 {
-    const TEMPLATE_CODE = 'fixture';
+    const TEMPLATE_CODE = 'email_exception_fixture';
 
     /**
      * @var \Magento\Theme\Model\Design\Config\Validator
@@ -44,7 +44,9 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
 
         $this->templateModel = $objectManager->create(\Magento\Email\Model\Template::class);
         $this->templateModel->load(self::TEMPLATE_CODE, 'template_code');
-
+        $this->templateFactoryMock->expects($this->once())
+            ->method("create")
+            ->willReturn($this->templateModel);
         $this->model = $objectManager->create(
             \Magento\Theme\Model\Design\Config\Validator::class,
             [ 'templateFactory' => $this->templateFactoryMock ]
@@ -58,9 +60,9 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
      */
     public function testValidateHasRecursiveReference()
     {
-        $this->templateFactoryMock->expects($this->once())
-            ->method("create")
-            ->willReturn($this->templateModel);
+        if (!$this->templateModel->getId()) {
+            $this->fail('Cannot load Template model');
+        }
 
         $fieldConfig = [
             'path' => 'design/email/header_template',
@@ -90,7 +92,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
             ->willReturn([$designElementMock]);
         $designElementMock->expects($this->any())->method('getFieldConfig')->willReturn($fieldConfig);
         $designElementMock->expects($this->once())->method('getPath')->willReturn($fieldConfig['path']);
-        $designElementMock->expects($this->once())->method('getValue')->willReturn(1);
+        $designElementMock->expects($this->once())->method('getValue')->willReturn($this->templateModel->getId());
 
         $this->model->validate($designConfigMock);
     }
@@ -132,7 +134,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
             ->willReturn([$designElementMock]);
         $designElementMock->expects($this->any())->method('getFieldConfig')->willReturn($fieldConfig);
         $designElementMock->expects($this->once())->method('getPath')->willReturn($fieldConfig['path']);
-        $designElementMock->expects($this->once())->method('getValue')->willReturn(1);
+        $designElementMock->expects($this->once())->method('getValue')->willReturn($this->templateModel->getId());
 
         $this->model->validate($designConfigMock);
     }
diff --git a/lib/internal/Magento/Framework/View/Asset/NotationResolver/Variable.php b/lib/internal/Magento/Framework/View/Asset/NotationResolver/Variable.php
index 59108ea0f5c427acfe367344fbfe7b6f9dcdcfaf..4e6bba487a1b7388f49483e43049892660836b14 100644
--- a/lib/internal/Magento/Framework/View/Asset/NotationResolver/Variable.php
+++ b/lib/internal/Magento/Framework/View/Asset/NotationResolver/Variable.php
@@ -58,18 +58,21 @@ class Variable
     }
 
     /**
-     * Retrieves the value of a given placeholder
+     * Process placeholder
      *
      * @param string $placeholder
      * @return string
      */
     public function getPlaceholderValue($placeholder)
     {
+        /** @var \Magento\Framework\View\Asset\File\FallbackContext $context */
         $context = $this->assetRepo->getStaticViewFileContext();
 
         switch ($placeholder) {
             case self::VAR_BASE_URL_PATH:
-                return $context->getBaseUrl() . $context->getPath();
+                return '{{' . self::VAR_BASE_URL_PATH . '}}' . $context->getAreaCode() .
+                    ($context->getThemePath() ? '/' . $context->getThemePath() . '/' : '') .
+                    '{{locale}}';
             default:
                 return '';
         }
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/NotationResolver/VariableTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/NotationResolver/VariableTest.php
index 77b81faf359aa316efb6415d3f2f506732d70169..b4bda4a93dfd51140e6cde6f6bf8e7fab5119b5a 100644
--- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/NotationResolver/VariableTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/NotationResolver/VariableTest.php
@@ -6,43 +6,51 @@
 
 namespace Magento\Framework\View\Test\Unit\Asset\NotationResolver;
 
-use Magento\Framework\App\Filesystem\DirectoryList;
-use Magento\Framework\View\Asset\NotationResolver;
+use Magento\Framework\UrlInterface;
+use Magento\Framework\View\Asset\File\FallbackContext;
+use Magento\Framework\View\Asset\NotationResolver\Variable;
+use Magento\Framework\View\Asset\Repository;
 
 class VariableTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Framework\View\Asset\File\Context|\PHPUnit_Framework_MockObject_MockObject
+     * @var FallbackContext|\PHPUnit_Framework_MockObject_MockObject
      */
     private $context;
 
     /**
-     * @var \Magento\Framework\View\Asset\Repository|\PHPUnit_Framework_MockObject_MockObject
+     * @var Repository|\PHPUnit_Framework_MockObject_MockObject
      */
     private $assetRepo;
 
     /**
-     * @var \Magento\Framework\View\Asset\NotationResolver\Variable
+     * @var Variable
      */
     private $object;
 
     protected function setUp()
     {
-        $baseUrl = 'http://example.com/pub/static/';
-        $path = 'frontend/Magento/blank/en_US';
+        $area = 'frontend';
+        $themePath = 'Magento/blank';
 
-        $this->context = $this->getMock(
-            \Magento\Framework\View\Asset\File\Context::class,
-            null,
-            [$baseUrl, DirectoryList::STATIC_VIEW, $path]
-        );
+        $this->context = $this->getMockBuilder(FallbackContext::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->context->expects($this->once())
+            ->method('getAreaCode')
+            ->willReturn($area);
+        $this->context->expects($this->exactly(2))
+            ->method('getThemePath')
+            ->willReturn($themePath);
 
-        $this->assetRepo = $this->getMock(\Magento\Framework\View\Asset\Repository::class, [], [], '', false);
+        $this->assetRepo = $this->getMockBuilder(Repository::class)
+            ->disableOriginalConstructor()
+            ->getMock();
         $this->assetRepo->expects($this->any())
             ->method('getStaticViewFileContext')
             ->will($this->returnValue($this->context));
 
-        $this->object = new \Magento\Framework\View\Asset\NotationResolver\Variable($this->assetRepo);
+        $this->object = new Variable($this->assetRepo);
     }
 
     /**
@@ -61,7 +69,7 @@ class VariableTest extends \PHPUnit_Framework_TestCase
     public function convertVariableNotationDataProvider()
     {
         return [
-            ['{{base_url_path}}/file.ext', 'http://example.com/pub/static/frontend/Magento/blank/en_US/file.ext'],
+            ['{{base_url_path}}/file.ext', '{{base_url_path}}frontend/Magento/blank/{{locale}}/file.ext'],
         ];
     }
 }
diff --git a/setup/pub/magento/setup/updater-success.js b/setup/pub/magento/setup/updater-success.js
index d2e98394251c8cc5233e2852a25fbc71b00890a3..36e58958ed6911949ad0852b9f3b1d87f57ce8ca 100644
--- a/setup/pub/magento/setup/updater-success.js
+++ b/setup/pub/magento/setup/updater-success.js
@@ -8,8 +8,16 @@ angular.module('updater-success', ['ngStorage'])
     .controller('updaterSuccessController', ['$scope', '$state', '$localStorage', '$window', 'navigationService', function ($scope, $state, $localStorage, $window, navigationService) {
         if ($localStorage.successPageAction) {
             $scope.successPageAction = $localStorage.successPageAction;
-            $scope.successPageActionMessage = $scope.successPageAction +
-                ($scope.endsWith($scope.successPageAction, 'e')  ? 'd' : 'ed');
+            switch (true) {
+                case $scope.endsWith($scope.successPageAction, 'd'):
+                    $scope.successPageActionMessage = $scope.successPageAction;
+                    break;
+                case $scope.endsWith($scope.successPageAction, 'e'):
+                    $scope.successPageActionMessage = $scope.successPageAction + 'd';
+                    break;
+                default:
+                    $scope.successPageActionMessage = $scope.successPageAction + 'ed';
+            }
         }
         if ($localStorage.packages) {
             $scope.packages = $localStorage.packages;
diff --git a/setup/pub/magento/setup/web-configuration.js b/setup/pub/magento/setup/web-configuration.js
index 164ce5ba63c419bfb41b30b9ff46f543dd60ad56..03a0fc7845dda90225d3be867f4bf9ddd1621f63 100644
--- a/setup/pub/magento/setup/web-configuration.js
+++ b/setup/pub/magento/setup/web-configuration.js
@@ -68,12 +68,12 @@ angular.module('web-configuration', ['ngStorage'])
 
         $scope.$watch('config.address.base_url', function() {
             if (angular.equals($scope.config.https.text, '') || angular.isUndefined($scope.config.https.text)) {
-                $scope.config.https.text = $scope.config.address.base_url.replace('http', 'https');
+                $scope.config.https.text = $scope.config.address.base_url.replace('http://', 'https://');
             }
         });
 
         $scope.populateHttps = function() {
-            $scope.config.https.text = $scope.config.address.base_url.replace('http', 'https');
+            $scope.config.https.text = $scope.config.address.base_url.replace('http://', 'https://');
         };
 
         $scope.showEncryptKey = function() {
diff --git a/setup/src/Magento/Setup/Module/Setup.php b/setup/src/Magento/Setup/Module/Setup.php
index 39fa5cbda13adb4c88ed30bc377b26efae26b4de..e805306e26ebf93704bc2ecb2990ead6b64bf09e 100644
--- a/setup/src/Magento/Setup/Module/Setup.php
+++ b/setup/src/Magento/Setup/Module/Setup.php
@@ -25,7 +25,7 @@ class Setup extends \Magento\Framework\Module\Setup implements SchemaSetupInterf
         $indexType = '',
         $connectionName = ResourceConnection::DEFAULT_CONNECTION
     ) {
-        return $this->getConnection($connectionName)->getIndexName($tableName, $fields, $indexType);
+        return $this->getConnection($connectionName)->getIndexName($this->getTable($tableName), $fields, $indexType);
     }
 
     /**
@@ -46,7 +46,7 @@ class Setup extends \Magento\Framework\Module\Setup implements SchemaSetupInterf
         $connectionName = ResourceConnection::DEFAULT_CONNECTION
     ) {
         return $this->getConnection($connectionName)->getForeignKeyName(
-            $priTableName,
+            $this->getTable($priTableName),
             $priColumnName,
             $refTableName,
             $refColumnName
diff --git a/setup/src/Magento/Setup/Test/Unit/Module/SetupTest.php b/setup/src/Magento/Setup/Test/Unit/Module/SetupTest.php
index 9a75c0a3d4bf307ae19152a8fe923f3d85594fa3..d97356cb1ff7f7e12d248fa82910a507b617d0b8 100644
--- a/setup/src/Magento/Setup/Test/Unit/Module/SetupTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/SetupTest.php
@@ -6,7 +6,8 @@
 
 namespace Magento\Setup\Test\Unit\Module;
 
-use \Magento\Setup\Module\Setup;
+use Magento\Framework\App\ResourceConnection;
+use Magento\Setup\Module\Setup;
 
 class SetupTest extends \PHPUnit_Framework_TestCase
 {
@@ -22,19 +23,24 @@ class SetupTest extends \PHPUnit_Framework_TestCase
      */
     private $setup;
 
+    /**
+     * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resourceModelMock;
+
     protected function setUp()
     {
-        $resourceModel = $this->getMock(\Magento\Framework\App\ResourceConnection::class, [], [], '', false);
+        $this->resourceModelMock = $this->getMock(ResourceConnection::class, [], [], '', false);
         $this->connection = $this->getMockForAbstractClass(\Magento\Framework\DB\Adapter\AdapterInterface::class);
-        $resourceModel->expects($this->any())
+        $this->resourceModelMock->expects($this->any())
             ->method('getConnection')
             ->with(self::CONNECTION_NAME)
             ->will($this->returnValue($this->connection));
-        $resourceModel->expects($this->any())
+        $this->resourceModelMock->expects($this->any())
             ->method('getConnectionByName')
-            ->with(\Magento\Framework\App\ResourceConnection::DEFAULT_CONNECTION)
+            ->with(ResourceConnection::DEFAULT_CONNECTION)
             ->willReturn($this->connection);
-        $this->setup = new Setup($resourceModel, self::CONNECTION_NAME);
+        $this->setup = new Setup($this->resourceModelMock, self::CONNECTION_NAME);
     }
 
     public function testGetIdxName()
@@ -44,6 +50,11 @@ class SetupTest extends \PHPUnit_Framework_TestCase
         $indexType = 'index_type';
         $expectedIdxName = 'idxName';
 
+        $this->resourceModelMock->expects($this->once())
+            ->method('getTableName')
+            ->with($tableName)
+            ->will($this->returnValue($tableName));
+
         $this->connection->expects($this->once())
             ->method('getIndexName')
             ->with($tableName, $fields, $indexType)
@@ -59,6 +70,11 @@ class SetupTest extends \PHPUnit_Framework_TestCase
         $columnName = 'columnName';
         $refColumnName = 'refColumnName';
 
+        $this->resourceModelMock->expects($this->once())
+            ->method('getTableName')
+            ->with($tableName)
+            ->will($this->returnValue($tableName));
+
         $this->connection->expects($this->once())
             ->method('getForeignKeyName')
             ->with($tableName, $columnName, $refTable, $refColumnName)
diff --git a/setup/view/magento/setup/web-configuration.phtml b/setup/view/magento/setup/web-configuration.phtml
index d2097f78527b5adaa69a09d471cb70aa21663468..35aa19484ed53f39bf37ae0e90e7b76c7f5efe87 100644
--- a/setup/view/magento/setup/web-configuration.phtml
+++ b/setup/view/magento/setup/web-configuration.phtml
@@ -68,13 +68,17 @@ $hints = [
                 ng-init="config.address.auto_base_url = '<?php echo $this->autoBaseUrl ?>'; fillBaseURL();"
                 ng-blur="addSlash()"
                 ng-change="populateHttps()"
+                ng-pattern="/^(https?:\/\/).*$/"
                 tooltip-placement="right"
                 tooltip-html-unsafe="<?php echo $hints['base_url']; ?>"
                 tooltip-trigger="focus"
                 tooltip-append-to-body="true"
                 >
             <div class="error-container">
-                <span ng-show="webconfig.base_url.$error.required || webconfig.base_url.$error.url">
+                <span ng-show="!webconfig.base_url.valid
+                                || webconfig.base_url.$error.required
+                                || webconfig.base_url.$error.url"
+                >
                     Please enter a valid base URL path. (ex: http://www.example.com/)
                 </span>
             </div>
@@ -189,10 +193,16 @@ $hints = [
                     ng-class="{'invalid': webconfig.https.$invalid && webconfig.submitted}"
                     ng-if="config.https.front || config.https.admin"
                     ng-focus=""
+                    ng-pattern="/^(https?:\/\/).*$/"
                     required
                     >
                 <div class="error-container">
-                    <span ng-show="webconfig.https.$error.required || webconfig.https.$error.url">Please enter a valid HTTPS base URL path. (ex: https://www.example.com/)</span>
+                    <span ng-show="!webconfig.https.$error.valid
+                                    || webconfig.https.$error.required
+                                    || webconfig.https.$error.url"
+                    >
+                        Please enter a valid HTTPS base URL path. (ex: https://www.example.com/)
+                    </span>
                 </div>
             </div>
         </div>